diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..56be9c4 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "core/twopc/circuits"] + path = core/twopc/circuits + url = https://github.com/tlsnotary/circuits diff --git a/README b/README index 8abad2e..ad082c9 100644 --- a/README +++ b/README @@ -1,22 +1,15 @@ ----------------------------------------------------------------- -UPDATE: Jul 2021 -A flaw in PageSigner has been brought to our attention which allows to create forged proofs under certain conditions. -We are working on a mitigation. +PageSigner - a cryptographically secure webpage screenshot tool. -Read more here: -https://github.com/tlsnotary/pagesigner/issues/46 ----------------------------------------------------------------- +PageSigner is a Chromium extension implementing a client for the TLSNotary protocol. + +You can install PageSigner from Chrome webstore: + +https://chrome.google.com/webstore/detail/pagesigner/abblaaeblmamacadkdmnejjikbdkemcj -PageSigner works with many Chromium-based browsers (e.g. Chromium, Vivaldi, Brave, Google Chrome) +Or you can install it by cloning this repo with: -You can load PageSigner from the source files of this repo this way: - -1. go to chrome://extensions and Enable "Developer mode" - -2. Click "Load unpacked" - -3. Navigate inside pagesigner's top folder and click Open. - ------ -Firefox addon creation is not supported anymore due to missing API in Firefox. +- git clone --recurse-submodules https://github.com/tlsnotary/pagesigner +- go to chrome://extensions and Enable "Developer mode" +- Click "Load unpacked" +- Navigate inside pagesigner's top folder and click Open. diff --git a/background.html b/background.html new file mode 100644 index 0000000..1a7a22f --- /dev/null +++ b/background.html @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/core/FirstTimeSetup.js b/core/FirstTimeSetup.js new file mode 100644 index 0000000..bff5ea3 --- /dev/null +++ b/core/FirstTimeSetup.js @@ -0,0 +1,144 @@ +import {wait} from './utils.js'; + +// class FakeFS imitates node.js's fs.readFileSync() by +// reading the files in advance and outputting their content when readFileSync() is called +class FakeFS{ + constructor(){ + this.fileList = {}; // {fileName: } + } + + // on init we read all .casm and .txt files in core/twopc/circuits + async init(){ + const that = this; + await new Promise(function(resolve) { + chrome.runtime.getPackageDirectoryEntry(function(root){ + root.getDirectory('core/twopc/circuits', {create: false}, function(dir) { + dir.createReader().readEntries(async function(results) { + for (let i=0; i < results.length; i+=1){ + const e = results[i]; + if (e.name.endsWith('.casm') || e.name.endsWith('.txt')){ + const url = chrome.extension.getURL('core/twopc/circuits/'+e.name); + const resp = await fetch(url); + const text = await resp.text(); + that.fileList[e.name] = text; + } + } + resolve(); + }); + }); + }); + }); + } + + // feed back all data read in init() + // eslint-disable-next-line no-unused-vars + readFileSync(path, _unused){ + return this.fileList[path]; + } +} + + +// FirstTimeSetup.start() is invoked once on first install. It assembles the circuits, +// serializes them into a compact binary format and stores them in the browser cache. +// All future invocations of Pagesigner use these serialized cached circuits. +export class FirstTimeSetup{ + async start(pm){ + const worker = new Worker(chrome.extension.getURL('core/twopc/webWorkers/serializeCircuits.js')); + console.log('parsing circuits, this is done only once on first launch and will take ~30 secs'); + console.time('parsing raw circuits'); + const obj = {}; + const oldfs = window['fs']; + window['fs'] = new FakeFS(); + await window['fs'].init(); + // start from the last circuits in order to give the user a quicker initial update + for (let n=1; n < 7; n++){ + const i = 7-n; + const text = CASM.parseAndAssemble('c'+i+'.casm'); + const newobj = await new Promise(function(resolve) { + worker.onmessage = function(event) { + let newobj = event.data.obj; + newobj['gatesBlob'] = new Uint8Array(event.data.blob); + resolve(newobj); + }; + worker.postMessage({'text': text}); + }); + obj[i] = newobj; + pm.update('first_time', {'current': n, 'total': 6}); + await wait(100); // make sure update reaches popup + } + window['fs'] = oldfs; + console.timeEnd('parsing raw circuits'); + return obj; + } + + parseCircuitFirstTime(text){ + const obj = {}; + // we don't do any sanity/formatting checks because the circuits + // were output by casm.js and have a well-defined structure + const rows = text.split('\n'); + obj['gatesCount'] = Number(rows[0].split(' ')[0]); + console.log('obj[\'gatesCount\']', obj['gatesCount']); + obj['wiresCount'] = Number(rows[0].split(' ')[1]); + obj['notaryInputSize'] = Number(rows[1].split(' ')[1]); + obj['clientInputSize'] = Number(rows[1].split(' ')[2]); + obj['outputSize'] = Number(rows[2].split(' ')[1]); + + // each gate is serialized as + // 1 byte: gate type XOR==0 AND==1 INV==2 + // 3 bytes: 1st input wire number + // 3 bytes: 2nd input wire number + // 3 bytes: output wire number + const gateByteSize = 10; + const opBytes = {'XOR': 0, 'AND': 1, 'INV': 2}; + // first 3 rows are not gates but metadata + const blob = new Uint8Array((rows.length-3)*gateByteSize); + let blobOffset = 0; + let andCount = 0; + for (let i=0; i < (rows.length-3); i++){ + const gate = rows[3+i]; + const tokens = gate.split(' '); + const op = tokens[tokens.length-1]; + const opByte = opBytes[op]; + blob.set([opByte], blobOffset); + blobOffset+=1; + if (op === 'XOR' || op === 'AND'){ + const in1 = this.intToThreeBytes(tokens[tokens.length-4]); + const in2 = this.intToThreeBytes(tokens[tokens.length-3]); + const out = this.intToThreeBytes(tokens[tokens.length-2]); + blob.set(in1, blobOffset); + blobOffset+=3; + blob.set(in2, blobOffset); + blobOffset+=3; + blob.set(out, blobOffset); + blobOffset+=3; + if (op == 'AND'){ + andCount+=1; + } + } + else if (op === 'INV'){ + const in1 = this.intToThreeBytes(tokens[tokens.length-3]); + const out = this.intToThreeBytes(tokens[tokens.length-2]); + blob.set(in1, blobOffset); + blobOffset+=3; + blob.set([0,0,0], blobOffset); + blobOffset+=3; + blob.set(out, blobOffset); + blobOffset+=3; + } + else { + throw('unknown op'); + } + } + obj['andGateCount'] = andCount; + obj['gatesBlob'] = blob; + return obj; + } + + intToThreeBytes(i){ + const byteArray = Array(3); + byteArray[0] = (i >> 16) & 0xFF; + byteArray[1] = (i >> 8) & 0xFF; + byteArray[2] = i & 0xFF; + return byteArray; + } +} \ No newline at end of file diff --git a/core/Main.js b/core/Main.js new file mode 100644 index 0000000..0d5e7eb --- /dev/null +++ b/core/Main.js @@ -0,0 +1,1073 @@ +/* eslint-disable no-import-assign */ +/* eslint-disable no-case-declarations */ +import {parse_certs, verifyChain, checkCertSubjName, getCommonName, getAltNames} from './verifychain.js'; +import {ba2str, b64decode, concatTA, int2ba, sha256, b64encode, str2ba, verifySig, assert, + ba2int, getTime, dechunk_http, gunzip_http, xor, eq, wait, AESECBencrypt, wildcardTest, + pubkeyPEM2raw, ba2hex} from './utils.js'; +import {getPref, getSessionBlob, getSession, getAllSessions, saveNewSession as saveNewSession, init_db, + addNewPreference, setPref, renameSession, deleteSession} from './indexeddb.js'; +import {global} from './globals.js'; +import {Socket} from './Socket.js'; +import {TLS, getExpandedKeys, decrypt_tls_responseV6} from './TLS.js'; +import {verify_oracle as verifyNotary, getURLFetcherDoc} from './oracles.js'; +import {TLSNotarySession} from './TLSNotarySession.js'; +import {ProgressMonitor} from './ProgressMonitor.js'; +import {FirstTimeSetup} from './FirstTimeSetup.js'; + +class Main{ + constructor(){ + this.messageListener; + this.notarization_in_progress = false; + this.isFirstTimeSetupNeeded = false; + this.waiting_for_click = false; + // popupError will be set to non-null when there is some error message that must be shown + // via the popup + this.popupError = null; + // tabid set to 0 is a sign that this is the main window when querying with .getViews() + this.tabid = 0; + // pendingAction is Firefox only: the action which must be taken as soon as the user allows + // access to the website (either notarize or notarizeAfter) + this.pendingAction = null; + // trustedOracle is an object {'IP':, 'pubkeyPEM':} + // describing the oracle server which was verified and can be used for notarization. + this.trustedOracle = null; + this.is_chrome = window.navigator.userAgent.match('Chrome') ? true : false; + this.is_firefox = window.navigator.userAgent.match('Firefox') ? true : false; + this.is_edge = window.navigator.userAgent.match('Edg') ? true : false; + this.is_opera = window.navigator.userAgent.match('OPR') ? true : false; + // pm is the only instance of ProgressMonitor that is reused between + // notarization sesions + this.pm = new ProgressMonitor(); + // trustedOracleReady will be set to true after we performed AWS HTTP queries + // and verified that an oracle is trusted (we verify only once) + this.trustedOracleReady = false; + } + + async main() { + // perform browser-specific init first + if (this.is_edge || this.is_firefox || this.is_opera){ + global.usePythonBackend = true; + } + if (this.is_firefox){ + // Firefox asks user for permission to access the current website. + // Listen when the permission was given and run the pending action. + // This way user doesnt have to click notarize->allow->notarize + const listener = function(permissions){ + if (permissions.origins.length != 1) { + // unknown permission granted + return; + } + if (this.pendingAction == 'notarize'){ + this.prepareNotarizing(false); + } + else if (this.pendingAction == 'notarizeAfter'){ + this.prepareNotarizing(true); + } + }; + browser.permissions.onAdded.addListener(listener); + } + + // browser-agnostic init + const that = this; + this.messageListener = chrome.runtime.onMessage.addListener(function(data) { + // processMessages is the main entrypoint for all extension's logic + that.processMessages(data); + }); + await init_db(); + + // Some preferences may not exist if we are upgrading from + // a previous PageSigner version. Create the preferences. + if (await getPref('firstTimeInitCompleted') === null){ + await addNewPreference('firstTimeInitCompleted', false); + await addNewPreference('parsedCircuits', null); + } + if (await getPref('trustedOracle') === null){ + await addNewPreference('trustedOracle', {}); + } + await parse_certs(); + if (global.useNotaryNoSandbox){ + await this.queryNotaryNoSandbox(global.defaultNotaryIP); + return; + } + this.trustedOracle = await getPref('trustedOracle'); + if (Object.keys(this.trustedOracle).length !== 0){ + if (await this.pingNotary(this.trustedOracle.IP) !== true) { + await this.tryBackupNotary(this.trustedOracle.IP); + } + else { + this.trustedOracleReady = true; + } + return; + } + // on first launch trustedOracle is not set, verify the default one asynchronously + if (await this.pingNotary(global.defaultNotaryIP) !== true){ + await this.tryBackupNotary(global.defaultNotaryIP); + return; + } + // notary is online + const URLFetcherDoc = await getURLFetcherDoc(global.defaultNotaryIP); + const trustedPubkeyPEM = await verifyNotary(URLFetcherDoc); + assert(trustedPubkeyPEM != undefined); + // verification was successful + const obj = { + 'IP': global.defaultNotaryIP, + 'pubkeyPEM': trustedPubkeyPEM, + 'URLFetcherDoc': URLFetcherDoc + }; + await setPref('trustedOracle', obj); + that.trustedOracle = obj; + that.trustedOracleReady = true; + } + + async queryNotaryNoSandbox(IP){ + // just fetch the pubkey and trust it + const resp = await fetch('http://'+IP+':' + global.defaultNotaryPort + '/getPubKey', { + method: 'POST', + mode: 'cors', + cache: 'no-store', + }); + const trustedPubkeyPEM = await resp.text(); + const obj = { + 'IP': IP, + 'pubkeyPEM': trustedPubkeyPEM, + }; + await setPref('trustedOracle', obj); + this.trustedOracle = obj; + this.trustedOracleReady = true; + } + + // pingNotary returns true if notary's IP address is reachable + async pingNotary(IP){ + // ping the notary, it should respond with 404 not found + const fProm = fetch('http://'+IP+':'+ global.defaultNotaryPort + '/ping', { + mode: 'no-cors' + }); + const out = await Promise.race([fProm, wait(5000)]) + .catch(err => { + // fetch got 404; do nothing, just prevent exception from propagating + }); + if (out === 'wait'){ + console.log('Notary is unreachable at IP: ', IP); + return false; + } + return true; + } + + // tryBackupNotary tries to use a backup notary. It checks that the backup notary + // is not the same as failedNotaryIP + async tryBackupNotary(failedNotaryIP){ + const resp = await fetch(global.backupUrl); + const backupIP = await resp.text(); + if (backupIP === failedNotaryIP){ + throw('Notary is unreachable. Please let the Pagesigner devs know about this.'); + } + if (this.pingNotary(backupIP) !== true){ + console.log('Backup notary is unreachable.'); + throw('Notary is unreachable. Please let the Pagesigner devs know about this.'); + } + const URLFetcherDoc = await getURLFetcherDoc(backupIP); + const trustedPubkeyPEM = await verifyNotary(URLFetcherDoc); + assert(trustedPubkeyPEM != undefined); + const obj = { + 'IP': backupIP, + 'pubkeyPEM': trustedPubkeyPEM, + 'URLFetcherDoc': URLFetcherDoc + }; + console.log('backup oracle verified'); + await setPref('trustedOracle', obj); + this.trustedOracle = obj; + this.trustedOracleReady = true; + } + + + openChromeExtensions(){ + chrome.tabs.query({url: 'chrome://extensions/*'}, + function(tabs) { + if (tabs.length == 0) { + chrome.tabs.create({url: 'chrome://extensions'}); + return; + } + chrome.tabs.update(tabs[0].id, {active: true}); + }); + } + + + // Pagesigner's popup has been clicked + async popupProcess(){ + if (this.notarization_in_progress) { + chrome.runtime.sendMessage({ + destination: 'popup', + message: 'notarization_in_progress', + firstTime: this.isFirstTimeSetupNeeded + }); + return; + } + if (this.waiting_for_click) { + chrome.runtime.sendMessage({ + destination: 'popup', + message: 'waiting_for_click' + }); + return; + } + // else{} the checks below are only for Chrome + // probe a non-existent port, if reject()ed with undefined, then the helper app is not running + try{ + const dummySock = new Socket('127.0.0.1', -1); + dummySock.connectTimeout = 200; // 200 ms + await dummySock.connect(); + } + catch(error){ + if (error == undefined || error == 'connection error'){ + chrome.runtime.sendMessage({ + destination: 'popup', + message: 'app_not_installed' + }); + return; + } + } + if (this.popupError) { + chrome.runtime.sendMessage({ + destination: 'popup', + message: 'popup error', + data: this.popupError + }); + this.popupError = null; + this.loadDefaultIcon(); + } else { + chrome.runtime.sendMessage({ + destination: 'popup', + message: 'show_menu' + }); + } + } + + // checkIfTabOpened checks if a "tab" containing window[property] has signalled that it has + // been loaded and its message listeners are ready + // openTabs is an optional array of tab ids to skip when checking because they were already + // opened BEFORE we initiated the opening of "tab" + // we abort if tab doesn't open after 5 secs. + checkIfTabOpened(tab, property, openTabs){ + openTabs = openTabs || []; + let isTimeoutTriggered = false; + setTimeout(function(){ + isTimeoutTriggered = true; + }, 5 * 1000); + + // eslint-disable-next-line no-async-promise-executor + return new Promise(async function(resolve) { + function tryAgain(){ + console.log('checking if '+property+' is ready...'); + const views = chrome.extension.getViews(); + // sometimes the View for the newly opened tab may not yet be available + // so we must wait a little longer + for (const win of views){ + if (win[property] == undefined) continue; + // found some viewer. Our viewer's tabid is null + if (win.tabid != null) continue; + if (win.isReady !== true) continue; + // else is ready + // save the tab id inside the window object + win.tabid = tab.id; + resolve(win); + return true; + } + } + while (tryAgain() !== true){ + if (isTimeoutTriggered){ + console.log('isTimeoutTriggered', isTimeoutTriggered); + return; + } + await wait(10); + } + }); + } + + openFileChooser(){ + const myTabs = []; + const views = chrome.extension.getViews(); + for (const win of views){ + if (win.isFileChooser){ + // re-focus if already opened + chrome.tabs.update(win.tabid, {active: true}); + return; + } + myTabs.push(win.tabid); + } + const that = this; + // #filechooser is in the URL only so that the user is not confused. We do not + // create a separate filechooser.html because as soon as a file is chosen, the + // same tab will be reused as a viewer. + // Otherwise we would have to close filechooser tab and instantly open a + // viewer tab with an unpleasant flicker. + const url = chrome.extension.getURL('ui/html/viewer.html#filechooser'); + chrome.tabs.create({url: url}, async function(t){ + const win = await that.checkIfTabOpened(t, 'isViewer', myTabs); + win.viewer.showFileChooser(); + }); + } + + + openManager() { + const url = chrome.extension.getURL('ui/html/manager.html'); + for (const win of chrome.extension.getViews()){ + if (win.isManager){ + // re-focus tab if manager already open + console.log('will refocus manger tab', win.tabid); + chrome.tabs.update(win.tabid, {active: true}); + return; + } + } + const that = this; + chrome.tabs.create({url: url}, function(t){ + that.checkIfTabOpened(t, 'is_manager'); + }); + } + + + async prepareNotarization(after_click) { + if (!this.trustedOracleReady) { + this.sendAlert({ + title: 'PageSigner error.', + text: 'Cannot notarize because something is wrong with PageSigner server. Please try again later' + }); + return; + } + + let clickTimeout = null; + const that = this; + + const active_tab = await new Promise(function(resolve) { + chrome.tabs.query({active: true}, function(t) { + resolve(t[0]); + }); + }); + + if (! active_tab.url.startsWith('https://')) { + this.sendAlert({ + 'title': 'PageSigner error.', + 'text': 'You can only notarize pages which start with https://' + }); + return; + } + + if (after_click){ + const url = chrome.extension.getURL('ui/img/arrow24.png'); + chrome.browserAction.setIcon({path: url}); + this.waiting_for_click = true; + clickTimeout = setTimeout(function() { + that.waiting_for_click = false; + that.loadDefaultIcon(); + that.sendAlert({ + title: 'PageSigner error.', + text: 'You haven\'t clicked any https:// links in 30 seconds. Please try again. If this error persists it may mean that the website you are trying to notarize is not compatible with PageSigner.' + }); + }, 30 * 1000); + } + + let oBR_details; + const oBR_handler = function(details){ + console.log('in onBeforeRequest', details); + chrome.webRequest.onBeforeRequest.removeListener(oBR_handler); + oBR_details = details; + }; + chrome.webRequest.onBeforeRequest.addListener( + oBR_handler, { + urls: [''], + tabId: active_tab.id, + types: ['main_frame', 'xmlhttprequest'] + // types: ["main_frame", "sub_frame", "stylesheet", "script", + // "image", "font", "object", "xmlhttprequest", "ping", "csp_report", "media", "websocket", "other"] + }, ['requestBody']); + + let oBSH_details; + const oBSH_handler = function(details){ + console.log('in onBeforeSendHeaders', details); + chrome.webRequest.onBeforeSendHeaders.removeListener(oBSH_handler); + oBSH_details = details; + console.log(oBR_details, oBSH_details); + }; + const extraInfoSpec = ['requestHeaders']; + if (this.is_chrome) extraInfoSpec.push('extraHeaders'); + chrome.webRequest.onBeforeSendHeaders.addListener( + oBSH_handler, { + urls: [''], + tabId: active_tab.id, + types: ['main_frame', 'xmlhttprequest'] + }, extraInfoSpec); + + + // wait for the request to pass oBR and oBHS and reach onSendHeaders + await new Promise(function(resolve) { + const oSH_handler = function(details){ + console.log('in onSendHeaders'); + chrome.webRequest.onSendHeaders.removeListener(oSH_handler); + resolve(details); + }; + chrome.webRequest.onSendHeaders.addListener( + oSH_handler, { + urls: [''], + tabId: active_tab.id, + types: ['main_frame', 'xmlhttprequest'] + }); + + // if not Notarize After Click mode, + // reload current tab in order to trigger the HTTP request + if (!that.waiting_for_click) chrome.tabs.reload(active_tab.id); + // otherwise just wait for the user to click smth and trigger onBeforeRequest + }); + + if (this.waiting_for_click) { + clearTimeout(clickTimeout); + this.waiting_for_click = false; + } + + if (oBR_details.url !== oBSH_details.url) return; + if (oBR_details.requestId !== oBSH_details.requestId) return; + if (oBR_details.method == 'POST') { + // POST payload is only available from onBeforeRequest + oBSH_details['requestBody'] = oBR_details.requestBody; + } + const rv = this.getHeaders(oBSH_details); + this.startNotarization(rv.headers, rv.server, rv.port) + .catch(err => { + console.log('Notarization aborted.', err); + console.trace(); + let errmsg = err; + if (typeof(err) === 'object'){ + errmsg = err.message; + if (err.message == 'Failed to fetch'){ + errmsg = 'Unable to connect to the notary server. Please check your internet connection.'; + } + } + this.sendAlert({ + title: 'PageSigner error.', + text: errmsg + }); + }) + .finally(()=> { + this.notarization_in_progress = false; + this.loadDefaultIcon(); + }); + } + + + getHeaders(obj) { + console.log('headers are', obj); + const x = obj.url.split('/'); + const host = x[2].split(':')[0]; + x.splice(0, 3); + const resource_url = x.join('/'); + + const http_version = global.useHTTP11 ? ' HTTP/1.1':' HTTP/1.0'; + let headers = obj.method + ' /' + resource_url + http_version + '\r\n'; + // Chrome doesnt add Host header. Firefox does + if (this.is_chrome){ + headers += 'Host: ' + host + '\r\n'; + } + for (let h of obj.requestHeaders) { + // we dont want any "br" encoding + if (h.name == 'Accept-Encoding') { + // h.value = 'gzip, deflate' + h.value = 'identity;q=1, *;q=0'; + } + headers += h.name + ': ' + h.value + '\r\n'; + } + if (obj.method == 'GET') { + headers += '\r\n'; + } + else if (obj.method == 'POST') { + let content; + if (obj.requestBody.raw != undefined) { + content = ba2str(new Uint8Array(obj.requestBody.raw[0].bytes)); + } + else{ + const keys = Object.keys(obj.requestBody.formData); + content = ''; + for (var key of keys) { + content += key + '=' + obj.requestBody.formData[key] + '&'; + } + // get rid of the last & + content = content.slice(0,-1); + // Chrome doesn't expose Content-Length which chokes nginx + headers += 'Content-Length: ' + parseInt(content.length) + '\r\n\r\n'; + headers += content; + } + } + let port = 443; + if (obj.url.split(':').length === 3) { + // the port is explicitely provided in URL + port = parseInt(obj.url.split(':')[2].split('/')[0]); + } + return { + 'headers': headers, + 'server': host, + 'port': port + }; + } + + + async getPGSG(sid){ + const blob = await getSessionBlob(sid); + return blob.pgsg; + } + + + + + // processMessages is the main entrypoint for all extension's logic + async processMessages(data) { + if (data.destination !== 'extension') return; + console.log('ext got msg', data); + switch (data.message){ + case 'rename': + await renameSession(data.args.dir, data.args.newname); + this.sendSessions(await getAllSessions()); + break; + case 'delete': + await deleteSession(data.args.dir); + this.sendSessions(await getAllSessions()); + break; + case 'import': + // data is js array + this.importPgsgAndShow(new Uint8Array(data.args.data)); + break; + case 'export': + const pgsg = await this.getPGSG(data.args.dir); + const value = await getSession(data.args.dir); + this.sendToManager({'pgsg': JSON.stringify(pgsg), 'name': value.sessionName}, 'export'); + break; + case 'notarize': + this.prepareNotarization(false); + break; + case 'notarizeAfter': + this.prepareNotarization(true); + break; + case 'manage': + this.openManager(); + break; + case 'refresh': + this.sendSessions(await getAllSessions()); + break; + case 'openLink1': + chrome.tabs.create({url: 'https://www.tlsnotary.org'}); + break; + case 'donate link': + chrome.tabs.create({url: 'https://www.tlsnotary.org/#Donate'}); + break; + case 'viewdata': + this.openViewer(data.args.dir); + break; + case 'viewraw': + this.openDetails(data.args.dir, false); + break; + case 'raw editor': + this.openDetails(data.args.dir, true); + break; + case 'file picker': + this.openFileChooser(); + break; + case 'openChromeExtensions': + this.openChromeExtensions(); + break; + case 'popup active': + this.popupProcess(); + break; + case 'open python script': + this.openPythonScript(); + break; + case 'pendingAction': + this.pendingAction = data.args; + break; + case 'useNotaryNoSandbox': + this.useNotaryNoSandbox(data.IP); + break; + case 'removeNotary': + await setPref('trustedOracle', {}); + } + } + + async startNotarization(headers, server, port) { + this.notarization_in_progress = true; + this.pm.init(); + this.isFirstTimeSetupNeeded = ! await getPref('firstTimeInitCompleted'); + chrome.runtime.sendMessage({ + destination: 'popup', + message: 'notarization_in_progress', + firstTime: this.isFirstTimeSetupNeeded + }); + if (this.isFirstTimeSetupNeeded){ + const obj = await new FirstTimeSetup().start(this.pm); + console.time('setPref'); + await setPref('parsedCircuits', obj); + console.timeEnd('setPref'); + await setPref('firstTimeInitCompleted', true); + } + const circuits = await getPref('parsedCircuits'); + const session = new TLSNotarySession( + server, port, headers, this.trustedOracle, global.sessionOptions, circuits, this.pm); + const obj = await session.start(); + obj['title'] = 'PageSigner notarization file'; + obj['version'] = 6; + if (! global.useNotaryNoSandbox){ + obj['URLFetcher attestation'] = this.trustedOracle.URLFetcherDoc; + } + const [host, request, response, date] = await this.verifyPgsgV6(obj); + const serializedPgsg = this.serializePgsg(obj); + await saveNewSession (date, host, request, response, serializedPgsg); + // date uniquely identifies a session + this.showSession(date); + } + + loadDefaultIcon(){ + const url = chrome.extension.getURL('ui/img/icon.png'); + chrome.browserAction.setIcon({path: url}); + } + + // opens a tab showing the session. sid is a unique session id + // creation time is sid. + async showSession (sid){ + await this.openViewer(sid); + this.sendSessions( await getAllSessions()); // refresh manager + } + + + openPythonScript(){ + const url = chrome.extension.getURL('pagesigner.py'); + chrome.tabs.create({url: url}, function(t){ + chrome.tabs.executeScript(t.id, {file: ('ui/python_script_header.js')}); + }); + } + + + async verifyPgsg(json){ + if (json['version'] == 6){ + return await this.verifyPgsgV6(json); + } + else { + throw ('Unrecognized version of the imported pgsg file.'); + } + } + + + // Serialize fields of json object + serializePgsg(json){ + // b64encode every field + const newjson = {}; + const keys = Object.keys(json); + for (const key of keys){ + if (['title', 'version'].includes(key)){ + newjson[key] = json[key]; + } + else if (key === 'certificates' || key === 'server response records'){ + // turn an array into obj with key as index i.e {"0": elem0, "1": elem1, ...} + const obj = {}; + for (let i=0; i { + console.log('Error in main: ', err); + m.sendAlert({ + title: 'PageSigner error.', + text: err + }); + }); +} + + +if (typeof module !== 'undefined'){ // we are in node.js environment + module.exports={ + save_session, + verifyPgsg + }; +} \ No newline at end of file diff --git a/core/ProgressMonitor.js b/core/ProgressMonitor.js new file mode 100644 index 0000000..f8585f5 --- /dev/null +++ b/core/ProgressMonitor.js @@ -0,0 +1,54 @@ +// class ProgressMonitor receives progress information about client's garbling, +// evaluation, blob upload, blob download. It dispatches progress status messages +// periodically or when queried. +// because Chrome has a bug and does not remove onMessage listener, we +// use only one ProgressMonitor and reset its state when a new notarization +// session starts + +export class ProgressMonitor{ + constructor(){ + this.progress = { + download: {}, + upload: {}, + garbling: {}, + last_stage: {}, + first_time: {}, + }; + // progress listeners may ask to give the current progress state + const that = this; + chrome.runtime.onMessage.addListener(function(data) { + if (data.destination != 'progress monitor') return; + chrome.runtime.sendMessage({ + destination: 'progress listeners', + progress: that.progress + }); + }); + + } + + init(){ + this.progress = { + download: {}, + upload: {}, + garbling: {}, + last_stage: {}, + first_time: {}, + }; + } + + // update is called with updates progress information + update(type, obj){ + this.progress[type] = obj; + chrome.runtime.sendMessage({ + destination: 'progress listeners', + progress: this.progress + }); + } + + // destroy de-registers listeners + // doesn't do anything because of what seems like a Chrome bug. + destroy(){ + // TODO it seems like Chrome does not remove onMessage listener + chrome.runtime.onMessage.removeListener(this.listener); + } +} \ No newline at end of file diff --git a/core/Socket.js b/core/Socket.js new file mode 100644 index 0000000..119a61e --- /dev/null +++ b/core/Socket.js @@ -0,0 +1,262 @@ +// The only way to determine if the server is done sending data is to check that out receiving +// buffer has nothing but complete TLS records i.e. that there is no incomplete TLS records +// However it was observed that in cases when getting e.g. zip files, some servers first send HTTP header as one +// TLS record followed by the body as another record(s) +// That's why after receiving a complete TLS record we wait to get some more data +// This extra waiting must not be done for the handshake messages to avoid adding latency and having the handshake +// dropped by the server +// We do not communicate directly with the server but we send messages to the helper app +// It is the helper app which opens a TCP socket and sends/receives data + +import {global} from './globals.js'; +import {ba2str, b64decode, concatTA, b64encode, str2ba, ba2int} from './utils.js'; + +export class Socket { + constructor(name, port){ + this.name = name; + this.port = port; + this.uid = Math.random().toString(36).slice(-10); + + this.buffer = new Uint8Array(); + // connect will throw if we couldnt establish a connection to the server for this long + this.connectTimeout = 5 * 1000; + // recv() will reject if no data was seen for this long + this.noDataTimeout = 5 * 1000; + // close the socket after this time, even if it is in the middle of receiving data + this.lifeTime = 40 * 1000; + // delay after which we make a final check of the receicing buffer and if there was no data, + // from the server, the we consider the data transmission finished + this.delayBeforeFinalIteration = 500; + this.wasClosed = false; + this.backendPort = 20022; + } + + async connect() { + const that = this; + let timer; + const response = await new Promise(async function(resolve, reject) { + // dont wait for connect for too long + timer = setTimeout(function() { + reject('Unable to connect to the webserver. Please check your internet connection.'); + return; + }, that.connectTimeout); + + const msg = {'command': 'connect','args': {'name': that.name,'port': that.port},'uid': that.uid}; + if (global.usePythonBackend){ + const url = 'http://127.0.0.1:' + that.backendPort; + const payload = JSON.stringify(msg); + try{ + var req = await fetch (url, {method:'POST', body: str2ba(payload).buffer, cache: 'no-store'}); + } + catch (error) { + reject('connection error'); + return; + } + const text = new Uint8Array (await req.arrayBuffer()); + const response = ba2str(text); + resolve(JSON.parse(response)); + return; + } + else { + chrome.runtime.sendMessage(global.appId, msg, function(response) {resolve(response);}); + } + }) + .catch(function(e){ + throw(e); + }); + + // we need to access runtime.lastError to prevent Chrome from complaining + // about unchecked error + chrome.runtime.lastError; + clearTimeout(timer); + if (response == undefined){ + throw (undefined); + } + if (response.retval != 'success') { + // throw(response.retval) + } + // else if (response.retval == 'success') { + setTimeout(function() { + if (! that.wasClosed) + that.close(); + }, that.lifeTime); + // endless data fetching loop for the lifetime of this Socket + that.fetchLoop(); + return 'ready'; + } + + async send(data_in) { + var msg = {'command': 'send', 'args': {'data': Array.from(data_in)}, 'uid': this.uid}; + if (global.usePythonBackend){ + msg.args.data = Array.from(b64encode(msg.args.data)); + await fetch('http://127.0.0.1:20022', {method:'POST', body: JSON.stringify(msg), + cache: 'no-store'}); + } + else{ + chrome.runtime.sendMessage(global.appId, msg); + } + } + + // poll the backend for more data + async fetchLoop() { + if (this.wasClosed) { + return; + } + var that = this; + var response = await new Promise(async function(resolve){ + var msg = {'command': 'recv', 'uid': that.uid}; + if (global.usePythonBackend){ + var req = await fetch('http://127.0.0.1:20022', {method:'POST', body: JSON.stringify(msg), + cache: 'no-store'}); + var text = new Uint8Array(await req.arrayBuffer()); + var response = JSON.parse(ba2str(text)); + if (response.data.length > 0){ + response.data = Array.from(b64decode(response.data)); + } + resolve(response); + } + else { + chrome.runtime.sendMessage(global.appId, msg, function(response) {resolve(response);}); + } + }); + if (response.data.length > 0){ + console.log('fetched some data', response.data.length, that.uid); + that.buffer = concatTA(that.buffer, new Uint8Array(response.data)); + } + setTimeout(function() { + that.fetchLoop(); + }, 100); + } + + // fetchLoop has built up the recv buffer + // check if there are complete records in the buffer,return them if yes or wait some more if no + recv (is_handshake) { + if (is_handshake == undefined) { + is_handshake = false; + } + var that = this; + return new Promise(function(resolve, reject) { + var dataLastSeen = new Date().getTime(); + var complete_records = new Uint8Array(); + var buf = new Uint8Array(); + var resolved = false; + var lastIteration = false; + + function finished_receiving() { + console.log('recv promise resolving', that.uid); + resolved = true; + resolve(complete_records); + } + + var check = function() { + var now = new Date().getTime(); + if ((now - dataLastSeen) > that.noDataTimeout){ + reject('recv: no data timeout'); + return; + } + // console.log('check()ing for more data', uid); + if (resolved) { + console.log('returning because resolved'); + return; + } + if (that.buffer.length === 0) { + if (lastIteration){ + finished_receiving(); + return; + } + setTimeout(function() {check();}, 100); + return; + } + // else got new data + if (lastIteration){ + console.log('more data received on last iteration', that.uid); + lastIteration = false; + } + console.log('new data in check', that.buffer.length); + dataLastSeen = now; + buf = concatTA(buf, that.buffer); + that.buffer = new Uint8Array(); + const rv = that.check_complete_records(buf); + complete_records = concatTA(complete_records, rv.comprecs); + if (!rv.is_complete) { + console.log('check_complete_records failed', that.uid); + buf = rv.incomprecs; + setTimeout(function() {check();}, 100); + return; + } + else { + console.log('got complete records', that.uid); + if (is_handshake) { + finished_receiving(); + return; + } + else { + console.log('in recv waiting for an extra second', that.uid); + buf = new Uint8Array(); + // give the server another second to send more data + lastIteration = true; + setTimeout(function() {check();}, that.delayBeforeFinalIteration); + } + } + }; + check(); + }) + .catch(function(error){ + throw(error); + }); + } + + async close() { + this.wasClosed = true; + var msg = {'command': 'close','uid': this.uid}; + console.log('closing socket', this.uid); + if (global.usePythonBackend){ + await fetch('http://127.0.0.1:20022', {method:'POST', body: JSON.stringify(msg), + cache: 'no-store'}); + } + else { + chrome.runtime.sendMessage(global.appId, msg); + } + } + + check_complete_records(d) { + /* '''Given a response d from a server, + we want to know if its contents represents + a complete set of records, however many.''' + */ + let complete_records = new Uint8Array(); + + while (d) { + if (d.length < 5) { + return { + 'is_complete': false, + 'comprecs': complete_records, + 'incomprecs': d + }; + } + var l = ba2int(d.slice(3, 5)); + if (d.length < (l + 5)) { + return { + 'is_complete': false, + 'comprecs': complete_records, + 'incomprecs': d + }; + } else if (d.length === (l + 5)) { + return { + 'is_complete': true, + 'comprecs': concatTA(complete_records, d) + }; + } else { + complete_records = concatTA(complete_records, d.slice(0, l + 5)); + d = d.slice(l + 5); + continue; + } + } + } +} + + +if (typeof module !== 'undefined'){ // we are in node.js environment + module.exports={ + }; +} \ No newline at end of file diff --git a/core/TLS.js b/core/TLS.js new file mode 100644 index 0000000..2ef3496 --- /dev/null +++ b/core/TLS.js @@ -0,0 +1,627 @@ +import {TWOPC} from './twopc/TWOPC.js'; +import {global} from './globals.js'; +import {ba2str, b64decode, concatTA, int2ba, sha256, b64encode, str2ba, assert, + ba2int, dechunk_http, gunzip_http, getRandom, sigDER2p1363, pubkeyPEM2raw, eq, + xor, AESECBencrypt, buildChunkMetadata, b64urlencode} from './utils.js'; +import {verifyChain, checkCertSubjName} from './verifychain.js'; +import {Socket} from './Socket.js'; + + +export class TLS { + // allHandshakes is a concatenation of all handshake messages up to this point. + // This is only data visible at the handshake layer and does not include record layer headers + allHandshakes; + // certPath is an array of certificates from the server arranged by pkijs in the ascending + // order from leaf to root + certPath; + // cke is TLS handshake's Client Key Exchange message + cke; + clientRandom; + commPrivkey; + commSymmetricKey; + headers; + isMhm; // multiple handshake messages + mustVerifyCert; + notaryWillEncryptRequest; + options; + port; + rsaSig; + serverRandom; + sckt; + serverEcPubkey; + secret; // for debug purposes only + // sid is id for this notarization session + sid; + serverName; + useMaxFragmentLength; + + constructor (serverName, port, headers, options){ + this.serverName = serverName; + this.port = port; + this.headers = headers; + this.sid = Math.random().toString(36).slice(-10); + this.options = options; + this.useMaxFragmentLength = options.useMaxFragmentLength; + this.notaryWillEncryptRequest = options.notaryWillEncryptRequest; + this.mustVerifyCert = options.mustVerifyCert; + this.sckt = new Socket(serverName, port); + } + + buildClientHello(){ + let tmp = []; + tmp.push(0x00, 0x0a); // Type supported_groups + tmp.push(0x00, 0x04); // Length + tmp.push(0x00, 0x02); // Supported Groups List Length + tmp.push(0x00, 0x17); // Supported Group: secp256r1 + const supported_groups_extension = new Uint8Array(tmp); + + tmp = []; + tmp.push(0x00, 0x0d); // Type signature_algorithms + tmp.push(0x00, 0x04); // Length + tmp.push(0x00, 0x02); // Signature Hash Algorithms Length + tmp.push(0x04, 0x01); // Signature Algorithm: rsa_pkcs1_sha256 (0x0401) + const signature_algorithm_extension = new Uint8Array(tmp); + + tmp = []; + const server_name = str2ba(this.serverName); + tmp.push(0x00, 0x00); // Extension type: server_name + tmp.push(...Array.from(int2ba(server_name.length+5, 2))); // Length + tmp.push(...Array.from(int2ba(server_name.length+3, 2))); // Server Name List Length + tmp.push(0x00); // Type: host name + tmp.push(...Array.from(int2ba(server_name.length, 2))); // Server Name Length + tmp.push(...Array.from(server_name)); + const server_name_extension = new Uint8Array(tmp); + + tmp = []; + if (this.useMaxFragmentLength){ + tmp.push(0x00, 0x01); // Type: max_fragment_length + tmp.push(0x00, 0x01); // Length + // allowed values 0x01 = 512 0x02 = 1024 0x03 = 2048 0x04 = 4096 + // some servers support 0x04 but send alert if < 0x04 + tmp.push(0x04); + } + const max_fragment_length_extension = new Uint8Array(tmp); + + const extlen = supported_groups_extension.length + signature_algorithm_extension.length + + server_name_extension.length + max_fragment_length_extension.length; + + tmp = []; + tmp.push(0x01); // Handshake type: Client Hello + tmp.push(...int2ba(extlen + 43, 3) ); // Length + tmp.push(0x03, 0x03); // Version: TLS 1.2 + this.clientRandom = getRandom(32); + tmp.push(...Array.from(this.clientRandom)); + tmp.push(0x00); // Session ID Length + tmp.push(0x00, 0x02); // Cipher Suites Length + tmp.push(0xc0, 0x2f); // Cipher Suite: TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 + tmp.push(0x01); // Compression Methods Length + tmp.push(0x00); // Compression Method: null + tmp.push(...int2ba(extlen, 2)); + const ch = concatTA( + new Uint8Array(tmp), + supported_groups_extension, + signature_algorithm_extension, + server_name_extension, + max_fragment_length_extension); + + this.allHandshakes = ch; + + tmp = []; + tmp.push(0x16); // Type: Handshake + tmp.push(0x03, 0x03); // Version: TLS 1.2 + tmp.push(...int2ba(ch.length, 2)); // Length + const tls_record_header = new Uint8Array(tmp); + + return concatTA(tls_record_header, ch); + } + + async verifyNotarySig(sigDER, pubKey, signed_data, options){ + const isRaw = (options == 'raw') ? true : false; + const sig_p1363 = sigDER2p1363(sigDER); + const notaryPubkey = isRaw ? pubKey : pubkeyPEM2raw(pubKey); + + const pubkeyCryptoKey = await crypto.subtle.importKey( + 'raw', notaryPubkey.buffer, {name: 'ECDSA', namedCurve:'P-256'}, true, ['verify']); + // eslint-disable-next-line no-unused-vars + const result = await crypto.subtle.verify( + {'name':'ECDSA', 'hash':'SHA-256'}, pubkeyCryptoKey, sig_p1363.buffer, signed_data.buffer); + return result; + } + + + async parse_commpk_commpksig_cpk(dataEnc){ + // Notary's EC pubkey (to derive ECDH secret for communication) is not encrypted + const comm_pk = dataEnc.slice(0,65); + // for debug purposes only + this.secret = dataEnc.slice(65,97); + + this.commSymmetricKey = await getECDHSecret(comm_pk, this.commPrivkey); + const data = await this.decryptFromNotary( + this.commSymmetricKey, + dataEnc.slice(65+this.secret.length)); + + let o = 0; // offset + // get signature over communication pubkey + const ssrvLen = ba2int(data.slice(o,o+=1)); + const signingServerRetval = data.slice(o, o+=ssrvLen); + const cpk = data.slice(o,o+=65); // Client's pubkey for ECDH + // parse signing server's return value + o = 0; + const sessionSigLen = ba2int(signingServerRetval.slice(o, o+=1)); + const sessionSig = signingServerRetval.slice(o, o+=sessionSigLen); + const ephemKeySigLen = ba2int(signingServerRetval.slice(o, o+=1)); + const ephemKeySig = signingServerRetval.slice(o, o+=ephemKeySigLen); + const ephemPubKey = signingServerRetval.slice(o, o+=65); + const ephemValidFrom = signingServerRetval.slice(o, o+=4); + const ephemValidUntil = signingServerRetval.slice(o, o+=4); + + // check signature + const to_be_signed = await sha256(comm_pk); + assert(await this.verifyNotarySig(sessionSig, ephemPubKey, to_be_signed, 'raw') == true); + // the ephemeral key with its validity time range is signed by master key + const ephemTBS = await sha256(concatTA(ephemPubKey, ephemValidFrom, ephemValidUntil)); + assert(await this.verifyNotarySig(ephemKeySig, this.notary.pubkeyPEM, ephemTBS) == true); + this.checkEphemKeyExpiration(ephemValidFrom, ephemValidUntil); + return cpk; + } + + parseServerHello(s){ + let p = 0; + assert(eq(s.slice(p, p+=1), [0x02])); // Server Hello + // eslint-disable-next-line no-unused-vars + const shlen = ba2int(s.slice(p, p+=3)); + assert(eq(s.slice(p, p+=2), [0x03, 0x03])); // Version: TLS 1.2 + this.serverRandom = s.slice(p, p+=32); + const sidlen = ba2int(s.slice(p, p+=1)); + if (sidlen > 0){ + p+=sidlen; // 32 bytes of session ID, if any + } + assert(eq(s.slice(p, p+=2), [0xc0, 0x2f])); // Cipher Suite: TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 + assert(eq(s.slice(p, p+=1), [0x00])); // Compression Method: null (0) + // May contain Extensions. We don't need to parse them + } + + async parseCertificate(s){ + let p = 0; + assert(eq(s.slice(p, p+=1), [0x0b])); // Certificate + // eslint-disable-next-line no-unused-vars + const clen = ba2int(s.slice(p, p+=3)); + const certslen = ba2int(s.slice(p, p+=3)); + const certs_last_pos = p + certslen; + const certs = []; + while (p < certs_last_pos){ + const certlen = ba2int(s.slice(p, p+=3)); + const certder = s.slice(p, p+certlen); + p+=certlen; + certs.push(certder); + } + const vcrv = await verifyChain(certs); + assert (vcrv.result == true); + this.certPath = vcrv.certificatePath; + assert(checkCertSubjName(this.certPath[0], this.serverName) == true); + return p; + } + + async parseServerKeyExchange(s){ + let p = 0; + assert(eq(s.slice(p, p+=1), [0x0c])); // Handshake Type: Server Key Exchange (12) + // eslint-disable-next-line no-unused-vars + const skelen = ba2int(s.slice(p, p+=3)); + // EC Diffie-Hellman Server Params + assert(eq(s.slice(p, p+=1), [0x03])); // Curve Type: named_curve (0x03) + assert(eq(s.slice(p, p+=2), [0x00, 0x17])); // Named Curve: secp256r1 (0x0017) + const pklen = ba2int(s.slice(p, p+=1)); + assert (pklen == 65); // Pubkey Length: 65 + this.serverEcPubkey = s.slice(p, p+=pklen); + assert(eq(s.slice(p, p+=2), [0x04, 0x01])); // #Signature Algorithm: rsa_pkcs1_sha256 (0x0401) + const siglen = ba2int(s.slice(p, p+=2)); + this.rsaSig = s.slice(p, p+=siglen); + + const result = await TLS.verifyECParamsSig(this.certPath[0], this.serverEcPubkey, this.rsaSig, this.clientRandom, this.serverRandom); + assert (result == true); + return p; + } + + // Obsolete: encrypt request without 2PC. + async encryptRequest(headers_str, client_write_key, client_write_IV, chunkSize){ + let headers = str2ba(headers_str); + chunkSize = chunkSize || headers.length; // one chunk only + const chunks = Math.ceil(headers.length/chunkSize); + const encReq = []; + for (let i=0; i < chunks; i++){ + let thisChunkSize = chunkSize; + if (i == chunks-1){ + // last chunk may be smaller + const rem = headers.length % chunkSize; + thisChunkSize = (rem == 0) ? chunkSize : rem; + } + const explicit_nonce = int2ba(2+i, 8); + // const explicit_nonce = getRandom(8) + const nonce = concatTA(client_write_IV, explicit_nonce); + const seq_num = 1+i; + const aad = concatTA( + int2ba(seq_num, 8), + new Uint8Array([0x17, 0x03, 0x03]), // type 0x17 = Application data , TLS Version 1.2 + int2ba(thisChunkSize, 2)); // unencrypted data length in bytes + const cwkCryptoKey = await crypto.subtle.importKey( + 'raw', + client_write_key.buffer, + 'AES-GCM', + true, + ['encrypt', 'decrypt']); + const ciphertext = await crypto.subtle.encrypt({ + name: 'AES-GCM', + iv: nonce.buffer, + additionalData: aad.buffer}, + cwkCryptoKey, + headers.slice(chunkSize*i, chunkSize*(i+1)).buffer); + encReq.push(concatTA(explicit_nonce, new Uint8Array(ciphertext))); + } + return encReq; + } + + // ephemeral key usage time must be within the time of ephemeral key validity + checkEphemKeyExpiration(validFrom, validUntil, time){ + time = time || Math.floor(new Date().getTime() / 1000); + if (ba2int(validFrom) > time || time > ba2int(validUntil)){ + throw('Ephemeral key expired'); + } + } + + async buildAndSendClientHello(){ + const ch = this.buildClientHello(); + await this.sckt.connect(); + this.sckt.send(ch); // Send Client Hello + } + + // receiveAndParseServerHelloAndFriends receives Server Hello, Certificate, + // Server Key Exchange, and Server Hello Done and parses them + async receiveAndParseServerHello(){ + try{ + this.sckt.recv_timeout = 5 * 1000; + var s = await this.sckt.recv(true); + } catch (err){ + await this.sckt.close(); + // some incompatible websites silently do not respond to ClientHello + throw('Failed to receive a response from a webserver. Make sure your internet connection is working and try again. If this error persists, this may mean that the webserver is not compatible with PageSigner. Please contact the PageSigner devs about this issue.'); + } + // restore normal timeout value + this.sckt.recv_timeout = 20 * 1000; + + // Parse Server Hello, Certificate, Server Key Exchange, Server Hello Done + if (eq(s.slice(0,2), [0x15, 0x03])){ + console.log('Server sent Alert instead of Server Hello'); + throw ('Unfortunately PageSigner is not yet able to notarize this website. Please contact the PageSigner devs about this issue.'); + } + let p = 0; // current position in the byte stream + assert(eq(s.slice(p, p+=1), [0x16])); // Type: Handshake + assert(eq(s.slice(p, p+=2), [0x03, 0x03])); // Version: TLS 1.2 + const handshakelen = ba2int(s.slice(p, p+=2)); + // This may be the length of multiple handshake messages (MHM) + // For MHM there is only 1 TLS Record layer header followed by Handshake layer messages + // Without MHM, each handshake message has its own TLS Record header + + // Parse Server Hello + const shlen = ba2int(s.slice(p+1, p+4)); + const sh = s.slice(p, p + 4 + shlen); + this.updateAllHandshakes(sh); + this.parseServerHello(sh); + p = 5+4+shlen; + + if (handshakelen > shlen+4) { + this.isMhm = true; }// multiple handshake messages + let reclenMhm = 0; + if (!this.isMhm){ + // read the TLS Record header + assert(eq(s.slice(p, p+=3), [0x16, 0x03, 0x03])); // Type: Handshake # Version: TLS 1.2 + reclenMhm = ba2int(s.slice(p, p+=2)); + } + + // Parse Certificate + const clen = ba2int(s.slice(p+1, p+4)); + if (!this.isMhm) { + assert(reclenMhm == clen+4);} + const c = s.slice(p, p + 4 + clen); + this.allHandshakes = concatTA(this.allHandshakes, c); + const cParsedByted = await this.parseCertificate(c); + p += cParsedByted; + + if (this.isMhm && (handshakelen+5 == p)){ + // another MHM header will follow, read its header + assert(eq(s.slice(p, p+=1), [0x16])); // Type: Handshake + assert(eq(s.slice(p, p+=2), [0x03, 0x03])); // Version: TLS 1.2 + // eslint-disable-next-line no-unused-vars + const handshakelen = ba2int(s.slice(p, p+=2)); // This may be the length of multiple handshake messages (MHM) + } + reclenMhm = 0; + if (!this.isMhm){ + // read the TLS Record header + assert(eq(s.slice(p, p+=3), [0x16, 0x03, 0x03])); // Type: Handshake # Version: TLS 1.2 + reclenMhm = ba2int(s.slice(p, p+=2)); + } + + // Parse Server Key Exchange + const skelen = ba2int(s.slice(p+1, p+4)); + if (!this.isMhm){ + assert(reclenMhm == skelen+4);} + const ske = s.slice(p, p + 4+ skelen); + this.allHandshakes = concatTA(this.allHandshakes, ske); + const skeParsedByted = await this.parseServerKeyExchange(ske); + p += skeParsedByted; + + // Parse Server Hello Done + if (!this.isMhm) { + // read the TLS Record header + assert(eq(s.slice(p, p+=3), [0x16, 0x03, 0x03])); // Type: Handshake # Version: TLS 1.2 + // eslint-disable-next-line no-unused-vars + const reclen = ba2int(s.slice(p, p+=2)); + } + const shd = s.slice(p, p+=4); + assert(eq(shd, [0x0e, 0x00, 0x00, 0x00])); + assert(p == s.length); + this.updateAllHandshakes(shd); + return this.serverEcPubkey; + } + + // buildClientKeyExchange builds the TLS handshake's Client Key Exchange message + // cpubBytes is client's pubkey for the ECDH + async buildClientKeyExchange(cpubBytes){ + let tmp = [0x10]; // Handshake type: Client Key Exchange + tmp.push(0x00, 0x00, 0x42); // Length + tmp.push(0x41); // Pubkey Length: 65 + // 0x04 means compressed pubkey format + this.cke = concatTA(new Uint8Array(tmp), new Uint8Array([0x04]), cpubBytes); + this.updateAllHandshakes(this.cke); + } + + getRandoms(){ + return [this.clientRandom, this.serverRandom]; + } + + getAllHandshakes(){ + return this.allHandshakes; + } + + getCertPath(){ + return this.certPath; + } + + getRSAsignature(){ + return this.rsaSig; + } + + // sendClientFinished accepts encrypted Client Finished (CF), auth tag for CF, verify_data for CF. + // It then sends Client Key Exchange, Change Cipher Spec and encrypted Client Finished + async sendClientFinished(encCF, tagCF){ + const cke_tls_record_header = new Uint8Array([0x16, 0x03, 0x03, 0x00, 0x46]); // Type: Handshake, Version: TLS 1.2, Length + const ccs = new Uint8Array([0x14, 0x03, 0x03, 0x00, 0x01, 0x01]); + const client_finished = concatTA(int2ba(1, 8), encCF, tagCF); + // Finished message of 40 (0x28) bytes length + const data_to_send = concatTA(cke_tls_record_header, this.cke, ccs, + new Uint8Array([0x16, 0x03, 0x03, 0x00, 0x28]), client_finished); + this.sckt.send(data_to_send); + } + + updateAllHandshakes(appendMsg){ + this.allHandshakes = concatTA(this.allHandshakes, appendMsg); + } + + // receiveServerFinished receives Change Cipher Spec and encrypted Server Finished. + // Returns encrypted Server Finished + async receiveServerFinished(){ + const data = await this.sckt.recv(true); + + if (eq(data.slice(0,2), [0x15, 0x03])){ + console.log('Server sent Alert instead of Server Finished'); + throw('Server sent Alert instead of Server Finished'); + } + // Parse CCS and Server's Finished + const ccs_server = data.slice(0,6); + assert(eq(ccs_server, [0x14, 0x03, 0x03, 0x00, 0x01, 0x01])); + + let f = null; // server finished + if (data.length === 6) { + // didnt receive the Server Finished, try again + f = await this.sckt.recv(true); + } + else { + f = data.slice(6); + } + + assert (eq(f.slice(0,5), [0x16, 0x03, 0x03, 0x00, 0x28])); + const encSF = f.slice(5, 45); // encrypted Server Finished + // There may be some extra data received after the Server Finished. We ignore it. + return encSF; + } + + async buildAndSendRequest(gctrBlocks, ghashOutputs, encRequestBlocks){ + // authTags contains authentication tag for each TLS record in the request + // (For now there's a limit of 1 TLS record for the client request) + const authTags = []; + assert(ghashOutputs.length === gctrBlocks.length); + for (let i=0; i < ghashOutputs.length; i++){ + authTags[i] = xor(ghashOutputs[i], gctrBlocks[i]); + } + + const finalRecords = []; + const TLSRecord = concatTA(int2ba(2, 8), ...encRequestBlocks, authTags[0]); + finalRecords.push(TLSRecord); + + let appdata = new Uint8Array(); + for (let i=0; i< finalRecords.length; i++){ + appdata = concatTA( + appdata, + new Uint8Array([0x17, 0x03, 0x03]), // Type: Application data, TLS Version 1.2 + int2ba(finalRecords[i].length, 2), // 2-byte length of encrypted data + finalRecords[i]); + } + console.log('sending http request'); + this.sckt.send(appdata); + } + + // receiveServerResponse returns encrypted server response split into TLS records + async receiveServerResponse(){ + const server_response = await this.sckt.recv(); + this.sckt.close(); + console.log('server_response.length', server_response.length); + const encRecords = this.splitResponseIntoRecords(server_response); + return encRecords; + } + + // Not in use now, will be used for the selective hiding in the future + async hashesOfAllCounterBlocks(server_write_key, server_write_IV, encRecords){ + // calculate hashes of every counter + var encCounters = []; // encrypted counters for each TLS recorsd + var hashesOfEncCounters = []; // hash of each AES block + + for (var i=0; i -1) isImported = true; + if (options.indexOf('edited') > -1) isEdited = true; + } + // sessionName can be changed by the user in the manager window + store.add({ + creationTime: date, + sessionName: host, + serverName: host, + isImported: isImported, + isEdited: isEdited, + version: 6}); + tx.oncomplete = function() { + resolve(); + }; + tx.onerror = function(event) { + alert('error storing note ' + event.target.errorCode); + reject(); + }; + }); + await new Promise(function(resolve, reject) { + const tx2 = db_blobs.transaction(['sessions'], 'readwrite'); + const store2 = tx2.objectStore('sessions'); + store2.add({ + creationTime: date, + serverName:host, + request:request, + response:response, + pgsg:pgsg}); + tx2.oncomplete = function() { + resolve(); + }; + tx2.onerror = function(event) { + alert('error storing note ' + event.target.errorCode); + reject(); + }; + }); +} + + +export async function getSession(idx){ + return await new Promise(function(resolve, reject) { + + const tx = db.transaction(['sessions'], 'readonly'); + const store = tx.objectStore('sessions'); + const req = store.get(idx); + req.onsuccess = function(event) { + const entry = event.target.result; + if (entry) { + console.log(entry); + resolve(entry); + } else { + console.log('entry 1 not found'); + resolve(null); + } + }; + req.onerror = function(event) { + console.log('error getting entry 1 ' + event.target.errorCode); + reject('error getting entry 1 ' + event.target.errorCode); + }; + + }); +} + + + + +// get data from blob store +export async function getSessionBlob(idx){ + + return await new Promise(function(resolve, reject) { + + const tx = db_blobs.transaction(['sessions'], 'readonly'); + const store = tx.objectStore('sessions'); + const req = store.get(idx); + req.onsuccess = function(event) { + const entry = event.target.result; + if (entry) { + resolve(entry); + } else { + console.log('note 1 not found'); + resolve(null); + } + }; + req.onerror = function(event) { + console.log('error getting entry 1 ' + event.target.errorCode); + reject('error getting entry 1 ' + event.target.errorCode); + }; + + }); +} + + +export async function getPref(pref){ + return await new Promise(function(resolve, reject) { + + let tx = db.transaction(['preferences'], 'readonly'); + let store = tx.objectStore('preferences'); + let req = store.get(pref); + req.onsuccess = function(event) { + let entry = event.target.result; + if (entry) { + console.log(entry); + resolve(entry.value); + } else { + resolve(null); + } + }; + req.onerror = function(event) { + console.log('error getting entry 1 ' + event.target.errorCode); + reject('error getting entry 1 ' + event.target.errorCode); + }; + + }); +} + + +export async function setPref(pref, newvalue) { + await new Promise(function(resolve, reject) { + + const tx = db.transaction(['preferences'], 'readwrite'); + const store = tx.objectStore('preferences'); + const request = store.get(pref); + + request.onsuccess = function(event) { + // Get the old value that we want to update + const data = event.target.result; + + // update the value(s) in the object that you want to change + data.value = newvalue; + + // Put this updated object back into the database. + const requestUpdate = store.put(data); + requestUpdate.onerror = function(event) { + // Do something with the error + reject(); + }; + requestUpdate.onsuccess = function(event) { + // Success - the data is updated! + resolve(); + }; + }; + }); +} + + + + +export async function renameSession(id, newname) { + await new Promise(function(resolve, reject) { + // Start a database transaction and get the notes object store + const tx = db.transaction(['sessions'], 'readwrite'); + const sessions = tx.objectStore('sessions'); + const request = sessions.get(id); + + request.onsuccess = function(event) { + // Get the old value that we want to update + const data = event.target.result; + + // update the value(s) in the object that you want to change + data.sessionName = newname; + + // Put this updated object back into the database. + const requestUpdate = sessions.put(data); + requestUpdate.onerror = function(event) { + // Do something with the error + reject(); + }; + requestUpdate.onsuccess = function(event) { + // Success - the data is updated! + resolve(); + }; + }; + }); +} \ No newline at end of file diff --git a/core/oracles.js b/core/oracles.js new file mode 100644 index 0000000..a7c969f --- /dev/null +++ b/core/oracles.js @@ -0,0 +1,342 @@ +import {global} from './globals.js'; +import {ba2str, b64decode, assert, ba2int, verifyAttestationDoc, ba2hex, eq, + sha256} from './utils.js'; + +// rootOfTrust id the id of an EBS snapshot +// essentially the whole oracle verification procedure boils down to proving that an EC2 instance was +// launched from an AMI which was created from the "rootOfTrust" snapshot id. +const rootOfTrust = 'snap-0ccb00d0e0fb4d4da'; +// URLFetcher trusted enclave measurements, see +// https://github.com/tlsnotary/URLFetcher +const URLFetcherPCR0 = 'f70217239e8a1cb0f3c010b842a279e2b8d30d3700d7e4722fef22291763479a13783dc76d5219fabbd7e5aa92a7b255'; +const URLFetcherPCR1 = 'c35e620586e91ed40ca5ce360eedf77ba673719135951e293121cb3931220b00f87b5a15e94e25c01fecd08fc9139342'; +const URLFetcherPCR2 = 'efba114128ccd6af1d1366a12c1ac89e4a4ca5ea1434d779efadfd3ec0d1da5b7c0d8525239fac29ffde2946e07d1c16'; + + +// assuming both events happened on the same day, get the time +// difference between them in seconds +// the time string looks like "2015-04-15T19:00:59.000Z" +function getSecondsDelta(later, sooner) { + assert(later.length == 24); + if (later.slice(0, 11) !== sooner.slice(0, 11)) { + return 999999; // not on the same day + } + const laterTime = later.slice(11, 19).split(':'); + const soonerTime = sooner.slice(11, 19).split(':'); + const laterSecs = parseInt(laterTime[0]) * 3600 + parseInt(laterTime[1]) * 60 + parseInt(laterTime[2]); + const soonerSecs = parseInt(soonerTime[0]) * 3600 + parseInt(soonerTime[1]) * 60 + parseInt(soonerTime[2]); + return laterSecs - soonerSecs; +} + + + +function checkDescribeInstances(xmlDoc, instanceId, imageId, volumeId) { + try { + assert(xmlDoc.getElementsByTagName('DescribeInstancesResponse').length == 1); + const rs = xmlDoc.getElementsByTagName('reservationSet'); + assert(rs.length === 1); + const rs_items = rs[0].children; + assert(rs_items.length === 1); + var ownerId = rs_items[0].getElementsByTagName('ownerId')[0].textContent; + const isets = rs_items[0].getElementsByTagName('instancesSet'); + assert(isets.length === 1); + const instances = isets[0].children; + assert(instances.length === 1); + const parent = instances[0]; + assert(parent.getElementsByTagName('instanceId')[0].textContent === instanceId); + assert(parent.getElementsByTagName('imageId')[0].textContent === imageId); + assert(parent.getElementsByTagName('instanceState')[0].getElementsByTagName('name')[0].textContent === 'running'); + var launchTime = parent.getElementsByTagName('launchTime')[0].textContent; + assert(parent.getElementsByTagName('rootDeviceType')[0].textContent === 'ebs'); + assert(parent.getElementsByTagName('rootDeviceName')[0].textContent === '/dev/sda1'); + const devices = parent.getElementsByTagName('blockDeviceMapping')[0].getElementsByTagName('item'); + assert(devices.length === 1); + assert(devices[0].getElementsByTagName('deviceName')[0].textContent === '/dev/sda1'); + assert(devices[0].getElementsByTagName('ebs')[0].getElementsByTagName('status')[0].textContent === 'attached'); + var volAttachTime = devices[0].getElementsByTagName('ebs')[0].getElementsByTagName('attachTime')[0].textContent; + assert(devices[0].getElementsByTagName('ebs')[0].getElementsByTagName('volumeId')[0].textContent === volumeId); + // get seconds from "2015-04-15T19:00:59.000Z" + assert(getSecondsDelta(volAttachTime, launchTime) <= 2); + assert(parent.getElementsByTagName('virtualizationType')[0].textContent === 'hvm'); + } catch (e) { + throw('checkDescribeInstances exception'); + } + return { + 'ownerId': ownerId, + 'volAttachTime': volAttachTime, + 'launchTime': launchTime + }; +} + + +function checkDescribeVolumes(xmlDoc, instanceId, volumeId, volAttachTime, snapshotId) { + try { + assert(xmlDoc.getElementsByTagName('DescribeVolumesResponse').length == 1); + const volumes = xmlDoc.getElementsByTagName('volumeSet')[0].children; + assert(volumes.length === 1); + const volume = volumes[0]; + assert(volume.getElementsByTagName('volumeId')[0].textContent === volumeId); + assert(volume.getElementsByTagName('snapshotId')[0].textContent === snapshotId); + assert(volume.getElementsByTagName('status')[0].textContent === 'in-use'); + const volCreateTime = volume.getElementsByTagName('createTime')[0].textContent; + const attVolumes = volume.getElementsByTagName('attachmentSet')[0].getElementsByTagName('item'); + assert(attVolumes.length === 1); + const attVolume = attVolumes[0]; + assert(attVolume.getElementsByTagName('volumeId')[0].textContent === volumeId); + assert(attVolume.getElementsByTagName('instanceId')[0].textContent === instanceId); + assert(attVolume.getElementsByTagName('device')[0].textContent === '/dev/sda1'); + assert(attVolume.getElementsByTagName('status')[0].textContent === 'attached'); + const attTime = attVolume.getElementsByTagName('attachTime')[0].textContent; + assert(volAttachTime === attTime); + // Crucial: volume was created from snapshot and attached at the same instant + // this guarantees that there was no time window to modify it + assert(getSecondsDelta(attTime, volCreateTime) === 0); + } catch (e) { + throw('checkDescribeVolumes exception'); + } + return true; +} + + +function checkGetConsoleOutput(xmlDoc, instanceId) { + try { + assert(xmlDoc.getElementsByTagName('GetConsoleOutputResponse').length == 1); + assert(xmlDoc.getElementsByTagName('instanceId')[0].textContent === instanceId); + const b64data = xmlDoc.getElementsByTagName('output')[0].textContent; + const logstr = ba2str(b64decode(b64data)); + // the only nvme* strings allowed are: nvme, nvme0, nvme0n1, nvme0n1p1 + // this ensures that instance has only one disk device. This is + // a redundant check, because the patched ramdisk must halt the boot process if + // it detects more than one disk device. + const allowedSet = ['nvme', 'nvme0', 'nvme0n1', 'nvme0n1p1']; + // match all substrings starting with nvme, folowed by a count of from 0 to 7 symbols from + // the ranges 0-9 and a-z + for (const match of [...logstr.matchAll(/nvme[0-9a-z]{0,7}/g)]){ + assert(match.length == 1); + assert(allowedSet.includes(match[0]), 'disallowed nvme* string present in log'); + } + + const sigmark = 'PageSigner public key for verification'; + const pkstartmark = '-----BEGIN PUBLIC KEY-----'; + const pkendmark = '-----END PUBLIC KEY-----'; + + const mark_start = logstr.search(sigmark); + assert(mark_start !== -1); + const pubkey_start = mark_start + logstr.slice(mark_start).search(pkstartmark); + const pubkey_end = pubkey_start + logstr.slice(pubkey_start).search(pkendmark) + pkendmark.length; + const chunk = logstr.slice(pubkey_start, pubkey_end); + const lines = chunk.split('\n'); + let pk = pkstartmark + '\n'; + for (let i = 1; i < lines.length-1; i++) { + const words = lines[i].split(' '); + pk = pk + words[words.length-1] + '\n'; + } + pk = pk + pkendmark; + assert(pk.length > 0); + const pubkeyPEM = pk.split('\r\n').join('\n'); + return pubkeyPEM; + } catch (e) { + throw('checkGetConsoleOutput exception'); + } +} + +// "userData" allows to pass an arbitrary script to the instance at launch. It MUST be empty. +// This is a sanity check because the instance is stripped of the code which parses userData. +function checkDescribeInstanceAttributeUserdata(xmlDoc, instanceId) { + try { + assert(xmlDoc.getElementsByTagName('DescribeInstanceAttributeResponse').length == 1); + assert(xmlDoc.getElementsByTagName('instanceId')[0].textContent === instanceId); + assert(xmlDoc.getElementsByTagName('userData')[0].textContent === ''); + } catch (e) { + throw('checkDescribeInstanceAttributeUserdata exception'); + } + return true; +} + +function checkDescribeInstanceAttributeKernel(xmlDoc, instanceId) { + try { + assert(xmlDoc.getElementsByTagName('DescribeInstanceAttributeResponse').length == 1); + assert(xmlDoc.getElementsByTagName('instanceId')[0].textContent === instanceId); + assert(xmlDoc.getElementsByTagName('kernel')[0].textContent === ''); + } catch (e) { + throw('checkDescribeInstanceAttributeKernel exception'); + } + return true; +} + +function checkDescribeInstanceAttributeRamdisk(xmlDoc, instanceId) { + try { + assert(xmlDoc.getElementsByTagName('DescribeInstanceAttributeResponse').length == 1); + assert(xmlDoc.getElementsByTagName('instanceId')[0].textContent === instanceId); + assert(xmlDoc.getElementsByTagName('ramdisk')[0].textContent === ''); + } catch (e) { + throw('checkDescribeInstanceAttributeRamdisk exception'); + } + return true; +} + + +function checkGetUser(xmlDoc, ownerId) { + try { + assert(xmlDoc.getElementsByTagName('GetUserResponse').length == 1); + assert(xmlDoc.getElementsByTagName('UserId')[0].textContent === ownerId); + assert(xmlDoc.getElementsByTagName('Arn')[0].textContent.slice(-(ownerId.length + ':root'.length)) === ownerId + ':root'); + } catch (e) { + throw('checkGetUser exception'); + } + return true; +} + + +function checkDescribeImages(xmlDoc, imageId, snapshotId){ + try { + assert(xmlDoc.getElementsByTagName('DescribeImagesResponse').length == 1); + const images = xmlDoc.getElementsByTagName('imagesSet')[0].children; + assert(images.length == 1); + const image = images[0]; + assert(image.getElementsByTagName('imageId')[0].textContent == imageId); + assert(image.getElementsByTagName('rootDeviceName')[0].textContent == '/dev/sda1'); + const devices = image.getElementsByTagName('blockDeviceMapping')[0].children; + assert(devices.length == 1); + const device = devices[0]; + const ebs = device.getElementsByTagName('ebs')[0]; + assert(ebs.getElementsByTagName('snapshotId')[0].textContent == snapshotId); + } catch (e) { + throw('checkDescribeImages exception'); + } + return true; +} + + +async function fetch_and_parse(obj){ + // we don't fetch it ourselves anymore. URLFetcher already did that for us. + // const req = await fetch(obj.request); + // const text = await req.text(); + const xmlDoc = new DOMParser().parseFromString(obj.response, 'text/xml'); + return xmlDoc; +} + +export async function getURLFetcherDoc(IP){ + // get URLFetcher document containing attestation for AWS HTTP API URLs needed to + // verify that the oracle was correctly set up. + // https://github.com/tlsnotary/URLFetcher + const resp = await fetch('http://' + IP + ':' + global.defaultNotaryPort + '/getURLFetcherDoc', { + method: 'POST', + mode: 'cors', + cache: 'no-store', + }); + return new Uint8Array(await resp.arrayBuffer()); +} + +export async function verify_oracle(URLFetcherDoc) { + // URLFetcherDoc is a concatenation of 4-byte transcript length | transcript | attestation doc + const transcriptLen = ba2int(URLFetcherDoc.slice(0,4)); + const transcript = URLFetcherDoc.slice(4,4+transcriptLen); + const attestation = URLFetcherDoc.slice(4+transcriptLen); + + // transcript is a JSON array for each request[ {"request":, "response":} , {...}] + const transJSON = JSON.parse(ba2str(transcript)); + // find which URL corresponds to which API call + const markers = [ + {'DescribeInstances': 'DI'}, + {'DescribeVolumes': 'DV'}, + {'GetConsoleOutput': 'GCO'}, + {'GetUser': 'GU'}, + {'userData': 'DIAud'}, + {'kernel': 'DIAk'}, + {'ramdisk': 'DIAr'}, + {'DescribeImages': 'DImg'}]; + const o = {}; + for (let i=0; i < markers.length; i++){ + const key = Object.keys(markers[i]); + for (let j=0; j < transJSON.length; j++){ + if (transJSON[j].request.indexOf(key) > -1){ + o[markers[i][key]] = transJSON[j]; + } + } + } + assert(Object.keys(o).length === markers.length); + + + // check that the URLs are formatted in a canonical way + // Note that AWS expects URL params to be sorted alphabetically. If we put them in + // arbitrary order, the query will be rejected + + // "AWSAccessKeyId" should be the same in all URLs to prove that the queries are made + // on behalf of AWS user "root". Otherwise, a potential attack opens up when AWS APi calls + // are made on behalf of a user with limited privileges for whom the API report only + // partial information. + const AWSAccessKeyId = o.DI.request.match(new RegExp('^https://ec2.us-east-1.amazonaws.com/\\?AWSAccessKeyId=[A-Z0-9]{20}'))[0].split('=')[1]; + // We only allow oracles instantiated from TLSNotary's AWS account. + assert(AWSAccessKeyId === 'AKIAI2NJVYXCCAQDCC5Q'); + assert(AWSAccessKeyId.length === 20); + + const instanceId = o.DI.request.match(new RegExp('^https://ec2.us-east-1.amazonaws.com/\\?AWSAccessKeyId='+AWSAccessKeyId+'&Action=DescribeInstances&Expires=2030-01-01&InstanceId=i-[a-f0-9]{17}'))[0].split('=')[4]; + assert(instanceId.length === 19); + + const volumeId = o.DV.request.match(new RegExp('^https://ec2.us-east-1.amazonaws.com/\\?AWSAccessKeyId='+AWSAccessKeyId+'&Action=DescribeVolumes&Expires=2030-01-01&SignatureMethod=HmacSHA256&SignatureVersion=2&Version=2014-10-01&VolumeId=vol-[a-f0-9]{17}'))[0].split('=')[7]; + assert(volumeId.length === 21); + + const amiId = o.DImg.request.match(new RegExp('^https://ec2.us-east-1.amazonaws.com/\\?AWSAccessKeyId='+AWSAccessKeyId+'&Action=DescribeImages&Expires=2030-01-01&ImageId.1=ami-[a-f0-9]{17}'))[0].split('=')[4]; + assert(amiId.length === 21); + + assert(new RegExp('^https://ec2.us-east-1.amazonaws.com/\\?AWSAccessKeyId='+AWSAccessKeyId+'&Action=DescribeInstances&Expires=2030-01-01&InstanceId='+instanceId+'&SignatureMethod=HmacSHA256&SignatureVersion=2&Version=2014-10-01&Signature=[a-zA-Z0-9%]{46,56}$').test(o.DI.request)); + + assert(new RegExp('^https://ec2.us-east-1.amazonaws.com/\\?AWSAccessKeyId='+AWSAccessKeyId+'&Action=DescribeVolumes&Expires=2030-01-01&SignatureMethod=HmacSHA256&SignatureVersion=2&Version=2014-10-01&VolumeId='+volumeId+'&Signature=[a-zA-Z0-9%]{46,56}$').test(o.DV.request)); + + assert(new RegExp('^https://ec2.us-east-1.amazonaws.com/\\?AWSAccessKeyId='+AWSAccessKeyId+'&Action=GetConsoleOutput&Expires=2030-01-01&InstanceId='+instanceId+'&SignatureMethod=HmacSHA256&SignatureVersion=2&Version=2014-10-01&Signature=[a-zA-Z0-9%]{46,56}$').test(o.GCO.request)); + + assert(new RegExp('^https://iam.amazonaws.com/\\?AWSAccessKeyId='+AWSAccessKeyId+'&Action=GetUser&Expires=2030-01-01&SignatureMethod=HmacSHA256&SignatureVersion=2&Version=2010-05-08&Signature=[a-zA-Z0-9%]{46,56}$').test(o.GU.request)); + + assert(new RegExp('^https://ec2.us-east-1.amazonaws.com/\\?AWSAccessKeyId='+AWSAccessKeyId+'&Action=DescribeInstanceAttribute&Attribute=userData&Expires=2030-01-01&InstanceId='+instanceId+'&SignatureMethod=HmacSHA256&SignatureVersion=2&Version=2014-10-01&Signature=[a-zA-Z0-9%]{46,56}$').test(o.DIAud.request)); + + assert(new RegExp('^https://ec2.us-east-1.amazonaws.com/\\?AWSAccessKeyId='+AWSAccessKeyId+'&Action=DescribeInstanceAttribute&Attribute=kernel&Expires=2030-01-01&InstanceId='+instanceId+'&SignatureMethod=HmacSHA256&SignatureVersion=2&Version=2014-10-01&Signature=[a-zA-Z0-9%]{46,56}$').test(o.DIAk.request)); + + assert(new RegExp('^https://ec2.us-east-1.amazonaws.com/\\?AWSAccessKeyId='+AWSAccessKeyId+'&Action=DescribeInstanceAttribute&Attribute=ramdisk&Expires=2030-01-01&InstanceId='+instanceId+'&SignatureMethod=HmacSHA256&SignatureVersion=2&Version=2014-10-01&Signature=[a-zA-Z0-9%]{46,56}$').test(o.DIAr.request)); + + assert(new RegExp('^https://ec2.us-east-1.amazonaws.com/\\?AWSAccessKeyId='+AWSAccessKeyId+'&Action=DescribeImages&Expires=2030-01-01&ImageId.1='+amiId+'&SignatureMethod=HmacSHA256&SignatureVersion=2&Version=2014-10-01&Signature=[a-zA-Z0-9%]{46,56}$').test(o.DImg.request)); + + const xmlDocDI = await fetch_and_parse(o.DI); + const rv = checkDescribeInstances(xmlDocDI, instanceId, amiId, volumeId); + const volAttachTime = rv.volAttachTime; + const ownerId = rv.ownerId; + + const xmlDocDV = await fetch_and_parse(o.DV); + checkDescribeVolumes(xmlDocDV, instanceId, volumeId, volAttachTime, rootOfTrust); + + const xmlDocGU = await fetch_and_parse(o.GU); + checkGetUser(xmlDocGU, ownerId); + + const xmlDocGCO = await fetch_and_parse(o.GCO); + const pubkeyPEM = checkGetConsoleOutput(xmlDocGCO, instanceId); + + const xmlDocDIAud = await fetch_and_parse(o.DIAud); + checkDescribeInstanceAttributeUserdata(xmlDocDIAud, instanceId); + + const xmlDocDIAk = await fetch_and_parse(o.DIAk); + checkDescribeInstanceAttributeKernel(xmlDocDIAk, instanceId); + + const xmlDocDIAr = await fetch_and_parse(o.DIAr); + checkDescribeInstanceAttributeRamdisk(xmlDocDIAr, instanceId); + + const xmlDocDImg = await fetch_and_parse(o.DImg); + checkDescribeImages(xmlDocDImg, amiId, rootOfTrust); + + // verify the attestation document + const attestRV = await verifyAttestationDoc(attestation); + assert(eq(attestRV[0], await sha256(transcript))); + assert(URLFetcherPCR0 === ba2hex(attestRV[1])); + assert(URLFetcherPCR1 === ba2hex(attestRV[2])); + assert(URLFetcherPCR2 === ba2hex(attestRV[3])); + + console.log('oracle verification successfully finished'); + return pubkeyPEM; +} + + +if (typeof module !== 'undefined'){ // we are in node.js environment + module.exports={ + check_oracle: verify_oracle, + oracle, + }; +} \ No newline at end of file diff --git a/core/third-party/SOURCES.third-party b/core/third-party/SOURCES.third-party new file mode 100644 index 0000000..643c135 --- /dev/null +++ b/core/third-party/SOURCES.third-party @@ -0,0 +1,32 @@ +pkijs folder contains files from the following sources: + +bytestream.js from https://github.com/PeculiarVentures/ByteStream.js/blob/681f2d08b1102dcd39b8a57e989dcdeadf34623d/src/bytestream.js +asn1.js from https://github.com/PeculiarVentures/ASN1.js/blob/5c64632d8d08955f07a9f80b9518a84d76f605cd/src/asn1.js +pvutils.js from https://github.com/PeculiarVentures/pvutils/blob/2d15272c34f05581eb268802c5bcfab7c4c04e03/src/utils.js +the rest of the *.js files are from +https://github.com/PeculiarVentures/PKI.js/tree/fa83e1ef003c8b450832b8c878cd36b73aaa0dee/src + +After putting all the files into the same folder, we changed the paths with +sed -i 's#from "asn1js"#from "./asn1.js"#g' * +sed -i 's#from "pvutils"#from "./pvutils.js"#g' * +sed -i 's#from "bytestreamjs"#from "./bytestream.js"#g' * + + +bigint-crypto-utils.esm.js from +https://github.com/juanelas/bigint-crypto-utils/tree/954321199d4a8038c3d27113aec825ff2e5bf544/dist/bundles + +https://github.com/Azero123/simple-js-ec-math +browserify simple-js-ec-math/src/index.js --standalone ECSimple > simple-js-ec-math.js + +https://raw.githubusercontent.com/dchest/fast-sha256-js/master/sha256.js > fastsha256.js + +cbor.js and cose.js are used to verify the enclave attestation document +cbor.js is from https://github.com/paroga/cbor-js/blob/master/cbor.js +cose.js was built with browserify coseverify.js --standalone COSE > cose.js + +pako.js ---> SOURCE??? + +certs.txt is Mozilla'a root store taken from +https://ccadb-public.secure.force.com/mozilla/IncludedCACertificateReportPEMCSV + + diff --git a/core/third-party/cbor.js b/core/third-party/cbor.js new file mode 100644 index 0000000..3e1f300 --- /dev/null +++ b/core/third-party/cbor.js @@ -0,0 +1,406 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2014-2016 Patrick Gansterer + * + * 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. + */ + +(function(global, undefined) { "use strict"; +var POW_2_24 = 5.960464477539063e-8, + POW_2_32 = 4294967296, + POW_2_53 = 9007199254740992; + +function encode(value) { + var data = new ArrayBuffer(256); + var dataView = new DataView(data); + var lastLength; + var offset = 0; + + function prepareWrite(length) { + var newByteLength = data.byteLength; + var requiredLength = offset + length; + while (newByteLength < requiredLength) + newByteLength <<= 1; + if (newByteLength !== data.byteLength) { + var oldDataView = dataView; + data = new ArrayBuffer(newByteLength); + dataView = new DataView(data); + var uint32count = (offset + 3) >> 2; + for (var i = 0; i < uint32count; ++i) + dataView.setUint32(i << 2, oldDataView.getUint32(i << 2)); + } + + lastLength = length; + return dataView; + } + function commitWrite() { + offset += lastLength; + } + function writeFloat64(value) { + commitWrite(prepareWrite(8).setFloat64(offset, value)); + } + function writeUint8(value) { + commitWrite(prepareWrite(1).setUint8(offset, value)); + } + function writeUint8Array(value) { + var dataView = prepareWrite(value.length); + for (var i = 0; i < value.length; ++i) + dataView.setUint8(offset + i, value[i]); + commitWrite(); + } + function writeUint16(value) { + commitWrite(prepareWrite(2).setUint16(offset, value)); + } + function writeUint32(value) { + commitWrite(prepareWrite(4).setUint32(offset, value)); + } + function writeUint64(value) { + var low = value % POW_2_32; + var high = (value - low) / POW_2_32; + var dataView = prepareWrite(8); + dataView.setUint32(offset, high); + dataView.setUint32(offset + 4, low); + commitWrite(); + } + function writeTypeAndLength(type, length) { + if (length < 24) { + writeUint8(type << 5 | length); + } else if (length < 0x100) { + writeUint8(type << 5 | 24); + writeUint8(length); + } else if (length < 0x10000) { + writeUint8(type << 5 | 25); + writeUint16(length); + } else if (length < 0x100000000) { + writeUint8(type << 5 | 26); + writeUint32(length); + } else { + writeUint8(type << 5 | 27); + writeUint64(length); + } + } + + function encodeItem(value) { + var i; + + if (value === false) + return writeUint8(0xf4); + if (value === true) + return writeUint8(0xf5); + if (value === null) + return writeUint8(0xf6); + if (value === undefined) + return writeUint8(0xf7); + + switch (typeof value) { + case "number": + if (Math.floor(value) === value) { + if (0 <= value && value <= POW_2_53) + return writeTypeAndLength(0, value); + if (-POW_2_53 <= value && value < 0) + return writeTypeAndLength(1, -(value + 1)); + } + writeUint8(0xfb); + return writeFloat64(value); + + case "string": + var utf8data = []; + for (i = 0; i < value.length; ++i) { + var charCode = value.charCodeAt(i); + if (charCode < 0x80) { + utf8data.push(charCode); + } else if (charCode < 0x800) { + utf8data.push(0xc0 | charCode >> 6); + utf8data.push(0x80 | charCode & 0x3f); + } else if (charCode < 0xd800) { + utf8data.push(0xe0 | charCode >> 12); + utf8data.push(0x80 | (charCode >> 6) & 0x3f); + utf8data.push(0x80 | charCode & 0x3f); + } else { + charCode = (charCode & 0x3ff) << 10; + charCode |= value.charCodeAt(++i) & 0x3ff; + charCode += 0x10000; + + utf8data.push(0xf0 | charCode >> 18); + utf8data.push(0x80 | (charCode >> 12) & 0x3f); + utf8data.push(0x80 | (charCode >> 6) & 0x3f); + utf8data.push(0x80 | charCode & 0x3f); + } + } + + writeTypeAndLength(3, utf8data.length); + return writeUint8Array(utf8data); + + default: + var length; + if (Array.isArray(value)) { + length = value.length; + writeTypeAndLength(4, length); + for (i = 0; i < length; ++i) + encodeItem(value[i]); + } else if (value instanceof Uint8Array) { + writeTypeAndLength(2, value.length); + writeUint8Array(value); + } else { + var keys = Object.keys(value); + length = keys.length; + writeTypeAndLength(5, length); + for (i = 0; i < length; ++i) { + var key = keys[i]; + encodeItem(key); + encodeItem(value[key]); + } + } + } + } + + encodeItem(value); + + if ("slice" in data) + return data.slice(0, offset); + + var ret = new ArrayBuffer(offset); + var retView = new DataView(ret); + for (var i = 0; i < offset; ++i) + retView.setUint8(i, dataView.getUint8(i)); + return ret; +} + +function decode(data, tagger, simpleValue) { + var dataView = new DataView(data); + var offset = 0; + + if (typeof tagger !== "function") + tagger = function(value) { return value; }; + if (typeof simpleValue !== "function") + simpleValue = function() { return undefined; }; + + function commitRead(length, value) { + offset += length; + return value; + } + function readArrayBuffer(length) { + return commitRead(length, new Uint8Array(data, offset, length)); + } + function readFloat16() { + var tempArrayBuffer = new ArrayBuffer(4); + var tempDataView = new DataView(tempArrayBuffer); + var value = readUint16(); + + var sign = value & 0x8000; + var exponent = value & 0x7c00; + var fraction = value & 0x03ff; + + if (exponent === 0x7c00) + exponent = 0xff << 10; + else if (exponent !== 0) + exponent += (127 - 15) << 10; + else if (fraction !== 0) + return (sign ? -1 : 1) * fraction * POW_2_24; + + tempDataView.setUint32(0, sign << 16 | exponent << 13 | fraction << 13); + return tempDataView.getFloat32(0); + } + function readFloat32() { + return commitRead(4, dataView.getFloat32(offset)); + } + function readFloat64() { + return commitRead(8, dataView.getFloat64(offset)); + } + function readUint8() { + return commitRead(1, dataView.getUint8(offset)); + } + function readUint16() { + return commitRead(2, dataView.getUint16(offset)); + } + function readUint32() { + return commitRead(4, dataView.getUint32(offset)); + } + function readUint64() { + return readUint32() * POW_2_32 + readUint32(); + } + function readBreak() { + if (dataView.getUint8(offset) !== 0xff) + return false; + offset += 1; + return true; + } + function readLength(additionalInformation) { + if (additionalInformation < 24) + return additionalInformation; + if (additionalInformation === 24) + return readUint8(); + if (additionalInformation === 25) + return readUint16(); + if (additionalInformation === 26) + return readUint32(); + if (additionalInformation === 27) + return readUint64(); + if (additionalInformation === 31) + return -1; + throw "Invalid length encoding"; + } + function readIndefiniteStringLength(majorType) { + var initialByte = readUint8(); + if (initialByte === 0xff) + return -1; + var length = readLength(initialByte & 0x1f); + if (length < 0 || (initialByte >> 5) !== majorType) + throw "Invalid indefinite length element"; + return length; + } + + function appendUtf16Data(utf16data, length) { + for (var i = 0; i < length; ++i) { + var value = readUint8(); + if (value & 0x80) { + if (value < 0xe0) { + value = (value & 0x1f) << 6 + | (readUint8() & 0x3f); + length -= 1; + } else if (value < 0xf0) { + value = (value & 0x0f) << 12 + | (readUint8() & 0x3f) << 6 + | (readUint8() & 0x3f); + length -= 2; + } else { + value = (value & 0x0f) << 18 + | (readUint8() & 0x3f) << 12 + | (readUint8() & 0x3f) << 6 + | (readUint8() & 0x3f); + length -= 3; + } + } + + if (value < 0x10000) { + utf16data.push(value); + } else { + value -= 0x10000; + utf16data.push(0xd800 | (value >> 10)); + utf16data.push(0xdc00 | (value & 0x3ff)); + } + } + } + + function decodeItem() { + var initialByte = readUint8(); + var majorType = initialByte >> 5; + var additionalInformation = initialByte & 0x1f; + var i; + var length; + + if (majorType === 7) { + switch (additionalInformation) { + case 25: + return readFloat16(); + case 26: + return readFloat32(); + case 27: + return readFloat64(); + } + } + + length = readLength(additionalInformation); + if (length < 0 && (majorType < 2 || 6 < majorType)) + throw "Invalid length"; + + switch (majorType) { + case 0: + return length; + case 1: + return -1 - length; + case 2: + if (length < 0) { + var elements = []; + var fullArrayLength = 0; + while ((length = readIndefiniteStringLength(majorType)) >= 0) { + fullArrayLength += length; + elements.push(readArrayBuffer(length)); + } + var fullArray = new Uint8Array(fullArrayLength); + var fullArrayOffset = 0; + for (i = 0; i < elements.length; ++i) { + fullArray.set(elements[i], fullArrayOffset); + fullArrayOffset += elements[i].length; + } + return fullArray; + } + return readArrayBuffer(length); + case 3: + var utf16data = []; + if (length < 0) { + while ((length = readIndefiniteStringLength(majorType)) >= 0) + appendUtf16Data(utf16data, length); + } else + appendUtf16Data(utf16data, length); + return String.fromCharCode.apply(null, utf16data); + case 4: + var retArray; + if (length < 0) { + retArray = []; + while (!readBreak()) + retArray.push(decodeItem()); + } else { + retArray = new Array(length); + for (i = 0; i < length; ++i) + retArray[i] = decodeItem(); + } + return retArray; + case 5: + var retObject = {}; + for (i = 0; i < length || length < 0 && !readBreak(); ++i) { + var key = decodeItem(); + retObject[key] = decodeItem(); + } + return retObject; + case 6: + return tagger(decodeItem(), length); + case 7: + switch (length) { + case 20: + return false; + case 21: + return true; + case 22: + return null; + case 23: + return undefined; + default: + return simpleValue(length); + } + } + } + + var ret = decodeItem(); + if (offset !== data.byteLength) + throw "Remaining bytes"; + return ret; +} + +var obj = { encode: encode, decode: decode }; + +if (typeof define === "function" && define.amd) + define("cbor/cbor", obj); +else if (typeof module !== "undefined" && module.exports) + module.exports = obj; +else if (!global.CBOR) + global.CBOR = obj; + +})(this); diff --git a/core/third-party/certs.txt b/core/third-party/certs.txt new file mode 100644 index 0000000..e501515 --- /dev/null +++ b/core/third-party/certs.txt @@ -0,0 +1,3803 @@ +"Owner","Certificate Issuer Organization","Certificate Issuer Organizational Unit","Common Name or Certificate Name","Certificate Serial Number","SHA-256 Fingerprint","Subject + SPKI SHA256","Valid From [GMT]","Valid To [GMT]","Public Key Algorithm","Signature Hash Algorithm","Trust Bits","Distrust for TLS After Date","Distrust for S/MIME After Date","EV Policy OID(s)","Approval Bug","NSS Release When First Included","Firefox Release When First Included","Test Website - Valid","Test Website - Expired","Test Website - Revoked","Mozilla Applied Constraints","Company Website","Geographic Focus","Certificate Policy (CP)","Certification Practice Statement (CPS)","Standard Audit","BR Audit","EV Audit","Auditor","Standard Audit Type","Standard Audit Statement Dt","PEM Info" +"AC Camerfirma, S.A.","AC Camerfirma SA CIF A82743287","http://www.chambersign.org","Chambers of Commerce Root","00","0C258A12A5674AEF25F28BA7DCFAECEEA348E541E6F5CC4EE63B71B361606AC3","BC2FD9EA61581CB22BB859690D61430E7D222D1119E8C41649B9B1D556D439A4","2003.09.30","2037.09.30","RSA 2048 bits","SHA1WithRSA","Email","","","Not EV","https://bugzilla.mozilla.org/show_bug.cgi?id=261778","","Firefox 1","","","","","http://www.camerfirma.com","Spain","","https://www.camerfirma.com/publico/DocumentosWeb/politicas/CPS_eidas_EN_1.2.12.pdf","https://www.csqa.it/getattachment/Sicurezza-ICT/Documenti/Attestazione-di-Audit-secondo-i-requisiti-ETSI/2020-03-CSQA-Attestation-CAMERFIRMA-rev-2-signed.pdf.aspx?lang=it-IT","https://bugzilla.mozilla.org/attachment.cgi?id=8995930","","CSQA Certificazioni srl","ETSI EN 319 411","2020.03.05","'-----BEGIN CERTIFICATE----- +MIIEvTCCA6WgAwIBAgIBADANBgkqhkiG9w0BAQUFADB/MQswCQYDVQQGEwJFVTEn +MCUGA1UEChMeQUMgQ2FtZXJmaXJtYSBTQSBDSUYgQTgyNzQzMjg3MSMwIQYDVQQL +ExpodHRwOi8vd3d3LmNoYW1iZXJzaWduLm9yZzEiMCAGA1UEAxMZQ2hhbWJlcnMg +b2YgQ29tbWVyY2UgUm9vdDAeFw0wMzA5MzAxNjEzNDNaFw0zNzA5MzAxNjEzNDRa +MH8xCzAJBgNVBAYTAkVVMScwJQYDVQQKEx5BQyBDYW1lcmZpcm1hIFNBIENJRiBB +ODI3NDMyODcxIzAhBgNVBAsTGmh0dHA6Ly93d3cuY2hhbWJlcnNpZ24ub3JnMSIw +IAYDVQQDExlDaGFtYmVycyBvZiBDb21tZXJjZSBSb290MIIBIDANBgkqhkiG9w0B +AQEFAAOCAQ0AMIIBCAKCAQEAtzZV5aVdGDDg2olUkfzIx1L4L1DZ77F1c2VHfRtb +unXF/KGIJPov7coISjlUxFF6tdpg6jg8gbLL8bvZkSM/SAFwdakFKq0fcfPJVD0d +BmpAPrMMhe5cG3nCYsS4No41XQEMIwRHNaqbYE6gZj3LJgqcQKH0XZi/caulAGgq +7YN6D6IUtdQis4CwPAxaUWktWBiP7Zme8a7ileb2R6jWDA+wWFjbw2Y3npuRVDM3 +0pQcakjJyfKl2qUMI/cjDpwyVV5xnIQFUZot/eZOKjRa3spAN2cMVCFVd9oKDMyX +roDclDZK9D7ONhMeU+SsTjoF7Nuucpw4i9A5O4kKPnf+dQIBA6OCAUQwggFAMBIG +A1UdEwEB/wQIMAYBAf8CAQwwPAYDVR0fBDUwMzAxoC+gLYYraHR0cDovL2NybC5j +aGFtYmVyc2lnbi5vcmcvY2hhbWJlcnNyb290LmNybDAdBgNVHQ4EFgQU45T1sU3p +26EpW1eLTXYGduHRooowDgYDVR0PAQH/BAQDAgEGMBEGCWCGSAGG+EIBAQQEAwIA +BzAnBgNVHREEIDAegRxjaGFtYmVyc3Jvb3RAY2hhbWJlcnNpZ24ub3JnMCcGA1Ud +EgQgMB6BHGNoYW1iZXJzcm9vdEBjaGFtYmVyc2lnbi5vcmcwWAYDVR0gBFEwTzBN +BgsrBgEEAYGHLgoDATA+MDwGCCsGAQUFBwIBFjBodHRwOi8vY3BzLmNoYW1iZXJz +aWduLm9yZy9jcHMvY2hhbWJlcnNyb290Lmh0bWwwDQYJKoZIhvcNAQEFBQADggEB +AAxBl8IahsAifJ/7kPMa0QOx7xP5IV8EnNrJpY0nbJaHkb5BkAFyk+cefV/2icZd +p0AJPaxJRUXcLo0waLIJuvvDL8y6C98/d3tGfToSJI6WjzwFCm/SlCgdbQzALogi +1djPHRPH8EjX1wWnz8dHnjs8NMiAT9QUu/wNUPf6s+xCX6ndbcj0dc97wXImsQEc +XCz9ek60AcUFV7nnPKoF2YjpB0ZBzu9Bga5Y34OirsrXdx/nADydb47kMgkdTXg0 +eDQ8lJsm7U9xxhl6vSAiSFr+S30Dt+dYvsYyTnQeaN2oaFuzPu5ifdmA6Ap1erfu +tGWaIZDgqtCYvDi1czyL+Nw= +-----END CERTIFICATE-----'" +"AC Camerfirma, S.A.","AC Camerfirma S.A.","","Chambers of Commerce Root - 2008","00A3DA427EA4B1AEDA","063E4AFAC491DFD332F3089B8542E94617D893D7FE944E10A7937EE29D9693C0","849AD3279D9B805A288339468C417744AC1CE2758A6E283A446685384D5D6CD2","2008.08.01","2038.07.31","RSA 4096 bits","SHA1WithRSA","Websites;Email","","","1.3.6.1.4.1.17326.10.14.2.1.2","https://bugzilla.mozilla.org/show_bug.cgi?id=406968","NSS 3.12.9","Firefox 4.0","https://server3ok.camerfirma.com","https://server3.camerfirma.com","https://server3rv.camerfirma.com","","http://www.camerfirma.com","Spain","","https://www.camerfirma.com/publico/DocumentosWeb/politicas/CPS_eidas_EN_1.2.12.pdf","https://www.csqa.it/getattachment/Sicurezza-ICT/Documenti/Attestazione-di-Audit-secondo-i-requisiti-ETSI/2020-03-CSQA-Attestation-CAMERFIRMA-rev-2-signed.pdf.aspx?lang=it-IT","https://www.csqa.it/getattachment/Sicurezza-ICT/Documenti/Attestazione-di-Audit-secondo-i-requisiti-ETSI/2020-03-CSQA-Attestation-CAMERFIRMA-rev-2-signed.pdf.aspx?lang=it-IT","https://www.csqa.it/getattachment/Sicurezza-ICT/Documenti/Attestazione-di-Audit-secondo-i-requisiti-ETSI/2020-03-CSQA-Attestation-CAMERFIRMA-rev-2-signed.pdf.aspx?lang=it-IT","CSQA Certificazioni srl","ETSI EN 319 411","2020.03.05","'-----BEGIN CERTIFICATE----- +MIIHTzCCBTegAwIBAgIJAKPaQn6ksa7aMA0GCSqGSIb3DQEBBQUAMIGuMQswCQYD +VQQGEwJFVTFDMEEGA1UEBxM6TWFkcmlkIChzZWUgY3VycmVudCBhZGRyZXNzIGF0 +IHd3dy5jYW1lcmZpcm1hLmNvbS9hZGRyZXNzKTESMBAGA1UEBRMJQTgyNzQzMjg3 +MRswGQYDVQQKExJBQyBDYW1lcmZpcm1hIFMuQS4xKTAnBgNVBAMTIENoYW1iZXJz +IG9mIENvbW1lcmNlIFJvb3QgLSAyMDA4MB4XDTA4MDgwMTEyMjk1MFoXDTM4MDcz +MTEyMjk1MFowga4xCzAJBgNVBAYTAkVVMUMwQQYDVQQHEzpNYWRyaWQgKHNlZSBj +dXJyZW50IGFkZHJlc3MgYXQgd3d3LmNhbWVyZmlybWEuY29tL2FkZHJlc3MpMRIw +EAYDVQQFEwlBODI3NDMyODcxGzAZBgNVBAoTEkFDIENhbWVyZmlybWEgUy5BLjEp +MCcGA1UEAxMgQ2hhbWJlcnMgb2YgQ29tbWVyY2UgUm9vdCAtIDIwMDgwggIiMA0G +CSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCvAMtwNyuAWko6bHiUfaN/Gh/2NdW9 +28sNRHI+JrKQUrpjOyhYb6WzbZSm891kDFX29ufyIiKAXuFixrYp4YFs8r/lfTJq +VKAyGVn+H4vXPWCGhSRv4xGzdz4gljUha7MI2XAuZPeEklPWDrCQiorjh40G072Q +DuKZoRuGDtqaCrsLYVAGUvGef3bsyw/QHg3PmTA9HMRFEFis1tPo1+XqxQEHd9ZR +5gN/ikilTWh1uem8nk4ZcfUyS5xtYBkL+8ydddy/Js2Pk3g5eXNeJQ7KXOt3EgfL +ZEFHcpOrUMPrCXZkNNI5t3YRCQ12RcSprj1qr7V9ZS+UWBDsXHyvfuK2GNnQm05a +Sd+pZgvMPMZ4fKecHePOjlO+Bd5gD2vlGts/4+EhySnB8esHnFIbAURRPHsl18Tl +UlRdJQfKFiC4reRB7noI/plvg6aRArBsNlVq5331lubKgdaX8ZSD6e2wsWsSaR6s ++12pxZjptFtYer49okQ6Y1nUCyXeG0+95QGezdIp1Z8XGQpvvwyQ0wlf2eOKNcx5 +Wk0ZN5K3xMGtr/R5JJqyAQuxr1yW84Ay+1w9mPGgP0revq+ULtlVmhduYJ1jbLhj +ya6BXBg14JC7vjxPNyK5fuvPnnchpj04gftI2jE9K+OJ9dC1vX7gUMQSibMjmhAx +hduub+84Mxh2EQIDAQABo4IBbDCCAWgwEgYDVR0TAQH/BAgwBgEB/wIBDDAdBgNV +HQ4EFgQU+SSsD7K1+HnA+mCIG8TZTQKeFxkwgeMGA1UdIwSB2zCB2IAU+SSsD7K1 ++HnA+mCIG8TZTQKeFxmhgbSkgbEwga4xCzAJBgNVBAYTAkVVMUMwQQYDVQQHEzpN +YWRyaWQgKHNlZSBjdXJyZW50IGFkZHJlc3MgYXQgd3d3LmNhbWVyZmlybWEuY29t +L2FkZHJlc3MpMRIwEAYDVQQFEwlBODI3NDMyODcxGzAZBgNVBAoTEkFDIENhbWVy +ZmlybWEgUy5BLjEpMCcGA1UEAxMgQ2hhbWJlcnMgb2YgQ29tbWVyY2UgUm9vdCAt +IDIwMDiCCQCj2kJ+pLGu2jAOBgNVHQ8BAf8EBAMCAQYwPQYDVR0gBDYwNDAyBgRV +HSAAMCowKAYIKwYBBQUHAgEWHGh0dHA6Ly9wb2xpY3kuY2FtZXJmaXJtYS5jb20w +DQYJKoZIhvcNAQEFBQADggIBAJASryI1wqM58C7e6bXpeHxIvj99RZJe6dqxGfwW +PJ+0W2aeaufDuV2I6A+tzyMP3iU6XsxPpcG1Lawk0lgH3qLPaYRgM+gQDROpI9CF +5Y57pp49chNyM/WqfcZjHwj0/gF/JM8rLFQJ3uIrbZLGOU8W6jx+ekbURWpGqOt1 +glanq6B8aBMz9p0w8G8nOSQjKpD9kCk18pPfNKXG9/jvjA9iSnyu0/VU+I22mlaH +FoI6M6taIgj3grrqLuBHmrS1RaMFO9ncLkVAO+rcf+g769HsJtg1pDDFOqxXnrN2 +pSB7+R5KBWIBpih1YJeSDW4+TTdDDZIVnBgizVGZoCkaPF+KMjNbMMeJL0eYD6MD +xvbxrN8y8NmBGuScvfaAFPDRLLmF9dijscilIeUcE5fuDr3fKanvNFNb0+RqE4QG +tjICxFKuItLcsiFCGtpA8CnJ7AoMXOLQusxI0zcKzBIKinmwPQN/aUv0NCB9szTq +jktk9T79syNnFQ0EuPAtwQlRPLJsFfClI9eDdOTlLsn+mCdCxqvGnrDQWzilm1De +fhiYtUU79nm06PcaewaD+9CL2rvHvRirCG88gGtAPxkZumWK5r7VXNM21+9AUiRg +OGcEMeyP84LG3rlV8zsxkVrctQgVrXYlCg17LofiDKYGvCYQbTed7N14jHyAxfDZ +d0jQ +-----END CERTIFICATE-----'" +"AC Camerfirma, S.A.","AC Camerfirma SA CIF A82743287","http://www.chambersign.org","Global Chambersign Root","00","EF3CB417FC8EBF6F97876C9E4ECE39DE1EA5FE649141D1028B7D11C0B2298CED","F33BD6DDC7576A7AC9BBA464D7425F26D58FD2C51A3A1F89878D5262BDD485E0","2003.09.30","2037.09.30","RSA 2048 bits","SHA1WithRSA","Email","","","Not EV","https://bugzilla.mozilla.org/show_bug.cgi?id=261778","","Firefox 1","","","","","http://www.camerfirma.com","Spain","","https://www.camerfirma.com/publico/DocumentosWeb/politicas/CPS_eidas_EN_1.2.12.pdf","https://www.csqa.it/getattachment/Sicurezza-ICT/Documenti/Attestazione-di-Audit-secondo-i-requisiti-ETSI/2020-03-CSQA-Attestation-CAMERFIRMA-rev-2-signed.pdf.aspx?lang=it-IT","https://bugzilla.mozilla.org/attachment.cgi?id=8995930","https://bugzilla.mozilla.org/attachment.cgi?id=8995931","CSQA Certificazioni srl","ETSI EN 319 411","2020.03.05","'-----BEGIN CERTIFICATE----- +MIIExTCCA62gAwIBAgIBADANBgkqhkiG9w0BAQUFADB9MQswCQYDVQQGEwJFVTEn +MCUGA1UEChMeQUMgQ2FtZXJmaXJtYSBTQSBDSUYgQTgyNzQzMjg3MSMwIQYDVQQL +ExpodHRwOi8vd3d3LmNoYW1iZXJzaWduLm9yZzEgMB4GA1UEAxMXR2xvYmFsIENo +YW1iZXJzaWduIFJvb3QwHhcNMDMwOTMwMTYxNDE4WhcNMzcwOTMwMTYxNDE4WjB9 +MQswCQYDVQQGEwJFVTEnMCUGA1UEChMeQUMgQ2FtZXJmaXJtYSBTQSBDSUYgQTgy +NzQzMjg3MSMwIQYDVQQLExpodHRwOi8vd3d3LmNoYW1iZXJzaWduLm9yZzEgMB4G +A1UEAxMXR2xvYmFsIENoYW1iZXJzaWduIFJvb3QwggEgMA0GCSqGSIb3DQEBAQUA +A4IBDQAwggEIAoIBAQCicKLQn0KuWxfH2H3PFIP8T8mhtxOviteePgQKkotgVvq0 +Mi+ITaFgCPS3CU6gSS9J1tPfnZdan5QEcOw/Wdm3zGaLmFIoCQLfxS+EjXqXd7/s +QJ0lcqu1PzKY+7e3/HKE5TWH+VX6ox8Oby4o3Wmg2UIQxvi1RMLQQ3/bvOSiPGpV +eAp3qdjqGTK3L/5cPxvusZjsyq16aUXjlg9V9ubtdepl6DJWk0aJqCWKZQbua795 +B9Dxt6/tLE2Su8CoX6dnfQTyFQhwrJLWfQTSM/tMtgsL+xrJxI0DqX5c8lCrEqWh +z0hQpe/SyBoT+rB/sYIcd2oPX9wLlY/vQ37mRQklAgEDo4IBUDCCAUwwEgYDVR0T +AQH/BAgwBgEB/wIBDDA/BgNVHR8EODA2MDSgMqAwhi5odHRwOi8vY3JsLmNoYW1i +ZXJzaWduLm9yZy9jaGFtYmVyc2lnbnJvb3QuY3JsMB0GA1UdDgQWBBRDnDafsJ4w +TcbOX60Qq+UDpfqpFDAOBgNVHQ8BAf8EBAMCAQYwEQYJYIZIAYb4QgEBBAQDAgAH +MCoGA1UdEQQjMCGBH2NoYW1iZXJzaWducm9vdEBjaGFtYmVyc2lnbi5vcmcwKgYD +VR0SBCMwIYEfY2hhbWJlcnNpZ25yb290QGNoYW1iZXJzaWduLm9yZzBbBgNVHSAE +VDBSMFAGCysGAQQBgYcuCgEBMEEwPwYIKwYBBQUHAgEWM2h0dHA6Ly9jcHMuY2hh +bWJlcnNpZ24ub3JnL2Nwcy9jaGFtYmVyc2lnbnJvb3QuaHRtbDANBgkqhkiG9w0B +AQUFAAOCAQEAPDtwkfkEVCeR4e3t/mh/YV3lQWVPMvEYBZRqHN4fcNs+ezICNLUM +bKGKfKX0j//U2K0X1S0E0T9YgOKBWYi+wONGkyT+kL0mojAt6JcmVzWJdJYY9hXi +ryQZVgICsroPFOrGimbBhkVVi76SvpykBMdJPJ7oKXqJ1/6v/2j1pReQvayZzKWG +VwlnRtvWFsJG8eSpUPWP0ZIV018+xgBJOm5YstHRJw0lyDL4IBHNfTIzSJRUTN3c +ecQwn+uOuFW114hcxWokPbLTBQNRxgfvzBRydD1ucs4YKIxKoHflCStFREest2d/ +AYoFWpO+ocH/+OcOZ6RHSXZddZAa9SaP8A== +-----END CERTIFICATE-----'" +"AC Camerfirma, S.A.","AC Camerfirma S.A.","","Global Chambersign Root - 2008","00C9CDD3E9D57D23CE","136335439334A7698016A0D324DE72284E079D7B5220BB8FBD747816EEBEBACA","7DB0C6863B891672A51E9D28B42610F1DB9F5651C8C87736B937536F8453F947","2008.08.01","2038.07.31","RSA 4096 bits","SHA1WithRSA","Websites;Email","","","Not EV","https://bugzilla.mozilla.org/show_bug.cgi?id=406968","NSS 3.12.9","Firefox 4.0","https://valid.ovcf.ca3.infocert.it","https://expired.ovcf.ca3.infocert.it","https://revoked.ovcf.ca3.infocert.it","","http://www.camerfirma.com","Spain","","https://www.camerfirma.com/publico/DocumentosWeb/politicas/CPS_eidas_EN_1.2.12.pdf","https://www.csqa.it/getattachment/Sicurezza-ICT/Documenti/Attestazione-di-Audit-secondo-i-requisiti-ETSI/2020-03-CSQA-Attestation-CAMERFIRMA-rev-2-signed.pdf.aspx?lang=it-IT","https://www.csqa.it/getattachment/Sicurezza-ICT/Documenti/Attestazione-di-Audit-secondo-i-requisiti-ETSI/2020-03-CSQA-Attestation-CAMERFIRMA-rev-2-signed.pdf.aspx?lang=it-IT","https://www.csqa.it/getattachment/Sicurezza-ICT/Documenti/Attestazione-di-Audit-secondo-i-requisiti-ETSI/2020-03-CSQA-Attestation-CAMERFIRMA-rev-2-signed.pdf.aspx?lang=it-IT","CSQA Certificazioni srl","ETSI EN 319 411","2020.03.05","'-----BEGIN CERTIFICATE----- +MIIHSTCCBTGgAwIBAgIJAMnN0+nVfSPOMA0GCSqGSIb3DQEBBQUAMIGsMQswCQYD +VQQGEwJFVTFDMEEGA1UEBxM6TWFkcmlkIChzZWUgY3VycmVudCBhZGRyZXNzIGF0 +IHd3dy5jYW1lcmZpcm1hLmNvbS9hZGRyZXNzKTESMBAGA1UEBRMJQTgyNzQzMjg3 +MRswGQYDVQQKExJBQyBDYW1lcmZpcm1hIFMuQS4xJzAlBgNVBAMTHkdsb2JhbCBD +aGFtYmVyc2lnbiBSb290IC0gMjAwODAeFw0wODA4MDExMjMxNDBaFw0zODA3MzEx +MjMxNDBaMIGsMQswCQYDVQQGEwJFVTFDMEEGA1UEBxM6TWFkcmlkIChzZWUgY3Vy +cmVudCBhZGRyZXNzIGF0IHd3dy5jYW1lcmZpcm1hLmNvbS9hZGRyZXNzKTESMBAG +A1UEBRMJQTgyNzQzMjg3MRswGQYDVQQKExJBQyBDYW1lcmZpcm1hIFMuQS4xJzAl +BgNVBAMTHkdsb2JhbCBDaGFtYmVyc2lnbiBSb290IC0gMjAwODCCAiIwDQYJKoZI +hvcNAQEBBQADggIPADCCAgoCggIBAMDfVtPkOpt2RbQT2//BthmLN0EYlVJH6xed +KYiONWwGMi5HYvNJBL99RDaxccy9Wglz1dmFRP+RVyXfXjaOcNFccUMd2drvXNL7 +G706tcuto8xEpw2uIRU/uXpbknXYpBI4iRmKt4DS4jJvVpyR1ogQC7N0ZJJ0YPP2 +zxhPYLIj0Mc7zmFLmY/CDNBAspjcDahOo7kKrmCgrUVSY7pmvWjg+b4aqIG7HkF4 +ddPB/gBVsIdU6CeQNR1MM62X/JcumIS/LMmjv9GYERTtY/jKmIhYF5ntRQOXfjyG +HoiMvvKRhI9lNNgATH23MRdaKXoKGCQwoze1eqkBfSbW+Q6OWfH9GzO1KTsXO0G2 +Id3UwD2ln58fQ1DJu7xsepeY7s2MH/ucUa6LcL0nn3HAa6x9kGbo1106DbDVwo3V +yJ2dwW3Q0L9R5OP4wzg2rtandeavhENdk5IMagfeOx2YItaswTXbo6Al/3K1dh3e +beksZixShNBFks4c5eUzHdwHU1SjqoI7mjcv3N2gZOnm3b2u/GSFHTynyQbehP9r +6GsaPMWis0L7iwk+XwhSx2LE1AVxv8Rk5Pihg+g+EpuoHtQ2TS9x9o0o9oOpE9Jh +wZG7SMA0j0GMS0zbaRL/UJScIINZc+18ofLx/d33SdNDWKBWY8o9PeU1VlnpDsog +zCtLkykPAgMBAAGjggFqMIIBZjASBgNVHRMBAf8ECDAGAQH/AgEMMB0GA1UdDgQW +BBS5CcqcHtvTbDprru1U8VuTBjUuXjCB4QYDVR0jBIHZMIHWgBS5CcqcHtvTbDpr +ru1U8VuTBjUuXqGBsqSBrzCBrDELMAkGA1UEBhMCRVUxQzBBBgNVBAcTOk1hZHJp +ZCAoc2VlIGN1cnJlbnQgYWRkcmVzcyBhdCB3d3cuY2FtZXJmaXJtYS5jb20vYWRk +cmVzcykxEjAQBgNVBAUTCUE4Mjc0MzI4NzEbMBkGA1UEChMSQUMgQ2FtZXJmaXJt +YSBTLkEuMScwJQYDVQQDEx5HbG9iYWwgQ2hhbWJlcnNpZ24gUm9vdCAtIDIwMDiC +CQDJzdPp1X0jzjAOBgNVHQ8BAf8EBAMCAQYwPQYDVR0gBDYwNDAyBgRVHSAAMCow +KAYIKwYBBQUHAgEWHGh0dHA6Ly9wb2xpY3kuY2FtZXJmaXJtYS5jb20wDQYJKoZI +hvcNAQEFBQADggIBAICIf3DekijZBZRG/5BXqfEv3xoNa/p8DhxJJHkn2EaqbylZ +UohwEurdPfWbU1Rv4WCiqAm57OtZfMY18dwY6fFn5a+6ReAJ3spED8IXDneRRXoz +X1+WLGiLwUePmJs9wOzL9dWCkoQ10b42OFZyMVtHLaoXpGNR6woBrX/sdZ7LoR/x +fxKxueRkf2fWIyr0uDldmOghp+G9PUIadJpwr2hsUF1Jz//7Dl3mLEfXgTpZALVz +a2Mg9jFFCDkO9HB+QHBaP9BrQql0PSgvAm11cpUJjUhjxsYjV5KTXjXBjfkK9yyd +Yhz2rXzdpjEetrHHfoUm+qRqtdpjMNHvkzeyZi99Bffnt0uYlDXA2TopwZ2yUDMd +SqlapskD7+3056huirRXhOukP9DuqqqHW2Pok+JrqNS4cnhrG+055F3Lm6qH1U9O +AP7Zap88MQ8oAgF9mOinsKJknnn4SPIVqczmyETrP3iZ8ntxPjzxmKfFGBI/5rso +M0LpRQp8bfKGeS/Fghl9CYl8slR2iK7ewfPM4W7bMdaTrpmg7yVqc5iJWzouE4ge +v8CSlDQb4ye3ix5vQv/n6TebUB0tovkC7stYWDpxvGjjqsGvHCgfotwjZT+B6q6Z +09gwzxMNTxXJhLynSC34MCN32EZLeW32jO06f2ARePTpm67VVMB0gNELQp/B +-----END CERTIFICATE-----'" +"Actalis","Actalis S.p.A./03358520967","","Actalis Authentication Root CA","570A119742C4E3CC","55926084EC963A64B96E2ABE01CE0BA86A64FBFEBCC7AAB5AFC155B37FD76066","362588CB736FFCA8E8CA1A485F8D0FD3FE4A32A1EDB3606E71A5F2F7986A4B34","2011.09.22","2030.09.22","RSA 4096 bits","SHA256WithRSA","Websites;Email","","","1.3.159.1.17.1","https://bugzilla.mozilla.org/show_bug.cgi?id=1176188","NSS 3.13.6","Firefox 16","https://ssltest-active.actalis.it/","https://ssltest-expired.actalis.it/","https://ssltest-revoked.actalis.it/","None","http://www.actalis.it/","Italy","","https://www.actalis.it/documenti-en/cps_for_ssl_server_and_code_signing_en.aspx","https://www.bureauveritas.it/sites/g/files/zypfnx256/files/media/document/CONFORMITY%20DECLARATION%20SSL%20ASSESSMENT%20ACTALIS%20SPA.pdf","https://www.bureauveritas.it/sites/g/files/zypfnx256/files/media/document/CONFORMITY%20DECLARATION%20SSL%20ASSESSMENT%20ACTALIS%20SPA.pdf","https://www.bureauveritas.it/sites/g/files/zypfnx256/files/media/document/CONFORMITY%20DECLARATION%20SSL%20ASSESSMENT%20ACTALIS%20SPA.pdf","Bureau Veritas Italia S.p.A.","ETSI EN 319 411","2020.05.31","'-----BEGIN CERTIFICATE----- +MIIFuzCCA6OgAwIBAgIIVwoRl0LE48wwDQYJKoZIhvcNAQELBQAwazELMAkGA1UE +BhMCSVQxDjAMBgNVBAcMBU1pbGFuMSMwIQYDVQQKDBpBY3RhbGlzIFMucC5BLi8w +MzM1ODUyMDk2NzEnMCUGA1UEAwweQWN0YWxpcyBBdXRoZW50aWNhdGlvbiBSb290 +IENBMB4XDTExMDkyMjExMjIwMloXDTMwMDkyMjExMjIwMlowazELMAkGA1UEBhMC +SVQxDjAMBgNVBAcMBU1pbGFuMSMwIQYDVQQKDBpBY3RhbGlzIFMucC5BLi8wMzM1 +ODUyMDk2NzEnMCUGA1UEAwweQWN0YWxpcyBBdXRoZW50aWNhdGlvbiBSb290IENB +MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAp8bEpSmkLO/lGMWwUKNv +UTufClrJwkg4CsIcoBh/kbWHuUA/3R1oHwiD1S0eiKD4j1aPbZkCkpAW1V8IbInX +4ay8IMKx4INRimlNAJZaby/ARH6jDuSRzVju3PvHHkVH3Se5CAGfpiEd9UEtL0z9 +KK3giq0itFZljoZUj5NDKd45RnijMCO6zfB9E1fAXdKDa0hMxKufgFpbOr3JpyI/ +gCczWw63igxdBzcIy2zSekciRDXFzMwujt0q7bd9Zg1fYVEiVRvjRuPjPdA1Yprb +rxTIW6HMiRvhMCb8oJsfgadHHwTrozmSBp+Z07/T6k9QnBn+locePGX2oxgkg4YQ +51Q+qDp2JE+BIcXjDwL4k5RHILv+1A7TaLndxHqEguNTVHnd25zS8gebLra8Pu2F +be8lEfKXGkJh90qX6IuxEAf6ZYGyojnP9zz/GPvG8VqLWeICrHuS0E4UT1lF9gxe +KF+w6D9Fz8+vm2/7hNN3WpVvrJSEnu68wEqPSpP4RCHiMUVhUE4Q2OM1fEwZtN4F +v6MGn8i1zeQf1xcGDXqVdFUNaBr8EBtiZJ1t4JWgw5QHVw0U5r0F+7if5t+L4sbn +fpb2U8WANFAoWPASUHEXMLrmeGO89LKtmyuy/uE5jF66CyCU3nuDuP/jVo23Eek7 +jPKxwV2dpAtMK9myGPW1n0sCAwEAAaNjMGEwHQYDVR0OBBYEFFLYiDrIn3hm7Ynz +ezhwlMkCAjbQMA8GA1UdEwEB/wQFMAMBAf8wHwYDVR0jBBgwFoAUUtiIOsifeGbt +ifN7OHCUyQICNtAwDgYDVR0PAQH/BAQDAgEGMA0GCSqGSIb3DQEBCwUAA4ICAQAL +e3KHwGCmSUyIWOYdiPcUZEim2FgKDk8TNd81HdTtBjHIgT5q1d07GjLukD0R0i70 +jsNjLiNmsGe+b7bAEzlgqqI0JZN1Ut6nna0Oh4lScWoWPBkdg/iaKWW+9D+a2fDz +WochcYBNy+A4mz+7+uAwTc+G02UQGRjRlwKxK3JCaKygvU5a2hi/a5iB0P2avl4V +SM0RFbnAKVy06Ij3Pjaut2L9HmLecHgQHEhb2rykOLpn7VU+Xlff1ANATIGk0k9j +pwlCCRT8AKnCgHNPLsBA2RF7SOp6AsDT6ygBJlh0wcBzIm2Tlf05fbsq4/aC4yyX +X04fkZT6/iyj2HYauE2yOE+b+h1IYHkm4vP9qdCa6HCPSXrW5b0KDtst842/6+Ok +fcvHlXHo2qN8xcL4dJIEG4aspCJTQLas/kx2z/uUMsA1n3Y/buWQbqCmJqK4LL7R +K4X9p2jIugErsWx0Hbhzlefut8cl8ABMALJ+tguLHPPAUJ4lueAI3jZm/zel0btU +ZCzJJ7VLkn5l/9Mt4blOvH+kQSGQQXemOR/qnuOf0GZvBeyqdn6/axag67XH/JJU +LysRJyU3eExRarDzzFhdFPFqSBX/wge2sY0PjlxQRrM9vwGYT7JZVEc+NHt4bVaT +LnPqZih4zR0Uv6CPLy64Lo7yFIrM6bV8+2ydDKXhlg== +-----END CERTIFICATE-----'" +"Amazon Trust Services","Amazon","","Amazon Root CA 1","066C9FCF99BF8C0A39E2F0788A43E696365BCA","8ECDE6884F3D87B1125BA31AC3FCB13D7016DE7F57CC904FE1CB97C6AE98196E","99D5D46631FE07C70451AFF54AD78F56A2FA84FED847B237F8D81F845FA88D20","2015.05.26","2038.01.17","RSA 2048 bits","SHA256WithRSA","Websites;Email","","","2.23.140.1.1","https://bugzilla.mozilla.org/show_bug.cgi?id=1172401","NSS 3.28.1","Firefox 51","https://good.sca1a.amazontrust.com/","https://expired.sca1a.amazontrust.com/","https://revoked.sca1a.amazontrust.com/","None","https://www.amazontrust.com/","USA, Global","https://www.amazontrust.com/repository/cp-1.0.7.pdf","https://www.amazontrust.com/repository/cps-1.0.8.pdf","https://www.cpacanada.ca/generichandlers/CPACHandler.ashx?attachmentid=239088","https://www.cpacanada.ca/generichandlers/CPACHandler.ashx?attachmentid=239089","https://www.cpacanada.ca/generichandlers/CPACHandler.ashx?attachmentid=239090","BDO International Limited","WebTrust","2020.04.08","'-----BEGIN CERTIFICATE----- +MIIDQTCCAimgAwIBAgITBmyfz5m/jAo54vB4ikPmljZbyjANBgkqhkiG9w0BAQsF +ADA5MQswCQYDVQQGEwJVUzEPMA0GA1UEChMGQW1hem9uMRkwFwYDVQQDExBBbWF6 +b24gUm9vdCBDQSAxMB4XDTE1MDUyNjAwMDAwMFoXDTM4MDExNzAwMDAwMFowOTEL +MAkGA1UEBhMCVVMxDzANBgNVBAoTBkFtYXpvbjEZMBcGA1UEAxMQQW1hem9uIFJv +b3QgQ0EgMTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALJ4gHHKeNXj +ca9HgFB0fW7Y14h29Jlo91ghYPl0hAEvrAIthtOgQ3pOsqTQNroBvo3bSMgHFzZM +9O6II8c+6zf1tRn4SWiw3te5djgdYZ6k/oI2peVKVuRF4fn9tBb6dNqcmzU5L/qw +IFAGbHrQgLKm+a/sRxmPUDgH3KKHOVj4utWp+UhnMJbulHheb4mjUcAwhmahRWa6 +VOujw5H5SNz/0egwLX0tdHA114gk957EWW67c4cX8jJGKLhD+rcdqsq08p8kDi1L +93FcXmn/6pUCyziKrlA4b9v7LWIbxcceVOF34GfID5yHI9Y/QCB/IIDEgEw+OyQm +jgSubJrIqg0CAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMC +AYYwHQYDVR0OBBYEFIQYzIU07LwMlJQuCFmcx7IQTgoIMA0GCSqGSIb3DQEBCwUA +A4IBAQCY8jdaQZChGsV2USggNiMOruYou6r4lK5IpDB/G/wkjUu0yKGX9rbxenDI +U5PMCCjjmCXPI6T53iHTfIUJrU6adTrCC2qJeHZERxhlbI1Bjjt/msv0tadQ1wUs +N+gDS63pYaACbvXy8MWy7Vu33PqUXHeeE6V/Uq2V8viTO96LXFvKWlJbYK8U90vv +o/ufQJVtMVT8QtPHRh8jrdkPSHCa2XV4cdFyQzR1bldZwgJcJmApzyMZFo6IQ6XU +5MsI+yMRQ+hDKXJioaldXgjUkK642M4UwtBV8ob2xJNDd2ZhwLnoQdeXeGADbkpy +rqXRfboQnoZsG4q5WTP468SQvvG5 +-----END CERTIFICATE-----'" +"Amazon Trust Services","Amazon","","Amazon Root CA 2","066C9FD29635869F0A0FE58678F85B26BB8A37","1BA5B2AA8C65401A82960118F80BEC4F62304D83CEC4713A19C39C011EA46DB4","932910001CD24A7F1F483CEFFF6D268CAAD9D93D7520575EFCE0057E1171505C","2015.05.26","2040.05.26","RSA 4096 bits","SHA384WithRSA","Websites;Email","","","2.23.140.1.1","https://bugzilla.mozilla.org/show_bug.cgi?id=1172401","NSS 3.28.1","Firefox 51","https://good.sca2a.amazontrust.com/","https://expired.sca2a.amazontrust.com/","https://revoked.sca2a.amazontrust.com/","None","https://www.amazontrust.com/","USA, Global","https://www.amazontrust.com/repository/cp-1.0.7.pdf","https://www.amazontrust.com/repository/cps-1.0.8.pdf","https://www.cpacanada.ca/generichandlers/CPACHandler.ashx?attachmentid=239088","https://www.cpacanada.ca/generichandlers/CPACHandler.ashx?attachmentid=239089","https://www.cpacanada.ca/generichandlers/CPACHandler.ashx?attachmentid=239090","BDO International Limited","WebTrust","2020.04.08","'-----BEGIN CERTIFICATE----- +MIIFQTCCAymgAwIBAgITBmyf0pY1hp8KD+WGePhbJruKNzANBgkqhkiG9w0BAQwF +ADA5MQswCQYDVQQGEwJVUzEPMA0GA1UEChMGQW1hem9uMRkwFwYDVQQDExBBbWF6 +b24gUm9vdCBDQSAyMB4XDTE1MDUyNjAwMDAwMFoXDTQwMDUyNjAwMDAwMFowOTEL +MAkGA1UEBhMCVVMxDzANBgNVBAoTBkFtYXpvbjEZMBcGA1UEAxMQQW1hem9uIFJv +b3QgQ0EgMjCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAK2Wny2cSkxK +gXlRmeyKy2tgURO8TW0G/LAIjd0ZEGrHJgw12MBvIITplLGbhQPDW9tK6Mj4kHbZ +W0/jTOgGNk3Mmqw9DJArktQGGWCsN0R5hYGCrVo34A3MnaZMUnbqQ523BNFQ9lXg +1dKmSYXpN+nKfq5clU1Imj+uIFptiJXZNLhSGkOQsL9sBbm2eLfq0OQ6PBJTYv9K +8nu+NQWpEjTj82R0Yiw9AElaKP4yRLuH3WUnAnE72kr3H9rN9yFVkE8P7K6C4Z9r +2UXTu/Bfh+08LDmG2j/e7HJV63mjrdvdfLC6HM783k81ds8P+HgfajZRRidhW+me +z/CiVX18JYpvL7TFz4QuK/0NURBs+18bvBt+xa47mAExkv8LV/SasrlX6avvDXbR +8O70zoan4G7ptGmh32n2M8ZpLpcTnqWHsFcQgTfJU7O7f/aS0ZzQGPSSbtqDT6Zj +mUyl+17vIWR6IF9sZIUVyzfpYgwLKhbcAS4y2j5L9Z469hdAlO+ekQiG+r5jqFoz +7Mt0Q5X5bGlSNscpb/xVA1wf+5+9R+vnSUeVC06JIglJ4PVhHvG/LopyboBZ/1c6 ++XUyo05f7O0oYtlNc/LMgRdg7c3r3NunysV+Ar3yVAhU/bQtCSwXVEqY0VThUWcI +0u1ufm8/0i2BWSlmy5A5lREedCf+3euvAgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMB +Af8wDgYDVR0PAQH/BAQDAgGGMB0GA1UdDgQWBBSwDPBMMPQFWAJI/TPlUq9LhONm +UjANBgkqhkiG9w0BAQwFAAOCAgEAqqiAjw54o+Ci1M3m9Zh6O+oAA7CXDpO8Wqj2 +LIxyh6mx/H9z/WNxeKWHWc8w4Q0QshNabYL1auaAn6AFC2jkR2vHat+2/XcycuUY ++gn0oJMsXdKMdYV2ZZAMA3m3MSNjrXiDCYZohMr/+c8mmpJ5581LxedhpxfL86kS +k5Nrp+gvU5LEYFiwzAJRGFuFjWJZY7attN6a+yb3ACfAXVU3dJnJUH/jWS5E4ywl +7uxMMne0nxrpS10gxdr9HIcWxkPo1LsmmkVwXqkLN1PiRnsn/eBG8om3zEK2yygm +btmlyTrIQRNg91CMFa6ybRoVGld45pIq2WWQgj9sAq+uEjonljYE1x2igGOpm/Hl +urR8FLBOybEfdF849lHqm/osohHUqS0nGkWxr7JOcQ3AWEbWaQbLU8uz/mtBzUF+ +fUwPfHJ5elnNXkoOrJupmHN5fLT0zLm4BwyydFy4x2+IoZCn9Kr5v2c69BoVYh63 +n749sSmvZ6ES8lgQGVMDMBu4Gon2nL2XA46jCfMdiyHxtN/kHNGfZQIG6lzWE7OE +76KlXIx3KadowGuuQNKotOrN8I1LOJwZmhsoVLiJkO/KdYE+HvJkJMcYr07/R54H +9jVlpNMKVv/1F2Rs76giJUmTtt8AF9pYfl3uxRuw0dFfIRDH+fO6AgonB8Xx1sfT +4PsJYGw= +-----END CERTIFICATE-----'" +"Amazon Trust Services","Amazon","","Amazon Root CA 3","066C9FD5749736663F3B0B9AD9E89E7603F24A","18CE6CFE7BF14E60B2E347B8DFE868CB31D02EBB3ADA271569F50343B46DB3A4","2FAB16B84325529639A1ECAA772A39814B6456CA68E5E017E3F9A8787E250FFC","2015.05.26","2040.05.26","EC secp256r1","ecdsaWithSHA256","Websites;Email","","","2.23.140.1.1","https://bugzilla.mozilla.org/show_bug.cgi?id=1172401","NSS 3.28.1","Firefox 51","https://good.sca3a.amazontrust.com/","https://expired.sca3a.amazontrust.com/","https://revoked.sca3a.amazontrust.com/","None","https://www.amazontrust.com/","USA, Global","https://www.amazontrust.com/repository/cp-1.0.7.pdf","https://www.amazontrust.com/repository/cps-1.0.8.pdf","https://www.cpacanada.ca/generichandlers/CPACHandler.ashx?attachmentid=239088","https://www.cpacanada.ca/generichandlers/CPACHandler.ashx?attachmentid=239089","https://www.cpacanada.ca/generichandlers/CPACHandler.ashx?attachmentid=239090","BDO International Limited","WebTrust","2020.04.08","'-----BEGIN CERTIFICATE----- +MIIBtjCCAVugAwIBAgITBmyf1XSXNmY/Owua2eiedgPySjAKBggqhkjOPQQDAjA5 +MQswCQYDVQQGEwJVUzEPMA0GA1UEChMGQW1hem9uMRkwFwYDVQQDExBBbWF6b24g +Um9vdCBDQSAzMB4XDTE1MDUyNjAwMDAwMFoXDTQwMDUyNjAwMDAwMFowOTELMAkG +A1UEBhMCVVMxDzANBgNVBAoTBkFtYXpvbjEZMBcGA1UEAxMQQW1hem9uIFJvb3Qg +Q0EgMzBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABCmXp8ZBf8ANm+gBG1bG8lKl +ui2yEujSLtf6ycXYqm0fc4E7O5hrOXwzpcVOho6AF2hiRVd9RFgdszflZwjrZt6j +QjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgGGMB0GA1UdDgQWBBSr +ttvXBp43rDCGB5Fwx5zEGbF4wDAKBggqhkjOPQQDAgNJADBGAiEA4IWSoxe3jfkr +BqWTrBqYaGFy+uGh0PsceGCmQ5nFuMQCIQCcAu/xlJyzlvnrxir4tiz+OpAUFteM +YyRIHN8wfdVoOw== +-----END CERTIFICATE-----'" +"Amazon Trust Services","Amazon","","Amazon Root CA 4","066C9FD7C1BB104C2943E5717B7B2CC81AC10E","E35D28419ED02025CFA69038CD623962458DA5C695FBDEA3C22B0BFB25897092","C9B81D09BD1E2C0B56D7199B112DA2B9A4A59DE2D0868B7DE7118E04FB931985","2015.05.26","2040.05.26","EC secp384r1","ecdsaWithSHA384","Websites;Email","","","2.23.140.1.1","https://bugzilla.mozilla.org/show_bug.cgi?id=1172401","NSS 3.28.1","Firefox 51","https://good.sca4a.amazontrust.com/","https://expired.sca4a.amazontrust.com/","https://revoked.sca4a.amazontrust.com/","None","https://www.amazontrust.com/","USA, Global","https://www.amazontrust.com/repository/cp-1.0.7.pdf","https://www.amazontrust.com/repository/cps-1.0.8.pdf","https://www.cpacanada.ca/generichandlers/CPACHandler.ashx?attachmentid=239088","https://www.cpacanada.ca/generichandlers/CPACHandler.ashx?attachmentid=239089","https://www.cpacanada.ca/generichandlers/CPACHandler.ashx?attachmentid=239090","BDO International Limited","WebTrust","2020.04.08","'-----BEGIN CERTIFICATE----- +MIIB8jCCAXigAwIBAgITBmyf18G7EEwpQ+Vxe3ssyBrBDjAKBggqhkjOPQQDAzA5 +MQswCQYDVQQGEwJVUzEPMA0GA1UEChMGQW1hem9uMRkwFwYDVQQDExBBbWF6b24g +Um9vdCBDQSA0MB4XDTE1MDUyNjAwMDAwMFoXDTQwMDUyNjAwMDAwMFowOTELMAkG +A1UEBhMCVVMxDzANBgNVBAoTBkFtYXpvbjEZMBcGA1UEAxMQQW1hem9uIFJvb3Qg +Q0EgNDB2MBAGByqGSM49AgEGBSuBBAAiA2IABNKrijdPo1MN/sGKe0uoe0ZLY7Bi +9i0b2whxIdIA6GO9mif78DluXeo9pcmBqqNbIJhFXRbb/egQbeOc4OO9X4Ri83Bk +M6DLJC9wuoihKqB1+IGuYgbEgds5bimwHvouXKNCMEAwDwYDVR0TAQH/BAUwAwEB +/zAOBgNVHQ8BAf8EBAMCAYYwHQYDVR0OBBYEFNPsxzplbszh2naaVvuc84ZtV+WB +MAoGCCqGSM49BAMDA2gAMGUCMDqLIfG9fhGt0O9Yli/W651+kI0rz2ZVwyzjKKlw +CkcO8DdZEv8tmZQoTipPNU0zWgIxAOp1AE47xDqUEpHJWEadIRNyp4iciuRMStuW +1KyLa2tJElMzrdfkviT8tQp21KW8EA== +-----END CERTIFICATE-----'" +"Amazon Trust Services","Starfield Technologies, Inc.","","Starfield Services Root Certificate Authority - G2","00","568D6905A2C88708A4B3025190EDCFEDB1974A606A13C6E5290FCB2AE63EDAB5","3455A4C6FBEC86F4F02B35A37B5E6CF74C35ACAC1F7AA3A056BE6E656CA17A06","2009.09.01","2037.12.31","RSA 2048 bits","SHA256WithRSA","Websites","","","2.23.140.1.1","https://bugzilla.mozilla.org/show_bug.cgi?id=1172401","NSS 3.12.10","Firefox 6.0","https://good.sca0a.amazontrust.com/","https://expired.sca0a.amazontrust.com/","https://revoked.sca0a.amazontrust.com/","None","https://www.amazontrust.com/","USA, Global","https://www.amazontrust.com/repository/cp-1.0.7.pdf","https://www.amazontrust.com/repository/cps-1.0.8.pdf","https://www.cpacanada.ca/generichandlers/CPACHandler.ashx?attachmentid=239088","https://www.cpacanada.ca/generichandlers/CPACHandler.ashx?attachmentid=239089","https://www.cpacanada.ca/generichandlers/CPACHandler.ashx?attachmentid=239090","BDO International Limited","WebTrust","2020.04.08","'-----BEGIN CERTIFICATE----- +MIID7zCCAtegAwIBAgIBADANBgkqhkiG9w0BAQsFADCBmDELMAkGA1UEBhMCVVMx +EDAOBgNVBAgTB0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxJTAjBgNVBAoT +HFN0YXJmaWVsZCBUZWNobm9sb2dpZXMsIEluYy4xOzA5BgNVBAMTMlN0YXJmaWVs +ZCBTZXJ2aWNlcyBSb290IENlcnRpZmljYXRlIEF1dGhvcml0eSAtIEcyMB4XDTA5 +MDkwMTAwMDAwMFoXDTM3MTIzMTIzNTk1OVowgZgxCzAJBgNVBAYTAlVTMRAwDgYD +VQQIEwdBcml6b25hMRMwEQYDVQQHEwpTY290dHNkYWxlMSUwIwYDVQQKExxTdGFy +ZmllbGQgVGVjaG5vbG9naWVzLCBJbmMuMTswOQYDVQQDEzJTdGFyZmllbGQgU2Vy +dmljZXMgUm9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkgLSBHMjCCASIwDQYJKoZI +hvcNAQEBBQADggEPADCCAQoCggEBANUMOsQq+U7i9b4Zl1+OiFOxHz/Lz58gE20p +OsgPfTz3a3Y4Y9k2YKibXlwAgLIvWX/2h/klQ4bnaRtSmpDhcePYLQ1Ob/bISdm2 +8xpWriu2dBTrz/sm4xq6HZYuajtYlIlHVv8loJNwU4PahHQUw2eeBGg6345AWh1K +Ts9DkTvnVtYAcMtS7nt9rjrnvDH5RfbCYM8TWQIrgMw0R9+53pBlbQLPLJGmpufe +hRhJfGZOozptqbXuNC66DQO4M99H67FrjSXZm86B0UVGMpZwh94CDklDhbZsc7tk +6mFBrMnUVN+HL8cisibMn1lUaJ/8viovxFUcdUBgF4UCVTmLfwUCAwEAAaNCMEAw +DwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFJxfAN+q +AdcwKziIorhtSpzyEZGDMA0GCSqGSIb3DQEBCwUAA4IBAQBLNqaEd2ndOxmfZyMI +bw5hyf2E3F/YNoHN2BtBLZ9g3ccaaNnRbobhiCPPE95Dz+I0swSdHynVv/heyNXB +ve6SbzJ08pGCL72CQnqtKrcgfU28elUSwhXqvfdqlS5sdJ/PHLTyxQGjhdByPq1z +qwubdQxtRbeOlKyWN7Wg0I8VRw7j6IPdj/3vQQF3zCepYoUz8jcI73HPdwbeyBkd +iEDPfUYd/x7H4c7/I9vG+o1VTqkC50cRRj70/b17KSa7qWFiNyi2LSr2EIZkyXCn +0q23KXB56jzaYyWf/Wi3MOxw+3WKt21gZ7IeyLnp2KhvAotnDU0mV3HaIPzBSlCN +sSi6 +-----END CERTIFICATE-----'" +"Asseco Data Systems S.A. (previously Unizeto Certum)","Unizeto Sp. z o.o.","","Certum CA","010020","D8E0FEBC1DB2E38D00940F37D27D41344D993E734B99D5656D9778D4D8143624","AA6315C8D0FEB53C5492B750F0E480840FDD33F2DEEE4B03D5458CB5C07FE8DA","2002.06.11","2027.06.11","RSA 2048 bits","SHA1WithRSA","Email","","","Not EV","https://bugzilla.mozilla.org/show_bug.cgi?id=167572","NSS 3.9.3","Firefox 1","https://valid-certum-ca.certificates.certum.pl","https://expired-certum-ca.certificates.certum.pl","https://revoked-certum-ca.certificates.certum.pl","","https://www.certum.eu/en/","Poland, Global","https://www.certum.eu/en/data/CCP-DK02-ZK01-Certification-Policy-of-CERTUM-Certification-Services_v4.5.pdf","https://www.certum.eu/en/data/CCP-DK02-ZK02-Certification-Practice-Statement-of-Certum-Certification-Services_v6.6-1.pdf","https://www.cpacanada.ca/generichandlers/CPACHandler.ashx?attachmentid=239794","https://www.cpacanada.ca/generichandlers/CPACHandler.ashx?attachmentid=239795","https://www.cpacanada.ca/generichandlers/CPACHandler.ashx?attachmentid=239796","Ernst & Young, LLP","WebTrust","2020.05.18","'-----BEGIN CERTIFICATE----- +MIIDDDCCAfSgAwIBAgIDAQAgMA0GCSqGSIb3DQEBBQUAMD4xCzAJBgNVBAYTAlBM +MRswGQYDVQQKExJVbml6ZXRvIFNwLiB6IG8uby4xEjAQBgNVBAMTCUNlcnR1bSBD +QTAeFw0wMjA2MTExMDQ2MzlaFw0yNzA2MTExMDQ2MzlaMD4xCzAJBgNVBAYTAlBM +MRswGQYDVQQKExJVbml6ZXRvIFNwLiB6IG8uby4xEjAQBgNVBAMTCUNlcnR1bSBD +QTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAM6xwS7TT3zNJc4YPk/E +jG+AanPIW1H4m9LcuwBcsaD8dQPugfCI7iNS6eYVM42sLQnFdvkrOYCJ5JdLkKWo +ePhzQ3ukYbDYWMzhbGZ+nPMJXlVjhNWo7/OxLjBos8Q82KxujZlakE403Daaj4GI +ULdtlkIJ89eVgw1BS7Bqa/j8D35in2fE7SZfECYPCE/wpFcozo+47UX2bu4lXapu +Ob7kky/ZR6By6/qmW6/KUz/iDsaWVhFu9+lmqSbYf5VT7QqFiLpPKaVCjF62/IUg +AKpoC6EahQGcxEZjgoi2IrHu/qpGWX7PNSzVttpd90gzFFS269lvzs2I1qsb2pY7 +HVkCAwEAAaMTMBEwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQUFAAOCAQEA +uI3O7+cUus/usESSbLQ5PqKEbq24IXfS1HeCh+YgQYHu4vgRt2PRFze+GXYkHAQa +TOs9qmdvLdTN/mUxcMUbpgIKumB7bVjCmkn+YzILa+M6wKyrO7Do0wlRjBCDxjTg +xSvgGrZgFCdsMneMvLJymM/NzD+5yCRCFNZX/OYmQ6kd5YCQzgNUKD73P9P4Te1q +CjqTE5s7FCMTY5w/0YcneeVMUeMBrYVdGjux1XMQpNPyvG5k9VpWkKjHDkx0Dy5x +O/fIR/RpbxXyEV6DHpx8Uq79AtoSqFlnGNu8cN2bsWntgM6JQEhqDjXKKWYVIZQs +6GAqm4VKQPNriiTsBhYscw== +-----END CERTIFICATE-----'" +"Asseco Data Systems S.A. (previously Unizeto Certum)","Unizeto Technologies S.A.","Certum Certification Authority","Certum Trusted Network CA","0444C0","5C58468D55F58E497E743982D2B50010B6D165374ACF83A7D4A32DB768C4408E","99997F529F3618B4AF9C33CAFFD9282ED7E22CD45379E3C828EDAC4D04C169ED","2008.10.22","2029.12.31","RSA 2048 bits","SHA1WithRSA","Websites;Email","","","1.2.616.1.113527.2.5.1.1","https://bugzilla.mozilla.org/show_bug.cgi?id=532377","NSS 3.12.10","Firefox 6.0","https://valid-certum-ctnca.certificates.certum.pl","https://expired-certum-ctnca.certificates.certum.pl","https://revoked-certum-ctnca.certificates.certum.pl","","https://www.certum.eu/en/","Poland, Global","https://www.certum.eu/en/data/CCP-DK02-ZK01-Certification-Policy-of-CERTUM-Certification-Services_v4.5.pdf","https://www.certum.eu/en/data/CCP-DK02-ZK02-Certification-Practice-Statement-of-Certum-Certification-Services_v6.6-1.pdf","https://www.cpacanada.ca/generichandlers/CPACHandler.ashx?attachmentid=239794","https://www.cpacanada.ca/generichandlers/CPACHandler.ashx?attachmentid=239795","https://www.cpacanada.ca/generichandlers/CPACHandler.ashx?attachmentid=239796","Ernst & Young, LLP","WebTrust","2020.05.18","'-----BEGIN CERTIFICATE----- +MIIDuzCCAqOgAwIBAgIDBETAMA0GCSqGSIb3DQEBBQUAMH4xCzAJBgNVBAYTAlBM +MSIwIAYDVQQKExlVbml6ZXRvIFRlY2hub2xvZ2llcyBTLkEuMScwJQYDVQQLEx5D +ZXJ0dW0gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxIjAgBgNVBAMTGUNlcnR1bSBU +cnVzdGVkIE5ldHdvcmsgQ0EwHhcNMDgxMDIyMTIwNzM3WhcNMjkxMjMxMTIwNzM3 +WjB+MQswCQYDVQQGEwJQTDEiMCAGA1UEChMZVW5pemV0byBUZWNobm9sb2dpZXMg +Uy5BLjEnMCUGA1UECxMeQ2VydHVtIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MSIw +IAYDVQQDExlDZXJ0dW0gVHJ1c3RlZCBOZXR3b3JrIENBMIIBIjANBgkqhkiG9w0B +AQEFAAOCAQ8AMIIBCgKCAQEA4/t9o3K6wvDJFIf1awFO4W5AB7ptJ11/91sts1rH +UV+rpDKmYYe2bg+G0jACl/jXaVehGDldamR5xgFZrDwxSjh80gTSSyjoIF87B6LM +TXPb865Px1bVWqeWifrzq2jUI4ZZJ88JJ7ysbnKDHDBy3+Ci6dLhdHUZvSqeexVU +BBvXQzmtVSjF4hq79MDkrjhJM8x2hZ85RdKknvISjFH4fOQtf/WsX+sWn7Et0brM +kUJ3TCXJkDhv2/DM+44el1k+1WBO5gUo7Ul5E0u6SNsv+XLTOcr+H9g0cvW0QM8x +AcPs3hEtF10fuFDRXhmnad4HMyjKUJX5p1TLVIZQRan5SQIDAQABo0IwQDAPBgNV +HRMBAf8EBTADAQH/MB0GA1UdDgQWBBQIds3LB/8k9sXN7buQvOKEN0Z19zAOBgNV +HQ8BAf8EBAMCAQYwDQYJKoZIhvcNAQEFBQADggEBAKaorSLOAT2mo/9i0Eidi15y +sHhE49wcrwn9I0j6vSrEuVUEtRCjjSfeC4Jj0O7eDDd5QVsisrCaQVymcODU0HfL +I9MA4GxWL+FpDQ3Zqr8hgVDZBqWo/5U30Kr+4rP1mS1FhIrlQgnXdAIv94nYmem8 +J9RHjboNRhx3zxSkHLmkMcScKHQDNP8zGSal6Q10tz6XxnboJ5ajZt3hrvJBW8qY +VoNzcOSGGtIxQbovvi0TWnZvTuhOgQ4/WwMioBK+ZlgRSssDxLQqKi2WF+A5VLxI +03YnnZotBqbJ7DnSq9ufmgsnAjUpsUCV5/nonFWIGUbWtzT1fs45mtk48VH3Tyw= +-----END CERTIFICATE-----'" +"Asseco Data Systems S.A. (previously Unizeto Certum)","Unizeto Technologies S.A.","Certum Certification Authority","Certum Trusted Network CA 2","21D6D04A4F250FC93237FCAA5E128DE9","B676F2EDDAE8775CD36CB0F63CD1D4603961F49E6265BA013A2F0307B6D0B804","B043D1B4FD46F2B87E32308BB707CC70B2AEEC7D72D079AFE545BCA05D03CBBF","2011.10.06","2046.10.06","RSA 4096 bits","SHA512WithRSA","Websites;Email","","","1.2.616.1.113527.2.5.1.1","https://bugzilla.mozilla.org/show_bug.cgi?id=999378","NSS 3.23","Firefox 46","https://valid-certum-ctnca2.certificates.certum.pl","https://expired-certum-ctnca2.certificates.certum.pl","https://revoked-certum-ctnca2.certificates.certum.pl","None","https://www.certum.eu/en/","Poland, Global","https://www.certum.eu/en/data/CCP-DK02-ZK01-Certification-Policy-of-CERTUM-Certification-Services_v4.5.pdf","https://www.certum.eu/en/data/CCP-DK02-ZK02-Certification-Practice-Statement-of-Certum-Certification-Services_v6.6-1.pdf","https://www.cpacanada.ca/generichandlers/CPACHandler.ashx?attachmentid=239794","https://www.cpacanada.ca/generichandlers/CPACHandler.ashx?attachmentid=239795","https://www.cpacanada.ca/generichandlers/CPACHandler.ashx?attachmentid=239796","Ernst & Young, LLP","WebTrust","2020.05.18","'-----BEGIN CERTIFICATE----- +MIIF0jCCA7qgAwIBAgIQIdbQSk8lD8kyN/yqXhKN6TANBgkqhkiG9w0BAQ0FADCB +gDELMAkGA1UEBhMCUEwxIjAgBgNVBAoTGVVuaXpldG8gVGVjaG5vbG9naWVzIFMu +QS4xJzAlBgNVBAsTHkNlcnR1bSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTEkMCIG +A1UEAxMbQ2VydHVtIFRydXN0ZWQgTmV0d29yayBDQSAyMCIYDzIwMTExMDA2MDgz +OTU2WhgPMjA0NjEwMDYwODM5NTZaMIGAMQswCQYDVQQGEwJQTDEiMCAGA1UEChMZ +VW5pemV0byBUZWNobm9sb2dpZXMgUy5BLjEnMCUGA1UECxMeQ2VydHVtIENlcnRp +ZmljYXRpb24gQXV0aG9yaXR5MSQwIgYDVQQDExtDZXJ0dW0gVHJ1c3RlZCBOZXR3 +b3JrIENBIDIwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC9+Xj45tWA +DGSdhhuWZGc/IjoedQF97/tcZ4zJzFxrqZHmuULlIEub2pt7uZld2ZuAS9eEQCsn +0+i6MLs+CRqnSZXvK0AkwpfHp+6bJe+oCgCXhVqqndwpyeI1B+twTUrWwbNWuKFB +OJvR+zF/j+Bf4bE/D44WSWDXBo0Y+aomEKsq09DRZ40bRr5HMNUuctHFY9rnY3lE +fktjJImGLjQ/KUxSiyqnwOKRKIm5wFv5HdnnJ63/mgKXwcZQkpsCLL2puTRZCr+E +Sv/f/rOf69me4Jgj7KZrdxYq28ytOxykh9xGc14ZYmhFV+SQgkK7QtbwYeDBoz1m +o130GO6IyY0XRSmZMnUCMe4pJshrAua1YkV/NxVaI2iJ1D7eTiew8EAMvE0Xy02i +sx7QBlrd9pPPV3WZ9fqGGmd4s7+W/jTcvedSVuWz5XV710GRBdxdaeOVDUO5/IOW +OZV7bIBaTxNyxtd9KXpEulKkKtVBRgkg/iKgtlswjbyJDNXXcPiHUv3a76xRLgez +Tv7QCdpw75j6VuZt27VXS9zlLCUVyJ4ueE742pyehizKV/Ma5ciSixqClnrDvFAS +adgOWkaLOusm+iPJtrCBvkIApPjW/jAux9JG9uWOdf3yzLnQh1vMBhBgu4M1t15n +3kfsmUjxpKEV/q2MYo45VU85FrmxY53/twIDAQABo0IwQDAPBgNVHRMBAf8EBTAD +AQH/MB0GA1UdDgQWBBS2oVQ5AsOgP46KvPrU+Bym0ToO/TAOBgNVHQ8BAf8EBAMC +AQYwDQYJKoZIhvcNAQENBQADggIBAHGlDs7k6b8/ONWJWsQCYftMxRQXLYtPU2sQ +F/xlhMcQSZDe28cmk4gmb3DWAl45oPePq5a1pRNcgRRtDoGCERuKTsZPpd1iHkTf +CVn0W3cLN+mLIMb4Ck4uWBzrM9DPhmDJ2vuAL55MYIR4PSFk1vtBHxgP58l1cb29 +XN40hz5BsA72udY/CROWFC/emh1auVbONTqwX3BNXuMp8SMoclm2q8KMZiYcdywm +djWLKKdpoPk79SPdhRB0yZADVpHnr7pH1BKXESLjokmUbOe3lEu6LaTaM4tMpkT/ +WjzGHWTYtTHkpjx6qFcL2+1hGsvxznN3Y6SHb0xRONbkX8eftoEq5IVIeVheO/jb +AoJnwTnbw3RLPTYe+SmTiGhbqEQZIfCn6IENLOiTNrQ3ssqwGyZ6miUfmpqAnksq +P/ujmv5zMnHCnsZy4YpoJ/HkD7TETKVhk/iXEAcqMCWpuchxuO9ozC1+9eB+D4Ko +b7a6bINDd82Kkhehnlt4Fj1F4jNy3eFmypnTycUm/Q1oBEauttmbjL4ZvrHG8hnj +XALKLNhvSgfZyTXaQHXyxKcZb55CEJh15pWLYLztxRLXis7VmFxWlgPF7ncGNf/P +5O4/E2Hu29othfDNrp2yGAlFw5Khchf8R7agCyzxxN5DaAhqXzvwdmP7zAYspsbi +DrW5viSP +-----END CERTIFICATE-----'" +"Atos","Atos","","Atos TrustedRoot 2011","5C33CB622C5FB332","F356BEA244B7A91EB35D53CA9AD7864ACE018E2D35D5F8F96DDF68A6F41AA474","2F9CF0C4A96CF91BC2C02E7C9314ADE03BB5EFEA989FFC233ABDF9AAB7837362","2011.07.07","2030.12.31","RSA 2048 bits","SHA256WithRSA","Websites;Email","","","Not EV","https://bugzilla.mozilla.org/show_bug.cgi?id=711366","NSS 3.16","Firefox 29","https://pki-valid.atos.net","https://pki-expired.atos.net","https://pki-revoked.atos.net","","https://pki.atos.net/TrustedRoot/","Germany, Europe","https://pki.atos.net/Download/Atos_TrustedRoot_CPS_RootCA_v2.3.0.pdf","https://pki.atos.net/Download/Atos_TrustedRoot_CPS_IssuingCAs_v2.2.0.pdf","https://www.datenschutz-cert.de/uploads/tx_dsnordreferenzen/DSC866_Atos_ATCA_Audit_Attestation_v13.pdf","https://www.datenschutz-cert.de/uploads/tx_dsnordreferenzen/DSC866_Atos_ATCA_Audit_Attestation_v13.pdf","","datenschutz cert GmbH","ETSI EN 319 411","2020.06.20","'-----BEGIN CERTIFICATE----- +MIIDdzCCAl+gAwIBAgIIXDPLYixfszIwDQYJKoZIhvcNAQELBQAwPDEeMBwGA1UE +AwwVQXRvcyBUcnVzdGVkUm9vdCAyMDExMQ0wCwYDVQQKDARBdG9zMQswCQYDVQQG +EwJERTAeFw0xMTA3MDcxNDU4MzBaFw0zMDEyMzEyMzU5NTlaMDwxHjAcBgNVBAMM +FUF0b3MgVHJ1c3RlZFJvb3QgMjAxMTENMAsGA1UECgwEQXRvczELMAkGA1UEBhMC +REUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCVhTuXbyo7LjvPpvMp +Nb7PGKw+qtn4TaA+Gke5vJrf8v7MPkfoepbCJI419KkM/IL9bcFyYie96mvr54rM +VD6QUM+A1JX76LWC1BTFtqlVJVfbsVD2sGBkWXppzwO3bw2+yj5vdHLqqjAqc2K+ +SZFhyBH+DgMq92og3AIVDV4VavzjgsG1xZ1kCWyjWZgHJ8cblithdHFsQ/H3NYkQ +4J7sVaE3IqKHBAUsR320HLliKWYoyrfhk/WklAOZuXCFteZI6o1Q/NnezG8HDt0L +cp2AMBYHlT8oDv3FdU9T1nSatCQujgKRz3bFmx5VdJx4IbHwLfELn8LVlhgf8FQi +eowHAgMBAAGjfTB7MB0GA1UdDgQWBBSnpQaxLKYJYO7Rl+lwrrw7GWzbITAPBgNV +HRMBAf8EBTADAQH/MB8GA1UdIwQYMBaAFKelBrEspglg7tGX6XCuvDsZbNshMBgG +A1UdIAQRMA8wDQYLKwYBBAGwLQMEAQEwDgYDVR0PAQH/BAQDAgGGMA0GCSqGSIb3 +DQEBCwUAA4IBAQAmdzTblEiGKkGdLD4GkGDEjKwLVLgfuXvTBznk+j57sj1O7Z8j +vZfza1zv7v1Apt+hk6EKhqzvINB5Ab149xnYJDE0BAGmuhWawyfc2E8PzBhj/5kP +DpFrdRbhIfzYJsdHt6bPWHJxfrrhTZVHO8mvbaG0weyJ9rQPOLXiZNwlz6bb65pc +maHFCN795trV1lpFDMS3wrUU77QR/w4VtfX128a961qn8FYiqTxlVMYVqL2Gns2D +lmh6cYGJ4Qvh6hEbaAjMaZ7snkGeRDImeuKHCnE96+RapNLbxc3G3mB/ufNPRJLv +KrcYPqcZ2Qt9sTdBQrC6YB3y/gkRsPCHe6ed +-----END CERTIFICATE-----'" +"Autoridad de Certificacion Firmaprofesional","","","Autoridad de Certificacion Firmaprofesional CIF A62634068","53EC3BEEFBB2485F","04048028BF1F2864D48F9AD4D83294366A828856553F3B14303F90147F5D40EF","B5DAFFA4766010AC1693044AFF780C954BC71DBE5ABB16E3ADA0DCC6C7FE550F","2009.05.20","2030.12.31","RSA 4096 bits","SHA1WithRSA","Websites;Email","","","1.3.6.1.4.1.13177.10.1.3.10","https://bugzilla.mozilla.org/show_bug.cgi?id=521439","NSS 3.12.9","Firefox 4.0","https://testssl.firmaprofesional.com","https://testexpiredssl.firmaprofesional.com","https://testrevokedssl.firmaprofesional.com","","http://www.firmaprofesional.com/","Spain","https://www.firmaprofesional.com/wp-content/uploads/pdfs/200205-FP_CP_Autenticacion_Web-200205-EN-sFP.pdf","https://www.firmaprofesional.com/wp-content/uploads/pdfs/FP_CPS-200417-EN-sFP.pdf","https://www.aenor.com/Certificacion_Documentos/eiDas/2019%20AENOR%20Anexo%202%20ETSI%20319%20411-2%20PSC-FP_v4.pdf","https://www.aenor.com/Certificacion_Documentos/eiDas/2019%20AENOR%20Anexo%202%20ETSI%20319%20411-2%20PSC-FP_v4.pdf","https://www.aenor.com/Certificacion_Documentos/eiDas/2019%20AENOR%20Anexo%202%20ETSI%20319%20411-2%20PSC-FP_v4.pdf","AENOR INTERNACIONAL, S.A. (Unipersonal)","ETSI EN 319 411","2020.06.02","'-----BEGIN CERTIFICATE----- +MIIGFDCCA/ygAwIBAgIIU+w77vuySF8wDQYJKoZIhvcNAQEFBQAwUTELMAkGA1UE +BhMCRVMxQjBABgNVBAMMOUF1dG9yaWRhZCBkZSBDZXJ0aWZpY2FjaW9uIEZpcm1h +cHJvZmVzaW9uYWwgQ0lGIEE2MjYzNDA2ODAeFw0wOTA1MjAwODM4MTVaFw0zMDEy +MzEwODM4MTVaMFExCzAJBgNVBAYTAkVTMUIwQAYDVQQDDDlBdXRvcmlkYWQgZGUg +Q2VydGlmaWNhY2lvbiBGaXJtYXByb2Zlc2lvbmFsIENJRiBBNjI2MzQwNjgwggIi +MA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDKlmuO6vj78aI14H9M2uDDUtd9 +thDIAl6zQyrET2qyyhxdKJp4ERppWVevtSBC5IsP5t9bpgOSL/UR5GLXMnE42QQM +cas9UX4PB99jBVzpv5RvwSmCwLTaUbDBPLutN0pcyvFLNg4kq7/DhHf9qFD0sefG +L9ItWY16Ck6WaVICqjaY7Pz6FIMMNx/Jkjd/14Et5cS54D40/mf0PmbR0/RAz15i +NA9wBj4gGFrO93IbJWyTdBSTo3OxDqqHECNZXyAFGUftaI6SEspd/NYrspI8IM/h +X68gvqB2f3bl7BqGYTM+53u0P6APjqK5am+5hyZvQWyIplD9amML9ZMWGxmPsu2b +m8mQ9QEM3xk9Dz44I8kvjwzRAv4bVdZO0I08r0+k8/6vKtMFnXkIoctXMbScyJCy +Z/QYFpM6/EfY0XiWMR+6KwxfXZmtY4laJCB22N/9q06mIqqdXuYnin1oKaPnirja +EbsXLZmdEyRG98Xi2J+Of8ePdG1asuhy9azuJBCtLxTa/y2aRnFHvkLfuwHb9H/T +KI8xWVvTyQKmtFLKbpf7Q8UIJm+K9Lv9nyiqDdVF8xM6HdjAeI9BZzwelGSuewvF +6NkBiDkal4ZkQdU7hwxu+g/GvUgUvzlN1J5Bto+WHWOWk9mVBngxaJ43BjuAiUVh +OSPHG0SjFeUc+JIwuwIDAQABo4HvMIHsMBIGA1UdEwEB/wQIMAYBAf8CAQEwDgYD +VR0PAQH/BAQDAgEGMB0GA1UdDgQWBBRlzeurNR4APn7VdMActHNHDhpkLzCBpgYD +VR0gBIGeMIGbMIGYBgRVHSAAMIGPMC8GCCsGAQUFBwIBFiNodHRwOi8vd3d3LmZp +cm1hcHJvZmVzaW9uYWwuY29tL2NwczBcBggrBgEFBQcCAjBQHk4AUABhAHMAZQBv +ACAAZABlACAAbABhACAAQgBvAG4AYQBuAG8AdgBhACAANAA3ACAAQgBhAHIAYwBl +AGwAbwBuAGEAIAAwADgAMAAxADcwDQYJKoZIhvcNAQEFBQADggIBABd9oPm03cXF +661LJLWhAqvdpYhKsg9VSytXjDvlMd3+xDLx51tkljYyGOylMnfX40S2wBEqgLk9 +am58m9Ot/MPWo+ZkKXzR4Tgegiv/J2Wv+xYVxC5xhOW1//qkR71kMrv2JYSiJ0L1 +ILDCExARzRAVukKQKtJE4ZYm6zFIEv0q2skGz3QeqUvVhyj5eTSSPi5E6PaPT481 +PyWzOdxjKpBrIF/EUhJOlywqrJ2X3kjyo2bbwtKDlaZmp54lD+kLM5FlClrD2VQS +3a/DTg4fJl4N3LON7NWBcN7STyQF82xO9UxJZo3R/9ILJUFI/lGExkKvgATP0H5k +SeTy36LssUzAKh3ntLFlosS88Zj0qnAHY7S42jtM+kAiMFsRpvAFDsYCA0irhpuF +3dvd6qJ2gHN99ZwExEWN57kci57q13XRcrHedUTnQn3iV2t93Jm8PYMo6oCTjcVM +ZcFwgbg4/EMxsvYDNEeyrPsiBsse3RdHHF9mudMaotoRsaS8I8nkvof/uZS2+F0g +StRf571oe2XyFR7SOqkt6dhrJKyXWERHrVkY8SFlcN7ONGCoQPHzPKTDKCOM/icz +Q0CgFzzr6juwcqajuUpLXhZI9LK8yIySxZ2frHI2vDSANGupi5LAuBft7HZT9SQB +jLMi6Et8Vcad+qMUu2WFbm5PEn4KPJ2V +-----END CERTIFICATE-----'" +"Buypass","Buypass AS-983163327","","Buypass Class 2 Root CA","02","9A114025197C5BB95D94E63D55CD43790847B646B23CDF11ADA4A00EFF15FB48","487CB58F08ED93A88AF14B840D5C19BE969C6C5D9E08691800327AC2ADDA2C8D","2010.10.26","2040.10.26","RSA 4096 bits","SHA256WithRSA","Websites","","","Not EV","https://bugzilla.mozilla.org/show_bug.cgi?id=685128","NSS 3.13.6","Firefox 16","https://valid.business.ca22.ssl.buypass.no","https://expired.business.ca22.ssl.buypass.no","https://revoked.business.ca22.ssl.buypass.no","","http://www.buypass.no/","Norway, Europe","https://www.buypass.com/security/ca-documentation-legal/_/attachment/download/b5ac176b-8023-443c-a0f1-24ce2777add2:a8a8e609fc452ed48103034ec2e4831413b60ca5/cpsSSL_CL2-2020-04-15.pdf","https://www.buypass.com/security/ca-documentation-legal/_/attachment/download/14f3c524-2327-44c3-be38-12cfa8eef383:bc2946220b17f9ba69563a5deeccaa384d06d91b/cpsSSL_CL3-2020-04-15.pdf","https://www.buypass.com/the-company/certification/_/attachment/download/413dca90-da68-483e-80e4-3978e33a8e98:76247c1b8cacd26f80531a2929c2a739db2b5159/ETS%20018.pdf","https://www.buypass.com/the-company/certification/_/attachment/download/413dca90-da68-483e-80e4-3978e33a8e98:76247c1b8cacd26f80531a2929c2a739db2b5159/ETS%20018.pdf","","BSI","ETSI EN 319 411","2020.01.29","'-----BEGIN CERTIFICATE----- +MIIFWTCCA0GgAwIBAgIBAjANBgkqhkiG9w0BAQsFADBOMQswCQYDVQQGEwJOTzEd +MBsGA1UECgwUQnV5cGFzcyBBUy05ODMxNjMzMjcxIDAeBgNVBAMMF0J1eXBhc3Mg +Q2xhc3MgMiBSb290IENBMB4XDTEwMTAyNjA4MzgwM1oXDTQwMTAyNjA4MzgwM1ow +TjELMAkGA1UEBhMCTk8xHTAbBgNVBAoMFEJ1eXBhc3MgQVMtOTgzMTYzMzI3MSAw +HgYDVQQDDBdCdXlwYXNzIENsYXNzIDIgUm9vdCBDQTCCAiIwDQYJKoZIhvcNAQEB +BQADggIPADCCAgoCggIBANfHXvfBB9R3+0Mh9PT1aeTuMgHbo4Yf5FkNuud1g1Lr +6hxhFUi7HQfKjK6w3Jad6sNgkoaCKHOcVgb/S2TwDCo3SbXlzwx87vFKu3MwZfPV +L4O2fuPn9Z6rYPnT8Z2SdIrkHJasW4DptfQxh6NR/Md+oW+OU3fUl8FVM5I+GC91 +1K2GScuVr1QGbNgGE41b/+EmGVnAJLqBcXmQRFBoJJRfuLMR8SlBYaNByyM21cHx +MlAQTn/0hpPshNOOvEu/XAFOBz3cFIqUCqTqc/sLUegTBxj6DvEr0VQVfTzh97QZ +QmdiXnfgolXsttlpF9U6r0TtSsWe5HonfOV116rLJeffawrbD02TTqigzXsu8lkB +arcNuAeBfos4GzjmCleZPe4h6KP1DBbdi+w0jpwqHAAVF41og9JwnxgIzRFo1clr +Us3ERo/ctfPYV3Me6ZQ5BL/T3jjetFPsaRyifsSP5BtwrfKi+fv3FmRmaZ9JUaLi +FRhnBkp/1Wy1TbMz4GHrXb7pmA8y1x1LPC5aAVKRCfLf6o3YBkBjqhHk/sM3nhRS +P/TizPJhk9H9Z2vXUq6/aKtAQ6BXNVN48FP4YUIHZMbXb5tMOA1jrGKvNouicwoN +9SG9dKpN6nIDSdvHXx1iY8f93ZHsM+71bbRuMGjeyNYmsHVee7QHIJihdjK4TWxP +AgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFMmAd+BikoL1Rpzz +uvdMw964o605MA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQsFAAOCAgEAU18h +9bqwOlI5LJKwbADJ784g7wbylp7ppHR/ehb8t/W2+xUbP6umwHJdELFx7rxP462s +A20ucS6vxOOto70MEae0/0qyexAQH6dXQbLArvQsWdZHEIjzIVEpMMpghq9Gqx3t +OluwlN5E40EIosHsHdb9T7bWR9AUC8rmyrV7d35BH16Dx7aMOZawP5aBQW9gkOLo ++fsicdl9sz1Gv7SEr5AcD48Saq/v7h56rgJKihcrdv6sVIkkLE8/trKnToyokZf7 +KcZ7XC25y2a2t6hbElGFtQl+Ynhw/qlqYLYdDnkM/crqJIByw5c/8nerQyIKx+u2 +DISCLIBrQYoIwOula9+ZEsuK1V6ADJHgJgg2SMX6OBE1/yWDLfJ6v9r9jv6ly0Us +H8SIU653DtmadsWOLB2jutXsMq7Aqqz30XpN69QH4kj3Io6wpJ9qzo6ysmD0oyLQ +I+uUWnpp3Q+/QFesa1lQ2aOZ4W7+jQF5JyMV3pKdewlNWudLSDBaGOYKbeaP4NK7 +5t98biGCwWg5TbSYWGZizEqQXsP6JwSxeRV0mcy+rSDeJmAc61ZRpqPq5KM/p/9h +3PFaTWwyI0PurKju7koSCTxdccK+efrCh2gdC/1cacwG0Jp9VJkqyTkaGa9LKkPz +Y11aWOIv4x3kqdbQCtCev9eBCfHJxyYNrJgWVqA= +-----END CERTIFICATE-----'" +"Buypass","Buypass AS-983163327","","Buypass Class 3 Root CA","02","EDF7EBBCA27A2A384D387B7D4010C666E2EDB4843E4C29B4AE1D5B9332E6B24D","7BFE75BC2F581D017F20CAF33D513EC107198A595B2C82AA1B89F0DAC5190782","2010.10.26","2040.10.26","RSA 4096 bits","SHA256WithRSA","Websites","","","2.16.578.1.26.1.3.3","https://bugzilla.mozilla.org/show_bug.cgi?id=685128","NSS 3.13.6","Firefox 16","https://valid.evident.ca23.ssl.buypass.no","https://expired.evident.ca23.ssl.buypass.no","https://revoked.evident.ca23.ssl.buypass.no","","http://www.buypass.no/","Norway, Europe","https://www.buypass.com/security/ca-documentation-legal/_/attachment/download/b5ac176b-8023-443c-a0f1-24ce2777add2:a8a8e609fc452ed48103034ec2e4831413b60ca5/cpsSSL_CL2-2020-04-15.pdf","https://www.buypass.com/security/ca-documentation-legal/_/attachment/download/14f3c524-2327-44c3-be38-12cfa8eef383:bc2946220b17f9ba69563a5deeccaa384d06d91b/cpsSSL_CL3-2020-04-15.pdf","https://www.buypass.com/the-company/certification/_/attachment/download/413dca90-da68-483e-80e4-3978e33a8e98:76247c1b8cacd26f80531a2929c2a739db2b5159/ETS%20018.pdf","https://www.buypass.com/the-company/certification/_/attachment/download/413dca90-da68-483e-80e4-3978e33a8e98:76247c1b8cacd26f80531a2929c2a739db2b5159/ETS%20018.pdf","https://www.buypass.com/the-company/certification/_/attachment/download/413dca90-da68-483e-80e4-3978e33a8e98:76247c1b8cacd26f80531a2929c2a739db2b5159/ETS%20018.pdf","BSI","ETSI EN 319 411","2020.01.29","'-----BEGIN CERTIFICATE----- +MIIFWTCCA0GgAwIBAgIBAjANBgkqhkiG9w0BAQsFADBOMQswCQYDVQQGEwJOTzEd +MBsGA1UECgwUQnV5cGFzcyBBUy05ODMxNjMzMjcxIDAeBgNVBAMMF0J1eXBhc3Mg +Q2xhc3MgMyBSb290IENBMB4XDTEwMTAyNjA4Mjg1OFoXDTQwMTAyNjA4Mjg1OFow +TjELMAkGA1UEBhMCTk8xHTAbBgNVBAoMFEJ1eXBhc3MgQVMtOTgzMTYzMzI3MSAw +HgYDVQQDDBdCdXlwYXNzIENsYXNzIDMgUm9vdCBDQTCCAiIwDQYJKoZIhvcNAQEB +BQADggIPADCCAgoCggIBAKXaCpUWUOOV8l6ddjEGMnqb8RB2uACatVI2zSRHsJ8Y +ZLya9vrVediQYkwiL944PdbgqOkcLNt4EemOaFEVcsfzM4fkoF0LXOBXByow9c3E +N3coTRiR5r/VUv1xLXA+58bEiuPwKAv0dpihi4dVsjoT/Lc+JzeOIuOoTyrvYLs9 +tznDDgFHmV0ST9tD+leh7fmdvhFHJlsTmKtdFoqwNxxXnUX/iJY2v7vKB3tvh2PX +0DJq1l1sDPGzbjniazEuOQAnFN44wOwZZoYS6J1yFhNkUsepNxz9gjDthBgd9K5c +/3ATAOux9TN6S9ZV+AWNS2mw9bMoNlwUxFFzTWsL8TQH2xc519woe2v1n/MuwU8X +KhDzzMro6/1rqy6any2CbgTUUgGTLT2G/H783+9CHaZr77kgxve9oKeV/afmiSTY +zIw0bOIjL9kSGiG5VZFvC5F5GQytQIgLcOJ60g7YaEi7ghM5EFjp2CoHxhLbWNvS +O1UQRwUVZ2J+GGOmRj8JDlQyXr8NYnon74Do29lLBlo3WiXQCBJ31G8JUJc9yB3D +34xFMFbG02SrZvPAXpacw8Tvw3xrizp5f7NJzz3iiZ+gMEuFuZyUJHmPfWupRWgP +K9Dx2hzLabjKSWJtyNBjYt1gD1iqj6G8BaVmos8bdrKEZLFMOVLAMLrwjEsCsLa3 +AgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFEe4zf/lb+74suwv +Tg75JbCOPGvDMA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQsFAAOCAgEAACAj +QTUEkMJAYmDv4jVM1z+s4jSQuKFvdvoWFqRINyzpkMLyPPgKn9iB5btb2iUspKdV +cSQy9sgL8rxq+JOssgfCX5/bzMiKqr5qb+FJEMwx14C7u8jYog5kV+qi9cKpMRXS +IGrs/CIBKM+GuIAeqcwRpTzyFrNHnfzSgCHEy9BHcEGhyoMZCCxt8l13nIoUE9Q2 +HJLw5QY33KbmkJs4j1xrG0aGQ0JfPgEHU1RdZX33inOhmlRaHylDFCfChQ+1iHsa +O5S3HWCntZznKWlXWpuTekMwGwPXYshApqr8ZORK15FTAaggiG6cX0S5y2CBNOxv +033aSF/rtJC8LakcC6wc1aJoIIAE1vyxjy+7SjENSoYc6+I2KSb12tjE8nVhz36u +dmNKekBlk4f4HoCMhuWG1o8O/FMsYOgWYRqiPkN7zTlgVGr18okmAWiDSKIz6MkE +kbIRNBE+6tBDGR8Dk5AM/1E9V/RBbuHLoL7ryWPNbczk+DaqaJ3tvV2XcEQNtg41 +3OEMXbugUZTLfhbrES+jkkXITHHZvMmZUldGL1DPvTVp9D0VzgalLA8+9oG6lLvD +u79leNKGef9JOxqDDPDeeOzI8k1MGt6CKfjBWtrt7uYnXuhF0J0cUahoq0Tj0Itq +4/g7u9xN12TyUb7mqqta6THuBrxzvxNiCp/HuZc= +-----END CERTIFICATE-----'" +"certSIGN","certSIGN","certSIGN ROOT CA","certSIGN ROOT CA","200605167002","EAA962C4FA4A6BAFEBE415196D351CCD888D4F53F3FA8AE6D7C466A94E6042BB","803207093030E6DA4EAF69969EDD5A4F9B2A4685B497A283BC4AEEBCA2A04361","2006.07.04","2031.07.04","RSA 2048 bits","SHA1WithRSA","Websites;Email","","","Not EV","https://bugzilla.mozilla.org/show_bug.cgi?id=470756","NSS 3.12.5","Firefox 3.6","https://testssl-valid.certsign.ro/","https://testssl-expired.certsign.ro/","https://testssl-revoked.certsign.ro/","","http://www.certsign.ro/certsign_en/","Romania","","https://www.certsign.ro/media/document/T1B0TmQ1V1NabEFHc1pnZE9EcGdmdz09/original/CPS%20QWAC%20SSL%20v1.16.pdf; https://www.certsign.ro/media/document/bzFwcnVYYUl4R3FpSmlZN2t3cDQydz09/original/CPS%20OV%20SSL%20v1.13.pdf","https://www.cpacanada.ca/generichandlers/CPACHandler.ashx?attachmentid=239757","https://www.cpacanada.ca/generichandlers/CPACHandler.ashx?attachmentid=239758","https://www.cpacanada.ca/generichandlers/CPACHandler.ashx?attachmentid=239760","Ernst & Young, LLP","WebTrust","2020.04.30","'-----BEGIN CERTIFICATE----- +MIIDODCCAiCgAwIBAgIGIAYFFnACMA0GCSqGSIb3DQEBBQUAMDsxCzAJBgNVBAYT +AlJPMREwDwYDVQQKEwhjZXJ0U0lHTjEZMBcGA1UECxMQY2VydFNJR04gUk9PVCBD +QTAeFw0wNjA3MDQxNzIwMDRaFw0zMTA3MDQxNzIwMDRaMDsxCzAJBgNVBAYTAlJP +MREwDwYDVQQKEwhjZXJ0U0lHTjEZMBcGA1UECxMQY2VydFNJR04gUk9PVCBDQTCC +ASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALczuX7IJUqOtdu0KBuqV5Do +0SLTZLrTk+jUrIZhQGpgV2hUhE28alQCBf/fm5oqrl0Hj0rDKH/v+yv6efHHrfAQ +UySQi2bJqIirr1qjAOm+ukbuW3N7LBeCgV5iLKECZbO9xSsAfsT8AzNXDe3i+s5d +RdY4zTW2ssHQnIFKquSyAVwdj1+ZxLGt24gh65AIgoDzMKND5pCCrlUoSe1b16kQ +OA7+j0xbm0bqQfWwCHTD0IgztnzXdN/chNFDDnU5oSVAKOp4yw4sLjmdjItuFhwv +JoIQ4uNllAoEwF73XVv4EOLQunpL+943AAAaWyjj0pxzPjKHmKHJUS/X3qwzs08C +AwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAcYwHQYDVR0O +BBYEFOCMm9slSbPxfIbWskKHC9BroNnkMA0GCSqGSIb3DQEBBQUAA4IBAQA+0hyJ +LjX8+HXd5n9liPRyTMks1zJO890ZeUe9jjtbkw9QSSQTaxQGcu8J06Gh40CEyecY +MnQ8SG4Pn0vU9x7Tk4ZkVJdjclDVVc/6IJMCopvDI5NOFlV2oHB5bc0hH88vLbwZ +44gx+FkagQnIl6Z0x2DEW8xXjrJ1/RsCCdtZb3KTafcxQdaIOL+Hsr0Wefmq5L6I +Jd1hJyMctTEHBDa0GpC9oHRxUIltvBTjD4au8as+x6AJzKNI0eDbZOeStc+vckNw +i/nDhDwTqn6Sm1dTk/pwwpEOMfmbZ13pljheX7NzTogVZ96edhBiIL5VaZVDADlN +9u6wWk5JRFRYX0KD +-----END CERTIFICATE-----'" +"certSIGN","CERTSIGN SA","certSIGN ROOT CA G2","certSIGN Root CA G2","110034B64EC6362D36","657CFE2FA73FAA38462571F332A2363A46FCE7020951710702CDFBB6EEDA3305","A0A51554F6F956CD4AFDD3B41E968828155DF6088EDC61EE90515BB651765030","2017.02.06","2042.02.06","RSA 4096 bits","SHA256WithRSA","Websites","","","2.23.140.1.1","https://bugzilla.mozilla.org/show_bug.cgi?id=1403453","NSS 3.54","Firefox 79","https://testssl-valid-evcp.certsign.ro/","https://testssl-expired-evcp.certsign.ro/","https://testssl-revoked-evcp.certsign.ro/","","http://www.certsign.ro/certsign_en/","Romania","","https://www.certsign.ro/media/document/T1B0TmQ1V1NabEFHc1pnZE9EcGdmdz09/original/CPS%20QWAC%20SSL%20v1.16.pdf; https://www.certsign.ro/media/document/bzFwcnVYYUl4R3FpSmlZN2t3cDQydz09/original/CPS%20OV%20SSL%20v1.13.pdf","https://lsti-certification.fr/images/LSTI_Audit_Atttestation_Letter_1612-163_V10_Certsign_S.pdf","https://lsti-certification.fr/images/LSTI_Audit_Atttestation_Letter_1612-163_V10_Certsign_S.pdf","https://lsti-certification.fr/images/LSTI_Audit_Atttestation_Letter_1612-163_V10_Certsign_S.pdf","LSTI","ETSI EN 319 411","2020.04.29","'-----BEGIN CERTIFICATE----- +MIIFRzCCAy+gAwIBAgIJEQA0tk7GNi02MA0GCSqGSIb3DQEBCwUAMEExCzAJBgNV +BAYTAlJPMRQwEgYDVQQKEwtDRVJUU0lHTiBTQTEcMBoGA1UECxMTY2VydFNJR04g +Uk9PVCBDQSBHMjAeFw0xNzAyMDYwOTI3MzVaFw00MjAyMDYwOTI3MzVaMEExCzAJ +BgNVBAYTAlJPMRQwEgYDVQQKEwtDRVJUU0lHTiBTQTEcMBoGA1UECxMTY2VydFNJ +R04gUk9PVCBDQSBHMjCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMDF +dRmRfUR0dIf+DjuW3NgBFszuY5HnC2/OOwppGnzC46+CjobXXo9X69MhWf05N0Iw +vlDqtg+piNguLWkh59E3GE59kdUWX2tbAMI5Qw02hVK5U2UPHULlj88F0+7cDBrZ +uIt4ImfkabBoxTzkbFpG583H+u/E7Eu9aqSs/cwoUe+StCmrqzWaTOTECMYmzPhp +n+Sc8CnTXPnGFiWeI8MgwT0PPzhAsP6CRDiqWhqKa2NYOLQV07YRaXseVO6MGiKs +cpc/I1mbySKEwQdPzH/iV8oScLumZfNpdWO9lfsbl83kqK/20U6o2YpxJM02PbyW +xPFsqa7lzw1uKA2wDrXKUXt4FMMgL3/7FFXhEZn91QqhngLjYl/rNUssuHLoPj1P +rCy7Lobio3aP5ZMqz6WryFyNSwb/EkaseMsUBzXgqd+L6a8VTxaJW732jcZZroiF +DsGJ6x9nxUWO/203Nit4ZoORUSs9/1F3dmKh7Gc+PoGD4FapUB8fepmrY7+EF3fx +DTvf95xhszWYijqy7DwaNz9+j5LP2RIUZNoQAhVB/0/E6xyjyfqZ90bp4RjZsbgy +LcsUDFDYg2WD7rlcz8sFWkz6GZdr1l0T08JcVLwyc6B49fFtHsufpaafItzRUZ6C +eWRgKRM+o/1Pcmqr4tTluCRVLERLiohEnMqE0yo7AgMBAAGjQjBAMA8GA1UdEwEB +/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBSCIS1mxteg4BXrzkwJ +d8RgnlRuAzANBgkqhkiG9w0BAQsFAAOCAgEAYN4auOfyYILVAzOBywaK8SJJ6ejq +kX/GM15oGQOGO0MBzwdw5AgeZYWR5hEit/UCI46uuR59H35s5r0l1ZUa8gWmr4UC +b6741jH/JclKyMeKqdmfS0mbEVeZkkMR3rYzpMzXjWR91M08KCy0mpbqTfXERMQl +qiCA2ClV9+BB/AYm/7k29UMUA2Z44RGx2iBfRgB4ACGlHgAoYXhvqAEBj500mv/0 +OJD7uNGzcgbJceaBxXntC6Z58hMLnPddDnskk7RI24Zf3lCGeOdA5jGokHZwYa+c +NywRtYK3qq4kNFtyDGkNzVmf9nGvnAvRCjj5BiKDUyUM/FHE5r7iOZULJK2v0ZXk +ltd0ZGtxTgI8qoXzIKNDOXZbbFD+mpwUHmUUihW9o4JFWklWatKcsWMy5WHgUyIO +pwpJ6st+H6jiYoD2EEVSmAYY3qXNL3+q1Ok+CHLsIwMCPKaq2LxndD0UF/tUSxfj +03k9bWtJySgOLnRQvwzZRjoQhsmnP+mg7H/rpXdYaXHmgwo38oZJar55CJD2AhZk +PuXaTH4MNMn5X7azKFGnpyuqSfqNZSlO42sTp5SjLVFteAxEy9/eCG/Oo2Sr05WE +1LlSVHJ7liXMvGnjSG4N0MedJ5qq+BOS3R7fY581qRY27Iy4g/Q9iY/NtBde17MX +QRBdJ3NghVdJIgc= +-----END CERTIFICATE-----'" +"China Financial Certification Authority (CFCA)","China Financial Certification Authority","","CFCA EV ROOT","184ACCD6","5CC3D78E4E1D5E45547A04E6873E64F90CF9536D1CCC2EF800F355C4C5FD70FD","5CBE245423ACEBA4450A3ADB752BE02649E2346ED69EC3CF3BDCCB63C3E98790","2012.08.08","2029.12.31","RSA 4096 bits","SHA256WithRSA","Websites","","","2.16.156.112554.3","https://bugzilla.mozilla.org/show_bug.cgi?id=926029","NSS 3.18","Firefox 38","https://www.anxinsign.com/Web/login/login.jsp","https://exp.cebnet.com.cn/","https://rev.cebnet.com.cn/","None","http://www.cfca.com.cn/","China","https://www.cfca.com.cn/upload/CFCACertificatePolicy20181119.pdf","https://www.cfca.com.cn/upload/CertificationPracticeStatementOfCFCAGlobal-TrustSystemENG.pdf","https://www.cpacanada.ca/generichandlers/CPACHandler.ashx?attachmentid=236836","https://www.cpacanada.ca/generichandlers/CPACHandler.ashx?attachmentid=236837","https://www.cpacanada.ca/generichandlers/CPACHandler.ashx?attachmentid=236838","PwC - PricewaterhouseCoopers International Limited","WebTrust","2019.10.31","'-----BEGIN CERTIFICATE----- +MIIFjTCCA3WgAwIBAgIEGErM1jANBgkqhkiG9w0BAQsFADBWMQswCQYDVQQGEwJD +TjEwMC4GA1UECgwnQ2hpbmEgRmluYW5jaWFsIENlcnRpZmljYXRpb24gQXV0aG9y +aXR5MRUwEwYDVQQDDAxDRkNBIEVWIFJPT1QwHhcNMTIwODA4MDMwNzAxWhcNMjkx +MjMxMDMwNzAxWjBWMQswCQYDVQQGEwJDTjEwMC4GA1UECgwnQ2hpbmEgRmluYW5j +aWFsIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MRUwEwYDVQQDDAxDRkNBIEVWIFJP +T1QwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDXXWvNED8fBVnVBU03 +sQ7smCuOFR36k0sXgiFxEFLXUWRwFsJVaU2OFW2fvwwbwuCjZ9YMrM8irq93VCpL +TIpTUnrD7i7es3ElweldPe6hL6P3KjzJIx1qqx2hp/Hz7KDVRM8Vz3IvHWOX6Jn5 +/ZOkVIBMUtRSqy5J35DNuF++P96hyk0g1CXohClTt7GIH//62pCfCqktQT+x8Rgp +7hZZLDRJGqgG16iI0gNyejLi6mhNbiyWZXvKWfry4t3uMCz7zEasxGPrb382KzRz +EpR/38wmnvFyXVBlWY9ps4deMm/DGIq1lY+wejfeWkU7xzbh72fROdOXW3NiGUgt +hxwG+3SYIElz8AXSG7Ggo7cbcNOIabla1jj0Ytwli3i/+Oh+uFzJlU9fpy25IGvP +a931DfSCt/SyZi4QKPaXWnuWFo8BGS1sbn85WAZkgwGDg8NNkt0yxoekN+kWzqot +aK8KgWU6cMGbrU1tVMoqLUuFG7OA5nBFDWteNfB/O7ic5ARwiRIlk9oKmSJgamNg +TnYGmE69g60dWIolhdLHZR4tjsbftsbhf4oEIRUpdPA+nJCdDC7xij5aqgwJHsfV +PKPtl8MeNPo4+QgO48BdK4PRVmrJtqhUUy54Mmc9gn900PvhtgVguXDbjgv5E1hv +cWAQUhC5wUEJ73IfZzF4/5YFjQIDAQABo2MwYTAfBgNVHSMEGDAWgBTj/i39KNAL +tbq2osS/BqoFjJP7LzAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAd +BgNVHQ4EFgQU4/4t/SjQC7W6tqLEvwaqBYyT+y8wDQYJKoZIhvcNAQELBQADggIB +ACXGumvrh8vegjmWPfBEp2uEcwPenStPuiB/vHiyz5ewG5zz13ku9Ui20vsXiObT +ej/tUxPQ4i9qecsAIyjmHjdXNYmEwnZPNDatZ8POQQaIxffu2Bq41gt/UP+TqhdL +jOztUmCypAbqTuv0axn96/Ua4CUqmtzHQTb3yHQFhDmVOdYLO6Qn+gjYXB74BGBS +ESgoA//vU2YApUo0FmZ8/Qmkrp5nGm9BC2sGE5uPhnEFtC+NiWYzKXZUmhH4J/qy +P5Hgzg0b8zAarb8iXRvTvyUFTeGSGn+ZnzxEk8rUQElsgIfXBDrDMlI1Dlb4pd19 +xIsNER9Tyx6yF7Zod1rg1MvIB671Oi6ON7fQAUtDKXeMOZePglr4UeWJoBjnaH9d +Ci77o0cOPaYjesYBx4/IXr9tgFa+iiS6M+qf4TIRnvHST4D2G0CvOJ4RUHlzEhLN +5mydLIhyPDCBBpEi6lmt2hkuIsKNuYyH4Ga8cyNfIWRjgEj1oDwYPZTISEEdQLpe +/v5WOaHIz16eGWRGENoXkbcFgKyLmZJ956LYBws2J+dIeWCKw9cTXPhyQN9Ky8+Z +AAoACxGV2lZFA4gKn2fQ1XmxqI1AbQ3CekD6819kR5LLU7m7Wc5P/dAVUwHY3+vZ +5nbv0CO7O6l5s9UCKc2Jo5YPSjXnTkLAdc0Hz+Ys63su +-----END CERTIFICATE-----'" +"Chunghwa Telecom","Chunghwa Telecom Co., Ltd.","ePKI Root Certification Authority","Chunghwa Telecom Co., Ltd. - ePKI Root Certification Authority","15C8BD65475CAFB897005EE406D2BC9D","C0A6F4DC63A24BFDCF54EF2A6A082A0A72DE35803E2FF5FF527AE5D87206DFD5","5F7314B8C34C1932B5A414A24494606BF760654A7F11562BA2845E81AD19A9D0","2004.12.20","2034.12.20","RSA 4096 bits","SHA1WithRSA","Websites;Email","","","Not EV","https://bugzilla.mozilla.org/show_bug.cgi?id=448794","NSS 3.12.5","Firefox 3.6","https://good.epkiov.hinet.net","https://expired.epkiov.hinet.net","https://revoked.epkiov.hinet.net","","http://www.cht.com.tw","Taiwan","http://eca.hinet.net/download/ePKI-CP-v1.7-Eng.pdf","http://eca.hinet.net/download/eCA-CPS-v1.6-Eng.pdf +http://eca.hinet.net/download/PublicCA-CPS-v1.9-Eng.pdf +http://eca.hinet.net/download/ePKI_EVSSL_CA_CPS_v1.2_Eng.pdf","https://www.cpacanada.ca/generichandlers/CPACHandler.ashx?attachmentid=232565","https://www.cpacanada.ca/generichandlers/CPACHandler.ashx?attachmentid=232566","https://www.cpacanada.ca/generichandlers/CPACHandler.ashx?attachmentid=233024","SunRise CPAs / DFK International","WebTrust","2019.07.22","'-----BEGIN CERTIFICATE----- +MIIFsDCCA5igAwIBAgIQFci9ZUdcr7iXAF7kBtK8nTANBgkqhkiG9w0BAQUFADBe +MQswCQYDVQQGEwJUVzEjMCEGA1UECgwaQ2h1bmdod2EgVGVsZWNvbSBDby4sIEx0 +ZC4xKjAoBgNVBAsMIWVQS0kgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAe +Fw0wNDEyMjAwMjMxMjdaFw0zNDEyMjAwMjMxMjdaMF4xCzAJBgNVBAYTAlRXMSMw +IQYDVQQKDBpDaHVuZ2h3YSBUZWxlY29tIENvLiwgTHRkLjEqMCgGA1UECwwhZVBL +SSBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIICIjANBgkqhkiG9w0BAQEF +AAOCAg8AMIICCgKCAgEA4SUP7o3biDN1Z82tH306Tm2d0y8U82N0ywEhajfqhFAH +SyZbCUNsIZ5qyNUD9WBpj8zwIuQf5/dqIjG3LBXy4P4AakP/h2XGtRrBp0xtInAh +ijHyl3SJCRImHJ7K2RKilTza6We/CKBk49ZCt0Xvl/T29de1ShUCWH2YWEtgvM3X +DZoTM1PRYfl61dd4s5oz9wCGzh1NlDivqOx4UXCKXBCDUSH3ET00hl7lSM2XgYI1 +TBnsZfZrxQWh7kcT1rMhJ5QQCtkkO7q+RBNGMD+XPNjX12ruOzjjK9SXDrkb5wdJ +fzcq+Xd4z1TtW0ado4AOkUPB1ltfFLqfpo0kR0BZv3I4sjZsN/+Z0V0OWQqraffA +sgRFelQArr5T9rXn4fg8ozHSqf4hUmTFpmfwdQcGlBSBVcYn5AGPF8Fqcde+S/uU +WH1+ETOxQvdibBjWzwloPn9s9h6PYq2lY9sJpx8iQkEeb5mKPtf5P0B6ebClAZLS +nT0IFaUQAS2zMnaolQ2zepr7BxB4EW/hj8e6DyUadCrlHJhBmd8hh+iVBmoKs2pH +dmX2Os+PYhcZewoozRrSgx4hxyy/vv9haLdnG7t4TY3OZ+XkwY63I2binZB1NJip +NiuKmpS5nezMirH4JYlcWrYvjB9teSSnUmjDhDXiZo1jDiVN1Rmy5nk3pyKdVDEC +AwEAAaNqMGgwHQYDVR0OBBYEFB4M97Zn8uGSJglFwFU5Lnc/QkqiMAwGA1UdEwQF +MAMBAf8wOQYEZyoHAAQxMC8wLQIBADAJBgUrDgMCGgUAMAcGBWcqAwAABBRFsMLH +ClZ87lt4DJX5GFPBphzYEDANBgkqhkiG9w0BAQUFAAOCAgEACbODU1kBPpVJufGB +uvl2ICO1J2B01GqZNF5sAFPZn/KmsSQHRGoqxqWOeBLoR9lYGxMqXnmbnwoqZ6Yl +PwZpVnPDimZI+ymBV3QGypzqKOg4ZyYr8dW1P2WT+DZdjo2NQCCHGervJ8A9tDkP +JXtoUHRVnAxZfVo9QZQlUgjgRywVMRnVvwdVxrsStZf0X4OFunHB2WyBEXYKCrC/ +gpf36j36+uwtqSiUO1bd0lEursC9CBWMd1I0ltabrNMdjmEPNXubrjlpC2JgQCA2 +j6/7Nu4tCEoduL+bXPjqpRugc6bY+G7gMwRfaKonh+3ZwZCc7b3jajWvY9+rGNm6 +5ulK6lCKD2GTHuItGeIwlDWSXQ62B68ZgI9HkFFLLk3dheLSClIKF5r8GrBQAuUB +o2M3IUxExJtRmREOc5wGj1QupyheRDmHVi03vYVElOEMSyycw5KFNGHLD7ibSkNS +/jQ6fbjpKdx2qcgw+BRxgMYeNkh0IkFch4LoGHGLQYlE535YW6i4jRPpp2zDR+2z +Gp1iro2C6pSe3VkQw63d4k3jMdXH7OjysP6SHhYKGvzZ8/gntsm+HbRsZJB/9OTE +W9c3rkIO3aQab3yIVMUWbuF6aC74Or8NpDyJO3inTmODBCEIZ43ygknQW/2xzQ+D +hNQ+IIX3Sj0rnP0qCglN6oH4EZw= +-----END CERTIFICATE-----'" +"Consorci Administració Oberta de Catalunya (Consorci AOC, CATCert)","Agencia Catalana de Certificacio (NIF Q-0801176-I)","Serveis Publics de Certificacio, Vegeu https://www.catcert.net/verarrel (c)03, Jerarquia Entitats de Certificacio Catalanes","EC-ACC","EE2B3DEBD421DE14A862AC04F3DDC401","88497F01602F3154246AE28C4D5AEF10F1D87EBB76626F4AE0B7F95BA7968799","DBAEE5018161205A34C28F9482A9C1D9775D83D161CDE803E3AB3684D8FE1F1C","2003.01.07","2031.01.07","RSA 2048 bits","SHA1WithRSA","Websites","","","Not EV","https://bugzilla.mozilla.org/show_bug.cgi?id=295474","NSS 3.13.2","Firefox 11","https://testcdsq.aoc.cat","https://testcdsqexpired.aoc.cat","https://testcdsqrevoked.aoc.cat","","http://www.aoc.cat/Inici/SERVEIS/Signatura-electronica-i-seguretat/CATCert","Catalunya in Spain","https://www.aoc.cat/wp-content/uploads/2019/07/pc_dispositius_i_infraestructures-6-1-en.pdf","https://www.aoc.cat/wp-content/uploads/2019/07/dpc-6-1-en.pdf","https://www.aenor.com/Certificacion_Documentos/eiDas/2020%20AENOR%20Anexo%20ETSI%20319%20411-1-2%20PSC-CAOC_v0.3%20(002).pdf","https://www.aenor.com/Certificacion_Documentos/eiDas/2020%20AENOR%20Anexo%20ETSI%20319%20411-1-2%20PSC-CAOC_v0.3%20(002).pdf","https://www.aenor.com/Certificacion_Documentos/eiDas/2020%20AENOR%20Anexo%20ETSI%20319%20411-1-2%20PSC-CAOC_v0.3%20(002).pdf","AENOR INTERNACIONAL, S.A. (Unipersonal)","ETSI EN 319 411","2020.06.11","'-----BEGIN CERTIFICATE----- +MIIFVjCCBD6gAwIBAgIQ7is969Qh3hSoYqwE893EATANBgkqhkiG9w0BAQUFADCB +8zELMAkGA1UEBhMCRVMxOzA5BgNVBAoTMkFnZW5jaWEgQ2F0YWxhbmEgZGUgQ2Vy +dGlmaWNhY2lvIChOSUYgUS0wODAxMTc2LUkpMSgwJgYDVQQLEx9TZXJ2ZWlzIFB1 +YmxpY3MgZGUgQ2VydGlmaWNhY2lvMTUwMwYDVQQLEyxWZWdldSBodHRwczovL3d3 +dy5jYXRjZXJ0Lm5ldC92ZXJhcnJlbCAoYykwMzE1MDMGA1UECxMsSmVyYXJxdWlh +IEVudGl0YXRzIGRlIENlcnRpZmljYWNpbyBDYXRhbGFuZXMxDzANBgNVBAMTBkVD +LUFDQzAeFw0wMzAxMDcyMzAwMDBaFw0zMTAxMDcyMjU5NTlaMIHzMQswCQYDVQQG +EwJFUzE7MDkGA1UEChMyQWdlbmNpYSBDYXRhbGFuYSBkZSBDZXJ0aWZpY2FjaW8g +KE5JRiBRLTA4MDExNzYtSSkxKDAmBgNVBAsTH1NlcnZlaXMgUHVibGljcyBkZSBD +ZXJ0aWZpY2FjaW8xNTAzBgNVBAsTLFZlZ2V1IGh0dHBzOi8vd3d3LmNhdGNlcnQu +bmV0L3ZlcmFycmVsIChjKTAzMTUwMwYDVQQLEyxKZXJhcnF1aWEgRW50aXRhdHMg +ZGUgQ2VydGlmaWNhY2lvIENhdGFsYW5lczEPMA0GA1UEAxMGRUMtQUNDMIIBIjAN +BgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAsyLHT+KXQpWIR4NA9h0X84NzJB5R +85iKw5K4/0CQBXCHYMkAqbWUZRkiFRfCQ2xmRJoNBD45b6VLeqpjt4pEndljkYRm +4CgPukLjbo73FCeTae6RDqNfDrHrZqJyTxIThmV6PttPB/SnCWDaOkKZx7J/sxaV +HMf5NLWUhdWZXqBIoH7nF2W4onW4HvPlQn2v7fOKSGRdghST2MDk/7NQcvJ29rNd +QlB50JQ+awwAvthrDk4q7D7SzIKiGGUzE3eeml0aE9jD2z3Il3rucO2n5nzbcc8t +lGLfbdb1OL4/pYUKGbio2Al1QnDE6u/LDsg0qBIimAy4E5S2S+zw0JDnJwIDAQAB +o4HjMIHgMB0GA1UdEQQWMBSBEmVjX2FjY0BjYXRjZXJ0Lm5ldDAPBgNVHRMBAf8E +BTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUoMOLRKo3pUW/l4Ba0fF4 +opvpXY0wfwYDVR0gBHgwdjB0BgsrBgEEAfV4AQMBCjBlMCwGCCsGAQUFBwIBFiBo +dHRwczovL3d3dy5jYXRjZXJ0Lm5ldC92ZXJhcnJlbDA1BggrBgEFBQcCAjApGidW +ZWdldSBodHRwczovL3d3dy5jYXRjZXJ0Lm5ldC92ZXJhcnJlbCAwDQYJKoZIhvcN +AQEFBQADggEBAKBIW4IB9k1IuDlVNZyAelOZ1Vr/sXE7zDkJlF7W2u++AVtd0x7Y +/X1PzaBB4DSTv8vihpw3kpBWHNzrKQXlxJ7HNd+KDM3FIUPpqojlNcAZQmNaAl6k +SBg6hW/cnbw/nZzBh7h6YQjpdwt/cKt63dmXLGQehb+8dJahw3oS7AwaboMMPOhy +Rp/7SNVel+axofjk70YllJyJ22k4vuxcDlbHZVHlUIiIv0LVKz3l+bqeLrPK9HOS +Agu+TGbrIP65y7WZf+a2E/rKS03Z7lNGBjvGTq2TWoF+bCpLagVFjPIhpDGQh2xl +nJ2lYJU6Un/10asIbvPuW/mIPX64b24D5EI= +-----END CERTIFICATE-----'" +"Cybertrust Japan / JCSI","Japan Certification Services, Inc.","","SecureSign RootCA11","01","BF0FEEFB9E3A581AD5F9E9DB7589985743D261085C4D314F6F5D7259AA421612","629844ED8C5DB0F721561FA3ED72F1780D3C37FFE2F8207CB5B3483A2ED6F217","2009.04.08","2029.04.08","RSA 2048 bits","SHA1WithRSA","Websites","","","Not EV","https://bugzilla.mozilla.org/show_bug.cgi?id=496863","NSS 3.12.6","Firefox 3.6.2","https://jcsi-valid.managedpki.ne.jp/","https://jcsi-expired.managedpki.ne.jp/","https://jcsi-revoke.managedpki.ne.jp/","","https://www.cybertrust.co.jp/","Japan","","https://www.cybertrust.co.jp/jcsi/CPS_JCSIRoot_LatestVer_EN.pdf","https://www.cpacanada.ca/generichandlers/CPACHandler.ashx?attachmentid=239751","https://www.cpacanada.ca/generichandlers/CPACHandler.ashx?attachmentid=239752","","KPMG","WebTrust","2020.05.15","'-----BEGIN CERTIFICATE----- +MIIDbTCCAlWgAwIBAgIBATANBgkqhkiG9w0BAQUFADBYMQswCQYDVQQGEwJKUDEr +MCkGA1UEChMiSmFwYW4gQ2VydGlmaWNhdGlvbiBTZXJ2aWNlcywgSW5jLjEcMBoG +A1UEAxMTU2VjdXJlU2lnbiBSb290Q0ExMTAeFw0wOTA0MDgwNDU2NDdaFw0yOTA0 +MDgwNDU2NDdaMFgxCzAJBgNVBAYTAkpQMSswKQYDVQQKEyJKYXBhbiBDZXJ0aWZp +Y2F0aW9uIFNlcnZpY2VzLCBJbmMuMRwwGgYDVQQDExNTZWN1cmVTaWduIFJvb3RD +QTExMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA/XeqpRyQBTvLTJsz +i1oURaTnkBbR31fSIRCkF/3frNYfp+TbfPfs37gD2pRY/V1yfIw/XwFndBWW4wI8 +h9uuywGOwvNmxoVF9ALGOrVisq/6nL+k5tSAMJjzDbaTj6nU2DbysPyKyiyhFTOV +MdrAG/LuYpmGYz+/3ZMqg6h2uRMft85OQoWPIucuGvKVCbIFtUROd6EgvanyTgp9 +UK31BQ1FT0Zx/Sg+U/sE2C3XZR1KG/rPO7AxmjVuyIsG0wCR8pQIZUyxNAYAeoni +8McDWc/V1uinMrPmmECGxc0nEovMe863ETxiYAcjPitAbpSACW22s293bzUIUPsC +h8U+iQIDAQABo0IwQDAdBgNVHQ4EFgQUW/hNT7KlhtQ60vFjmqC+CfZXt94wDgYD +VR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggEB +AKChOBZmLqdWHyGcBvod7bkixTgm2E5P7KN/ed5GIaGHd48HCJqypMWvDzKYC3xm +KbabfSVSSUOrTC4rbnpwrxYO4wJs+0LmGJ1F2FXI6Dvd5+H0LgscNFxsWEr7jIhQ +X5Ucv+2rIrVls4W6ng+4reV6G4pQOh29Dbx7VFALuUKvVaAYga1lme++5Jy/xIWr +QbJUb9wlze144o4MjQlJ3WN7WmmWAiGovVJZ6X01y8hSyn+B/tlr0/cR7SXf+Of5 +pPpyl4RTDaXQMhhRdlkUbA/r7F+AjHVDg8OFmP9Mni0N5HeDk061lgeLKBObjBmN +QSdJQO7e5iNEOdyhIta6A/I= +-----END CERTIFICATE-----'" +"D-TRUST","D-Trust GmbH","","D-TRUST Root CA 3 2013","0FDDAC","A1A86D04121EB87F027C66F53303C28E5739F943FC84B38AD6AF009035DD9457","416F841381AD182ED1AA90A3C10BD1B0E2F9276B8D9AF8021B006459C70A8EF1","2013.09.20","2028.09.20","RSA 2048 bits","SHA256WithRSA","Email","","","Not EV","https://bugzilla.mozilla.org/show_bug.cgi?id=1166723","NSS 3.30.2","Firefox 54","","","","None","https://www.bundesdruckerei.de/en/Solutions-Products/Secure-digital-identities/PKI-Certificates","Germany, Europe, Global","http://www.d-trust.net/internet/files/D-TRUST_CP.pdf","http://www.d-trust.net/internet/files/D-TRUST_Root_PKI_CPS.pdf","https://www.tuvit.de/fileadmin/Content/TUV_IT/zertifikate/de/AA2019120301_D-TRUST_Root_CA3_V1.0_s.pdf","","","TÜViT - TÜV Informationstechnik GmbH","ETSI EN 319 411","2019.12.03","'-----BEGIN CERTIFICATE----- +MIIEDjCCAvagAwIBAgIDD92sMA0GCSqGSIb3DQEBCwUAMEUxCzAJBgNVBAYTAkRF +MRUwEwYDVQQKDAxELVRydXN0IEdtYkgxHzAdBgNVBAMMFkQtVFJVU1QgUm9vdCBD +QSAzIDIwMTMwHhcNMTMwOTIwMDgyNTUxWhcNMjgwOTIwMDgyNTUxWjBFMQswCQYD +VQQGEwJERTEVMBMGA1UECgwMRC1UcnVzdCBHbWJIMR8wHQYDVQQDDBZELVRSVVNU +IFJvb3QgQ0EgMyAyMDEzMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA +xHtCkoIf7O1UmI4SwMoJ35NuOpNcG+QQd55OaYhs9uFp8vabomGxvQcgdJhl8Ywm +CM2oNcqANtFjbehEeoLDbF7eu+g20sRoNoyfMr2EIuDcwu4QRjltr5M5rofmw7wJ +ySxrZ1vZm3Z1TAvgu8XXvD558l++0ZBX+a72Zl8xv9Ntj6e6SvMjZbu376Ml1wrq +WLbviPr6ebJSWNXwrIyhUXQplapRO5AyA58ccnSQ3j3tYdLl4/1kR+W5t0qp9x+u +loYErC/jpIF3t1oW/9gPP/a3eMykr/pbPBJbqFKJcu+I89VEgYaVI5973bzZNO98 +lDyqwEHC451QGsDkGSL8swIDAQABo4IBBTCCAQEwDwYDVR0TAQH/BAUwAwEB/zAd +BgNVHQ4EFgQUP5DIfccVb/Mkj6nDL0uiDyGyL+cwDgYDVR0PAQH/BAQDAgEGMIG+ +BgNVHR8EgbYwgbMwdKByoHCGbmxkYXA6Ly9kaXJlY3RvcnkuZC10cnVzdC5uZXQv +Q049RC1UUlVTVCUyMFJvb3QlMjBDQSUyMDMlMjAyMDEzLE89RC1UcnVzdCUyMEdt +YkgsQz1ERT9jZXJ0aWZpY2F0ZXJldm9jYXRpb25saXN0MDugOaA3hjVodHRwOi8v +Y3JsLmQtdHJ1c3QubmV0L2NybC9kLXRydXN0X3Jvb3RfY2FfM18yMDEzLmNybDAN +BgkqhkiG9w0BAQsFAAOCAQEADlkOWOR0SCNEzzQhtZwUGq2aS7eziG1cqRdw8Cqf +jXv5e4X6xznoEAiwNStfzwLS05zICx7uBVSuN5MECX1sj8J0vPgclL4xAUAt8yQg +t4RVLFzI9XRKEBmLo8ftNdYJSNMOwLo5qLBGArDbxohZwr78e7Erz35ih1WWzAFv +m2chlTWL+BD8cRu3SzdppjvW7IvuwbDzJcmPkn2h6sPKRL8mpXSSnON065102ctN +h9j8tGlsi6BDB2B4l+nZk3zCRrybN1Kj7Yo8E6l7U0tJmhEFLAtuVqwfLoJs4Gln +tQ5tLdnkwBXxP/oYcuEVbSdbLTAoK59ImmQrme/ydUlfXA== +-----END CERTIFICATE-----'" +"D-TRUST","D-Trust GmbH","","D-TRUST Root Class 3 CA 2 2009","0983F3","49E7A442ACF0EA6287050054B52564B650E4F49E42E348D6AA38E039E957B1C1","1B7B9A04A98606AEE87D5921003A18911B63D304B02B0909BBC3F1D5061D5BD0","2009.11.05","2029.11.05","RSA 2048 bits","SHA256WithRSA","Websites","","","Not EV","https://bugzilla.mozilla.org/show_bug.cgi?id=467891","NSS 3.15","Firefox 23","https://certdemo-ov-valid.ssl.d-trust.net/","https://certdemo-ov-expired.ssl.d-trust.net/","https://certdemo-ov-revoked.ssl.d-trust.net/","","https://www.bundesdruckerei.de/en/Solutions-Products/Secure-digital-identities/PKI-Certificates","Germany, Europe, Global","http://www.d-trust.net/internet/files/D-TRUST_CP.pdf","http://www.d-trust.net/internet/files/D-TRUST_Root_PKI_CPS.pdf","https://www.tuvit.de/fileadmin/Content/TUV_IT/zertifikate/de/AA2019120302_D-TRUST_Root_Class_3_CA_2_2009_V1.0_s.pdf","https://www.tuvit.de/fileadmin/Content/TUV_IT/zertifikate/de/AA2019120302_D-TRUST_Root_Class_3_CA_2_2009_V1.0_s.pdf","","TÜViT - TÜV Informationstechnik GmbH","ETSI EN 319 411","2019.12.03","'-----BEGIN CERTIFICATE----- +MIIEMzCCAxugAwIBAgIDCYPzMA0GCSqGSIb3DQEBCwUAME0xCzAJBgNVBAYTAkRF +MRUwEwYDVQQKDAxELVRydXN0IEdtYkgxJzAlBgNVBAMMHkQtVFJVU1QgUm9vdCBD +bGFzcyAzIENBIDIgMjAwOTAeFw0wOTExMDUwODM1NThaFw0yOTExMDUwODM1NTha +ME0xCzAJBgNVBAYTAkRFMRUwEwYDVQQKDAxELVRydXN0IEdtYkgxJzAlBgNVBAMM +HkQtVFJVU1QgUm9vdCBDbGFzcyAzIENBIDIgMjAwOTCCASIwDQYJKoZIhvcNAQEB +BQADggEPADCCAQoCggEBANOySs96R+91myP6Oi/WUEWJNTrGa9v+2wBoqOADER03 +UAifTUpolDWzU9GUY6cgVq/eUXjsKj3zSEhQPgrfRlWLJ23DEE0NkVJD2IfgXU42 +tSHKXzlABF9bfsyjxiupQB7ZNoTWSPOSHjRGICTBpFGOShrvUD9pXRl/RcPHAY9R +ySPocq60vFYJfxLLHLGvKZAKyVXMD9O0Gu1HNVpK7ZxzBCHQqr0ME7UAyiZsxGsM +lFqVlNpQmvH/pStmMaTJOKDfHR+4CS7zp+hnUquVH+BGPtikw8paxTGA6Eian5Rp +/hnd2HN8gcqW3o7tszIFZYQ05ub9VxC1X3a/L7AQDcUCAwEAAaOCARowggEWMA8G +A1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFP3aFMSfMN4hvR5COfyrYyNJ4PGEMA4G +A1UdDwEB/wQEAwIBBjCB0wYDVR0fBIHLMIHIMIGAoH6gfIZ6bGRhcDovL2RpcmVj +dG9yeS5kLXRydXN0Lm5ldC9DTj1ELVRSVVNUJTIwUm9vdCUyMENsYXNzJTIwMyUy +MENBJTIwMiUyMDIwMDksTz1ELVRydXN0JTIwR21iSCxDPURFP2NlcnRpZmljYXRl +cmV2b2NhdGlvbmxpc3QwQ6BBoD+GPWh0dHA6Ly93d3cuZC10cnVzdC5uZXQvY3Js +L2QtdHJ1c3Rfcm9vdF9jbGFzc18zX2NhXzJfMjAwOS5jcmwwDQYJKoZIhvcNAQEL +BQADggEBAH+X2zDI36ScfSF6gHDOFBJpiBSVYEQBrLLpME+bUMJm2H6NMLVwMeni +acfzcNsgFYbQDfC+rAF1hM5+n02/t2A7nPPKHeJeaNijnZflQGDSNiH+0LS4F9p0 +o3/U37CYAqxva2ssJSRyoWXuJVrl5jLn8t+rSfrzkGkj2wTZ51xY/GXUl77M/C4K +zCUqNQT4YJEVdT1B/yMfGchs64JTBKbkTCJNjYy6zltz7GRUUG3RnFX7acM2w4y8 +PIWmawomDeCTmGCufsYkl4phX5GOZpIJhzbNi5stPvZR1FDUWSi9g/LMKHtThm3Y +Johw1+qRzT65ysCQblrGXnRl11z+o+I= +-----END CERTIFICATE-----'" +"D-TRUST","D-Trust GmbH","","D-TRUST Root Class 3 CA 2 EV 2009","0983F4","EEC5496B988CE98625B934092EEC2908BED0B0F316C2D4730C84EAF1F3D34881","46E31E20F6A411B76056A18A4752A1AB2FC134D48E98F488ED475F40D2ED9474","2009.11.05","2029.11.05","RSA 2048 bits","SHA256WithRSA","Websites","","","1.3.6.1.4.1.4788.2.202.1","https://bugzilla.mozilla.org/show_bug.cgi?id=467891","NSS 3.15","Firefox 23","https://certdemo-ev-valid.ssl.d-trust.net/","https://certdemo-ev-expired.ssl.d-trust.net/","https://certdemo-ev-revoked.ssl.d-trust.net/","","https://www.bundesdruckerei.de/en/Solutions-Products/Secure-digital-identities/PKI-Certificates","Germany, Europe, Global","http://www.d-trust.net/internet/files/D-TRUST_CP.pdf","http://www.d-trust.net/internet/files/D-TRUST_Root_PKI_CPS.pdf","https://www.tuvit.de/fileadmin/Content/TUV_IT/zertifikate/de/AA2019120303_D-TRUST_Root_Class3_CA2_EV_V1.0_s.pdf","https://www.tuvit.de/fileadmin/Content/TUV_IT/zertifikate/de/AA2019120303_D-TRUST_Root_Class3_CA2_EV_V1.0_s.pdf","https://www.tuvit.de/fileadmin/Content/TUV_IT/zertifikate/de/AA2019120303_D-TRUST_Root_Class3_CA2_EV_V1.0_s.pdf","TÜViT - TÜV Informationstechnik GmbH","ETSI EN 319 411","2019.12.03","'-----BEGIN CERTIFICATE----- +MIIEQzCCAyugAwIBAgIDCYP0MA0GCSqGSIb3DQEBCwUAMFAxCzAJBgNVBAYTAkRF +MRUwEwYDVQQKDAxELVRydXN0IEdtYkgxKjAoBgNVBAMMIUQtVFJVU1QgUm9vdCBD +bGFzcyAzIENBIDIgRVYgMjAwOTAeFw0wOTExMDUwODUwNDZaFw0yOTExMDUwODUw +NDZaMFAxCzAJBgNVBAYTAkRFMRUwEwYDVQQKDAxELVRydXN0IEdtYkgxKjAoBgNV +BAMMIUQtVFJVU1QgUm9vdCBDbGFzcyAzIENBIDIgRVYgMjAwOTCCASIwDQYJKoZI +hvcNAQEBBQADggEPADCCAQoCggEBAJnxhDRwui+3MKCOvXwEz75ivJn9gpfSegpn +ljgJ9hBOlSJzmY3aFS3nBfwZcyK3jpgAvDw9rKFs+9Z5JUut8Mxk2og+KbgPCdM0 +3TP1YtHhzRnp7hhPTFiu4h7WDFsVWtg6uMQYZB7jM7K1iXdODL/ZlGsTl28So/6Z +qQTMFexgaDbtCHu39b+T7WYxg4zGcTSHThfqr4uRjRxWQa4iN1438h3Z0S0NL2lR +p75mpoo6Kr3HGrHhFPC+Oh25z1uxav60sUYgovseO3Dvk5h9jHOW8sXvhXCtKSb8 +HgQ+HKDYD8tSg2J87otTlZCpV6LqYQXY+U3EJ/pure3511H3a6UCAwEAAaOCASQw +ggEgMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFNOUikxiEyoZLsyvcop9Ntea +HNxnMA4GA1UdDwEB/wQEAwIBBjCB3QYDVR0fBIHVMIHSMIGHoIGEoIGBhn9sZGFw +Oi8vZGlyZWN0b3J5LmQtdHJ1c3QubmV0L0NOPUQtVFJVU1QlMjBSb290JTIwQ2xh +c3MlMjAzJTIwQ0ElMjAyJTIwRVYlMjAyMDA5LE89RC1UcnVzdCUyMEdtYkgsQz1E +RT9jZXJ0aWZpY2F0ZXJldm9jYXRpb25saXN0MEagRKBChkBodHRwOi8vd3d3LmQt +dHJ1c3QubmV0L2NybC9kLXRydXN0X3Jvb3RfY2xhc3NfM19jYV8yX2V2XzIwMDku +Y3JsMA0GCSqGSIb3DQEBCwUAA4IBAQA07XtaPKSUiO8aEXUHL7P+PPoeUSbrh/Yp +3uDx1MYkCenBz1UbtDDZzhr+BlGmFaQt77JLvyAoJUnRpjZ3NOhk31KxEcdzes05 +nsKtjHEh8lprr988TlWvsoRlFIm5d8sqMb7Po23Pb0iUMkZv53GMoKaEGTcH8gNF +CSuGdXzfX2lXANtu2KZyIktQ1HWYVt+3GP9DQ1CuekR78HlR10M9p9OB0/DJT7na +xpeG0ILD5EJt/rDiZE4OJudANCa1CInXCGNjOCd1HjPqbqjdn5lPdE2BiYBL3ZqX +KVwvvoFBuYz/6n1gBp7N1z3TLqMVvKjmJuVvw9y4AyHqnxbxLFS1 +-----END CERTIFICATE-----'" +"Deutsche Telekom Security GmbH","T-Systems Enterprise Services GmbH","T-Systems Trust Center","T-TeleSec GlobalRoot Class 2","01","91E2F5788D5810EBA7BA58737DE1548A8ECACD014598BC0B143E041B17052552","0F0AFC4D1673EDDDCDB11A28B9E688AD043454DE33930CCF448B0282AD77EDB4","2008.10.01","2033.10.01","RSA 2048 bits","SHA256WithRSA","Websites;Email","","","Not EV","https://bugzilla.mozilla.org/show_bug.cgi?id=892390","NSS 3.16","Firefox 29","https://root-class2.test.telesec.de/","https://root-class2-expired.test.telesec.de/","https://root-class2-revoked.test.telesec.de/","","https://www.telesec.de/","Germany","https://telesec.de/assets/downloads/PKI-Repository/Telekom-Security-PKI-CP_12.00_EN.pdf","https://telesec.de/assets/downloads/PKI-Repository/Telekom-Security_Root-CPS-12.00_EN.pdf","https://www.tuvit.de/fileadmin/Content/TUV_IT/zertifikate/de/AA2020071702_T-TeleSec-GlobalRoot-Class-2_V1.1.pdf","https://www.tuvit.de/fileadmin/Content/TUV_IT/zertifikate/de/AA2020071702_T-TeleSec-GlobalRoot-Class-2_V1.1.pdf","","TÜViT - TÜV Informationstechnik GmbH","ETSI EN 319 411","2020.07.17","'-----BEGIN CERTIFICATE----- +MIIDwzCCAqugAwIBAgIBATANBgkqhkiG9w0BAQsFADCBgjELMAkGA1UEBhMCREUx +KzApBgNVBAoMIlQtU3lzdGVtcyBFbnRlcnByaXNlIFNlcnZpY2VzIEdtYkgxHzAd +BgNVBAsMFlQtU3lzdGVtcyBUcnVzdCBDZW50ZXIxJTAjBgNVBAMMHFQtVGVsZVNl +YyBHbG9iYWxSb290IENsYXNzIDIwHhcNMDgxMDAxMTA0MDE0WhcNMzMxMDAxMjM1 +OTU5WjCBgjELMAkGA1UEBhMCREUxKzApBgNVBAoMIlQtU3lzdGVtcyBFbnRlcnBy +aXNlIFNlcnZpY2VzIEdtYkgxHzAdBgNVBAsMFlQtU3lzdGVtcyBUcnVzdCBDZW50 +ZXIxJTAjBgNVBAMMHFQtVGVsZVNlYyBHbG9iYWxSb290IENsYXNzIDIwggEiMA0G +CSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCqX9obX+hzkeXaXPSi5kfl82hVYAUd +AqSzm1nzHoqvNK38DcLZSBnuaY/JIPwhqgcZ7bBcrGXHX+0CfHt8LRvWurmAwhiC +FoT6ZrAIxlQjgeTNuUk/9k9uN0goOA/FvudocP05l03Sx5iRUKrERLMjfTlH6VJi +1hKTXrcxlkIF+3anHqP1wvzpesVsqXFP6st4vGCvx9702cu+fjOlbpSD8DT6Iavq +jnKgP6TeMFvvhk1qlVtDRKgQFRzlAVfFmPHmBiiRqiDFt1MmUUOyCxGVWOHAD3bZ +wI18gfNycJ5v/hqO2V81xrJvNHy+SE/iWjnX2J14np+GPgNeGYtEotXHAgMBAAGj +QjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBS/ +WSA2AHmgoCJrjNXyYdK4LMuCSjANBgkqhkiG9w0BAQsFAAOCAQEAMQOiYQsfdOhy +NsZt+U2e+iKo4YFWz827n+qrkRk4r6p8FU3ztqONpfSO9kSpp+ghla0+AGIWiPAC +uvxhI+YzmzB6azZie60EI4RYZeLbK4rnJVM3YlNfvNoBYimipidx5joifsFvHZVw +IEoHNN/q/xWA5brXethbdXwFeilHfkCoMRN3zUA7tFFHei4R40cR3p1m0IvVVGb6 +g1XqfMIpiRvpb7PO4gWEyS8+eIVibslfwXhjdFjASBgMmTnrpMwatXlajRWc2BQN +9noHV8cigwUtPJslJj0Ys6lDfMjIq2SPDqO/nBudMNva0Bkuqjzx+zOAduTNrRlP +BSeOE6Fuwg== +-----END CERTIFICATE-----'" +"Deutsche Telekom Security GmbH","T-Systems Enterprise Services GmbH","T-Systems Trust Center","T-TeleSec GlobalRoot Class 3","01","FD73DAD31C644FF1B43BEF0CCDDA96710B9CD9875ECA7E31707AF3E96D522BBD","412D555AA1AFDE0B362954E066CC10DD3EF6B7E27E1DB37BDFBBA49AF4CE3434","2008.10.01","2033.10.01","RSA 2048 bits","SHA256WithRSA","Websites","","","1.3.6.1.4.1.7879.13.24.1","https://bugzilla.mozilla.org/show_bug.cgi?id=669849","NSS 3.14","Firefox 18","https://root-class3.test.telesec.de/","https://root-class3-expired.test.telesec.de/","https://root-class3-revoked.test.telesec.de/","","https://www.telesec.de/","Germany","https://telesec.de/assets/downloads/PKI-Repository/Telekom-Security-PKI-CP_12.00_EN.pdf","https://telesec.de/assets/downloads/PKI-Repository/Telekom-Security_Root-CPS-12.00_EN.pdf","https://www.tuvit.de/fileadmin/Content/TUV_IT/zertifikate/de/AA2020071701_T-TeleSec-GlobalRoot-Class-3_V1.1.pdf","https://www.tuvit.de/fileadmin/Content/TUV_IT/zertifikate/de/AA2020071701_T-TeleSec-GlobalRoot-Class-3_V1.1.pdf","https://www.tuvit.de/fileadmin/Content/TUV_IT/zertifikate/de/AA2020071701_T-TeleSec-GlobalRoot-Class-3_V1.1.pdf","TÜViT - TÜV Informationstechnik GmbH","ETSI EN 319 411","2020.07.17","'-----BEGIN CERTIFICATE----- +MIIDwzCCAqugAwIBAgIBATANBgkqhkiG9w0BAQsFADCBgjELMAkGA1UEBhMCREUx +KzApBgNVBAoMIlQtU3lzdGVtcyBFbnRlcnByaXNlIFNlcnZpY2VzIEdtYkgxHzAd +BgNVBAsMFlQtU3lzdGVtcyBUcnVzdCBDZW50ZXIxJTAjBgNVBAMMHFQtVGVsZVNl +YyBHbG9iYWxSb290IENsYXNzIDMwHhcNMDgxMDAxMTAyOTU2WhcNMzMxMDAxMjM1 +OTU5WjCBgjELMAkGA1UEBhMCREUxKzApBgNVBAoMIlQtU3lzdGVtcyBFbnRlcnBy +aXNlIFNlcnZpY2VzIEdtYkgxHzAdBgNVBAsMFlQtU3lzdGVtcyBUcnVzdCBDZW50 +ZXIxJTAjBgNVBAMMHFQtVGVsZVNlYyBHbG9iYWxSb290IENsYXNzIDMwggEiMA0G +CSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC9dZPwYiJvJK7genasfb3ZJNW4t/zN +8ELg63iIVl6bmlQdTQyK9tPPcPRStdiTBONGhnFBSivwKixVA9ZIw+A5OO3yXDw/ +RLyTPWGrTs0NvvAgJ1gORH8EGoel15YUNpDQSXuhdfsaa3Ox+M6pCSzyU9XDFES4 +hqX2iys52qMzVNn6chr3IhUciJFrf2blw2qAsCTz34ZFiP0Zf3WHHx+xGwpzJFu5 +ZeAsVMhg02YXP+HMVDNzkQI6pn97djmiH5a2OK61yJN0HZ65tOVgnS9W0eDrXltM +EnAMbEQgqxHY9Bn20pxSN+f6tsIxO0rUFJmtxxr1XV/6B7h8DR/Wgx6zAgMBAAGj +QjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBS1 +A/d2O2GCahKqGFPrAyGUv/7OyjANBgkqhkiG9w0BAQsFAAOCAQEAVj3vlNW92nOy +WL6ukK2YJ5f+AbGwUgC4TeQbIXQbfsDuXmkqJa9c1h3a0nnJ85cp4IaH3gRZD/FZ +1GSFS5mvJQQeyUapl96Cshtwn5z2r3Ex3XsFpSzTucpH9sry9uetuUg/vBa3wW30 +6gmv7PO15wWeph6KU1HWk4HMdJP2udqmJQV0eVp+QD6CSyYRMG7hP0HHRwA11fXT +91Q+gT3aSWqas+8QPebrb9HIIkfLzM8BMZLZGOMivgkeGj5asuRrDFR6fUNOuIml +e9eiPZaGzPImNC1qkp2aGtAw4l1OBLBfiyB+d8E9lYLRRpo7PHi4b6HQDWSieB4p +TpPDpFQUWw== +-----END CERTIFICATE-----'" +"Dhimyotis / Certigna","Dhimyotis","","Certigna","00FEDCE3010FC948FF","E3B6A2DB2ED7CE48842F7AC53241C7B71D54144BFB40C11F3F1D0B42F5EEA12D","7FF020518ED3585257B86DE356AB4C0873AAC32AAC1FB74BA3B81BDF00EA593A","2007.06.29","2027.06.29","RSA 2048 bits","SHA1WithRSA","Websites;Email","","","Not EV","https://bugzilla.mozilla.org/show_bug.cgi?id=393166","NSS 3.12.4","Firefox 3.5","https://valid.servicesca-racine.dhimyotis.com","https://expired.servicesca-racine.dhimyotis.com","https://revoked.servicesca-racine.dhimyotis.com","","http://www.certigna.fr/","France, Europe","http://politique.certigna.fr/en/PCcertignaservicesca.pdf","http://politique.certigna.fr/en/DPCcertignaservicesca.pdf","https://lsti-certification.fr/images/23_1377_AT_V10__LSTI_-_Attestation_letter_2020.pdf","https://lsti-certification.fr/images/23_1377_AT_V10__LSTI_-_Attestation_letter_2020.pdf","https://lsti-certification.fr/images/23_1377_AT_V10__LSTI_-_Attestation_letter_2020.pdf","LSTI","ETSI EN 319 411","2019.12.18","'-----BEGIN CERTIFICATE----- +MIIDqDCCApCgAwIBAgIJAP7c4wEPyUj/MA0GCSqGSIb3DQEBBQUAMDQxCzAJBgNV +BAYTAkZSMRIwEAYDVQQKDAlEaGlteW90aXMxETAPBgNVBAMMCENlcnRpZ25hMB4X +DTA3MDYyOTE1MTMwNVoXDTI3MDYyOTE1MTMwNVowNDELMAkGA1UEBhMCRlIxEjAQ +BgNVBAoMCURoaW15b3RpczERMA8GA1UEAwwIQ2VydGlnbmEwggEiMA0GCSqGSIb3 +DQEBAQUAA4IBDwAwggEKAoIBAQDIaPHJ1tazNHUmgh7stL7qXOEm7RFHYeGifBZ4 +QCHkYJ5ayGPhxLGWkv8YbWkj4Sti993iNi+RB7lIzw7sebYs5zRLcAglozyHGxny +gQcPOJAZ0xH+hrTy0V4eHpbNgGzOOzGTtvKg0KmVEn2lmsxryIRWijOp5yIVUxbw +zBfsV1/pogqYCd7jX5xv3EjjhQsVWqa6n6xI4wmy9/Qy3l40vhx4XUJbzg4ij02Q +130yGLMLLGq/jj8UEYkgDncUtT2UCIf3JR7VsmAA7G8qKCVuKj4YYxclPz5EIBb2 +JsglrgVKtOdjLPOMFlN+XPsRGgjBRmKfIrjxwo1p3Po6WAbfAgMBAAGjgbwwgbkw +DwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUGu3+QTmQtCRZvgHyUtVF9lo53BEw +ZAYDVR0jBF0wW4AUGu3+QTmQtCRZvgHyUtVF9lo53BGhOKQ2MDQxCzAJBgNVBAYT +AkZSMRIwEAYDVQQKDAlEaGlteW90aXMxETAPBgNVBAMMCENlcnRpZ25hggkA/tzj +AQ/JSP8wDgYDVR0PAQH/BAQDAgEGMBEGCWCGSAGG+EIBAQQEAwIABzANBgkqhkiG +9w0BAQUFAAOCAQEAhQMeknH2Qq/ho2Ge6/PAD/Kl1NqV5ta+aDY9fm4fTIrv0Q8h +bV6lUmPOEvjvKtpv6zf+EwLHyzs+ImvaYS5/1HI93TDhHkxAGYwP15zRgzB7mFnc +fca5DClMoTOi62c6ZYTTluLtdkVwj7Ur3vkj1kluPBS1xp81HlDQwY9qcEQCYsuu +HWhBp6pX6FOqB9IG9tUUBguRA3UsbHK1YZWaDYu5Def131TN3ubY1gkIl2PlwS6w +t0QmwCbAr1UwnjvVNioZBPRcHv/PLLf/0P2HQBHVESO7SMAhqaQoLf0V+LBOK/Qw +WyH8EZE0vkHve52Xdf+XlcCWWC/qu0bXu+TZLg== +-----END CERTIFICATE-----'" +"Dhimyotis / Certigna","Dhimyotis","0002 48146308100036","Certigna Root CA","00CAE91B89F155030DA3E6416DC4E3A6E1","D48D3D23EEDB50A459E55197601C27774B9D7B18C94D5A059511A10250B93168","4D9ED852A75AC7B92823B4745C46287FF52AE2E9F15F145FF5B7F9352C2FB23A","2013.10.01","2033.10.01","RSA 4096 bits","SHA256WithRSA","Websites;Email","","","Not EV","https://bugzilla.mozilla.org/show_bug.cgi?id=1265683","NSS 3.41","Firefox 65","https://valid.servicesca.dhimyotis.com","https://expired.servicesca.dhimyotis.com","https://revoked.servicesca.dhimyotis.com","N/A","http://www.certigna.fr/","France, Europe","http://politique.certigna.fr/en/PCcertignaservicesca.pdf","http://politique.certigna.fr/en/DPCcertignaservicesca.pdf","https://lsti-certification.fr/images/23_1377_AT_V10__LSTI_-_Attestation_letter_2020.pdf","https://lsti-certification.fr/images/23_1377_AT_V10__LSTI_-_Attestation_letter_2020.pdf","https://lsti-certification.fr/images/23_1377_AT_V10__LSTI_-_Attestation_letter_2020.pdf","LSTI","ETSI EN 319 411","2019.12.18","'-----BEGIN CERTIFICATE----- +MIIGWzCCBEOgAwIBAgIRAMrpG4nxVQMNo+ZBbcTjpuEwDQYJKoZIhvcNAQELBQAw +WjELMAkGA1UEBhMCRlIxEjAQBgNVBAoMCURoaW15b3RpczEcMBoGA1UECwwTMDAw +MiA0ODE0NjMwODEwMDAzNjEZMBcGA1UEAwwQQ2VydGlnbmEgUm9vdCBDQTAeFw0x +MzEwMDEwODMyMjdaFw0zMzEwMDEwODMyMjdaMFoxCzAJBgNVBAYTAkZSMRIwEAYD +VQQKDAlEaGlteW90aXMxHDAaBgNVBAsMEzAwMDIgNDgxNDYzMDgxMDAwMzYxGTAX +BgNVBAMMEENlcnRpZ25hIFJvb3QgQ0EwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAw +ggIKAoICAQDNGDllGlmx6mQWDoyUJJV8g9PFOSbcDO8WV43X2KyjQn+Cyu3NW9sO +ty3tRQgXstmzy9YXUnIo245Onoq2C/mehJpNdt4iKVzSs9IGPjA5qXSjklYcoW9M +CiBtnyN6tMbaLOQdLNyzKNAT8kxOAkmhVECe5uUFoC2EyP+YbNDrihqECB63aCPu +I9Vwzm1RaRDuoXrC0SIxwoKF0vJVdlB8JXrJhFwLrN1CTivngqIkicuQstDuI7pm +TLtipPlTWmR7fJj6o0ieD5Wupxj0auwuA0Wv8HT4Ks16XdG+RCYyKfHx9WzMfgIh +C59vpD++nVPiz32pLHxYGpfhPTc3GGYo0kDFUYqMwy3OU4gkWGQwFsWq4NYKpkDf +ePb1BHxpE4S80dGnBs8B92jAqFe7OmGtBIyT46388NtEbVncSVmurJqZNjBBe3Yz +IoejwpKGbvlw7q6Hh5UbxHq9MfPU0uWZ/75I7HX1eBYdpnDBfzwboZL7z8g81sWT +Co/1VTp2lc5ZmIoJlXcymoO6LAQ6l73UL77XbJuiyn1tJslV1c/DeVIICZkHJC1k +JWumIWmbat10TWuXekG9qxf5kBdIjzb5LdXF2+6qhUVB+s06RbFo5jZMm5BX7CO5 +hwjCxAnxl4YqKE3idMDaxIzb3+KhF1nOJFl0Mdp//TBt2dzhauH8XwIDAQABo4IB +GjCCARYwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYE +FBiHVuBud+4kNTxOc5of1uHieX4rMB8GA1UdIwQYMBaAFBiHVuBud+4kNTxOc5of +1uHieX4rMEQGA1UdIAQ9MDswOQYEVR0gADAxMC8GCCsGAQUFBwIBFiNodHRwczov +L3d3d3cuY2VydGlnbmEuZnIvYXV0b3JpdGVzLzBtBgNVHR8EZjBkMC+gLaArhilo +dHRwOi8vY3JsLmNlcnRpZ25hLmZyL2NlcnRpZ25hcm9vdGNhLmNybDAxoC+gLYYr +aHR0cDovL2NybC5kaGlteW90aXMuY29tL2NlcnRpZ25hcm9vdGNhLmNybDANBgkq +hkiG9w0BAQsFAAOCAgEAlLieT/DjlQgi581oQfccVdV8AOItOoldaDgvUSILSo3L +6btdPrtcPbEo/uRTVRPPoZAbAh1fZkYJMyjhDSSXcNMQH+pkV5a7XdrnxIxPTGRG +HVyH41neQtGbqH6mid2PHMkwgu07nM3A6RngatgCdTer9zQoKJHyBApPNeNgJgH6 +0BGM+RFq7q89w1DTj18zeTyGqHNFkIwgtnJzFyO+B2XleJINugHA64wcZr+shncB +lA2c5uk5jR+mUYyZDDl34bSb+hxnV29qao6pK0xXeXpXIs/NX2NGjVxZOob4Mkdi +o2cNGJHc+6Zr9UhhcyNZjgKnvETq9Emd8VRY+WCv2hikLyhF3HqgiIZd8zvn/yk1 +gPxkQ5Tm4xxvvq0OKmOZK8l+hfZx6AYDlf7ej0gcWtSS6Cvu5zHbugRqh5jnxV/v +faci9wHYTfmJ0A6aBVmknpjZbyvKcL5kwlWj9Omvw5Ip3IgWJJk8jSaYtlu3zM63 +Nwf9JtmYhST/WSMDmu2dnajkXjjO11INb9I/bbEFa0nOipFGc/T2L/Coc3cOZayh +jWZSaX5LaAzHHjcng6WMxwLkFM1JAbBzs/3GkDpv0mztO+7skb6iQ12LAEpmJURw +3kAP+HwV96LOPNdeE4yBFxgX0b3xdxA61GU5wSesVywlVP+i2k+KYTlerj1KjL0= +-----END CERTIFICATE-----'" +"DigiCert","Baltimore","CyberTrust","Baltimore CyberTrust Root","020000B9","16AF57A9F676B0AB126095AA5EBADEF22AB31119D644AC95CD4B93DBF3F26AEB","973A321CE7AB6CD2A8681EF8BD4F17968EE8390840C2AF7B529545C5B2A28D7D","2000.05.12","2025.05.12","RSA 2048 bits","SHA1WithRSA","Websites;Email","","","Not EV","https://bugzilla.mozilla.org/show_bug.cgi?id=430698","","Firefox 1","https://baltimore-cybertrust-root.chain-demos.digicert.com/","https://baltimore-cybertrust-root-expired.chain-demos.digicert.com/","https://baltimore-cybertrust-root-revoked.chain-demos.digicert.com/","","http://www.digicert.com/","USA, Global","https://www.digicert.com/wp-content/uploads/2019/11/DigiCert_CP_v420.pdf","https://www.digicert.com/wp-content/uploads/2019/11/DigiCert_CPS_v420.pdf","https://bug1458024.bmoattachments.org/attachment.cgi?id=9123443","https://bug1458024.bmoattachments.org/attachment.cgi?id=9123442","https://bug1458024.bmoattachments.org/attachment.cgi?id=9123445","BDO International Limited","WebTrust","2020.01.29","'-----BEGIN CERTIFICATE----- +MIIDdzCCAl+gAwIBAgIEAgAAuTANBgkqhkiG9w0BAQUFADBaMQswCQYDVQQGEwJJ +RTESMBAGA1UEChMJQmFsdGltb3JlMRMwEQYDVQQLEwpDeWJlclRydXN0MSIwIAYD +VQQDExlCYWx0aW1vcmUgQ3liZXJUcnVzdCBSb290MB4XDTAwMDUxMjE4NDYwMFoX +DTI1MDUxMjIzNTkwMFowWjELMAkGA1UEBhMCSUUxEjAQBgNVBAoTCUJhbHRpbW9y +ZTETMBEGA1UECxMKQ3liZXJUcnVzdDEiMCAGA1UEAxMZQmFsdGltb3JlIEN5YmVy +VHJ1c3QgUm9vdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKMEuyKr +mD1X6CZymrV51Cni4eiVgLGw41uOKymaZN+hXe2wCQVt2yguzmKiYv60iNoS6zjr +IZ3AQSsBUnuId9Mcj8e6uYi1agnnc+gRQKfRzMpijS3ljwumUNKoUMMo6vWrJYeK +mpYcqWe4PwzV9/lSEy/CG9VwcPCPwBLKBsua4dnKM3p31vjsufFoREJIE9LAwqSu +XmD+tqYF/LTdB1kC1FkYmGP1pWPgkAx9XbIGevOF6uvUA65ehD5f/xXtabz5OTZy +dc93Uk3zyZAsuT3lySNTPx8kmCFcB5kpvcY67Oduhjprl3RjM71oGDHweI12v/ye +jl0qhqdNkNwnGjkCAwEAAaNFMEMwHQYDVR0OBBYEFOWdWTCCR1jMrPoIVDaGezq1 +BE3wMBIGA1UdEwEB/wQIMAYBAf8CAQMwDgYDVR0PAQH/BAQDAgEGMA0GCSqGSIb3 +DQEBBQUAA4IBAQCFDF2O5G9RaEIFoN27TyclhAO992T9Ldcw46QQF+vaKSm2eT92 +9hkTI7gQCvlYpNRhcL0EYWoSihfVCr3FvDB81ukMJY2GQE/szKN+OMY3EU/t3Wgx +jkzSswF07r51XgdIGn9w/xZchMB5hbgF/X++ZRGjD8ACtPhSNzkE1akxehi/oCr0 +Epn3o0WC4zxe9Z2etciefC7IpJ5OCBRLbf1wbWsaY71k5h+3zvDyny67G7fyUIhz +ksLi4xaNmjICq44Y3ekQEe5+NauQrz4wlHrQMz2nZQ/1/I6eYs9HRCwBXbsdtTLS +R9I4LtD+gdwyah617jzV/OeBHRnDJELqYzmp +-----END CERTIFICATE-----'" +"DigiCert","Cybertrust, Inc","","Cybertrust Global Root","0400000000010F85AA2D48","960ADF0063E96356750C2965DD0A0867DA0B9CBD6E77714AEAFB2349AB393DA3","3809F4A8D037A3475CAB0213DE94551E1B9879FADB9D42845076B81C372D4E82","2006.12.15","2021.12.15","RSA 2048 bits","SHA1WithRSA","Websites","","","1.3.6.1.4.1.6334.1.100.1","https://bugzilla.mozilla.org/show_bug.cgi?id=430700","NSS 3.12.4","Firefox 3.5","https://cybertrust-global-root.chain-demos.ctjssl.com","https://cybertrust-global-root-expired.chain-demos.ctjssl.com","https://cybertrust-global-root-revoked.chain-demos.ctjssl.com","","http://www.digicert.com/","USA, Global","https://www.digicert.com/wp-content/uploads/2019/11/DigiCert_CP_v420.pdf","https://www.digicert.com/wp-content/uploads/2019/11/DigiCert_CPS_v420.pdf","https://bug1458024.bmoattachments.org/attachment.cgi?id=9123443","https://bug1458024.bmoattachments.org/attachment.cgi?id=9123442","https://bug1458024.bmoattachments.org/attachment.cgi?id=9123445","BDO International Limited","WebTrust","2020.01.29","'-----BEGIN CERTIFICATE----- +MIIDoTCCAomgAwIBAgILBAAAAAABD4WqLUgwDQYJKoZIhvcNAQEFBQAwOzEYMBYG +A1UEChMPQ3liZXJ0cnVzdCwgSW5jMR8wHQYDVQQDExZDeWJlcnRydXN0IEdsb2Jh +bCBSb290MB4XDTA2MTIxNTA4MDAwMFoXDTIxMTIxNTA4MDAwMFowOzEYMBYGA1UE +ChMPQ3liZXJ0cnVzdCwgSW5jMR8wHQYDVQQDExZDeWJlcnRydXN0IEdsb2JhbCBS +b290MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA+Mi8vRRQZhP/8NN5 +7CPytxrHjoXxEnOmGaoQ25yiZXRadz5RfVb23CO21O1fWLE3TdVJDm71aofW0ozS +J8bi/zafmGWgE07GKmSb1ZASzxQG9Dvj1Ci+6A74q05IlG2OlTEQXO2iLb3VOm2y +HLtgwEZLAfVJrn5GitB0jaEMAs7u/OePuGtm839EAL9mJRQr3RAwHQeWP032a7iP +t3sMpTjr3kfb1V05/Iin89cqdPHoWqI7n1C6poxFNcJQZZXcY4Lv3b93TZxiyWNz +FtApD0mpSPCzqrdsxacwOUBdrsTiXSZT8M4cIwhhqJQZugRiQOwfOHB3EgZxpzAY +XSUnpQIDAQABo4GlMIGiMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/ +MB0GA1UdDgQWBBS2CHsNesysIEyGVjJez6tuhS1wVzA/BgNVHR8EODA2MDSgMqAw +hi5odHRwOi8vd3d3Mi5wdWJsaWMtdHJ1c3QuY29tL2NybC9jdC9jdHJvb3QuY3Js +MB8GA1UdIwQYMBaAFLYIew16zKwgTIZWMl7Pq26FLXBXMA0GCSqGSIb3DQEBBQUA +A4IBAQBW7wojoFROlZfJ+InaRcHUowAl9B8Tq7ejhVhpwjCt2BWKLePJzYFa+HMj +Wqd8BfP9IjsO0QbE2zZMcwSO5bAi5MXzLqXZI+O4Tkogp24CJJ8iYGd7ix1yCcUx +XOl5n4BHPa2hCwcUPUf/A2kaDAtE52Mlp3+yybh2hO0j9n0Hq0V+09+zv+mKts2o +omcrUtW3ZfA5TGOgkXmTUg9U3YO7n9GPp1Nzw8v/MOx8BLjYRB+TX3EJIrduPuoc +A06dGiBh+4E37F78CkWr1+cXVdCg6mCbpvbjjFspwgZgFJ0tl0ypkxWdYcQBX0jW +WL1WMRJOEcgh4LMRkWXbtKaIOM5V +-----END CERTIFICATE-----'" +"DigiCert","DigiCert Inc","www.digicert.com","DigiCert Assured ID Root CA","0CE7E0E517D846FE8FE560FC1BF03039","3E9099B5015E8F486C00BCEA9D111EE721FABA355A89BCF1DF69561E3DC6325C","8B09F71254C1FDE209B244249740AA7F5E2424608AAF726C6BB163B623052E3E","2006.11.10","2031.11.10","RSA 2048 bits","SHA1WithRSA","Websites;Email","","","Not EV","https://bugzilla.mozilla.org/show_bug.cgi?id=364568","NSS 3.11.8","Firefox 2","https://assured-id-root-ca.chain-demos.digicert.com","https://assured-id-root-ca-expired.chain-demos.digicert.com/","https://assured-id-root-ca-revoked.chain-demos.digicert.com/","","http://www.digicert.com/","USA, Global","https://www.digicert.com/wp-content/uploads/2019/11/DigiCert_CP_v420.pdf","https://www.digicert.com/wp-content/uploads/2019/11/DigiCert_CPS_v420.pdf","https://bug1458024.bmoattachments.org/attachment.cgi?id=9123443","https://bug1458024.bmoattachments.org/attachment.cgi?id=9123442","https://bug1458024.bmoattachments.org/attachment.cgi?id=9123445","BDO International Limited","WebTrust","2020.01.29","'-----BEGIN CERTIFICATE----- +MIIDtzCCAp+gAwIBAgIQDOfg5RfYRv6P5WD8G/AwOTANBgkqhkiG9w0BAQUFADBl +MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 +d3cuZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJv +b3QgQ0EwHhcNMDYxMTEwMDAwMDAwWhcNMzExMTEwMDAwMDAwWjBlMQswCQYDVQQG +EwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNl +cnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3QgQ0EwggEi +MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCtDhXO5EOAXLGH87dg+XESpa7c +JpSIqvTO9SA5KFhgDPiA2qkVlTJhPLWxKISKityfCgyDF3qPkKyK53lTXDGEKvYP +mDI2dsze3Tyoou9q+yHyUmHfnyDXH+Kx2f4YZNISW1/5WBg1vEfNoTb5a3/UsDg+ +wRvDjDPZ2C8Y/igPs6eD1sNuRMBhNZYW/lmci3Zt1/GiSw0r/wty2p5g0I6QNcZ4 +VYcgoc/lbQrISXwxmDNsIumH0DJaoroTghHtORedmTpyoeb6pNnVFzF1roV9Iq4/ +AUaG9ih5yLHa5FcXxH4cDrC0kqZWs72yl+2qp/C3xag/lRbQ/6GW6whfGHdPAgMB +AAGjYzBhMA4GA1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQW +BBRF66Kv9JLLgjEtUYunpyGd823IDzAfBgNVHSMEGDAWgBRF66Kv9JLLgjEtUYun +pyGd823IDzANBgkqhkiG9w0BAQUFAAOCAQEAog683+Lt8ONyc3pklL/3cmbYMuRC +dWKuh+vy1dneVrOfzM4UKLkNl2BcEkxY5NM9g0lFWJc1aRqoR+pWxnmrEthngYTf +fwk8lOa4JiwgvT2zKIn3X/8i4peEH+ll74fg38FnSbNd67IJKusm7Xi+fT8r87cm +NW1fiQG2SVufAQWbqz0lwcy2f8Lxb4bG+mRo64EtlOtCt/qMHt1i8b5QZ7dsvfPx +H2sMNgcWfzd8qVttevESRmCD1ycEvkvOl77DZypoEd+A5wwzZr8TDRRu838fYxAe ++o0bJW1sj6W3YQGx0qMmoRBxna3iw/nDmVG3KwcIzi7mULKn+gpFL6Lw8g== +-----END CERTIFICATE-----'" +"DigiCert","DigiCert Inc","www.digicert.com","DigiCert Assured ID Root G2","0B931C3AD63967EA6723BFC3AF9AF44B","7D05EBB682339F8C9451EE094EEBFEFA7953A114EDB2F44949452FAB7D2FC185","9995A1B0AD7AC1C1D9B2905939B8F4D6295762D71D5349B82F4AAF520F4CB3E5","2013.08.01","2038.01.15","RSA 2048 bits","SHA256WithRSA","Websites;Email","","","2.16.840.1.114412.2.1","https://bugzilla.mozilla.org/show_bug.cgi?id=908827","NSS 3.16.3","Firefox 32","https://assured-id-root-g2.chain-demos.digicert.com","https://assured-id-root-g2-expired.chain-demos.digicert.com/","https://assured-id-root-g2-revoked.chain-demos.digicert.com/","","http://www.digicert.com/","USA, Global","https://www.digicert.com/wp-content/uploads/2019/11/DigiCert_CP_v420.pdf","https://www.digicert.com/wp-content/uploads/2019/11/DigiCert_CPS_v420.pdf","https://bug1458024.bmoattachments.org/attachment.cgi?id=9123443","https://bug1458024.bmoattachments.org/attachment.cgi?id=9123442","https://bug1458024.bmoattachments.org/attachment.cgi?id=9123445","BDO International Limited","WebTrust","2020.01.29","'-----BEGIN CERTIFICATE----- +MIIDljCCAn6gAwIBAgIQC5McOtY5Z+pnI7/Dr5r0SzANBgkqhkiG9w0BAQsFADBl +MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 +d3cuZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJv +b3QgRzIwHhcNMTMwODAxMTIwMDAwWhcNMzgwMTE1MTIwMDAwWjBlMQswCQYDVQQG +EwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNl +cnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3QgRzIwggEi +MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDZ5ygvUj82ckmIkzTz+GoeMVSA +n61UQbVH35ao1K+ALbkKz3X9iaV9JPrjIgwrvJUXCzO/GU1BBpAAvQxNEP4Htecc +biJVMWWXvdMX0h5i89vqbFCMP4QMls+3ywPgym2hFEwbid3tALBSfK+RbLE4E9Hp +EgjAALAcKxHad3A2m67OeYfcgnDmCXRwVWmvo2ifv922ebPynXApVfSr/5Vh88lA +bx3RvpO704gqu52/clpWcTs/1PPRCv4o76Pu2ZmvA9OPYLfykqGxvYmJHzDNw6Yu +YjOuFgJ3RFrngQo8p0Quebg/BLxcoIfhG69Rjs3sLPr4/m3wOnyqi+RnlTGNAgMB +AAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgGGMB0GA1UdDgQW +BBTOw0q5mVXyuNtgv6l+vVa1lzan1jANBgkqhkiG9w0BAQsFAAOCAQEAyqVVjOPI +QW5pJ6d1Ee88hjZv0p3GeDgdaZaikmkuOGybfQTUiaWxMTeKySHMq2zNixya1r9I +0jJmwYrA8y8678Dj1JGG0VDjA9tzd29KOVPt3ibHtX2vK0LRdWLjSisCx1BL4Gni +lmwORGYQRI+tBev4eaymG+g3NJ1TyWGqolKvSnAWhsI6yLETcDbYz+70CjTVW0z9 +B5yiutkBclzzTcHdDrEcDcRjvq30FPuJ7KJBDkzMyFdA0G4Dqs0MjomZmWzwPDCv +ON9vvKO+KSAnq3T/EyJ43pdSVR6DtVQgA+6uwE9W3jfMw3+qBCe703e4YtsXfJwo +IhNzbM8m9Yop5w== +-----END CERTIFICATE-----'" +"DigiCert","DigiCert Inc","www.digicert.com","DigiCert Assured ID Root G3","0BA15AFA1DDFA0B54944AFCD24A06CEC","7E37CB8B4C47090CAB36551BA6F45DB840680FBA166A952DB100717F43053FC2","D8217508C8209158A4F8A94E9BF0C22F92D8D92A9A692868AF7E949293754794","2013.08.01","2038.01.15","EC secp384r1","ecdsaWithSHA384","Websites;Email","","","2.16.840.1.114412.2.1","https://bugzilla.mozilla.org/show_bug.cgi?id=908827","NSS 3.16.3","Firefox 32","https://assured-id-root-g3.chain-demos.digicert.com","https://assured-id-root-g3-expired.chain-demos.digicert.com/","https://assured-id-root-g3-revoked.chain-demos.digicert.com/","","http://www.digicert.com/","USA, Global","https://www.digicert.com/wp-content/uploads/2019/11/DigiCert_CP_v420.pdf","https://www.digicert.com/wp-content/uploads/2019/11/DigiCert_CPS_v420.pdf","https://bug1458024.bmoattachments.org/attachment.cgi?id=9123443","https://bug1458024.bmoattachments.org/attachment.cgi?id=9123442","https://bug1458024.bmoattachments.org/attachment.cgi?id=9123445","BDO International Limited","WebTrust","2020.01.29","'-----BEGIN CERTIFICATE----- +MIICRjCCAc2gAwIBAgIQC6Fa+h3foLVJRK/NJKBs7DAKBggqhkjOPQQDAzBlMQsw +CQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cu +ZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3Qg +RzMwHhcNMTMwODAxMTIwMDAwWhcNMzgwMTE1MTIwMDAwWjBlMQswCQYDVQQGEwJV +UzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQu +Y29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3QgRzMwdjAQBgcq +hkjOPQIBBgUrgQQAIgNiAAQZ57ysRGXtzbg/WPuNsVepRC0FFfLvC/8QdJ+1YlJf +Zn4f5dwbRXkLzMZTCp2NXQLZqVneAlr2lSoOjThKiknGvMYDOAdfVdp+CW7if17Q +RSAPWXYQ1qAk8C3eNvJsKTmjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/ +BAQDAgGGMB0GA1UdDgQWBBTL0L2p4ZgFUaFNN6KDec6NHSrkhDAKBggqhkjOPQQD +AwNnADBkAjAlpIFFAmsSS3V0T8gj43DydXLefInwz5FyYZ5eEJJZVrmDxxDnOOlY +JjZ91eQ0hjkCMHw2U/Aw5WJjOpnitqM7mzT6HtoQknFekROn3aRukswy1vUhZscv +6pZjamVFkpUBtA== +-----END CERTIFICATE-----'" +"DigiCert","DigiCert Inc","www.digicert.com","DigiCert Global Root CA","083BE056904246B1A1756AC95991C74A","4348A0E9444C78CB265E058D5E8944B4D84F9662BD26DB257F8934A443C70161","E3A02DD6922883C21CC810B412523E4DA4A26431F9204A090201312120312851","2006.11.10","2031.11.10","RSA 2048 bits","SHA1WithRSA","Websites;Email","","","Not EV","https://bugzilla.mozilla.org/show_bug.cgi?id=364568","NSS 3.11.8","Firefox 2","https://global-root-ca.chain-demos.digicert.com","https://global-root-ca-expired.chain-demos.digicert.com","https://global-root-ca-revoked.chain-demos.digicert.com","","http://www.digicert.com/","USA, Global","https://www.digicert.com/wp-content/uploads/2020/02/DigiCert-Certificate-Policy-Version-5.0.pdf","https://www.digicert.com/wp-content/uploads/2020/02/DigiCert-CPS-Version-5.0.pdf","https://bugzilla.mozilla.org/attachment.cgi?id=9131333","https://bugzilla.mozilla.org/attachment.cgi?id=9131332","https://bugzilla.mozilla.org/attachment.cgi?id=9131334","Scott S. Perry CPA, PLLC","WebTrust","2020.02.29","'-----BEGIN CERTIFICATE----- +MIIDrzCCApegAwIBAgIQCDvgVpBCRrGhdWrJWZHHSjANBgkqhkiG9w0BAQUFADBh +MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 +d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBD +QTAeFw0wNjExMTAwMDAwMDBaFw0zMTExMTAwMDAwMDBaMGExCzAJBgNVBAYTAlVT +MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5j +b20xIDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IENBMIIBIjANBgkqhkiG +9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4jvhEXLeqKTTo1eqUKKPC3eQyaKl7hLOllsB +CSDMAZOnTjC3U/dDxGkAV53ijSLdhwZAAIEJzs4bg7/fzTtxRuLWZscFs3YnFo97 +nh6Vfe63SKMI2tavegw5BmV/Sl0fvBf4q77uKNd0f3p4mVmFaG5cIzJLv07A6Fpt +43C/dxC//AH2hdmoRBBYMql1GNXRor5H4idq9Joz+EkIYIvUX7Q6hL+hqkpMfT7P +T19sdl6gSzeRntwi5m3OFBqOasv+zbMUZBfHWymeMr/y7vrTC0LUq7dBMtoM1O/4 +gdW7jVg/tRvoSSiicNoxBN33shbyTApOB6jtSj1etX+jkMOvJwIDAQABo2MwYTAO +BgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUA95QNVbR +TLtm8KPiGxvDl7I90VUwHwYDVR0jBBgwFoAUA95QNVbRTLtm8KPiGxvDl7I90VUw +DQYJKoZIhvcNAQEFBQADggEBAMucN6pIExIK+t1EnE9SsPTfrgT1eXkIoyQY/Esr +hMAtudXH/vTBH1jLuG2cenTnmCmrEbXjcKChzUyImZOMkXDiqw8cvpOp/2PV5Adg +06O/nVsJ8dWO41P0jmP6P6fbtGbfYmbW0W5BjfIttep3Sp+dWOIrWcBAI+0tKIJF +PnlUkiaY4IBIqDfv8NZ5YBberOgOzW6sRBc4L0na4UU+Krk2U886UAb3LujEV0ls +YSEY1QSteDwsOoBrp+uvFRTp2InBuThs4pFsiv9kuXclVzDAGySj4dzp30d8tbQk +CAUw7C29C79Fv1C5qfPrmAESrciIxpg0X40KPMbp1ZWVbd4= +-----END CERTIFICATE-----'" +"DigiCert","DigiCert Inc","www.digicert.com","DigiCert Global Root G2","033AF1E6A711A9A0BB2864B11D09FAE5","CB3CCBB76031E5E0138F8DD39A23F9DE47FFC35E43C1144CEA27D46A5AB1CB5F","59FFC36A1E03C7E86DD444D1E90558E9F547F0D7EC2F036B92F81E208E14C32C","2013.08.01","2038.01.15","RSA 2048 bits","SHA256WithRSA","Websites;Email","","","2.16.840.1.114412.2.1","https://bugzilla.mozilla.org/show_bug.cgi?id=908827","NSS 3.16.3","Firefox 32","https://global-root-g2.chain-demos.digicert.com","https://global-root-g2-expired.chain-demos.digicert.com","https://global-root-g2-revoked.chain-demos.digicert.com","","http://www.digicert.com/","USA, Global","https://www.digicert.com/wp-content/uploads/2020/02/DigiCert-Certificate-Policy-Version-5.0.pdf","https://www.digicert.com/wp-content/uploads/2020/02/DigiCert-CPS-Version-5.0.pdf","https://bugzilla.mozilla.org/attachment.cgi?id=9131333","https://bugzilla.mozilla.org/attachment.cgi?id=9131332","https://bugzilla.mozilla.org/attachment.cgi?id=9131334","Scott S. Perry CPA, PLLC","WebTrust","2020.02.29","'-----BEGIN CERTIFICATE----- +MIIDjjCCAnagAwIBAgIQAzrx5qcRqaC7KGSxHQn65TANBgkqhkiG9w0BAQsFADBh +MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 +d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBH +MjAeFw0xMzA4MDExMjAwMDBaFw0zODAxMTUxMjAwMDBaMGExCzAJBgNVBAYTAlVT +MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5j +b20xIDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IEcyMIIBIjANBgkqhkiG +9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuzfNNNx7a8myaJCtSnX/RrohCgiN9RlUyfuI +2/Ou8jqJkTx65qsGGmvPrC3oXgkkRLpimn7Wo6h+4FR1IAWsULecYxpsMNzaHxmx +1x7e/dfgy5SDN67sH0NO3Xss0r0upS/kqbitOtSZpLYl6ZtrAGCSYP9PIUkY92eQ +q2EGnI/yuum06ZIya7XzV+hdG82MHauVBJVJ8zUtluNJbd134/tJS7SsVQepj5Wz +tCO7TG1F8PapspUwtP1MVYwnSlcUfIKdzXOS0xZKBgyMUNGPHgm+F6HmIcr9g+UQ +vIOlCsRnKPZzFBQ9RnbDhxSJITRNrw9FDKZJobq7nMWxM4MphQIDAQABo0IwQDAP +BgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBhjAdBgNVHQ4EFgQUTiJUIBiV +5uNu5g/6+rkS7QYXjzkwDQYJKoZIhvcNAQELBQADggEBAGBnKJRvDkhj6zHd6mcY +1Yl9PMWLSn/pvtsrF9+wX3N3KjITOYFnQoQj8kVnNeyIv/iPsGEMNKSuIEyExtv4 +NeF22d+mQrvHRAiGfzZ0JFrabA0UWTW98kndth/Jsw1HKj2ZL7tcu7XUIOGZX1NG +Fdtom/DzMNU+MeKNhJ7jitralj41E6Vf8PlwUHBHQRFXGU7Aj64GxJUTFy8bJZ91 +8rGOmaFvE7FBcf6IKshPECBV1/MUReXgRPTqh5Uykw7+U0b6LJ3/iyK5S9kJRaTe +pLiaWN0bfVKfjllDiIGknibVb63dDcY3fe0Dkhvld1927jyNxF1WW6LZZm6zNTfl +MrY= +-----END CERTIFICATE-----'" +"DigiCert","DigiCert Inc","www.digicert.com","DigiCert Global Root G3","055556BCF25EA43535C3A40FD5AB4572","31AD6648F8104138C738F39EA4320133393E3A18CC02296EF97C2AC9EF6731D0","F0F8ADBB0A616D89538FFE80B1A59B2DDA5ED615CDA1001A2A1B9E1738066E33","2013.08.01","2038.01.15","EC secp384r1","ecdsaWithSHA384","Websites;Email","","","2.16.840.1.114412.2.1","https://bugzilla.mozilla.org/show_bug.cgi?id=908827","NSS 3.16.3","Firefox 32","https://global-root-g3.chain-demos.digicert.com","https://global-root-g3-expired.chain-demos.digicert.com","https://global-root-g3-revoked.chain-demos.digicert.com","","http://www.digicert.com/","USA, Global","https://www.digicert.com/wp-content/uploads/2020/02/DigiCert-Certificate-Policy-Version-5.0.pdf","https://www.digicert.com/wp-content/uploads/2020/02/DigiCert-CPS-Version-5.0.pdf","https://bugzilla.mozilla.org/attachment.cgi?id=9131333","https://bugzilla.mozilla.org/attachment.cgi?id=9131332","https://bugzilla.mozilla.org/attachment.cgi?id=9131334","Scott S. Perry CPA, PLLC","WebTrust","2020.02.29","'-----BEGIN CERTIFICATE----- +MIICPzCCAcWgAwIBAgIQBVVWvPJepDU1w6QP1atFcjAKBggqhkjOPQQDAzBhMQsw +CQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cu +ZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBHMzAe +Fw0xMzA4MDExMjAwMDBaFw0zODAxMTUxMjAwMDBaMGExCzAJBgNVBAYTAlVTMRUw +EwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20x +IDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IEczMHYwEAYHKoZIzj0CAQYF +K4EEACIDYgAE3afZu4q4C/sLfyHS8L6+c/MzXRq8NOrexpu80JX28MzQC7phW1FG +fp4tn+6OYwwX7Adw9c+ELkCDnOg/QW07rdOkFFk2eJ0DQ+4QE2xy3q6Ip6FrtUPO +Z9wj/wMco+I+o0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBhjAd +BgNVHQ4EFgQUs9tIpPmhxdiuNkHMEWNpYim8S8YwCgYIKoZIzj0EAwMDaAAwZQIx +AK288mw/EkrRLTnDCgmXc/SINoyIJ7vmiI1Qhadj+Z4y3maTD/HMsQmP3Wyr+mt/ +oAIwOWZbwmSNuJ5Q3KjVSaLtx9zRSX8XAbjIho9OjIgrqJqpisXRAL34VOKa5Vt8 +sycX +-----END CERTIFICATE-----'" +"DigiCert","DigiCert Inc","www.digicert.com","DigiCert High Assurance EV Root CA","02AC5C266A0B409B8F0B79F2AE462577","7431E5F4C3C1CE4690774F0B61E05440883BA9A01ED00BA6ABD7806ED3B118CF","065D43F4C81B18BE6989435AEA98144938DB896DC9EB6573BF219CDEC2AF6D80","2006.11.10","2031.11.10","RSA 2048 bits","SHA1WithRSA","Websites;Email","","","2.16.840.1.114412.2.1","https://bugzilla.mozilla.org/show_bug.cgi?id=364568","NSS 3.11.8","Firefox 2","https://ev-root.chain-demos.digicert.com","https://ev-root-expired.chain-demos.digicert.com","https://ev-root-revoked.chain-demos.digicert.com","","http://www.digicert.com/","USA, Global","https://www.digicert.com/wp-content/uploads/2020/02/DigiCert-Certificate-Policy-Version-5.0.pdf","https://www.digicert.com/wp-content/uploads/2020/02/DigiCert-CPS-Version-5.0.pdf","https://bugzilla.mozilla.org/attachment.cgi?id=9131333","https://bugzilla.mozilla.org/attachment.cgi?id=9131332","https://bugzilla.mozilla.org/attachment.cgi?id=9131334","Scott S. Perry CPA, PLLC","WebTrust","2020.02.29","'-----BEGIN CERTIFICATE----- +MIIDxTCCAq2gAwIBAgIQAqxcJmoLQJuPC3nyrkYldzANBgkqhkiG9w0BAQUFADBs +MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 +d3cuZGlnaWNlcnQuY29tMSswKQYDVQQDEyJEaWdpQ2VydCBIaWdoIEFzc3VyYW5j +ZSBFViBSb290IENBMB4XDTA2MTExMDAwMDAwMFoXDTMxMTExMDAwMDAwMFowbDEL +MAkGA1UEBhMCVVMxFTATBgNVBAoTDERpZ2lDZXJ0IEluYzEZMBcGA1UECxMQd3d3 +LmRpZ2ljZXJ0LmNvbTErMCkGA1UEAxMiRGlnaUNlcnQgSGlnaCBBc3N1cmFuY2Ug +RVYgUm9vdCBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMbM5XPm ++9S75S0tMqbf5YE/yc0lSbZxKsPVlDRnogocsF9ppkCxxLeyj9CYpKlBWTrT3JTW +PNt0OKRKzE0lgvdKpVMSOO7zSW1xkX5jtqumX8OkhPhPYlG++MXs2ziS4wblCJEM +xChBVfvLWokVfnHoNb9Ncgk9vjo4UFt3MRuNs8ckRZqnrG0AFFoEt7oT61EKmEFB +Ik5lYYeBQVCmeVyJ3hlKV9Uu5l0cUyx+mM0aBhakaHPQNAQTXKFx01p8VdteZOE3 +hzBWBOURtCmAEvF5OYiiAhF8J2a3iLd48soKqDirCmTCv2ZdlYTBoSUeh10aUAsg +EsxBu24LUTi4S8sCAwEAAaNjMGEwDgYDVR0PAQH/BAQDAgGGMA8GA1UdEwEB/wQF +MAMBAf8wHQYDVR0OBBYEFLE+w2kD+L9HAdSYJhoIAu9jZCvDMB8GA1UdIwQYMBaA +FLE+w2kD+L9HAdSYJhoIAu9jZCvDMA0GCSqGSIb3DQEBBQUAA4IBAQAcGgaX3Nec +nzyIZgYIVyHbIUf4KmeqvxgydkAQV8GK83rZEWWONfqe/EW1ntlMMUu4kehDLI6z +eM7b41N5cdblIZQB2lWHmiRk9opmzN6cN82oNLFpmyPInngiK3BD41VHMWEZ71jF +hS9OMPagMRYjyOfiZRYzy78aG6A9+MpeizGLYAiJLQwGXFK3xPkKmNEVX58Svnw2 +Yzi9RKR/5CYrCsSXaQ3pjOLAEFe4yHYSkVXySGnYvCoCWw9E1CAx2/S6cCZdkGCe +vEsXCS+0yx5DaMkHJ8HSXPfqIbloEpw8nL+e/IBcm2PN7EeqJSdnoDfzAIJ9VNep ++OkuE6N36B9K +-----END CERTIFICATE-----'" +"DigiCert","DigiCert Inc","www.digicert.com","DigiCert Trusted Root G4","059B1B579E8E2132E23907BDA777755C","552F7BDCF1A7AF9E6CE672017F4F12ABF77240C78E761AC203D1D9D20AC89988","1F327BEAC723431896AEA29C156BB057A27057DA1728C71731DAD52D2200EE69","2013.08.01","2038.01.15","RSA 4096 bits","SHA384WithRSA","Websites;Email","","","2.16.840.1.114412.2.1","https://bugzilla.mozilla.org/show_bug.cgi?id=908827","NSS 3.16.3","Firefox 32","https://trusted-root-g4.chain-demos.digicert.com/","https://trusted-root-g4-expired.chain-demos.digicert.com/","https://trusted-root-g4-revoked.chain-demos.digicert.com/","","http://www.digicert.com/","USA, Global","https://www.digicert.com/wp-content/uploads/2019/11/DigiCert_CP_v420.pdf","https://www.digicert.com/wp-content/uploads/2019/11/DigiCert_CPS_v420.pdf","https://bug1458024.bmoattachments.org/attachment.cgi?id=9123443","https://bug1458024.bmoattachments.org/attachment.cgi?id=9123442","https://bug1458024.bmoattachments.org/attachment.cgi?id=9123445","BDO International Limited","WebTrust","2020.01.29","'-----BEGIN CERTIFICATE----- +MIIFkDCCA3igAwIBAgIQBZsbV56OITLiOQe9p3d1XDANBgkqhkiG9w0BAQwFADBi +MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 +d3cuZGlnaWNlcnQuY29tMSEwHwYDVQQDExhEaWdpQ2VydCBUcnVzdGVkIFJvb3Qg +RzQwHhcNMTMwODAxMTIwMDAwWhcNMzgwMTE1MTIwMDAwWjBiMQswCQYDVQQGEwJV +UzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQu +Y29tMSEwHwYDVQQDExhEaWdpQ2VydCBUcnVzdGVkIFJvb3QgRzQwggIiMA0GCSqG +SIb3DQEBAQUAA4ICDwAwggIKAoICAQC/5pBzaN675F1KPDAiMGkz7MKnJS7JIT3y +ithZwuEppz1Yq3aaza57G4QNxDAf8xukOBbrVsaXbR2rsnnyyhHS5F/WBTxSD1If +xp4VpX6+n6lXFllVcq9ok3DCsrp1mWpzMpTREEQQLt+C8weE5nQ7bXHiLQwb7iDV +ySAdYyktzuxeTsiT+CFhmzTrBcZe7FsavOvJz82sNEBfsXpm7nfISKhmV1efVFiO +DCu3T6cw2Vbuyntd463JT17lNecxy9qTXtyOj4DatpGYQJB5w3jHtrHEtWoYOAMQ +jdjUN6QuBX2I9YI+EJFwq1WCQTLX2wRzKm6RAXwhTNS8rhsDdV14Ztk6MUSaM0C/ +CNdaSaTC5qmgZ92kJ7yhTzm1EVgX9yRcRo9k98FpiHaYdj1ZXUJ2h4mXaXpI8OCi +EhtmmnTK3kse5w5jrubU75KSOp493ADkRSWJtppEGSt+wJS00mFt6zPZxd9LBADM +fRyVw4/3IbKyEbe7f/LVjHAsQWCqsWMYRJUadmJ+9oCw++hkpjPRiQfhvbfmQ6QY +uKZ3AeEPlAwhHbJUKSWJbOUOUlFHdL4mrLZBdd56rF+NP8m800ERElvlEFDrMcXK +chYiCd98THU/Y+whX8QgUWtvsauGi0/C1kVfnSD8oR7FwI+isX4KJpn15GkvmB0t +9dmpsh3lGwIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIB +hjAdBgNVHQ4EFgQU7NfjgtJxXWRM3y5nP+e6mK4cD08wDQYJKoZIhvcNAQEMBQAD +ggIBALth2X2pbL4XxJEbw6GiAI3jZGgPVs93rnD5/ZpKmbnJeFwMDF/k5hQpVgs2 +SV1EY+CtnJYYZhsjDT156W1r1lT40jzBQ0CuHVD1UvyQO7uYmWlrx8GnqGikJ9yd ++SeuMIW59mdNOj6PWTkiU0TryF0Dyu1Qen1iIQqAyHNm0aAFYF/opbSnr6j3bTWc +fFqK1qI4mfN4i/RN0iAL3gTujJtHgXINwBQy7zBZLq7gcfJW5GqXb5JQbZaNaHqa +sjYUegbyJLkJEVDXCLG4iXqEI2FCKeWjzaIgQdfRnGTZ6iahixTXTBmyUEFxPT9N +cCOGDErcgdLMMpSEDQgJlxxPwO5rIHQw0uA5NBCFIRUBCOhVMt5xSdkoF1BN5r5N +0XWs0Mr7QbhDparTwwVETyw2m+L64kW4I1NsBm9nVX9GtUw/bihaeSbSpKhil9Ie +4u1Ki7wb/UdKDd9nZn6yW0HQO+T0O/QEY+nvwlQAUaCKKsnOeMzV6ocEGLPOr0mI +r/OSmbaz5mEP0oUA51Aa5BuVnRmhuZyxm7EAHu/QD09CbMkKvO5D+jpxpchNJqU1 +/YldvIViHTLSoCtU7ZpXwdv6EM8Zt4tKG48BtieVU+i2iW1bvGjUI+iLUaJW+fCm +gKDWHrO8Dw9TdSmq6hN35N6MgSGtBxBHEa2HPQfRdbzP82Z+ +-----END CERTIFICATE-----'" +"DigiCert","GeoTrust Inc.","","GeoTrust Global CA","023456","FF856A2D251DCD88D36656F450126798CFABAADE40799C722DE4D2B5DB36A73A","8128A1C605DB96C2555BE6D0FF1629E3E4A94E521F1AB1D8DA070E5C47DFC202","2002.05.21","2022.05.21","RSA 2048 bits","SHA1WithRSA","Websites","","","Not EV","legacy","","Firefox 1","https://valid-root10.geotrust.com","https://expired-root10.geotrust.com","https://revoked-root10.geotrust.com","","http://www.digicert.com/","USA, Global","https://content.digicert.com/wp-content/uploads/2019/06/STN-CP-v.2.12-.pdf","https://content.digicert.com/wp-content/uploads/2019/06/GT-CPS-v1.6-.pdf","https://bug1458024.bmoattachments.org/attachment.cgi?id=9123448","https://bug1458024.bmoattachments.org/attachment.cgi?id=9123447","","BDO International Limited","WebTrust","2020.01.29","'-----BEGIN CERTIFICATE----- +MIIDVDCCAjygAwIBAgIDAjRWMA0GCSqGSIb3DQEBBQUAMEIxCzAJBgNVBAYTAlVT +MRYwFAYDVQQKEw1HZW9UcnVzdCBJbmMuMRswGQYDVQQDExJHZW9UcnVzdCBHbG9i +YWwgQ0EwHhcNMDIwNTIxMDQwMDAwWhcNMjIwNTIxMDQwMDAwWjBCMQswCQYDVQQG +EwJVUzEWMBQGA1UEChMNR2VvVHJ1c3QgSW5jLjEbMBkGA1UEAxMSR2VvVHJ1c3Qg +R2xvYmFsIENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA2swYYzD9 +9BcjGlZ+W988bDjkcbd4kdS8odhM+KhDtgPpTSEHCIjaWC9mOSm9BXiLnTjoBbdq +fnGk5sRgprDvgOSJKA+eJdbtg/OtppHHmMlCGDUUna2YRpIuT8rxh0PBFpVXLVDv +iS2Aelet8u5fa9IAjbkU+BQVNdnARqN7csiRv8lVK83Qlz6cJmTM386DGXHKTubU +1XupGc1V3sjs0l44U+VcT4wt/lAjNvxm5suOpDkZALeVAjmRCw7+OC7RHQWa9k0+ +bw8HHa8sHo9gOeL6NlMTOdReJivbPagUvTLrGAMoUgRx5aszPeE4uwc2hGKceeoW +MPRfwCvocWvk+QIDAQABo1MwUTAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBTA +ephojYn7qwVkDBF9qn1luMrMTjAfBgNVHSMEGDAWgBTAephojYn7qwVkDBF9qn1l +uMrMTjANBgkqhkiG9w0BAQUFAAOCAQEANeMpauUvXVSOKVCUn5kaFOSPeCpilKIn +Z57QzxpeR+nBsqTP3UEaBU6bS+5Kb1VSsyShNwrrZHYqLizz/Tt1kL/6cdjHPTfS +tQWVYrmm3ok9Nns4d0iXrKYgjy6myQzCsplFAMfOEVEiIuCl6rYVSAlk6l5PdPcF +PseKUgzbFbS9bZvlxrFUaKnjaZC2mqUPuLk/IH2uSrW4nOQdtqvmlKXBx4Ot2/Un +hw4EbNX/3aBd7YdStysVAq45pmp06drE57xNNB6pXE0zX5IJL4hmXXeXxx12E6nV +5fEWCRE11azbJHFwLJhWC9kXtNHjUStedejV0NxPNO3CBWaAocvmMw== +-----END CERTIFICATE-----'" +"DigiCert","GeoTrust Inc.","","GeoTrust Primary Certification Authority","18ACB56AFD69B6153A636CAFDAFAC4A1","37D51006C512EAAB626421F1EC8C92013FC5F82AE98EE533EB4619B8DEB4D06C","0AD748AD619481803A03D372543B42D402BEC6F273323D364E8BCBE6526C4560","2006.11.27","2036.07.16","RSA 2048 bits","SHA1WithRSA","Websites","","","1.3.6.1.4.1.14370.1.6","https://bugzilla.mozilla.org/show_bug.cgi?id=407168","NSS 3.11.10","Firefox 3.0.2","https://valid-root11.geotrust.com","https://expired-root11.geotrust.com/","https://revoked-root11.geotrust.com/","","http://www.digicert.com/","USA, Global","https://content.digicert.com/wp-content/uploads/2019/06/STN-CP-v.2.12-.pdf","https://content.digicert.com/wp-content/uploads/2019/06/GT-CPS-v1.6-.pdf","https://bug1458024.bmoattachments.org/attachment.cgi?id=9123448","https://bug1458024.bmoattachments.org/attachment.cgi?id=9123447","https://bug1458024.bmoattachments.org/attachment.cgi?id=9123449","BDO International Limited","WebTrust","2020.01.29","'-----BEGIN CERTIFICATE----- +MIIDfDCCAmSgAwIBAgIQGKy1av1pthU6Y2yv2vrEoTANBgkqhkiG9w0BAQUFADBY +MQswCQYDVQQGEwJVUzEWMBQGA1UEChMNR2VvVHJ1c3QgSW5jLjExMC8GA1UEAxMo +R2VvVHJ1c3QgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0wNjEx +MjcwMDAwMDBaFw0zNjA3MTYyMzU5NTlaMFgxCzAJBgNVBAYTAlVTMRYwFAYDVQQK +Ew1HZW9UcnVzdCBJbmMuMTEwLwYDVQQDEyhHZW9UcnVzdCBQcmltYXJ5IENlcnRp +ZmljYXRpb24gQXV0aG9yaXR5MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC +AQEAvrgVe//UfH1nrYNke8hCUy3f9oQIIGHWAVlqnEQRr+92/ZV+zmEwu3qDXwK9 +AWbK7hWNb6EwnL2hhZ6UOvNWiAAxz9juapYC2e0DjPt1befquFUWBRaa9OBesYjA +ZIVcFU2Ix7e64HXprQU9nceJSOC7KMgD4TCTZF5SwFlwIjVXiIrxlQqD17wxcwE0 +7e9GceBrAqg1cmuXm2bgyxx5X9gaBGgeRwLmnWDiNpcB3841kt++Z8dtd1k7j53W +kBWUvEI0EME5+bEnPn7WinXFsq+W06Lem+SYvn3h6YGttm/81w7a4DSwDRp35+MI +mO9Y+pyEtzavwt+s0vQQBnBxNQIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4G +A1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQULNVQQZcVi/CPNmFbSvtr2ZnJM5IwDQYJ +KoZIhvcNAQEFBQADggEBAFpwfyzdtzRP9YZRqSa+S7iq8XEN3GHHoOo0Hnp3DwQ1 +6CePbJC/kRYkRj5KTs4rFtULUh38H2eiAkUxT87z+gOneZ1TatnaYzr4gNfTmeGl +4b7UVXGYNTq+k+qurUKykG/g/CFNNWMziUnWm07Kx+dOCQD32sfvmWKZd7aVIl6K +oKv0uHiYyjgZmclynnjNS6yvGaBzEi38wkG6gZHaFloxt/m0cYASSJlyc1pZU8Fj +UjPtp8nSOQJw+uCxQmYpqptR7TBUIhRf2asdweSU8Pj1K/fqynhG1riR/aYNKxoU +AT6A8EKglQdebc3MS6RFjasS6LPeWuWgfOgPIh1a6Vk= +-----END CERTIFICATE-----'" +"DigiCert","GeoTrust Inc.","(c) 2007 GeoTrust Inc. - For authorized use only","GeoTrust Primary Certification Authority - G2","3CB2F4480A00E2FEEB243B5E603EC36B","5EDB7AC43B82A06A8761E8D7BE4979EBF2611F7DD79BF91C1C6B566A219ED766","A073D36CA9EBA1345C9D7FA2780755CDE195186DAA6C99B01CAD94DB2BF236E8","2007.11.05","2038.01.18","EC secp384r1","ecdsaWithSHA384","Websites","","","Not EV","https://bugzilla.mozilla.org/show_bug.cgi?id=409236","NSS 3.12.6","Firefox 3.6.2","https://valid-root12.geotrust.com","https://expired-root12.geotrust.com/","https://revoked-root12.geotrust.com/","","http://www.digicert.com/","USA, Global","https://content.digicert.com/wp-content/uploads/2019/06/STN-CP-v.2.12-.pdf","https://content.digicert.com/wp-content/uploads/2019/06/GT-CPS-v1.6-.pdf","https://bug1458024.bmoattachments.org/attachment.cgi?id=9123448","https://bug1458024.bmoattachments.org/attachment.cgi?id=9123447","https://bug1458024.bmoattachments.org/attachment.cgi?id=9123449","BDO International Limited","WebTrust","2020.01.29","'-----BEGIN CERTIFICATE----- +MIICrjCCAjWgAwIBAgIQPLL0SAoA4v7rJDteYD7DazAKBggqhkjOPQQDAzCBmDEL +MAkGA1UEBhMCVVMxFjAUBgNVBAoTDUdlb1RydXN0IEluYy4xOTA3BgNVBAsTMChj +KSAyMDA3IEdlb1RydXN0IEluYy4gLSBGb3IgYXV0aG9yaXplZCB1c2Ugb25seTE2 +MDQGA1UEAxMtR2VvVHJ1c3QgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0 +eSAtIEcyMB4XDTA3MTEwNTAwMDAwMFoXDTM4MDExODIzNTk1OVowgZgxCzAJBgNV +BAYTAlVTMRYwFAYDVQQKEw1HZW9UcnVzdCBJbmMuMTkwNwYDVQQLEzAoYykgMjAw +NyBHZW9UcnVzdCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxNjA0BgNV +BAMTLUdlb1RydXN0IFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgLSBH +MjB2MBAGByqGSM49AgEGBSuBBAAiA2IABBWx6P0DFUPlrOuHNxFi79KDNlJ9RVcL +So17VDs6bl8VAsBQps8lL33KSLjHUGMcKiEIfJo22Av+0SbFWDEwKCXzXV2juLal +tJLtbCyf691DiaI8S0iRHVDsJt/WYC69IaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAO +BgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFBVfNVdRVfslsq0DafwBo/q+EVXVMAoG +CCqGSM49BAMDA2cAMGQCMGSWWaboCd6LuvpaiIjwH5HTRqjySkwCY/tsXzjbLkGT +qQ7mndwxHLKgpxgceeHHNgIwOlavmnRs9vuD4DPTCF+hnMJbn0bWtsuRBmOiBucz +rD6ogRLQy7rQkgu2npaqBA+K +-----END CERTIFICATE-----'" +"DigiCert","GeoTrust Inc.","(c) 2008 GeoTrust Inc. - For authorized use only","GeoTrust Primary Certification Authority - G3","15AC6E9419B2794B41F627A9C3180F1F","B478B812250DF878635C2AA7EC7D155EAA625EE82916E2CD294361886CD1FBD4","4A3F0BB40C980AFFC2B039F6F0BAC88FBEDBD6A54AECF102291BAF6C07CAAD3B","2008.04.02","2037.12.01","RSA 2048 bits","SHA256WithRSA","Websites","","","1.3.6.1.4.1.14370.1.6","https://bugzilla.mozilla.org/show_bug.cgi?id=484899","NSS 3.12.5","Firefox 3.6","https://valid-root13.geotrust.com/","https://expired-root13.geotrust.com/","https://revoked-root13.geotrust.com/","","http://www.digicert.com/","USA, Global","https://content.digicert.com/wp-content/uploads/2019/06/STN-CP-v.2.12-.pdf","https://content.digicert.com/wp-content/uploads/2019/06/GT-CPS-v1.6-.pdf","https://bug1458024.bmoattachments.org/attachment.cgi?id=9123448","https://bug1458024.bmoattachments.org/attachment.cgi?id=9123447","https://bug1458024.bmoattachments.org/attachment.cgi?id=9123449","BDO International Limited","WebTrust","2020.01.29","'-----BEGIN CERTIFICATE----- +MIID/jCCAuagAwIBAgIQFaxulBmyeUtB9iepwxgPHzANBgkqhkiG9w0BAQsFADCB +mDELMAkGA1UEBhMCVVMxFjAUBgNVBAoTDUdlb1RydXN0IEluYy4xOTA3BgNVBAsT +MChjKSAyMDA4IEdlb1RydXN0IEluYy4gLSBGb3IgYXV0aG9yaXplZCB1c2Ugb25s +eTE2MDQGA1UEAxMtR2VvVHJ1c3QgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhv +cml0eSAtIEczMB4XDTA4MDQwMjAwMDAwMFoXDTM3MTIwMTIzNTk1OVowgZgxCzAJ +BgNVBAYTAlVTMRYwFAYDVQQKEw1HZW9UcnVzdCBJbmMuMTkwNwYDVQQLEzAoYykg +MjAwOCBHZW9UcnVzdCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxNjA0 +BgNVBAMTLUdlb1RydXN0IFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkg +LSBHMzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANziXmJYHTNXOTIz ++uvLh4yn1ErdBojqZI4xmKU4kB6Yzy5jK/BGvESyiaHAKAxJcCGVn2TAppMSAmUm +hsalifD614SgcK9PGpc/BkTVyetyEH3kMSj7HGHmKAdEc5IiaacDiGydY8hS2pgn +5whMcD60yRLBxWeDXTPzAxHsatBT4tG6NmCUgLthY2xbF37fQJQeqw3CIShwiP/W +JmxsYAQlTlV+fe+/lEjetx3dcI0FX4ilm/LC7urRQEFtYjgdVgbFA0dRIBn8exAL +DmKudlW/X3e+PkkBUz2YJQN2JFodtNuJ6nnltrM7P7pMKEF/BqxqjsHQ9gUdfeZC +huOl1UcCAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYw +HQYDVR0OBBYEFMR5yo6hTgMdHNxr2zFblD4/MH8tMA0GCSqGSIb3DQEBCwUAA4IB +AQAtxRPPVoB7eni9n64smefv2t+UXglpp+duaIy9cr5HqQ6XErhK8WTTOd8lNNTB +zU6B8A8ExCSzNJbGpqow32hhc9f5joWJ7w5elShKKiePEI4ufIbEAp7aDHdlDkQN +kv39sxY2+hENHYwOB4lqKVb3cvTdFZx3NWZXqxNT2I7BQMXXExZacse3aQHEerGD +AWh9jUGhlBjBJVz88P6DAod8DQ3PLghcSkANPuyBYeYk28rgDi0Hsj5W3I31QYUH +SJsMC8tJP33st/3LjWeJGqvtux6jAAgIFyqCXDFdRootD4abdNlF+9RAsXqqaC2G +spki4cErx5z481+oghLrGREt +-----END CERTIFICATE-----'" +"DigiCert","GeoTrust Inc.","","GeoTrust Universal CA","01","A0459B9F63B22559F5FA5D4C6DB3F9F72FF19342033578F073BF1D1B46CBB912","A375D830815CBA5D8DA3B4B1564FBBECB879BD40EE44AAE341CD314A0F42B373","2004.03.04","2029.03.04","RSA 4096 bits","SHA1WithRSA","Websites","","","Not EV","https://bugzilla.mozilla.org/show_bug.cgi?id=294916","NSS 3.11.4","Firefox 2","https://valid-root14.geotrust.com/","https://expired-root14.geotrust.com/","https://revoked-root14.geotrust.com/","","http://www.digicert.com/","USA, Global","https://content.digicert.com/wp-content/uploads/2019/06/STN-CP-v.2.12-.pdf","https://content.digicert.com/wp-content/uploads/2019/06/GT-CPS-v1.6-.pdf","https://bug1458024.bmoattachments.org/attachment.cgi?id=9123448","https://bug1458024.bmoattachments.org/attachment.cgi?id=9123447","","BDO International Limited","WebTrust","2020.01.29","'-----BEGIN CERTIFICATE----- +MIIFaDCCA1CgAwIBAgIBATANBgkqhkiG9w0BAQUFADBFMQswCQYDVQQGEwJVUzEW +MBQGA1UEChMNR2VvVHJ1c3QgSW5jLjEeMBwGA1UEAxMVR2VvVHJ1c3QgVW5pdmVy +c2FsIENBMB4XDTA0MDMwNDA1MDAwMFoXDTI5MDMwNDA1MDAwMFowRTELMAkGA1UE +BhMCVVMxFjAUBgNVBAoTDUdlb1RydXN0IEluYy4xHjAcBgNVBAMTFUdlb1RydXN0 +IFVuaXZlcnNhbCBDQTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAKYV +VaCjxuAfjJ0hUNfBvitbtaSeodlyWL0AG0y/YckUHUWCq8YdgNY96xCcOq9tJPi8 +cQGeBvV8Xx7BDlXKg5pZMK4ZyzBIle0iN430SppyZj6tlcDgFgDgEB8rMQ7XlFTT +QjOgNB0eRXbdT8oYN+yFFXoZCPzVx5zw8qkuEKmS5j1YPakWaDwvdSEYfyh3peFh +F7em6fgemdtzbvQKoiFs7tqqhZJmr/Z6a4LauiIINQ/PQvE1+mrufislzDoR5G2v +c7J2Ha3QsnhnGqQ5HFELZ1aD/ThdDc7d8Lsrlh/eezJS/R27tQahsiFepdaVaH/w +mZ7cRQg+59IJDTWU3YBOU5fXtQlEIGQWFwMCTFMNaN7VqnJNk22CDtucvc+081xd +VHppCZbW2xHBjXWotM85yM48vCR85mLK4b19p71XZQvk/iXttmkQ3CgaRr0BHdCX +teGYO8A3ZNY9lO4L4fUorgtWv3GLIylBjobFS1J72HGrH4oVpjuDWtdYAVHGTEHZ +f9hBZ3KiKN9gg6meyHv8U3NyWfWTehd2Ds735VzZC1U0oqpbtWpU5xPKV+yXbfRe +Bi9Fi1jUIxaS5BZuKGNZMN9QAZxjiRqf2xeUgnA3wySemkfWWspOqGmJch+RbNt+ +nhutxx9z3SxPGWX9f5NAEC7S8O08ni4oPmkmM8V7AgMBAAGjYzBhMA8GA1UdEwEB +/wQFMAMBAf8wHQYDVR0OBBYEFNq7LqqwDLiIJlF0XG0D08DYj3rWMB8GA1UdIwQY +MBaAFNq7LqqwDLiIJlF0XG0D08DYj3rWMA4GA1UdDwEB/wQEAwIBhjANBgkqhkiG +9w0BAQUFAAOCAgEAMXjmx7XfuJRAyXHEqDXsRh3ChfMoWIawC/yOsjmPRFWrZIRc +aanQmjg8+uUfNeVE44B5lGiku8SfPeE0zTBGi1QrlaXv9z+ZhP015s8xxtxqv6fX +IwjhmF7DWgh2qaavdy+3YL1ERmrvl/9zlcGO6JP7/TG37FcREUWbMPEaiDnBTzyn +ANXH/KttgCJwpQzgXQQpAvvLoJHRfNbDflDVnVi+QTjruXU8FdmbyUqDWcDaU/0z +uzYYm4UPFd3uLax2k7nZAY1IEKj79TiG8dsKxr2EoyNB3tZ3b4XUhRxQ4K5RirqN +Pnbiucon8l+f725ZDQbYKxek0nxru18UGkiPGkzns0ccjkxFKyDuSN/n3QmOGKja +QI2SJhFTYXNd673nxE0pN2HrrDktZy4W1vUAg4WhzH92xH3kt0tm7wNFYGm2DFKW +koRepqO1pD4r2czYG0eq8kTaT/kD6PAUyz/zg97QwVTjt+gKN02LIFkDMBmhLMi9 +ER/frslKxfMnZmaGrGiR/9nmUxwPi1xpZQomyB40w11Re9epnAahNt3ViZS82eQt +DF4JbAiXfKM9fJP/P6EUp8+1Xevb2xzEdt+Iub1FBZUbrvxGakyvSOPOrg/Sfuvm +bJxPgWp6ZKy7PtXny3YuxadIwVyQD8vIP/rmMuGNG2+k5o7Y+SlIis5z/iw= +-----END CERTIFICATE-----'" +"DigiCert","GeoTrust Inc.","","GeoTrust Universal CA 2","01","A0234F3BC8527CA5628EEC81AD5D69895DA5680DC91D1CB8477F33F878B95B0B","8F83F7135B6613E980BD82C690DC845F5F12557BEDB322373BB2097B439BB493","2004.03.04","2029.03.04","RSA 4096 bits","SHA1WithRSA","Websites","","","Not EV","https://bugzilla.mozilla.org/show_bug.cgi?id=294916","NSS 3.11.4","Firefox 2","https://valid-root15.geotrust.com/","https://expired-root15.geotrust.com/","https://revoked-root15.geotrust.com/","","http://www.digicert.com/","USA, Global","https://content.digicert.com/wp-content/uploads/2019/06/STN-CP-v.2.12-.pdf","https://content.digicert.com/wp-content/uploads/2019/06/GT-CPS-v1.6-.pdf","https://bug1458024.bmoattachments.org/attachment.cgi?id=9123448","https://bug1458024.bmoattachments.org/attachment.cgi?id=9123447","","BDO International Limited","WebTrust","2020.01.29","'-----BEGIN CERTIFICATE----- +MIIFbDCCA1SgAwIBAgIBATANBgkqhkiG9w0BAQUFADBHMQswCQYDVQQGEwJVUzEW +MBQGA1UEChMNR2VvVHJ1c3QgSW5jLjEgMB4GA1UEAxMXR2VvVHJ1c3QgVW5pdmVy +c2FsIENBIDIwHhcNMDQwMzA0MDUwMDAwWhcNMjkwMzA0MDUwMDAwWjBHMQswCQYD +VQQGEwJVUzEWMBQGA1UEChMNR2VvVHJ1c3QgSW5jLjEgMB4GA1UEAxMXR2VvVHJ1 +c3QgVW5pdmVyc2FsIENBIDIwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoIC +AQCzVFLByT7y2dyxUxpZKeexw0Uo5dfR7cXFS6GqdHtXr0om/Nj1XqduGdt0DE81 +WzILAePb63p3NeqqWuDW6KFXlPCQo3RWlEQwAx5cTiuFJnSCegx2oG9NzkEtoBUG +FF+3Qs17j1hhNNwqCPkuwwGmIkQcTAeC5lvO0Ep8BNMZcyfwqph/Lq9O64ceJHdq +XbboW0W63MOhBW9Wjo8QJqVJwy7XQYci4E+GymC16qFjwAGXEHm9ADwSbSsVsaxL +se4YuU6W3Nx2/zu+z18DwPw76L5GG//aQMJS9/7jOvdqdzXQ2o3rXhhqMcceujwb +KNZrVMaqW9eiLBsZzKIC9ptZvTdrhrVtgrrY6slWvKk2WP0+GfPtDCapkzj4T8Fd +IgbQl+rhrcZV4IErKIM6+vR7IVEAvlI4zs1meaj0gVbi0IMJR1FbUGrP20gaXT73 +y/Zl92zxlfgCOzJWgjl6W70viRu/obTo/3+NjN8D8WBOWBFM66M/ECuDmgFz2ZRt +hAAnZqzwcEAJQpKtT5MNYQlRJNiS1QuUYbKHsu3/mjX/hVTK7URDrBs8FmtISgoc +QIgfksILAAX/8sgCSqSqqcyZlpwvWOB94b67B9xfBHJcMTTD7F8t4D1kkCLm0ey4 +Lt1ZrtmhN79UNdxzMk+MBB4zsslG8dhcyFVQyWi9qLo2CQIDAQABo2MwYTAPBgNV +HRMBAf8EBTADAQH/MB0GA1UdDgQWBBR281Xh+qQ2+/CfXGJx7Tz0RzgQKzAfBgNV +HSMEGDAWgBR281Xh+qQ2+/CfXGJx7Tz0RzgQKzAOBgNVHQ8BAf8EBAMCAYYwDQYJ +KoZIhvcNAQEFBQADggIBAGbBxiPz2eAubl/oz66wsCVNK/g7WJtAJDday6sWSf+z +dXkzoS9tcBc0kf5nfo/sm+VegqlVHy/c1FEHEv6sFj4sNcZj/NwQ6w2jqtB8zNHQ +L1EuxBRa3ugZ4T7GzKQp5y6EqgYweHZUcyiYWTjgAA1i00J9IZ+uPTqM1fp3DRgr +Fg5fNuH8KrUwJM/gYwx7WBr+mbpCErGR9Hxo4sjoryzqyX6uuyo9DRXcNJW2GHSo +ag/HtPQTxORb7QrSpJdMKu0vbBKJPfEncKpqA1Ihn0CoZ1Dy81of398j9tx4TuaY +T1U6U+Pv8vSfx3zYWK8pIpe44L2RLrB27FcRz+8pRPPphXpgY+RdM4kX2TGq2tbz +GDVyz4crL2MjhF2EjD9XoIj8mZEoJmmZ1I+XRL6O1UixpCgp8RW04eWe3fiPpm8m +1wk8OhwRDqZsN/etRIcsKMfYdIKz0G9KV7s1KSegi+ghp4dkNl3M2Basx7InQJJV +OCiNUW7dFGdTbHFcJoRNdVq2fmBWqU2t+5sel/MN2dKXVHfaPRK34B7vCAas+YWH +6aLcr34YEoP9VhdBLtUpgn2Z9DH2canPLAEnpQW5qrJITirvn5NSUZU8UnOOVkwX +QMAJKOSLakhT2+zNVVXxxvjpoixMptEmX36vWkzaH6byHCx+rgIW0lbQL1dTR+iS +-----END CERTIFICATE-----'" +"DigiCert","Symantec Corporation","Symantec Trust Network","Symantec Class 1 Public Primary Certification Authority - G6","243275F21D2FD20933F7B46ACAD0F398","9D190B2E314566685BE8A889E27AA8C7D7AE1D8AADDBA3C1ECF9D24863CD34B9","D4AC680A231DDF0ED15416C3CCA32E028C0CBD02512B12D9F6E4DE583939BC56","2011.10.18","2037.12.01","RSA 2048 bits","SHA256WithRSA","Email","","","","https://bugzilla.mozilla.org/show_bug.cgi?id=833986","NSS 3.28.1","Firefox 51","","","","None","http://www.digicert.com/","USA, Global","https://content.digicert.com/wp-content/uploads/2019/06/STN-CP-v.2.12-.pdf","https://content.digicert.com/wp-content/uploads/2019/06/STN-CPS-v3.13.pdf","https://bug1458024.bmoattachments.org/attachment.cgi?id=9123453","","","BDO International Limited","WebTrust","2020.01.29","'-----BEGIN CERTIFICATE----- +MIID9jCCAt6gAwIBAgIQJDJ18h0v0gkz97RqytDzmDANBgkqhkiG9w0BAQsFADCB +lDELMAkGA1UEBhMCVVMxHTAbBgNVBAoTFFN5bWFudGVjIENvcnBvcmF0aW9uMR8w +HQYDVQQLExZTeW1hbnRlYyBUcnVzdCBOZXR3b3JrMUUwQwYDVQQDEzxTeW1hbnRl +YyBDbGFzcyAxIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5 +IC0gRzYwHhcNMTExMDE4MDAwMDAwWhcNMzcxMjAxMjM1OTU5WjCBlDELMAkGA1UE +BhMCVVMxHTAbBgNVBAoTFFN5bWFudGVjIENvcnBvcmF0aW9uMR8wHQYDVQQLExZT +eW1hbnRlYyBUcnVzdCBOZXR3b3JrMUUwQwYDVQQDEzxTeW1hbnRlYyBDbGFzcyAx +IFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IC0gRzYwggEi +MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDHOddJZKmZgiJM6kXZBxbje/SD +6Jlz+muxNuCad6BAwoGNAcfMjL2Pffd543pMA03Z+/2HOCgs3ZqLVAjbZ/sbjP4o +ki++t7JIp4Gh2F6Iw8w5QEFa0dzl2hCfL9oBTf0uRnz5LicKaTfukaMbasxEvxvH +w9QRslBglwm9LiL1QYRmn81ApqkAgMEflZKf3vNI79sdd2H8f9/ulqRy0LY+/3gn +r8uSFWkI22MQ4uaXrG7crPaizh5HmbmJtxLmodTNWRFnw2+F2EJOKL5ZVVkElauP +N4C/DfD8HzpkMViBeNfiNfYgPym4jxZuPkjctUwH4fIa6n4KedaovetdhitNAgMB +AAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQW +BBQzQejIORIVk0jyljIuWvXalF9TYDANBgkqhkiG9w0BAQsFAAOCAQEAFeNzV7EX +tl9JaUSm9l56Z6zS3nVJq/4lVcc6yUQVEG6/MWvL2QeTfxyFYwDjMhLgzMv7OWyP +4lPiPEAz2aSMR+atWPuJr+PehilWNCxFuBL6RIluLRQlKCQBZdbqUqwFblYSCT3Q +dPTXvQbKqDqNVkL6jXI+dPEDct+HG14OelWWLDi3mIXNTTNEyZSPWjEwN0ujOhKz +5zbRIWhLLTjmU64cJVYIVgNnhJ3Gw84kYsdMNs+wBkS39V8C3dlU6S+QTnrIToNA +DJqXPDe/v+z28LSFdyjBC8hnghAXOKK3Buqbvzr46SMHv3TgmDgVVXjucgBcGaP0 +0jPg/73RVDkpDw== +-----END CERTIFICATE-----'" +"DigiCert","Symantec Corporation","Symantec Trust Network","Symantec Class 2 Public Primary Certification Authority - G6","64829EFC371E745DFC97FF97C8B1FF41","CB627D18B58AD56DDE331A30456BC65C601A4E9B18DEDCEA08E7DAAA07815FF0","F93FF99D3D2D7BDC7F5F22CF14E47C81018FF2565352BEF8E885956BD2DB70DD","2011.10.18","2037.12.01","RSA 2048 bits","SHA256WithRSA","Email","","","","https://bugzilla.mozilla.org/show_bug.cgi?id=833986","NSS 3.28.1","Firefox 51","","","","None","http://www.digicert.com/","USA, Global","https://content.digicert.com/wp-content/uploads/2019/06/STN-CP-v.2.12-.pdf","https://content.digicert.com/wp-content/uploads/2019/06/STN-CPS-v3.13.pdf","https://bug1458024.bmoattachments.org/attachment.cgi?id=9123453","","","BDO International Limited","WebTrust","2020.01.29","'-----BEGIN CERTIFICATE----- +MIID9jCCAt6gAwIBAgIQZIKe/DcedF38l/+XyLH/QTANBgkqhkiG9w0BAQsFADCB +lDELMAkGA1UEBhMCVVMxHTAbBgNVBAoTFFN5bWFudGVjIENvcnBvcmF0aW9uMR8w +HQYDVQQLExZTeW1hbnRlYyBUcnVzdCBOZXR3b3JrMUUwQwYDVQQDEzxTeW1hbnRl +YyBDbGFzcyAyIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5 +IC0gRzYwHhcNMTExMDE4MDAwMDAwWhcNMzcxMjAxMjM1OTU5WjCBlDELMAkGA1UE +BhMCVVMxHTAbBgNVBAoTFFN5bWFudGVjIENvcnBvcmF0aW9uMR8wHQYDVQQLExZT +eW1hbnRlYyBUcnVzdCBOZXR3b3JrMUUwQwYDVQQDEzxTeW1hbnRlYyBDbGFzcyAy +IFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IC0gRzYwggEi +MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDNzOkFyGOFyz9AYxe9GPo15gRn +V2WYKaRPyVyPDzTS+NqoE2KquB5QZ3iwFkygOakVeq7t0qLA8JA3KRgmXOgNPLZs +ST/B4NzZS7YUGQum05bh1gnjGSYc+R9lS/kaQxwAg9bQqkmi1NvmYji6UBRDbfkx ++FYW2TgCkc/rbN27OU6Z4TBnRfHU8I3D3/7yOAchfQBeVkSz5GC9kSucq1sEcg+y +KNlyqwUgQiWpWwNqIBDMMfAr2jUs0Pual07wgksr2F82owstr2MNHSV/oW5cYqGN +KD6h/Bwg+AEvulWaEbAZ0shQeWsOagXXqgQ2sqPy4V93p3ec5R7c6d9qwWVdAgMB +AAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQW +BBSHjCCVyJhK0daABkqQNETfHE2/sDANBgkqhkiG9w0BAQsFAAOCAQEAgY6ypWaW +tyGltu9vI1pf24HFQqV4wWn99DzX+VxrcHIa/FqXTQCAiIiCisNxDY7FiZss7Y0L +0nJU9X3UXENX6fOupQIR9nYrgVfdfdp0MP1UR/bgFm6mtApI5ud1Bw8pGTnOefS2 +bMVfmdUfS/rfbSw8DVSAcPCIC4DPxmiiuB1w2XaM/O6lyc+tHc+ZJVdaYkXLFmu9 +Sc2lo4xpeSWuuExsi0BmSxY/zwIa3eFsawdhanYVKZl/G92IgMG/tY9zxaaWI4Sm +KIYkM2oBLldzJbZev4/mHWGoQClnHYebHX+bn5nNMdZUvmK7OaxoEkiRIKXLsd3+ +b/xa5IJVWa8xqQ== +-----END CERTIFICATE-----'" +"DigiCert","thawte, Inc.","Certification Services Division, (c) 2006 thawte, Inc. - For authorized use only","thawte Primary Root CA","344ED55720D5EDEC49F42FCE37DB2B6D","8D722F81A9C113C0791DF136A2966DB26C950A971DB46B4199F4EA54B78BFB9F","3DC6A0079602409063B020D72676BED736485B09620129C383120130863C9114","2006.11.17","2036.07.16","RSA 2048 bits","SHA1WithRSA","Websites","","","2.16.840.1.113733.1.7.48.1","https://bugzilla.mozilla.org/show_bug.cgi?id=407163","NSS 3.11.10","Firefox 3.0.2","https://valid-root7.thawte.com","https://expired-root7.thawte.com","https://revoked-root7.thawte.com","","http://www.digicert.com/","USA, Global","https://content.digicert.com/wp-content/uploads/2019/06/STN-CP-v.2.12-.pdf","https://content.digicert.com/wp-content/uploads/2019/06/THT-CPS-v3.7.23.pdf","https://bug1458024.bmoattachments.org/attachment.cgi?id=9123456","https://bug1458024.bmoattachments.org/attachment.cgi?id=9123455","https://bug1458024.bmoattachments.org/attachment.cgi?id=9123457","BDO International Limited","WebTrust","2020.01.29","'-----BEGIN CERTIFICATE----- +MIIEIDCCAwigAwIBAgIQNE7VVyDV7exJ9C/ON9srbTANBgkqhkiG9w0BAQUFADCB +qTELMAkGA1UEBhMCVVMxFTATBgNVBAoTDHRoYXd0ZSwgSW5jLjEoMCYGA1UECxMf +Q2VydGlmaWNhdGlvbiBTZXJ2aWNlcyBEaXZpc2lvbjE4MDYGA1UECxMvKGMpIDIw +MDYgdGhhd3RlLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxHzAdBgNV +BAMTFnRoYXd0ZSBQcmltYXJ5IFJvb3QgQ0EwHhcNMDYxMTE3MDAwMDAwWhcNMzYw +NzE2MjM1OTU5WjCBqTELMAkGA1UEBhMCVVMxFTATBgNVBAoTDHRoYXd0ZSwgSW5j +LjEoMCYGA1UECxMfQ2VydGlmaWNhdGlvbiBTZXJ2aWNlcyBEaXZpc2lvbjE4MDYG +A1UECxMvKGMpIDIwMDYgdGhhd3RlLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNl +IG9ubHkxHzAdBgNVBAMTFnRoYXd0ZSBQcmltYXJ5IFJvb3QgQ0EwggEiMA0GCSqG +SIb3DQEBAQUAA4IBDwAwggEKAoIBAQCsoPD7gFnUnMekz52hWXMJEEUMDSxuaPFs +W0hoSVk3/AszGcJ3f8wQLZU0HObrTQmnHNK4yZc2AreJ1CRfBsDMRJSUjQJib+ta +3RGNKJpchJAQeg29dGYvajig4tVUROsdB58Hum/u6f1OCyn1PoSgAfGcq/gcfomk +6KHYcWUNo1F77rzSImANuVud37r8UVsLr5iy6S7pBOhih94ryNdOwUxkHt3Ph1i6 +Sk/KaAcdHJ1KxtUvkcx8cXIcxcBn6zL9yZJclNqFwJu/U30rCfSMnZEfl2pSy94J +NqR32HuHUETVPm4pafs5SSYeCaWAe0At6+gnhcn+Yf1+5nyXHdWdAgMBAAGjQjBA +MA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBR7W0XP +r87Lev0xkhpqtvNG61dIUDANBgkqhkiG9w0BAQUFAAOCAQEAeRHAS7ORtvzw6WfU +DW5FvlXok9LOAz/t2iWwHVfLHjp2oEzsUHboZHIMpKnxuIvW1oeEuzLlQRHAd9mz +YJ3rG9XRbkREqaYB7FViHXe4XI5ISXycO1cRrK1zN44veFyQaEfZYGDm/Ac9IiAX +xPcW6cTYcvnIc3zfFi8VqT79aie2oetaupgf1eNNZAqdE8hhuvU5HIe6uL17In/2 +/qxAeeWsEG89jxt5dovEN7MhGITlNgDrYyCZuen+MwS7QcjBAvlEYyCegc5C09Y/ +LHbTY5xZ3Y+m4Q6gLkH3LpVHz7z9M/P2C2F+fpErgUfCJzDupxBdN49cOSvkBPB7 +jVaMaA== +-----END CERTIFICATE-----'" +"DigiCert","thawte, Inc.","(c) 2007 thawte, Inc. - For authorized use only","thawte Primary Root CA - G2","35FC265CD9844FC93D263D579BAED756","A4310D50AF18A6447190372A86AFAF8B951FFB431D837F1E5688B45971ED1557","112633F3DCB6C8735B5B0DCB9616B86CD26DAB9DC7039756EEC29637ECF4D82E","2007.11.05","2038.01.18","EC secp384r1","ecdsaWithSHA384","Websites","","","Not EV","https://bugzilla.mozilla.org/show_bug.cgi?id=409237","NSS 3.12.6","Firefox 3.6.2","https://valid-root8.thawte.com","https://expired-root8.thawte.com","https://revoked-root8.thawte.com","","http://www.digicert.com/","USA, Global","https://content.digicert.com/wp-content/uploads/2019/06/STN-CP-v.2.12-.pdf","https://content.digicert.com/wp-content/uploads/2019/06/THT-CPS-v3.7.23.pdf","https://bug1458024.bmoattachments.org/attachment.cgi?id=9123456","https://bug1458024.bmoattachments.org/attachment.cgi?id=9123455","https://bug1458024.bmoattachments.org/attachment.cgi?id=9123457","BDO International Limited","WebTrust","2020.01.29","'-----BEGIN CERTIFICATE----- +MIICiDCCAg2gAwIBAgIQNfwmXNmET8k9Jj1Xm67XVjAKBggqhkjOPQQDAzCBhDEL +MAkGA1UEBhMCVVMxFTATBgNVBAoTDHRoYXd0ZSwgSW5jLjE4MDYGA1UECxMvKGMp +IDIwMDcgdGhhd3RlLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxJDAi +BgNVBAMTG3RoYXd0ZSBQcmltYXJ5IFJvb3QgQ0EgLSBHMjAeFw0wNzExMDUwMDAw +MDBaFw0zODAxMTgyMzU5NTlaMIGEMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMdGhh +d3RlLCBJbmMuMTgwNgYDVQQLEy8oYykgMjAwNyB0aGF3dGUsIEluYy4gLSBGb3Ig +YXV0aG9yaXplZCB1c2Ugb25seTEkMCIGA1UEAxMbdGhhd3RlIFByaW1hcnkgUm9v +dCBDQSAtIEcyMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEotWcgnuVnfFSeIf+iha/ +BebfowJPDQfGAFG6DAJSLSKkQjnE/o/qycG+1E3/n3qe4rF8mq2nhglzh9HnmuN6 +papu+7qzcMBniKI11KOasf2twu8x+qi58/sIxpHR+ymVo0IwQDAPBgNVHRMBAf8E +BTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUmtgAMADna3+FGO6Lts6K +DPgR4bswCgYIKoZIzj0EAwMDaQAwZgIxAN344FdHW6fmCsO99YCKlzUNG4k8VIZ3 +KMqh9HneteY4sPBlcIx/AlTCv//YoT7ZzwIxAMSNlPzcU9LcnXgWHxUzI1NS41ox +XZ3Krr0TKUQNJ1uo52icEvdYPy5yAlejj6EULg== +-----END CERTIFICATE-----'" +"DigiCert","thawte, Inc.","Certification Services Division, (c) 2008 thawte, Inc. - For authorized use only","thawte Primary Root CA - G3","600197B746A7EAB4B49AD64B2FF790FB","4B03F45807AD70F21BFC2CAE71C9FDE4604C064CF5FFB686BAE5DBAAD7FDD34C","04029026491D69AED10E10EB031CCAA4F4965049DBC07F456C51ED1F378AAB4E","2008.04.02","2037.12.01","RSA 2048 bits","SHA256WithRSA","Websites","","","2.16.840.1.113733.1.7.48.1","https://bugzilla.mozilla.org/show_bug.cgi?id=484903","NSS 3.12.5","Firefox 3.6","https://valid-root9.thawte.com","https://expired-root9.thawte.com","https://revoked-root9.thawte.com","","http://www.digicert.com/","USA, Global","https://content.digicert.com/wp-content/uploads/2019/06/STN-CP-v.2.12-.pdf","https://content.digicert.com/wp-content/uploads/2019/06/THT-CPS-v3.7.23.pdf","https://bug1458024.bmoattachments.org/attachment.cgi?id=9123456","https://bug1458024.bmoattachments.org/attachment.cgi?id=9123455","https://bug1458024.bmoattachments.org/attachment.cgi?id=9123457","BDO International Limited","WebTrust","2020.01.29","'-----BEGIN CERTIFICATE----- +MIIEKjCCAxKgAwIBAgIQYAGXt0an6rS0mtZLL/eQ+zANBgkqhkiG9w0BAQsFADCB +rjELMAkGA1UEBhMCVVMxFTATBgNVBAoTDHRoYXd0ZSwgSW5jLjEoMCYGA1UECxMf +Q2VydGlmaWNhdGlvbiBTZXJ2aWNlcyBEaXZpc2lvbjE4MDYGA1UECxMvKGMpIDIw +MDggdGhhd3RlLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxJDAiBgNV +BAMTG3RoYXd0ZSBQcmltYXJ5IFJvb3QgQ0EgLSBHMzAeFw0wODA0MDIwMDAwMDBa +Fw0zNzEyMDEyMzU5NTlaMIGuMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMdGhhd3Rl +LCBJbmMuMSgwJgYDVQQLEx9DZXJ0aWZpY2F0aW9uIFNlcnZpY2VzIERpdmlzaW9u +MTgwNgYDVQQLEy8oYykgMjAwOCB0aGF3dGUsIEluYy4gLSBGb3IgYXV0aG9yaXpl +ZCB1c2Ugb25seTEkMCIGA1UEAxMbdGhhd3RlIFByaW1hcnkgUm9vdCBDQSAtIEcz +MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAsr8nLPvb2FvdeHsbnndm +gcs+vHyu86YnmjSjaDFxODNi5PNxZnmxqWWjpYvVj2AtP0LMqmsywCPLLEHd5N/8 +YZzic7IilRFDGF/Eth9XbAoFWCLINkw6fKXRz4aviKdEAhN0cXMKQlkC+BsUa0Lf +b1+6a4KinVvnSr0eAXLbS3ToO39/fR8EtCab4LRarEc9VbjXsCZSKAExQGbY2SS9 +9irY7CFJXJv2eul/VTV+lmuNk5Mny5K76qxAwJ/C+IDPXfRa3M50hqY+bAtTyr2S +zhkGcuYMXDhpxwTWvGzOW/b3aJzcJRVIiKHpqfiYnODz1TEoYRFsZ5aNOZnLwkUk +OQIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNV +HQ4EFgQUrWyqlGCc7eT/+j4KdCtjA/e2Wb8wDQYJKoZIhvcNAQELBQADggEBABpA +2JVlrAmSicY59BDlqQ5mU1143vokkbvnRFHfxhY0Cu9qRFHqKweKA3rD6z8KLFIW +oCtDuSWQP3CpMyVtRRooOyfPqsMpQhvfO0zAMzRbQYi/aytlryjvsvXDqmbOe1bu +t8jLZ8HJnBoYuMTDSQPxYA5QzUbF83d597YV4Djbxy8ooAw/dyZ02SUS2jHaGh7c +KUGRIjxpp7sC8rZcJwOJ9Abqm+RyguOhCcHpABnTPtRwa7pxpqpYrvS76Wy274fM +m7v/OeZWYdMKp8RcTGB7BXcmer/YB1IsYvdwY9k5vG8cwnncdimvzsUsZAReiDZu +MdRAGmI0Nj81Aa6sY6A= +-----END CERTIFICATE-----'" +"DigiCert","VeriSign, Inc.","VeriSign Trust Network, (c) 1999 VeriSign, Inc. - For authorized use only","VeriSign Class 1 Public Primary Certification Authority - G3","008B5B75568454850B00CFAF3848CEB1A4","CBB5AF185E942A2402F9EACBC0ED5BB876EEA3C1223623D00447E4F3BA554B65","CE63AAADB196370A0323AF847C40E4909CE53F7793180D4893AC3EAEFF3C7972","1999.10.01","2036.07.16","RSA 2048 bits","SHA1WithRSA","Email","","","Not EV","https://bugzilla.mozilla.org/show_bug.cgi?id=490895","NSS 3.12.8","Firefox 3.6.12","","","","","http://www.digicert.com/","USA, Global","https://content.digicert.com/wp-content/uploads/2019/06/STN-CP-v.2.12-.pdf","https://content.digicert.com/wp-content/uploads/2019/06/STN-CPS-v3.13.pdf","https://bug1458024.bmoattachments.org/attachment.cgi?id=9123453","","","BDO International Limited","WebTrust","2020.01.29","'-----BEGIN CERTIFICATE----- +MIIEGjCCAwICEQCLW3VWhFSFCwDPrzhIzrGkMA0GCSqGSIb3DQEBBQUAMIHKMQsw +CQYDVQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZl +cmlTaWduIFRydXN0IE5ldHdvcmsxOjA4BgNVBAsTMShjKSAxOTk5IFZlcmlTaWdu +LCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxRTBDBgNVBAMTPFZlcmlT +aWduIENsYXNzIDEgUHVibGljIFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3Jp +dHkgLSBHMzAeFw05OTEwMDEwMDAwMDBaFw0zNjA3MTYyMzU5NTlaMIHKMQswCQYD +VQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZlcmlT +aWduIFRydXN0IE5ldHdvcmsxOjA4BgNVBAsTMShjKSAxOTk5IFZlcmlTaWduLCBJ +bmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxRTBDBgNVBAMTPFZlcmlTaWdu +IENsYXNzIDEgUHVibGljIFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkg +LSBHMzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAN2E1Lm0+afY8wR4 +nN493GwTFtl63SRRZsDHJlkNrAYIwpTRMx/wgzUfbhvI3qpuFU5UJ+/EbRrsC+MO +8ESlV8dAWB6jRx9x7GD2bZTIGDnt/kIYVt/kTEkQeE4BdjVjEjbdZrwBBDajVWjV +ojYJrKshJlQGrT/KFOCsyq0GHZXi+J3x4GD/wn91K0zM2v6HmSHquv4+VNfSWXjb +PG7PoBMAGrgnoeS+Z5bKoMWznN3JdZ7rMJpfo83ZrngZPyPpXNspva1VyBtUjGP2 +6KbqxzcSXKMpHgLZ2x87tNcPVkeBFQRKr4Mn0cVYiMHd9qqnoxjaaKptEVHhv2Vr +n5Z20T0CAwEAATANBgkqhkiG9w0BAQUFAAOCAQEAq2aN17O6x5q25lXQBfGfMY1a +qtmqRiYPce2lrVNWYgFHKkTp/j90CxObufRNG7LRX7K20ohcs5/Ny9Sn2WCVhDr4 +wTcdYcrnsMXlkdpUpqwxga6X3s0IrLjAl4B/bnKk52kTlWUfxJM8/XmPBNQ+T+r3 +ns7NZ3xPZQL/kYVUc8f/NveGLezQXk//EZ9yBta4GvFMDSZl4kSAHsef493oCtrs +pSCAaWihT37ha88HQfqDjrw43bAuEbFrskLMmrz5SCJ5ShkPshw+IHTZasO+8ih4 +E1Z5T21Q6huwtVexN2ZYI/PcD98Kh8TvhgXVOBRgmaNL3gaWcSzy27YfpO8/7g== +-----END CERTIFICATE-----'" +"DigiCert","VeriSign, Inc.","VeriSign Trust Network, (c) 1999 VeriSign, Inc. - For authorized use only","VeriSign Class 2 Public Primary Certification Authority - G3","6170CB498C5F984529E7B0A6D9505B7A","92A9D9833FE1944DB366E8BFAE7A95B6480C2D6C6C2A1BE65D4236B608FCA1BB","9F355C654B91AAAD690EC0FF5C06C2827F65B1D4DCBD17E1FC864568A274F3F8","1999.10.01","2036.07.16","RSA 2048 bits","SHA1WithRSA","Email","","","Not EV","https://bugzilla.mozilla.org/show_bug.cgi?id=490895","NSS 3.12.8","Firefox 3.6.12","","","","","http://www.digicert.com/","USA, Global","https://content.digicert.com/wp-content/uploads/2019/06/STN-CP-v.2.12-.pdf","https://content.digicert.com/wp-content/uploads/2019/06/STN-CPS-v3.13.pdf","https://bug1458024.bmoattachments.org/attachment.cgi?id=9123453","","","BDO International Limited","WebTrust","2020.01.29","'-----BEGIN CERTIFICATE----- +MIIEGTCCAwECEGFwy0mMX5hFKeewptlQW3owDQYJKoZIhvcNAQEFBQAwgcoxCzAJ +BgNVBAYTAlVTMRcwFQYDVQQKEw5WZXJpU2lnbiwgSW5jLjEfMB0GA1UECxMWVmVy +aVNpZ24gVHJ1c3QgTmV0d29yazE6MDgGA1UECxMxKGMpIDE5OTkgVmVyaVNpZ24s +IEluYy4gLSBGb3IgYXV0aG9yaXplZCB1c2Ugb25seTFFMEMGA1UEAxM8VmVyaVNp +Z24gQ2xhc3MgMiBQdWJsaWMgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0 +eSAtIEczMB4XDTk5MTAwMTAwMDAwMFoXDTM2MDcxNjIzNTk1OVowgcoxCzAJBgNV +BAYTAlVTMRcwFQYDVQQKEw5WZXJpU2lnbiwgSW5jLjEfMB0GA1UECxMWVmVyaVNp +Z24gVHJ1c3QgTmV0d29yazE6MDgGA1UECxMxKGMpIDE5OTkgVmVyaVNpZ24sIElu +Yy4gLSBGb3IgYXV0aG9yaXplZCB1c2Ugb25seTFFMEMGA1UEAxM8VmVyaVNpZ24g +Q2xhc3MgMiBQdWJsaWMgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAt +IEczMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEArwoNwtUs22e5LeWU +J92lvuCwTY+zYVY81nzD9M0+hsuiiOLh2KRpxbXiv8GmR1BeRjmL1Za6tW8UvxDO +JxOeBUebMXoT2B/Z0wI3i60sR/COgQanDTAM6/c8DyAd3HJG7qUCyFvDyVZpTMUY +wZF7C9UTAJu878NIPkZgIIUq1ZC2zYugzDLdt/1AVbJQHFauzI13TccgTacxdu9o +koqQHgiBVrKtaaNS0MscxCM9H5n+TOgWY47GCI72MfbS+uV23bUckqNJzc0BzWjN +qWm6o+sdDZykIKbBoMXRRkwXbdKsZj+WjOCE1Db/IlnF+RFgqF8EffIa9iVCYQ/E +Srg+iQIDAQABMA0GCSqGSIb3DQEBBQUAA4IBAQA0JhU8wI1NQ0kdvekhktdmnLfe +xbjQ5F1fdiLAJvmEOjr5jLX77GDx6M4EsMjdpwOPMPOY36TmpDHf0xwLRtxyID+u +7gU8pDM/CzmscHhzS5kr3zDCVLCoO1Wh/hYozUK9dG6A2ydEp85EXdQbkJgNHkKU +sQAsBNB0owIFImNjzYO1+8FtYmtpdf1dcEG59b98377BMnMiIYtYgXsVkXq642RI +sH/7NiXaldDxJBQX3RiAa0YjOVT1jmIJBB2UkKab5iXiQkWquJCtvgiPqQtCGJTP +cjnhsUPgKM+351psE2tJs//jGHyJizNdrDPXp/naOlXJWBD5qu9ats9LS98q +-----END CERTIFICATE-----'" +"DigiCert","VeriSign, Inc.","VeriSign Trust Network, (c) 2007 VeriSign, Inc. - For authorized use only","VeriSign Class 3 Public Primary Certification Authority - G4","2F80FE238C0E220F486712289187ACB3","69DDD7EA90BB57C93E135DC85EA6FCD5480B603239BDC454FC758B2A26CF7F79","9E492D60F68B82D42E8003C2387932E7B1180EF867B135BA4C0E7AAC15B5EC7D","2007.11.05","2038.01.18","EC secp384r1","ecdsaWithSHA384","Websites","","","2.16.840.1.113733.1.7.23.6","https://bugzilla.mozilla.org/show_bug.cgi?id=409235","NSS 3.12.6","Firefox 3.6.2","https://valid-root3.websecurity.symantec.com","https://expired-root3.websecurity.symantec.com","https://revoked-root3.websecurity.symantec.com","","http://www.digicert.com/","USA, Global","https://content.digicert.com/wp-content/uploads/2019/06/STN-CP-v.2.12-.pdf","https://content.digicert.com/wp-content/uploads/2019/06/STN-CPS-v3.13.pdf","https://bug1458024.bmoattachments.org/attachment.cgi?id=9123453","https://bug1458024.bmoattachments.org/attachment.cgi?id=9123452","https://bug1458024.bmoattachments.org/attachment.cgi?id=9123454","BDO International Limited","WebTrust","2020.01.29","'-----BEGIN CERTIFICATE----- +MIIDhDCCAwqgAwIBAgIQL4D+I4wOIg9IZxIokYesszAKBggqhkjOPQQDAzCByjEL +MAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQLExZW +ZXJpU2lnbiBUcnVzdCBOZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwNyBWZXJpU2ln +biwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MUUwQwYDVQQDEzxWZXJp +U2lnbiBDbGFzcyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9y +aXR5IC0gRzQwHhcNMDcxMTA1MDAwMDAwWhcNMzgwMTE4MjM1OTU5WjCByjELMAkG +A1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQLExZWZXJp +U2lnbiBUcnVzdCBOZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwNyBWZXJpU2lnbiwg +SW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MUUwQwYDVQQDEzxWZXJpU2ln +biBDbGFzcyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5 +IC0gRzQwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAASnVnp8Utpkmw4tXNherJI9/gHm +GUo9FANL+mAnINmDiWn6VMaaGF5VKmTeBvaNSjutEDxlPZCIBIngMGGzrl0Bp3ve +fLK+ymVhAIau2o970ImtTR1ZmkGxvEeA3J5iw/mjgbIwga8wDwYDVR0TAQH/BAUw +AwEB/zAOBgNVHQ8BAf8EBAMCAQYwbQYIKwYBBQUHAQwEYTBfoV2gWzBZMFcwVRYJ +aW1hZ2UvZ2lmMCEwHzAHBgUrDgMCGgQUj+XTGoasjY5rw8+AatRIGCx7GS4wJRYj +aHR0cDovL2xvZ28udmVyaXNpZ24uY29tL3ZzbG9nby5naWYwHQYDVR0OBBYEFLMW +kf3upm7ktS5Jj4d4gYDs5bG1MAoGCCqGSM49BAMDA2gAMGUCMGYhDBgmYFo4e1ZC +4Kf8NoRRkSAsdk1DPcQdhCPQrNZ8NQbOzWm9kA3bbEhCHQ6qQgIxAJw9SDkjOVga +FRJZap7v1VmyHVIsmXHNxynfGyphe3HR3vPA5Q06Sqotp9iGKt0uEA== +-----END CERTIFICATE-----'" +"DigiCert","VeriSign, Inc.","VeriSign Trust Network, (c) 2006 VeriSign, Inc. - For authorized use only","VeriSign Class 3 Public Primary Certification Authority - G5","18DAD19E267DE8BB4A2158CDCC6B3B4A","9ACFAB7E43C8D880D06B262A94DEEEE4B4659989C3D0CAF19BAF6405E41AB7DF","09E9E469F981C8F10C494D3B20822F41E8E1586A31405BC8561A8609AFAA24A1","2006.11.08","2036.07.16","RSA 2048 bits","SHA1WithRSA","Websites","","","2.16.840.1.113733.1.7.23.6","https://bugzilla.mozilla.org/show_bug.cgi?id=402947","NSS 3.11.10","Firefox 3.0.2","https://valid-root1.websecurity.symantec.com","https://expired-root1.websecurity.symantec.com","https://revoked-root1.websecurity.symantec.com","","http://www.digicert.com/","USA, Global","https://content.digicert.com/wp-content/uploads/2019/06/STN-CP-v.2.12-.pdf","https://content.digicert.com/wp-content/uploads/2019/06/STN-CPS-v3.13.pdf","https://bug1458024.bmoattachments.org/attachment.cgi?id=9123453","https://bug1458024.bmoattachments.org/attachment.cgi?id=9123452","https://bug1458024.bmoattachments.org/attachment.cgi?id=9123454","BDO International Limited","WebTrust","2020.01.29","'-----BEGIN CERTIFICATE----- +MIIE0zCCA7ugAwIBAgIQGNrRniZ96LtKIVjNzGs7SjANBgkqhkiG9w0BAQUFADCB +yjELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQL +ExZWZXJpU2lnbiBUcnVzdCBOZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwNiBWZXJp +U2lnbiwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MUUwQwYDVQQDEzxW +ZXJpU2lnbiBDbGFzcyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0 +aG9yaXR5IC0gRzUwHhcNMDYxMTA4MDAwMDAwWhcNMzYwNzE2MjM1OTU5WjCByjEL +MAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQLExZW +ZXJpU2lnbiBUcnVzdCBOZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwNiBWZXJpU2ln +biwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MUUwQwYDVQQDEzxWZXJp +U2lnbiBDbGFzcyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9y +aXR5IC0gRzUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCvJAgIKXo1 +nmAMqudLO07cfLw8RRy7K+D+KQL5VwijZIUVJ/XxrcgxiV0i6CqqpkKzj/i5Vbex +t0uz/o9+B1fs70PbZmIVYc9gDaTY3vjgw2IIPVQT60nKWVSFJuUrjxuf6/WhkcIz +SdhDY2pSS9KP6HBRTdGJaXvHcPaz3BJ023tdS1bTlr8Vd6Gw9KIl8q8ckmcY5fQG +BO+QueQA5N06tRn/Arr0PO7gi+s3i+z016zy9vA9r911kTMZHRxAy3QkGSGT2RT+ +rCpSx4/VBEnkjWNHiDxpg8v+R70rfk/Fla4OndTRQ8Bnc+MUCH7lP59zuDMKz10/ +NIeWiu5T6CUVAgMBAAGjgbIwga8wDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8E +BAMCAQYwbQYIKwYBBQUHAQwEYTBfoV2gWzBZMFcwVRYJaW1hZ2UvZ2lmMCEwHzAH +BgUrDgMCGgQUj+XTGoasjY5rw8+AatRIGCx7GS4wJRYjaHR0cDovL2xvZ28udmVy +aXNpZ24uY29tL3ZzbG9nby5naWYwHQYDVR0OBBYEFH/TZafC3ey78DAJ80M5+gKv +MzEzMA0GCSqGSIb3DQEBBQUAA4IBAQCTJEowX2LP2BqYLz3q3JktvXf2pXkiOOzE +p6B4Eq1iDkVwZMXnl2YtmAl+X6/WzChl8gGqCBpH3vn5fJJaCGkgDdk+bW48DW7Y +5gaRQBi5+MHt39tBquCWIMnNZBU4gcmU7qKEKQsTb47bDN0lAtukixlE0kF6BWlK +WE9gyn6CagsCqiUXObXbf+eEZSqVir2G3l6BFoMtEMze/aiCKm0oHw0LxOXnGiYZ +4fQRbxC1lfznQgUy286dUV4otp6F01vvpX1FQHKOtw5rDgb7MzVIcbidJ4vEZV8N +hnacRHr2lVz2XTIIM6RUthg/aFzyQkqFOFSDX9HoLPKsEdao7WNq +-----END CERTIFICATE-----'" +"DigiCert","VeriSign, Inc.","VeriSign Trust Network, (c) 2008 VeriSign, Inc. - For authorized use only","VeriSign Universal Root Certification Authority","401AC46421B31321030EBBE4121AC51D","2399561127A57125DE8CEFEA610DDF2FA078B5C8067F4E828290BFB860E84B3C","95CFF1062FF431C179C0D5BF1D2E09A9C551EA17CC85960CE8D13F57485191B2","2008.04.02","2037.12.01","RSA 2048 bits","SHA256WithRSA","Websites;Email","","","2.16.840.1.113733.1.7.23.6","https://bugzilla.mozilla.org/show_bug.cgi?id=484901","NSS 3.12.5","Firefox 3.6","https://valid-root2.websecurity.symantec.com/","https://expired-root2.websecurity.symantec.com/","https://revoked-root2.websecurity.symantec.com/","","http://www.digicert.com/","USA, Global","https://content.digicert.com/wp-content/uploads/2019/06/STN-CP-v.2.12-.pdf","https://content.digicert.com/wp-content/uploads/2019/06/STN-CPS-v3.13.pdf","https://bug1458024.bmoattachments.org/attachment.cgi?id=9123453","https://bug1458024.bmoattachments.org/attachment.cgi?id=9123452","https://bug1458024.bmoattachments.org/attachment.cgi?id=9123454","BDO International Limited","WebTrust","2020.01.29","'-----BEGIN CERTIFICATE----- +MIIEuTCCA6GgAwIBAgIQQBrEZCGzEyEDDrvkEhrFHTANBgkqhkiG9w0BAQsFADCB +vTELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQL +ExZWZXJpU2lnbiBUcnVzdCBOZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwOCBWZXJp +U2lnbiwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MTgwNgYDVQQDEy9W +ZXJpU2lnbiBVbml2ZXJzYWwgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAe +Fw0wODA0MDIwMDAwMDBaFw0zNzEyMDEyMzU5NTlaMIG9MQswCQYDVQQGEwJVUzEX +MBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZlcmlTaWduIFRydXN0 +IE5ldHdvcmsxOjA4BgNVBAsTMShjKSAyMDA4IFZlcmlTaWduLCBJbmMuIC0gRm9y +IGF1dGhvcml6ZWQgdXNlIG9ubHkxODA2BgNVBAMTL1ZlcmlTaWduIFVuaXZlcnNh +bCBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIIBIjANBgkqhkiG9w0BAQEF +AAOCAQ8AMIIBCgKCAQEAx2E3XrEBNNti1xWb/1hajCMj1mCOkdeQmIN65lgZOIzF +9uVkhbSicfvtvbnazU0AtMgtc6XHaXGVHzk8skQHnOgO+k1KxCHfKWGPMiJhgsWH +H26MfF8WIFFE0XBPV+rjHOPMee5Y2A7Cs0WTwCznmhcrewA3ekEzeOEz4vMQGn+H +LL729fdC4uW/h2KJXwBL38Xd5HVEMkE6HnFuacsLdUYI0crSK5XQz/u5QGtkjFdN +/BMReYTtXlT2NJ8IAfMQJQYXStrxHXpma5hgZqTZ79IugvHw7wnqRMkVauIDbjPT +rJ9VAMf2CGqUuV/c4DPxhGD5WycRtPwW8rtWaoAljQIDAQABo4GyMIGvMA8GA1Ud +EwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMG0GCCsGAQUFBwEMBGEwX6FdoFsw +WTBXMFUWCWltYWdlL2dpZjAhMB8wBwYFKw4DAhoEFI/l0xqGrI2Oa8PPgGrUSBgs +exkuMCUWI2h0dHA6Ly9sb2dvLnZlcmlzaWduLmNvbS92c2xvZ28uZ2lmMB0GA1Ud +DgQWBBS2d/ppSEefUxLVwuoHMnYH0ZcHGTANBgkqhkiG9w0BAQsFAAOCAQEASvj4 +sAPmLGd75JR3Y8xuTPl9Dg3cyLk1uXBPY/ok+myDjEedO2Pzmvl2MpWRsXe8rJq+ +seQxIcaBlVZaDrHC1LGmWazxY8u4TB1ZkErvkBYoH1quEPuBUDgMbMzxPcP1Y+Oz +4yHJJDnp/RVmRvQbEdBNc6N9Rvk97ahfYtTxP/jgdFcrGJ2BtMQo2pSXpXDrrB2+ +BxHw1dvd5Yzw1TKwg+ZX4o+/vqGqvz0dtdQ46tewXDpPaj+PwGZsY6rp2aQW9IHR +lRQOfc2VNNnSj3BzgXucfr2YYdhFh5iQxeuGMMY1v/D/w1WIg0vvBZIGcfK4mJO3 +7M2CYfE45k+XmCpajQ== +-----END CERTIFICATE-----'" +"Disig, a.s.","Disig a.s.","","CA Disig Root R2","0092B888DBB08AC163","E23D4A036D7B70E9F595B1422079D2B91EDFBB1FB651A0633EAA8A9DC5F80703","F6204B87DF263B5B9C82AA5A9912D511CB870C4B46E25DE1CCAB16FF4FBD6ECC","2012.07.19","2042.07.19","RSA 4096 bits","SHA256WithRSA","Websites;Email","","","Not EV","https://bugzilla.mozilla.org/show_bug.cgi?id=792377","NSS 3.15","Firefox 23","https://testssl-valid-r2i2.disig.sk/","https://testssl-expire-r2i2.disig.sk/","https://testssl-revoked-r2i2.disig.sk/","","https://eidas.disig.sk/en/cacert/","Slovak Republic","https://eidas.disig.sk/pdf/cp-disig-en.pdf","https://eidas.disig.sk/pdf/cps_ra_cadisig_en.pdf","https://www.qscert.sk/buxus/docs//sk/vzory_certifikatov/ETSI_2020.pdf","https://www.qscert.sk/buxus/docs//sk/vzory_certifikatov/ETSI_2020.pdf","","QSCert","ETSI EN 319 411","2020.06.10","'-----BEGIN CERTIFICATE----- +MIIFaTCCA1GgAwIBAgIJAJK4iNuwisFjMA0GCSqGSIb3DQEBCwUAMFIxCzAJBgNV +BAYTAlNLMRMwEQYDVQQHEwpCcmF0aXNsYXZhMRMwEQYDVQQKEwpEaXNpZyBhLnMu +MRkwFwYDVQQDExBDQSBEaXNpZyBSb290IFIyMB4XDTEyMDcxOTA5MTUzMFoXDTQy +MDcxOTA5MTUzMFowUjELMAkGA1UEBhMCU0sxEzARBgNVBAcTCkJyYXRpc2xhdmEx +EzARBgNVBAoTCkRpc2lnIGEucy4xGTAXBgNVBAMTEENBIERpc2lnIFJvb3QgUjIw +ggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCio8QACdaFXS1tFPbCw3Oe +NcJxVX6B+6tGUODBfEl45qt5WDza/3wcn9iXAng+a0EE6UG9vgMsRfYvZNSrXaNH +PWSb6WiaxswbP7q+sos0Ai6YVRn8jG+qX9pMzk0DIaPY0jSTVpbLTAwAFjxfGs3I +x2ymrdMxp7zo5eFm1tL7A7RBZckQrg4FY8aAamkw/dLukO8NJ9+flXP04SXabBbe +QTg06ov80egEFGEtQX6sx3dOy1FU+16SGBsEWmjGycT6txOgmLcRK7fWV8x8nhfR +yyX+hk4kLlYMeE2eARKmK6cBZW58Yh2EhN/qwGu1pSqVg8NTEQxzHQuyRpDRQjrO +QG6Vrf/GlK1ul4SOfW+eioANSW1z4nuSHsPzwfPrLgVv2RvPN3YEyLRa5Beny912 +H9AZdugsBbPWnDTYltxhh5EF5EQIM8HauQhl1K6yNg3ruji6DOWbnuuNZt2Zz9aJ +QfYEkoopKW1rOhzndX0CcQ7zwOe9yxndnWCywmZgtrEE7snmhrmaZkCo5xHtgUUD +i/ZnWejBBhG93c+AAk9lQHhcR1DIm+YfgXvkRKhbhZri3lrVx/k6RGZL5DJUfORs +nLMOPReisjQS1n6yqEm70XooQL6iFh/f5DcfEXP7kAplQ6INfPgGAVUzfbANuPT1 +rqVCV3w2EYx7XsQDnYx5nQIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1Ud +DwEB/wQEAwIBBjAdBgNVHQ4EFgQUtZn4r7CU9eMg1gqtzk5WpC5uQu0wDQYJKoZI +hvcNAQELBQADggIBACYGXnDnZTPIgm7ZnBc6G3pmsgH2eDtpXi/q/075KMOYKmFM +tCQSin1tERT3nLXK5ryeJ45MGcipvXrA1zYObYVybqjGom32+nNjf7xueQgcnYqf +GopTpti72TVVsRHFqQOzVju5hJMiXn7B9hJSi+osZ7z+Nkz1uM/Rs0mSO9MpDpkb +lvdhuDvEK7Z4bLQjb/D907JedR+Zlais9trhxTF7+9FGs9K8Z7RiVLoJ92Owk6Ka ++elSLotgEqv89WBW7xBci8QaQtyDW2QOy7W81k/BfDxujRNt+3vrMNDcTa/F1bal +TFtxyegxvug4BkihGuLq0t4SOVga/4AOgnXmt8kHbA7v/zjxmHHEt38OFdAlab0i +nSvtBfZGR6ztwPDUO+Ls7pZbkBNOHlY667DvlruWIxG68kOGdGSVyCh13x01utI3 +gzhTODY7z2zp+WsO0PsE6E9312UBeIYMej4hYvF/Y3EMyZ9E26gnonW+boE+18Dr +G5gPcFw0sorMwIUY6256s/daoQe/qUKS82Ail+QUoQebTnbAjn39pCXHR+3/H3Os +zMOl6W8KjptlwlCFtaOgUxLMVYdh84GuEEZhvUQhuMI9dM9+JDX6HAcOmz0iyu8x +L4ysEr3vQCj8KWefshNPZiTEUxnpHikV7+ZtsH8tZ/3zbBt1RqPlShfppNcL +-----END CERTIFICATE-----'" +"E-Tugra","E-Tuğra EBG Bilişim Teknolojileri ve Hizmetleri A.Ş.","E-Tugra Sertifikasyon Merkezi","E-Tugra Certification Authority","6A683E9C519BCB53","B0BFD52BB0D7D9BD92BF5D4DC13DA255C02C542F378365EA893911F55E55F23C","E74F96BD9C3ECBDF0FE0D56969BE3B56A6130795A4F3402AC993951674D4621A","2013.03.05","2023.03.03","RSA 4096 bits","SHA256WithRSA","Websites","","","2.16.792.3.0.4.1.1.4","https://bugzilla.mozilla.org/show_bug.cgi?id=877744","NSS 3.16","Firefox 29","https://evvalid.e-tugra.com.tr/","https://sslev.e-tugra.com.tr/","https://evrevoked.e-tugra.com.tr/","","http://www.etugra.com.tr/","Turkey","https://www.e-tugra.com.tr/portals/6/Documents/E-Tugra_SI_v4.5_EN.pdf","https://www.e-tugra.com.tr/portals/6/Documents/E-Tugra_SUE_v4.5_EN.pdf","https://lsti-certification.fr/images/LSTI_1646_135_AL-V10_E-Tugra.pdf","https://lsti-certification.fr/images/LSTI_1646_135_AL-V10_E-Tugra.pdf","https://lsti-certification.fr/images/LSTI_1646_135_AL-V10_E-Tugra.pdf","LSTI","ETSI EN 319 411","2019.10.18","'-----BEGIN CERTIFICATE----- +MIIGSzCCBDOgAwIBAgIIamg+nFGby1MwDQYJKoZIhvcNAQELBQAwgbIxCzAJBgNV +BAYTAlRSMQ8wDQYDVQQHDAZBbmthcmExQDA+BgNVBAoMN0UtVHXEn3JhIEVCRyBC +aWxpxZ9pbSBUZWtub2xvamlsZXJpIHZlIEhpem1ldGxlcmkgQS7Fni4xJjAkBgNV +BAsMHUUtVHVncmEgU2VydGlmaWthc3lvbiBNZXJrZXppMSgwJgYDVQQDDB9FLVR1 +Z3JhIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTEzMDMwNTEyMDk0OFoXDTIz +MDMwMzEyMDk0OFowgbIxCzAJBgNVBAYTAlRSMQ8wDQYDVQQHDAZBbmthcmExQDA+ +BgNVBAoMN0UtVHXEn3JhIEVCRyBCaWxpxZ9pbSBUZWtub2xvamlsZXJpIHZlIEhp +em1ldGxlcmkgQS7Fni4xJjAkBgNVBAsMHUUtVHVncmEgU2VydGlmaWthc3lvbiBN +ZXJrZXppMSgwJgYDVQQDDB9FLVR1Z3JhIENlcnRpZmljYXRpb24gQXV0aG9yaXR5 +MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA4vU/kwVRHoViVF56C/UY +B4Oufq9899SKa6VjQzm5S/fDxmSJPZQuVIBSOTkHS0vdhQd2h8y/L5VMzH2nPbxH +D5hw+IyFHnSOkm0bQNGZDbt1bsipa5rAhDGvykPL6ys06I+XawGb1Q5KCKpbknSF +Q9OArqGIW66z6l7LFpp3RMih9lRozt6Plyu6W0ACDGQXwLWTzeHxE2bODHnv0ZEo +q1+gElIwcxmOj+GMB6LDu0rw6h8VqO4lzKRG+Bsi77MOQ7osJLjFLFzUHPhdZL3D +k14opz8n8Y4e0ypQBaNV2cvnOVPAmJ6MVGKLJrD3fY185MaeZkJVgkfnsliNZvcH +fC425lAcP9tDJMW/hkd5s3kc91r0E+xs+D/iWR+V7kI+ua2oMoVJl0b+SzGPWsut +dEcf6ZG33ygEIqDUD13ieU/qbIWGvaimzuT6w+Gzrt48Ue7LE3wBf4QOXVGUnhMM +ti6lTPk5cDZvlsouDERVxcr6XQKj39ZkjFqzAQqptQpHF//vkUAqjqFGOjGY5RH8 +zLtJVor8udBhmm9lbObDyz51Sf6Pp+KJxWfXnUYTTjF2OySznhFlhqt/7x3U+Lzn +rFpct1pHXFXOVbQicVtbC/DP3KBhZOqp12gKY6fgDT+gr9Oq0n7vUaDmUStVkhUX +U8u3Zg5mTPj5dUyQ5xJwx0UCAwEAAaNjMGEwHQYDVR0OBBYEFC7j27JJ0JxUeVz6 +Jyr+zE7S6E5UMA8GA1UdEwEB/wQFMAMBAf8wHwYDVR0jBBgwFoAULuPbsknQnFR5 +XPonKv7MTtLoTlQwDgYDVR0PAQH/BAQDAgEGMA0GCSqGSIb3DQEBCwUAA4ICAQAF +Nzr0TbdF4kV1JI+2d1LoHNgQk2Xz8lkGpD4eKexd0dCrfOAKkEh47U6YA5n+KGCR +HTAduGN8qOY1tfrTYXbm1gdLymmasoR6d5NFFxWfJNCYExL/u6Au/U5Mh/jOXKqY +GwXgAEZKgoClM4so3O0409/lPun++1ndYYRP0lSWE2ETPo+Aab6TR7U1Q9Jauz1c +77NCR807VRMGsAnb/WP2OogKmW9+4c4bU2pEZiNRCHu8W1Ki/QY3OEBhj0qWuJA3 ++GbHeJAAFS6LrVE1Uweoa2iu+U48BybNCAVwzDk/dr2l02cmAYamU9JgO3xDf1WK +vJUawSg5TB9D0pH0clmKuVb8P7Sd2nCcdlqMQ1DujjByTd//SffGqWfZbawCEeI6 +FiWnWAjLb1NBnEg4R2gz0dfHj9R0IdTDBZB6/86WiLEVKV0jq9BgoRJP3vQXzTLl +yb/IQ639Lo7xr+L0mPoSHyDYwKcMhcWQ9DstliaxLL5Mq+ux0orJ23gTDx4JnW2P +AJ8C2sH6H3p6CcRK5ogql5+Ji/03X186zjhZhkuvcQu02PJwT58yE+Owp1fl2tpD +y4Q08ijE6m30Ku/Ba3ba+367hTzSU8JNvnHhRdH9I2cNE3X7z2VnIp2usAnRCf8d +NL/+I5c30jn6PQ0GC7TbO6Orb1wdtn7os4I07QZcJA== +-----END CERTIFICATE-----'" +"eMudhra Technologies Limited","eMudhra Inc","emSign PKI","emSign ECC Root CA - C3","7B71B68256B8127C9CA8","BC4D809B15189D78DB3E1D8CF4F9726A795DA1643CA5F1358E1DDB0EDC0D7EB3","7787DB2349664D6D38541977225C6CA7429024291F2CAAD5BE9393D26300A04C","2018.02.18","2043.02.18","EC secp384r1","ecdsaWithSHA384","Websites;Email","","","2.23.140.1.1","https://bugzilla.mozilla.org/show_bug.cgi?id=1442337","NSS 3.43","Firefox 67","https://testevc3.emsign.com","https://testevc3e.emsign.com","https://testevc3r.emsign.com","","https://www.emudhra.com/","India, Global","","https://repository.emsign.com/cps/CP-CPS-v1.05.pdf","https://www.cpacanada.ca/generichandlers/CPACHandler.ashx?attachmentid=234195","https://www.cpacanada.ca/generichandlers/CPACHandler.ashx?attachmentid=234196","https://www.cpacanada.ca/generichandlers/CPACHandler.ashx?attachmentid=234204","BDO International Limited","WebTrust","2019.07.26","'-----BEGIN CERTIFICATE----- +MIICKzCCAbGgAwIBAgIKe3G2gla4EnycqDAKBggqhkjOPQQDAzBaMQswCQYDVQQG +EwJVUzETMBEGA1UECxMKZW1TaWduIFBLSTEUMBIGA1UEChMLZU11ZGhyYSBJbmMx +IDAeBgNVBAMTF2VtU2lnbiBFQ0MgUm9vdCBDQSAtIEMzMB4XDTE4MDIxODE4MzAw +MFoXDTQzMDIxODE4MzAwMFowWjELMAkGA1UEBhMCVVMxEzARBgNVBAsTCmVtU2ln +biBQS0kxFDASBgNVBAoTC2VNdWRocmEgSW5jMSAwHgYDVQQDExdlbVNpZ24gRUND +IFJvb3QgQ0EgLSBDMzB2MBAGByqGSM49AgEGBSuBBAAiA2IABP2lYa57JhAd6bci +MK4G9IGzsUJxlTm801Ljr6/58pc1kjZGDoeVjbk5Wum739D+yAdBPLtVb4Ojavti +sIGJAnB9SMVK4+kiVCJNk7tCDK93nCOmfddhEc5lx/h//vXyqaNCMEAwHQYDVR0O +BBYEFPtaSNCAIEDyqOkAB2kZd6fmw/TPMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMB +Af8EBTADAQH/MAoGCCqGSM49BAMDA2gAMGUCMQC02C8Cif22TGK6Q04ThHK1rt0c +3ta13FaPWEBaLd4gTCKDypOofu4SQMfWh0/434UCMBwUZOR8loMRnLDRWmFLpg9J +0wD8ofzkpf9/rdcw0Md3f76BB1UwUCAU9Vc4CqgxUQ== +-----END CERTIFICATE-----'" +"eMudhra Technologies Limited","eMudhra Technologies Limited","emSign PKI","emSign ECC Root CA - G3","3CF607A968700EDA8B84","86A1ECBA089C4A8D3BBE2734C612BA341D813E043CF9E8A862CD5C57A36BBE6B","98AD944FA2A5BB2DDDB76050690D9ACFFA4AF0A9684FAB3C1ACC3E5E9CE58425","2018.02.18","2043.02.18","EC secp384r1","ecdsaWithSHA384","Websites;Email","","","2.23.140.1.1","https://bugzilla.mozilla.org/show_bug.cgi?id=1442337","NSS 3.43","Firefox 67","https://testevg3.emsign.com","https://testevg3e.emsign.com","https://testevg3r.emsign.com","","https://www.emudhra.com/","India, Global","","https://repository.emsign.com/cps/CP-CPS-v1.05.pdf","https://www.cpacanada.ca/generichandlers/CPACHandler.ashx?attachmentid=234195","https://www.cpacanada.ca/generichandlers/CPACHandler.ashx?attachmentid=234196","https://www.cpacanada.ca/generichandlers/CPACHandler.ashx?attachmentid=234204","BDO International Limited","WebTrust","2019.07.26","'-----BEGIN CERTIFICATE----- +MIICTjCCAdOgAwIBAgIKPPYHqWhwDtqLhDAKBggqhkjOPQQDAzBrMQswCQYDVQQG +EwJJTjETMBEGA1UECxMKZW1TaWduIFBLSTElMCMGA1UEChMcZU11ZGhyYSBUZWNo +bm9sb2dpZXMgTGltaXRlZDEgMB4GA1UEAxMXZW1TaWduIEVDQyBSb290IENBIC0g +RzMwHhcNMTgwMjE4MTgzMDAwWhcNNDMwMjE4MTgzMDAwWjBrMQswCQYDVQQGEwJJ +TjETMBEGA1UECxMKZW1TaWduIFBLSTElMCMGA1UEChMcZU11ZGhyYSBUZWNobm9s +b2dpZXMgTGltaXRlZDEgMB4GA1UEAxMXZW1TaWduIEVDQyBSb290IENBIC0gRzMw +djAQBgcqhkjOPQIBBgUrgQQAIgNiAAQjpQy4LRL1KPOxst3iAhKAnjlfSU2fySU0 +WXTsuwYc58Byr+iuL+FBVIcUqEqy6HyC5ltqtdyzdc6LBtCGI79G1Y4PPwT01xyS +fvalY8L1X44uT6EYGQIrMgqCZH0Wk9GjQjBAMB0GA1UdDgQWBBR8XQKEE9TMipuB +zhccLikenEhjQjAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAKBggq +hkjOPQQDAwNpADBmAjEAvvNhzwIQHWSVB7gYboiFBS+DCBeQyh+KTOgNG3qxrdWB +CUfvO6wIBHxcmbHtRwfSAjEAnbpV/KlK6O3t5nYBQnvI+GDZjVGLVTv7jHvrZQnD ++JbNR6iC8hZVdyR+EhCVBCyj +-----END CERTIFICATE-----'" +"eMudhra Technologies Limited","eMudhra Inc","emSign PKI","emSign Root CA - C1","00AECF00BAC4CF32F843B2","125609AA301DA0A249B97A8239CB6A34216F44DCAC9F3954B14292F2E8C8608F","CCB6CDFECF7DE18D1BD25E88950D436C85195A9176507BBF69883865BDA5360B","2018.02.18","2043.02.18","RSA 2048 bits","SHA256WithRSA","Websites;Email","","","2.23.140.1.1","https://bugzilla.mozilla.org/show_bug.cgi?id=1442337","NSS 3.43","Firefox 67","https://testevc1.emsign.com","https://testevc1e.emsign.com","https://testevc1r.emsign.com","","https://www.emudhra.com/","India, Global","","https://repository.emsign.com/cps/CP-CPS-v1.05.pdf","https://www.cpacanada.ca/generichandlers/CPACHandler.ashx?attachmentid=234195","https://www.cpacanada.ca/generichandlers/CPACHandler.ashx?attachmentid=234196","https://www.cpacanada.ca/generichandlers/CPACHandler.ashx?attachmentid=234204","BDO International Limited","WebTrust","2019.07.26","'-----BEGIN CERTIFICATE----- +MIIDczCCAlugAwIBAgILAK7PALrEzzL4Q7IwDQYJKoZIhvcNAQELBQAwVjELMAkG +A1UEBhMCVVMxEzARBgNVBAsTCmVtU2lnbiBQS0kxFDASBgNVBAoTC2VNdWRocmEg +SW5jMRwwGgYDVQQDExNlbVNpZ24gUm9vdCBDQSAtIEMxMB4XDTE4MDIxODE4MzAw +MFoXDTQzMDIxODE4MzAwMFowVjELMAkGA1UEBhMCVVMxEzARBgNVBAsTCmVtU2ln +biBQS0kxFDASBgNVBAoTC2VNdWRocmEgSW5jMRwwGgYDVQQDExNlbVNpZ24gUm9v +dCBDQSAtIEMxMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAz+upufGZ +BczYKCFK83M0UYRWEPWgTywS4/oTmifQz/l5GnRfHXk5/Fv4cI7gklL35CX5VIPZ +HdPIWoU/Xse2B+4+wM6ar6xWQio5JXDWv7V7Nq2s9nPczdcdioOl+yuQFTdrHCZH +3DspVpNqs8FqOp099cGXOFgFixwR4+S0uF2FHYP+eF8LRWgYSKVGczQ7/g/IdrvH +GPMF0Ybzhe3nudkyrVWIzqa2kbBPrH4VI5b2P/AgNBbeCsbEBEV5f6f9vtKppa+c +xSMq9zwhbL2vj07FOrLzNBL834AaSaTUqZX3noleoomslMuoaJuvimUnzYnu3Yy1 +aylwQ6BpC+S5DwIDAQABo0IwQDAdBgNVHQ4EFgQU/qHgcB4qAzlSWkK+XJGFehiq +TbUwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEL +BQADggEBAMJKVvoVIXsoounlHfv4LcQ5lkFMOycsxGwYFYDGrK9HWS8mC+M2sO87 +/kOXSTKZEhVb3xEp/6tT+LvBeA+snFOvV71ojD1pM/CjoCNjO2RnIkSt1XHLVip4 +kqNPEjE2NuLe/gDEo2APJ62gsIq1NnpSob0n9CAnYuhNlCQT5AoE6TyrLshDCUrG +YQTlSTR+08TI9Q/Aqum6VF7zYytPT1DU/rl7mYw9wC68AivTxEDkigcxHpvOJpkT ++xHqmiIMERnHXhuBUDDIlhJu58tBf5E7oke3VIAb3ADMmpDqw8NQBmIMMMAVSKeo +WXzhriKi4gp6D/piq1JM4fHfyr6DDUI= +-----END CERTIFICATE-----'" +"eMudhra Technologies Limited","eMudhra Technologies Limited","emSign PKI","emSign Root CA - G1","31F5E4620C6C58EDD6D8","40F6AF0346A99AA1CD1D555A4E9CCE62C7F9634603EE406615833DC8C8D00367","2F5F7B65D92C06EFD67801DDEE03FF143B82F11236946842DA74052246B02530","2018.02.18","2043.02.18","RSA 2048 bits","SHA256WithRSA","Websites;Email","","","2.23.140.1.1","https://bugzilla.mozilla.org/show_bug.cgi?id=1442337","NSS 3.43","Firefox 67","https://testevg1.emSign.com","https://testevg1e.emsign.com","https://testevg1r.emsign.com","","https://www.emudhra.com/","India, Global","","https://repository.emsign.com/cps/CP-CPS-v1.05.pdf","https://www.cpacanada.ca/generichandlers/CPACHandler.ashx?attachmentid=234195","https://www.cpacanada.ca/generichandlers/CPACHandler.ashx?attachmentid=234196","https://www.cpacanada.ca/generichandlers/CPACHandler.ashx?attachmentid=234204","BDO International Limited","WebTrust","2019.07.26","'-----BEGIN CERTIFICATE----- +MIIDlDCCAnygAwIBAgIKMfXkYgxsWO3W2DANBgkqhkiG9w0BAQsFADBnMQswCQYD +VQQGEwJJTjETMBEGA1UECxMKZW1TaWduIFBLSTElMCMGA1UEChMcZU11ZGhyYSBU +ZWNobm9sb2dpZXMgTGltaXRlZDEcMBoGA1UEAxMTZW1TaWduIFJvb3QgQ0EgLSBH +MTAeFw0xODAyMTgxODMwMDBaFw00MzAyMTgxODMwMDBaMGcxCzAJBgNVBAYTAklO +MRMwEQYDVQQLEwplbVNpZ24gUEtJMSUwIwYDVQQKExxlTXVkaHJhIFRlY2hub2xv +Z2llcyBMaW1pdGVkMRwwGgYDVQQDExNlbVNpZ24gUm9vdCBDQSAtIEcxMIIBIjAN +BgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAk0u76WaK7p1b1TST0Bsew+eeuGQz +f2N4aLTNLnF115sgxk0pvLZoYIr3IZpWNVrzdr3YzZr/k1ZLpVkGoZM0Kd0WNHVO +8oG0x5ZOrRkVUkr+PHB1cM2vK6sVmjM8qrOLqs1D/fXqcP/tzxE7lM5OMhbTI0Aq +d7OvPAEsbO2ZLIvZTmmYsvePQbAyeGHWDV/D+qJAkh1cF+ZwPjXnorfCYuKrpDhM +tTk1b+oDafo6VGiFbdbyL0NVHpENDtjVaqSW0RM8LHhQ6DqS0hdW5TUaQBw+jSzt +Od9C4INBdN+jzcKGYEho42kLVACL5HZpIQ15TjQIXhTCzLG3rdd8cIrHhQIDAQAB +o0IwQDAdBgNVHQ4EFgQU++8Nhp6w492pufEhF38+/PB3KxowDgYDVR0PAQH/BAQD +AgEGMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEBAFn/8oz1h31x +PaOfG1vR2vjTnGs2vZupYeveFix0PZ7mddrXuqe8QhfnPZHr5X3dPpzxz5KsbEjM +wiI/aTvFthUvozXGaCocV685743QNcMYDHsAVhzNixl03r4PEuDQqqE/AjSxcM6d +GNYIAwlG7mDgfrbESQRRfXBgvKqy/3lyeqYdPV8q+Mri/Tm3R7nrft8EI6/6nAYH +6ftjk4BAtcZsCjEozgyfz7MjNYBBjWzEN3uBL4ChQEKF6dk4jeihU80Bv2noWgby +RQuQ+q7hv53yrlc8pa6yVvSLZUDp/TGBLPQ5Cdjua6e0ph0VpZj3AYHYhX3zUVxx +iN66zB+Afko= +-----END CERTIFICATE-----'" +"Entrust","AffirmTrust","","AffirmTrust Commercial","7777062726A9B17C","0376AB1D54C5F9803CE4B2E201A0EE7EEF7B57B636E8A93C9B8D4860C96F5FA7","866456F052487489EE02750771E07C0F1422AC5AC30CCC3ADB9C1B4CCF34BB02","2010.01.29","2030.12.31","RSA 2048 bits","SHA256WithRSA","Websites","","","1.3.6.1.4.1.34697.2.1","https://bugzilla.mozilla.org/show_bug.cgi?id=543639","NSS 3.12.10","Firefox 6.0","https://validcommercial.affirmtrust.com/","https://expiredcommercial.affirmtrust.com/","https://revokedcommercial.affirmtrust.com/","","http://www.entrust.net/","North America, Global","","https://www.affirmtrust.com/wp-content/uploads/AffirmTrust-SSL-CPS-3.8.pdf","https://www.cpacanada.ca/generichandlers/CPACHandler.ashx?attachmentid=239755","https://www.affirmtrust.com/wp-content/uploads/2020-AFT-BR-NetSec-Report.pdf","https://www.cpacanada.ca/generichandlers/CPACHandler.ashx?attachmentid=239755","Deloitte","WebTrust","2020.04.17","'-----BEGIN CERTIFICATE----- +MIIDTDCCAjSgAwIBAgIId3cGJyapsXwwDQYJKoZIhvcNAQELBQAwRDELMAkGA1UE +BhMCVVMxFDASBgNVBAoMC0FmZmlybVRydXN0MR8wHQYDVQQDDBZBZmZpcm1UcnVz +dCBDb21tZXJjaWFsMB4XDTEwMDEyOTE0MDYwNloXDTMwMTIzMTE0MDYwNlowRDEL +MAkGA1UEBhMCVVMxFDASBgNVBAoMC0FmZmlybVRydXN0MR8wHQYDVQQDDBZBZmZp +cm1UcnVzdCBDb21tZXJjaWFsMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC +AQEA9htPZwcroRX1BiLLHwGy43NFBkRJLLtJJRTWzsO3qyxPxkEylFf6EqdbDuKP +Hx6GGaeqtS25Xw2Kwq+FNXkyLbscYjfysVtKPcrNcV/pQr6U6Mje+SJIZMblq8Yr +ba0F8PrVC8+a5fBQpIs7R6UjW3p6+DM/uO+Zl+MgwdYoic+U+7lF7eNAFxHUdPAL +MeIrJmqbTFeurCA+ukV6BfO9m2kVrn1OIGPENXY6BwLJN/3HR+7o8XYdcxXyl6S1 +yHp52UKqK39c/s4mT6NmgTWvRLpUHhwwMmWd5jyTXlBOeuM61G7MGvv50jeuJCqr +VwMiKA1JdX+3KNp1v47j3A55MQIDAQABo0IwQDAdBgNVHQ4EFgQUnZPGU4teyq8/ +nx4P5ZmVvCT2lI8wDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwDQYJ +KoZIhvcNAQELBQADggEBAFis9AQOzcAN/wr91LoWXym9e2iZWEnStB03TX8nfUYG +XUPGhi4+c7ImfU+TqbbEKpqrIZcUsd6M06uJFdhrJNTxFq7YpFzUf1GO7RgBsZNj +vbz4YYCanrHOQnDiqX0GJX0nof5v7LMeJNrjS1UaADs1tDvZ110w/YETifLCBivt +Z8SOyUOyXGsViQK8YvxO8rUzqrJv0wqiUOP2O+guRMLbZjipM1ZI8W0bM40NjD9g +N53Tym1+NH4Nn3J2ixufcv1SNUFFApYvHLKac0khsUlHRUe072o0EclNmsxZt9YC +nlpOZbWUrhvfKbAW8b8Angc6F2S1BLUjIZkKlTuXfO8= +-----END CERTIFICATE-----'" +"Entrust","AffirmTrust","","AffirmTrust Networking","7C4F04391CD4992D","0A81EC5A929777F145904AF38D5D509F66B5E2C58FCDB531058B0E17F3F0B41B","EBD02E0C68BC983B28945E6ED327B6FB93A59CF62764E54912A018445A606EEB","2010.01.29","2030.12.31","RSA 2048 bits","SHA1WithRSA","Websites","","","1.3.6.1.4.1.34697.2.2","https://bugzilla.mozilla.org/show_bug.cgi?id=543639","NSS 3.12.10","Firefox 6.0","https://validnetworking.affirmtrust.com/","https://expirednetworking.affirmtrust.com/","https://revokednetworking.affirmtrust.com/","","http://www.entrust.net/","North America, Global","","https://www.affirmtrust.com/wp-content/uploads/AffirmTrust-SSL-CPS-3.8.pdf","https://www.cpacanada.ca/generichandlers/CPACHandler.ashx?attachmentid=239755","https://www.affirmtrust.com/wp-content/uploads/2020-AFT-BR-NetSec-Report.pdf","https://www.cpacanada.ca/generichandlers/CPACHandler.ashx?attachmentid=239755","Deloitte","WebTrust","2020.04.17","'-----BEGIN CERTIFICATE----- +MIIDTDCCAjSgAwIBAgIIfE8EORzUmS0wDQYJKoZIhvcNAQEFBQAwRDELMAkGA1UE +BhMCVVMxFDASBgNVBAoMC0FmZmlybVRydXN0MR8wHQYDVQQDDBZBZmZpcm1UcnVz +dCBOZXR3b3JraW5nMB4XDTEwMDEyOTE0MDgyNFoXDTMwMTIzMTE0MDgyNFowRDEL +MAkGA1UEBhMCVVMxFDASBgNVBAoMC0FmZmlybVRydXN0MR8wHQYDVQQDDBZBZmZp +cm1UcnVzdCBOZXR3b3JraW5nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC +AQEAtITMMxcua5Rsa2FSoOujz3mUTOWUgJnLVWREZY9nZOIG41w3SfYvm4SEHi3y +YJ0wTsyEheIszx6e/jarM3c1RNg1lho9Nuh6DtjVR6FqaYvZ/Ls6rnla1fTWcbua +kCNrmreIdIcMHl+5ni36q1Mr3Lt2PpNMCAiMHqIjHNRqrSK6mQEubWXLviRmVSRL +QESxG9fhwoXA3hA/Pe24/PHxI1Pcv2WXb9n5QHGNfb2V1M6+oF4nI979ptAmDgAp +6zxG8D1gvz9Q0twmQVGeFDdCBKNwV6gbh+0t+nvujArjqWaJGctB+d1ENmHP4ndG +yH329JKBNv3bNPFyfvMMFr20FQIDAQABo0IwQDAdBgNVHQ4EFgQUBx/S55zawm6i +QLSwelAQUHTEyL0wDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwDQYJ +KoZIhvcNAQEFBQADggEBAIlXshZ6qML91tmbmzTCnLQyFE2npN/svqe++EPbkTfO +tDIuUFUaNU52Q3Eg75N3ThVwLofDwR1t3Mu1J9QsVtFSUzpE0nPIxBsFZVpikpzu +QY0x2+c06lkh1QF612S4ZDnNye2v7UsDSKegmQGA3GWjNq5lWUhPgkvIZfFXHeVZ +Lgo/bNjR9eUJtGxUAArgFU2HdW23WJZa3W3SAKD0m0i+wzekujbgfIeFlxoVot4u +olu9rxj5kFDNcFn4J2dHy8egBzp90SxdbBk6ZrV9/ZFvgrG+CJPbFEfxojfHRZ48 +x3evZKiT3/Zpg4Jg8klCNO1aAFSFHBY2kgxc+qatv9s= +-----END CERTIFICATE-----'" +"Entrust","AffirmTrust","","AffirmTrust Premium","6D8C1446B1A60AEE","70A73F7F376B60074248904534B11482D5BF0E698ECC498DF52577EBF2E93B9A","76297959FB01D1831DD657ACCF26D39CA40E7F650275E3030D4C3AC67BADC69F","2010.01.29","2040.12.31","RSA 4096 bits","SHA384WithRSA","Websites","","","1.3.6.1.4.1.34697.2.3","https://bugzilla.mozilla.org/show_bug.cgi?id=543639","NSS 3.12.10","Firefox 6.0","https://validpremium.affirmtrust.com/","https://expiredpremium.affirmtrust.com/","https://revokedpremium.affirmtrust.com/","","http://www.entrust.net/","North America, Global","","https://www.affirmtrust.com/wp-content/uploads/AffirmTrust-SSL-CPS-3.8.pdf","https://www.cpacanada.ca/generichandlers/CPACHandler.ashx?attachmentid=239755","https://www.affirmtrust.com/wp-content/uploads/2020-AFT-BR-NetSec-Report.pdf","https://www.cpacanada.ca/generichandlers/CPACHandler.ashx?attachmentid=239755","Deloitte","WebTrust","2020.04.17","'-----BEGIN CERTIFICATE----- +MIIFRjCCAy6gAwIBAgIIbYwURrGmCu4wDQYJKoZIhvcNAQEMBQAwQTELMAkGA1UE +BhMCVVMxFDASBgNVBAoMC0FmZmlybVRydXN0MRwwGgYDVQQDDBNBZmZpcm1UcnVz +dCBQcmVtaXVtMB4XDTEwMDEyOTE0MTAzNloXDTQwMTIzMTE0MTAzNlowQTELMAkG +A1UEBhMCVVMxFDASBgNVBAoMC0FmZmlybVRydXN0MRwwGgYDVQQDDBNBZmZpcm1U +cnVzdCBQcmVtaXVtMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAxBLf +qV/+Qd3d9Z+K4/as4Tx4mrzY8H96oDMq3I0gW64tb+eT2TZwamjPjlGjhVtnBKAQ +JG9dKILBl1fYSCkTtuG+kU3fhQxTGJoeJKJPj/CihQvL9Cl/0qRY7iZNyaqoe5rZ ++jjeRFcV5fiMyNlI4g0WJx0eyIOFJbe6qlVBzAMiSy2RjYvmia9mx+n/K+k8rNrS +s8PhaJyJ+HoAVt70VZVs+7pk3WKL3wt3MutizCaam7uqYoNMtAZ6MMgpv+0GTZe5 +HMQxK9VfvFMSF5yZVylmd2EhMQcuJUmdGPLu8ytxjLW6OQdJd/zvLpKQBY0tL3d7 +70O/Nbua2Plzpyzy0FfuKE4mX4+QaAkvuPjcBukumj5Rp9EixAqnOEhss/n/fauG +V+O61oV4d7pD6kh/9ti+I20ev9E2bFhc8e6kGVQa9QPSdubhjL08s9NIS+LI+H+S +qHZGnEJlPqQewQcDWkYtuJfzt9WyVSHvutxMAJf7FJUnM7/oQ0dG0giZFmA7mn7S +5u046uwBHjxIVkkJx0w3AJ6IDsBz4W9m6XJHMD4Q5QsDyZpCAGzFlH5hxIrff4Ia +C1nEWTJ3s7xgaVY5/bQGeyzWZDbZvUjthB9+pSKPKrhC9IK31FOQeE4tGv2Bb0TX +OwF0lkLgAOIua+rF7nKsu7/+6qqo+Nz2snmKtmcCAwEAAaNCMEAwHQYDVR0OBBYE +FJ3AZ6YMItkm9UWrpmVSESfYRaxjMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/ +BAQDAgEGMA0GCSqGSIb3DQEBDAUAA4ICAQCzV00QYk465KzquByvMiPIs0laUZx2 +KI15qldGF9X1Uva3ROgIRL8YhNILgM3FEv0AVQVhh0HctSSePMTYyPtwni94loMg +Nt58D2kTiKV1NpgIpsbfrM7jWNa3Pt668+s0QNiigfV4Py/VpfzZotReBA4Xrf5B +8OWycvpEgjNC6C1Y91aMYj+6QrCcDFx+LmUmXFNPALJ4fqENmS2NuB2OosSw/WDQ +MKSOyARiqcTtNd56l+0OOF6SL5Nwpamcb6d9Ex1+xghIsV5n61EIJenmJWtSKZGc +0jlzCFfemQa0W50QBuHCAKi4HEoCChTQwUHK+4w1IX2COPKpVJEZNZOUbWo6xbLQ +u4mGk+ibyQ86p3q4ofB4Rvr8Ny/lioTz3/4E2aFooC8k4gmVBtWVyuEklut89pMF +u+1z6S3RdTnX5yTb2E5fQ4+e0BQ5v1VwSJlXMbSc7kqYA5YwH2AG7hsj/oFgIxpH +YoWlzBk0gG+zrBrjn/B7SK3VAdlntqlyk+otZrWyuOQ9PLLvTIzq6we/qzWaVYa8 +GKa1qF60g2xraUDTn9zxw2lrueFtCfTxqlB2Cnp9ehehVZZCmTEJ3WARjQUwfuaO +RtGdFNrHF+QFlozEJLUbzxQHskD4o55BhrwE0GuWyCqANP2/7waj3VjFhT0+j/6e +KeC2uAloGRwYQw== +-----END CERTIFICATE-----'" +"Entrust","AffirmTrust","","AffirmTrust Premium ECC","7497258AC73F7A54","BD71FDF6DA97E4CF62D1647ADD2581B07D79ADF8397EB4ECBA9C5E8488821423","56C26F47C33DA02AFA6D306E6C8BB2C317369277F6C18984B5F588DD35F867BC","2010.01.29","2040.12.31","EC secp384r1","ecdsaWithSHA384","Websites","","","1.3.6.1.4.1.34697.2.4","https://bugzilla.mozilla.org/show_bug.cgi?id=543639","NSS 3.12.10","Firefox 6.0","https://validpremiumecc.affirmtrust.com/","https://expiredpremiumecc.affirmtrust.com/","https://revokedpremiumecc.affirmtrust.com/","","http://www.entrust.net/","North America, Global","","https://www.affirmtrust.com/wp-content/uploads/AffirmTrust-SSL-CPS-3.8.pdf","https://www.cpacanada.ca/generichandlers/CPACHandler.ashx?attachmentid=239755","https://www.affirmtrust.com/wp-content/uploads/2020-AFT-BR-NetSec-Report.pdf","https://www.cpacanada.ca/generichandlers/CPACHandler.ashx?attachmentid=239755","Deloitte","WebTrust","2020.04.17","'-----BEGIN CERTIFICATE----- +MIIB/jCCAYWgAwIBAgIIdJclisc/elQwCgYIKoZIzj0EAwMwRTELMAkGA1UEBhMC +VVMxFDASBgNVBAoMC0FmZmlybVRydXN0MSAwHgYDVQQDDBdBZmZpcm1UcnVzdCBQ +cmVtaXVtIEVDQzAeFw0xMDAxMjkxNDIwMjRaFw00MDEyMzExNDIwMjRaMEUxCzAJ +BgNVBAYTAlVTMRQwEgYDVQQKDAtBZmZpcm1UcnVzdDEgMB4GA1UEAwwXQWZmaXJt +VHJ1c3QgUHJlbWl1bSBFQ0MwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAAQNMF4bFZ0D +0KF5Nbc6PJJ6yhUczWLznCZcBz3lVPqj1swS6vQUX+iOGasvLkjmrBhDeKzQN8O9 +ss0s5kfiGuZjuD0uL3jET9v0D6RoTFVya5UdThhClXjMNzyR4ptlKymjQjBAMB0G +A1UdDgQWBBSaryl6wBE1NSZRMADDav5A1a7WPDAPBgNVHRMBAf8EBTADAQH/MA4G +A1UdDwEB/wQEAwIBBjAKBggqhkjOPQQDAwNnADBkAjAXCfOHiFBar8jAQr9HX/Vs +aobgxCd05DhT1wV/GzTjxi+zygk8N53X57hG8f2h4nECMEJZh0PUUd+60wkyWs6I +flc9nF9Ca/UHLbXwgpP5WW+uZPpY5Yse42O+tYHNbwKMeQ== +-----END CERTIFICATE-----'" +"Entrust","Entrust, Inc.","www.entrust.net/CPS is incorporated by reference, (c) 2006 Entrust, Inc.","Entrust Root Certification Authority","456B5054","73C176434F1BC6D5ADF45B0E76E727287C8DE57616C1E6E6141A2B2CBC7D8E4C","45D455E704C234EF5B169B5FEF6626D83BD3BA060F9EA849BCE3BD1363F17B1D","2006.11.27","2026.11.27","RSA 2048 bits","SHA1WithRSA","Websites","","","2.16.840.1.114028.10.1.2","https://bugzilla.mozilla.org/show_bug.cgi?id=382352","NSS 3.11.10","Firefox 3.0.2","https://validev.entrust.net","https://expiredev.entrust.net","https://revokedev.entrust.net","","http://www.entrust.net/","North America, Global","https://www.entrustdatacard.com/-/media/documentation/licensingandagreements/ev-cps-english-20180531-v2-2.pdf","https://www.entrustdatacard.com/-/media/documentation/licensingandagreements/ssl-cps-english-20190930-version-36.pdf","https://www.cpacanada.ca/generichandlers/CPACHandler.ashx?attachmentid=239756","https://www.entrustdatacard.com/-/media/documentation/licensingandagreements/ecs/2020-entrust-baseline-requirements-report.pdf","https://www.cpacanada.ca/generichandlers/CPACHandler.ashx?attachmentid=239756","Deloitte","WebTrust","2020.04.17","'-----BEGIN CERTIFICATE----- +MIIEkTCCA3mgAwIBAgIERWtQVDANBgkqhkiG9w0BAQUFADCBsDELMAkGA1UEBhMC +VVMxFjAUBgNVBAoTDUVudHJ1c3QsIEluYy4xOTA3BgNVBAsTMHd3dy5lbnRydXN0 +Lm5ldC9DUFMgaXMgaW5jb3Jwb3JhdGVkIGJ5IHJlZmVyZW5jZTEfMB0GA1UECxMW +KGMpIDIwMDYgRW50cnVzdCwgSW5jLjEtMCsGA1UEAxMkRW50cnVzdCBSb290IENl +cnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTA2MTEyNzIwMjM0MloXDTI2MTEyNzIw +NTM0MlowgbAxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1FbnRydXN0LCBJbmMuMTkw +NwYDVQQLEzB3d3cuZW50cnVzdC5uZXQvQ1BTIGlzIGluY29ycG9yYXRlZCBieSBy +ZWZlcmVuY2UxHzAdBgNVBAsTFihjKSAyMDA2IEVudHJ1c3QsIEluYy4xLTArBgNV +BAMTJEVudHJ1c3QgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTCCASIwDQYJ +KoZIhvcNAQEBBQADggEPADCCAQoCggEBALaVtkNC+sZtKm9I35RMOVcF7sN5EUFo +Nu3s/poBj6E4KPz3EEZmLk0eGrEaTsbRwJWIsMn/MYszA9u3g3s+IIRe7bJWKKf4 +4LlAcTfFy0cOlypowCKVYhXbR9n10Cv/gkvJrT7eTNuQgFA/CYqEAOwwCj0Yzfv9 +KlmaI5UXLEWeH25DeW0MXJj+SKfFI0dcXv1u5x609mhF0YaDW6KKjbHjKYD+JXGI +rb68j6xSlkuqUY3kEzEZ6E5Nn9uss2rVvDlUccp6en+Q3X0dgNmBu1kmwhH+5pPi +94DkZfs0Nw4pgHBNrziGLp5/V6+eF67rHMsoIV+2HNjnogQi+dPa2MsCAwEAAaOB +sDCBrTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zArBgNVHRAEJDAi +gA8yMDA2MTEyNzIwMjM0MlqBDzIwMjYxMTI3MjA1MzQyWjAfBgNVHSMEGDAWgBRo +kORnpKZTgMeGZqTx90tD+4S9bTAdBgNVHQ4EFgQUaJDkZ6SmU4DHhmak8fdLQ/uE +vW0wHQYJKoZIhvZ9B0EABBAwDhsIVjcuMTo0LjADAgSQMA0GCSqGSIb3DQEBBQUA +A4IBAQCT1DCw1wMgKtD5Y+iRDAUgqV8ZyntyTtSx29CW+1RaGSwMCPeyvIWonX9t +O1KzKtvn1ISMY/YPyyYBkVBs9F8U4pN0wBOeMDpQ47RgxRzwIkSNcUesyBrJ6Zua +AGAT/3B+XxFNSRuzFVJ7yVTav52Vr2ua2J7p8eRDjeIRRDq/r72DQnNSi6q7pynP +9WQcCk3RvKqsnyrQ/39/2n3qse0wJcGE2jTSW3iDVuycNsMm4hH2Z0kdkquM++v/ +eu6FSqdQgPCnXEqULl8FmTxSQeDNtGPPAUO6nIPcj2A781q0tHuu2guQOHXvgR1m +0vdXcDazv/wor3ElhVsT/h5/WrQ8 +-----END CERTIFICATE-----'" +"Entrust","Entrust, Inc.","See www.entrust.net/legal-terms, (c) 2012 Entrust, Inc. - for authorized use only","Entrust Root Certification Authority - EC1","00A68B79290000000050D091F9","02ED0EB28C14DA45165C566791700D6451D7FB56F0B2AB1D3B8EB070E56EDFF5","34F6AA8CA6ECB68A12E8956F6C91FA42A0986737D606E4F45E58E53A16806B69","2012.12.18","2037.12.18","EC secp384r1","ecdsaWithSHA384","Websites;Email","","","2.16.840.1.114028.10.1.2","https://bugzilla.mozilla.org/show_bug.cgi?id=849950","NSS 3.18","Firefox 38","https://validec.entrust.net","https://expiredec.entrust.net","https://revokedec.entrust.net","None","http://www.entrust.net/","North America, Global","https://www.entrustdatacard.com/-/media/documentation/licensingandagreements/ev-cps-english-20180531-v2-2.pdf","https://www.entrustdatacard.com/-/media/documentation/licensingandagreements/ssl-cps-english-20190930-version-36.pdf","https://www.cpacanada.ca/generichandlers/CPACHandler.ashx?attachmentid=239756","https://www.entrustdatacard.com/-/media/documentation/licensingandagreements/ecs/2020-entrust-baseline-requirements-report.pdf","https://www.cpacanada.ca/generichandlers/CPACHandler.ashx?attachmentid=239756","Deloitte","WebTrust","2020.04.17","'-----BEGIN CERTIFICATE----- +MIIC+TCCAoCgAwIBAgINAKaLeSkAAAAAUNCR+TAKBggqhkjOPQQDAzCBvzELMAkG +A1UEBhMCVVMxFjAUBgNVBAoTDUVudHJ1c3QsIEluYy4xKDAmBgNVBAsTH1NlZSB3 +d3cuZW50cnVzdC5uZXQvbGVnYWwtdGVybXMxOTA3BgNVBAsTMChjKSAyMDEyIEVu +dHJ1c3QsIEluYy4gLSBmb3IgYXV0aG9yaXplZCB1c2Ugb25seTEzMDEGA1UEAxMq +RW50cnVzdCBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IC0gRUMxMB4XDTEy +MTIxODE1MjUzNloXDTM3MTIxODE1NTUzNlowgb8xCzAJBgNVBAYTAlVTMRYwFAYD +VQQKEw1FbnRydXN0LCBJbmMuMSgwJgYDVQQLEx9TZWUgd3d3LmVudHJ1c3QubmV0 +L2xlZ2FsLXRlcm1zMTkwNwYDVQQLEzAoYykgMjAxMiBFbnRydXN0LCBJbmMuIC0g +Zm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxMzAxBgNVBAMTKkVudHJ1c3QgUm9vdCBD +ZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEVDMTB2MBAGByqGSM49AgEGBSuBBAAi +A2IABIQTydC6bUF74mzQ61VfZgIaJPRbiWlH47jCffHyAsWfoPZb1YsGGYZPUxBt +ByQnoaD41UcZYUx9ypMn6nQM72+WCf5j7HBdNq1nd67JnXxVRDqiY1Ef9eNi1KlH +Bz7MIKNCMEAwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0O +BBYEFLdj5xrdjekIplWDpOBqUEFlEUJJMAoGCCqGSM49BAMDA2cAMGQCMGF52OVC +R98crlOZF7ZvHH3hvxGU0QOIdeSNiaSKd0bebWHvAvX7td/M/k7//qnmpwIwW5nX +hTcGtXsI/esni0qU+eH6p44mCOh8kmhtc9hvJqwhAriZtyZBWyVgrtBIGu4G +-----END CERTIFICATE-----'" +"Entrust","Entrust, Inc.","See www.entrust.net/legal-terms, (c) 2009 Entrust, Inc. - for authorized use only","Entrust Root Certification Authority - G2","4A538C28","43DF5774B03E7FEF5FE40D931A7BEDF1BB2E6B42738C4E6D3841103D3AA7F339","0F90E5FF2D330507951E77F0E6AE849A85043D2F8E7A5BAF3289FE0930403B51","2009.07.07","2030.12.07","RSA 2048 bits","SHA256WithRSA","Websites;Email","","","2.16.840.1.114028.10.1.2","https://bugzilla.mozilla.org/show_bug.cgi?id=849950","NSS 3.18","Firefox 38","https://validg2.entrust.net","https://expiredg2.entrust.net","https://revokedg2.entrust.net","None","http://www.entrust.net/","North America, Global","https://www.entrustdatacard.com/-/media/documentation/licensingandagreements/ev-cps-english-20180531-v2-2.pdf","https://www.entrustdatacard.com/-/media/documentation/licensingandagreements/ssl-cps-english-20190930-version-36.pdf","https://www.cpacanada.ca/generichandlers/CPACHandler.ashx?attachmentid=239756","https://www.entrustdatacard.com/-/media/documentation/licensingandagreements/ecs/2020-entrust-baseline-requirements-report.pdf","https://www.cpacanada.ca/generichandlers/CPACHandler.ashx?attachmentid=239756","Deloitte","WebTrust","2020.04.17","'-----BEGIN CERTIFICATE----- +MIIEPjCCAyagAwIBAgIESlOMKDANBgkqhkiG9w0BAQsFADCBvjELMAkGA1UEBhMC +VVMxFjAUBgNVBAoTDUVudHJ1c3QsIEluYy4xKDAmBgNVBAsTH1NlZSB3d3cuZW50 +cnVzdC5uZXQvbGVnYWwtdGVybXMxOTA3BgNVBAsTMChjKSAyMDA5IEVudHJ1c3Qs +IEluYy4gLSBmb3IgYXV0aG9yaXplZCB1c2Ugb25seTEyMDAGA1UEAxMpRW50cnVz +dCBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IC0gRzIwHhcNMDkwNzA3MTcy +NTU0WhcNMzAxMjA3MTc1NTU0WjCBvjELMAkGA1UEBhMCVVMxFjAUBgNVBAoTDUVu +dHJ1c3QsIEluYy4xKDAmBgNVBAsTH1NlZSB3d3cuZW50cnVzdC5uZXQvbGVnYWwt +dGVybXMxOTA3BgNVBAsTMChjKSAyMDA5IEVudHJ1c3QsIEluYy4gLSBmb3IgYXV0 +aG9yaXplZCB1c2Ugb25seTEyMDAGA1UEAxMpRW50cnVzdCBSb290IENlcnRpZmlj +YXRpb24gQXV0aG9yaXR5IC0gRzIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK +AoIBAQC6hLZy254Ma+KZ6TABp3bqMriVQRrJ2mFOWHLP/vaCeb9zYQYKpSfYs1/T +RU4cctZOMvJyig/3gxnQaoCAAEUesMfnmr8SVycco2gvCoe9amsOXmXzHHfV1IWN +cCG0szLni6LVhjkCsbjSR87kyUnEO6fe+1R9V77w6G7CebI6C1XiUJgWMhNcL3hW +wcKUs/Ja5CeanyTXxuzQmyWC48zCxEXFjJd6BmsqEZ+pCm5IO2/b1BEZQvePB7/1 +U1+cPvQXLOZprE4yTGJ36rfo5bs0vBmLrpxR57d+tVOxMyLlbc9wPBr64ptntoP0 +jaWvYkxN4FisZDQSA/i2jZRjJKRxAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAP +BgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBRqciZ60B7vfec7aVHUbI2fkBJmqzAN +BgkqhkiG9w0BAQsFAAOCAQEAeZ8dlsa2eT8ijYfThwMEYGprmi5ZiXMRrEPR9RP/ +jTkrwPK9T3CMqS/qF8QLVJ7UG5aYMzyorWKiAHarWWluBh1+xLlEjZivEtRh2woZ +Rkfz6/djwUAFQKXSt/S1mja/qYh2iARVBCuch38aNzx+LaUa2NSJXsq9rD1s2G2v +1fN2D807iDginWyTmsQ9v4IbZT+mD12q/OWyFcq1rca8PdCE6OoGcrBNOTJ4vz4R +nAuknZoh8/CbCzB428Hch0P+vGOaysXCHMnHjf87ElgI5rY97HosTvuDls4MPGmH +VHOkc8KT/1EQrBVUAdj8BbGJoX90g5pJ19xOe4pIb4tF9g== +-----END CERTIFICATE-----'" +"Entrust","Entrust, Inc.","See www.entrust.net/legal-terms, (c) 2015 Entrust, Inc. - for authorized use only","Entrust Root Certification Authority - G4","00D9B5437FAFA9390F000000005565AD58","DB3517D1F6732A2D5AB97C533EC70779EE3270A62FB4AC4238372460E6F01E88","47E10321DE2408B5CEFCF90497B92C4A771F73983A75FEC54EB615311F11840E","2015.05.27","2037.12.27","RSA 4096 bits","SHA256WithRSA","Websites;Email","","","2.16.840.1.114028.10.1.2","https://bugzilla.mozilla.org/show_bug.cgi?id=1480510","NSS 3.48","Firefox 72","https://validg4.entrust.net/","https://expiredg4.entrust.net/","https://revokedg4.entrust.net/","","http://www.entrust.net/","North America, Global","https://www.entrustdatacard.com/-/media/documentation/licensingandagreements/ev-cps-english-20180531-v2-2.pdf","https://www.entrustdatacard.com/-/media/documentation/licensingandagreements/ssl-cps-english-20190930-version-36.pdf","https://www.cpacanada.ca/generichandlers/CPACHandler.ashx?attachmentid=239756","https://www.entrustdatacard.com/-/media/documentation/licensingandagreements/ecs/2020-entrust-baseline-requirements-report.pdf","https://www.cpacanada.ca/generichandlers/CPACHandler.ashx?attachmentid=239756","Deloitte","WebTrust","2020.04.17","'-----BEGIN CERTIFICATE----- +MIIGSzCCBDOgAwIBAgIRANm1Q3+vqTkPAAAAAFVlrVgwDQYJKoZIhvcNAQELBQAw +gb4xCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1FbnRydXN0LCBJbmMuMSgwJgYDVQQL +Ex9TZWUgd3d3LmVudHJ1c3QubmV0L2xlZ2FsLXRlcm1zMTkwNwYDVQQLEzAoYykg +MjAxNSBFbnRydXN0LCBJbmMuIC0gZm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxMjAw +BgNVBAMTKUVudHJ1c3QgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEc0 +MB4XDTE1MDUyNzExMTExNloXDTM3MTIyNzExNDExNlowgb4xCzAJBgNVBAYTAlVT +MRYwFAYDVQQKEw1FbnRydXN0LCBJbmMuMSgwJgYDVQQLEx9TZWUgd3d3LmVudHJ1 +c3QubmV0L2xlZ2FsLXRlcm1zMTkwNwYDVQQLEzAoYykgMjAxNSBFbnRydXN0LCBJ +bmMuIC0gZm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxMjAwBgNVBAMTKUVudHJ1c3Qg +Um9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEc0MIICIjANBgkqhkiG9w0B +AQEFAAOCAg8AMIICCgKCAgEAsewsQu7i0TD/pZJH4i3DumSXbcr3DbVZwbPLqGgZ +2K+EbTBwXX7zLtJTmeH+H17ZSK9dE43b/2MzTdMAArzE+NEGCJR5WIoV3imz/f3E +T+iq4qA7ec2/a0My3dl0ELn39GjUu9CH1apLiipvKgS1sqbHoHrmSKvS0VnM1n4j +5pds8ELl3FFLFUHtSUrJ3hCX1nbB76W1NhSXNdh4IjVS70O92yfbYVaCNNzLiGAM +C1rlLAHGVK/XqsEQe9IFWrhAnoanw5CGAlZSCXqc0ieCU0plUmr1POeo8pyvi73T +DtTUXm6Hnmo9RR3RXRv06QqsYJn7ibT/mCzPfB3pAqoEmh643IhuJbNsZvc8kPNX +wbMv9W3y+8qh+CmdRouzavbmZwe+LGcKKh9asj5XxNMhIWNlUpEbsZmOeX7m640A +2Vqq6nPopIICR5b+W45UYaPrL0swsIsjdXJ8ITzI9vF01Bx7owVV7rtNOzK+mndm +nqxpkCIHH2E6lr7lmk/MBTwoWdPBDFSoWWG9yHJM6Nyfh3+9nEg2XpWjDrk4JFX8 +dWbrAuMINClKxuMrLzOg2qOGpRKX/YAr2hRC45K9PvJdXmd0LhyIRyk0X+IyqJwl +N4y6mACXi0mWHv0liqzc2thddG5msP9E36EYxr5ILzeUePiVSj9/E15dWf10hkNj +c0kCAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYD +VR0OBBYEFJ84xFYjwznooHFs6FRM5Og6sb9nMA0GCSqGSIb3DQEBCwUAA4ICAQAS +5UKme4sPDORGpbZgQIeMJX6tuGguW8ZAdjwD+MlZ9POrYs4QjbRaZIxowLByQzTS +Gwv2LFPSypBLhmb8qoMi9IsabyZIrHZ3CL/FmFz0Jomee8O5ZDIBf9PD3Vht7LGr +hFV0d4QEJ1JrhkzO3bll/9bGXp+aEJlLdWr+aumXIOTkdnrG0CSqkM0gkLpHZPt/ +B7NTeLUKYvJzQ85BK4FqLoUWlFPUa19yIqtRLULVAJyZv967lDtX/Zr1hstWO1uI +AeV8KEsD+UmDfLJ/fOPtjqF/YFOOVZ1QNBIPt5d7bIdKROf1beyAN/BYGW5KaHbw +H5Lk6rWS02FREAutp9lfx1/cH6NcjKF+m7ee01ZvZl4HliDtC3T7Zk6LERXpgUl+ +b7DUUH8i119lAg2m9IUe2K4GS0qn0jFmwvjO5QimpAKWRGhXxNUzzxkvFMSUHHuk +2fCfDrGA4tGeEWSpiBE6doLlYsKA2KSD7ZPvfC+QsDJMlhVoSFLUmQjAJOgc47Ol +IQ6SwJAfzyBfyjs4x7dtOvPmRLgOMWuIjnDrnBdSqEGULoe256YSxXXfW8AKbnuk +5F6G+TaU33fD6Q3AOfF5u0aOq0NZJ7cguyPpVkAh7DE9ZapD8j3fcEThuk0mEDuY +n/PIjhs4ViFqUZPTkcpG2om3PVODLAgfi49T3f+sHw== +-----END CERTIFICATE-----'" +"Entrust","Entrust.net","www.entrust.net/CPS_2048 incorp. by ref. (limits liab.), (c) 1999 Entrust.net Limited","Entrust.net Certification Authority (2048)","3863DEF8","6DC47172E01CBCB0BF62580D895FE2B8AC9AD4F873801E0C10B9C837D21EB177","7E17A7DEA5386D7B45DA4305B772E6473CFC27157DEE9D16E3CD15CC9F39DEF1","1999.12.24","2029.07.24","RSA 2048 bits","SHA1WithRSA","Websites;Email","","","2.16.840.1.114028.10.1.2","https://bugzilla.mozilla.org/show_bug.cgi?id=694536","NSS 3.15","Firefox 23","https://2048test.entrust.net","https://expired2048.entrust.net","https://revoked2048.entrust.net","None","http://www.entrust.net/","North America, Global","https://www.entrustdatacard.com/-/media/documentation/licensingandagreements/ev-cps-english-20180531-v2-2.pdf","https://www.entrustdatacard.com/-/media/documentation/licensingandagreements/ssl-cps-english-20190930-version-36.pdf","https://www.cpacanada.ca/generichandlers/CPACHandler.ashx?attachmentid=239756","https://www.entrustdatacard.com/-/media/documentation/licensingandagreements/ecs/2020-entrust-baseline-requirements-report.pdf","https://www.cpacanada.ca/generichandlers/CPACHandler.ashx?attachmentid=239756","Deloitte","WebTrust","2020.04.17","'-----BEGIN CERTIFICATE----- +MIIEKjCCAxKgAwIBAgIEOGPe+DANBgkqhkiG9w0BAQUFADCBtDEUMBIGA1UEChML +RW50cnVzdC5uZXQxQDA+BgNVBAsUN3d3dy5lbnRydXN0Lm5ldC9DUFNfMjA0OCBp +bmNvcnAuIGJ5IHJlZi4gKGxpbWl0cyBsaWFiLikxJTAjBgNVBAsTHChjKSAxOTk5 +IEVudHJ1c3QubmV0IExpbWl0ZWQxMzAxBgNVBAMTKkVudHJ1c3QubmV0IENlcnRp +ZmljYXRpb24gQXV0aG9yaXR5ICgyMDQ4KTAeFw05OTEyMjQxNzUwNTFaFw0yOTA3 +MjQxNDE1MTJaMIG0MRQwEgYDVQQKEwtFbnRydXN0Lm5ldDFAMD4GA1UECxQ3d3d3 +LmVudHJ1c3QubmV0L0NQU18yMDQ4IGluY29ycC4gYnkgcmVmLiAobGltaXRzIGxp +YWIuKTElMCMGA1UECxMcKGMpIDE5OTkgRW50cnVzdC5uZXQgTGltaXRlZDEzMDEG +A1UEAxMqRW50cnVzdC5uZXQgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgKDIwNDgp +MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEArU1LqRKGsuqjIAcVFmQq +K0vRvwtKTY7tgHalZ7d4QMBzQshowNtTK91euHaYNZOLGp18EzoOH1u3Hs/lJBQe +sYGpjX24zGtLA/ECDNyrpUAkAH90lKGdCCmziAv1h3edVc3kw37XamSrhRSGlVuX +MlBvPci6Zgzj/L24ScF2iUkZ/cCovYmjZy/Gn7xxGWC4LeksyZB2ZnuU4q941mVT +XTzWnLLPKQP5L6RQstRIzgUyVYr9smRMDuSYB3Xbf9+5CFVghTAp+XtIpGmG4zU/ +HoZdenoVve8AjhUiVBcAkCaTvA5JaJG/+EfTnZVCwQ5N328mz8MYIWJmQ3DW1cAH +4QIDAQABo0IwQDAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNV +HQ4EFgQUVeSB0RGAvtiJuQijMfmhJAkWuXAwDQYJKoZIhvcNAQEFBQADggEBADub +j1abMOdTmXx6eadNl9cZlZD7Bh/KM3xGY4+WZiT6QBshJ8rmcnPyT/4xmf3IDExo +U8aAghOY+rat2l098c5u9hURlIIM7j+VrxGrD9cv3h8Dj1csHsm7mhpElesYT6Yf +zX1XEC+bBAlahLVu2B064dae0Wx5XnkcFMXj0EyTO2U87d89vqbllRrDtRnDvV5b +u/8j72gZyxKTJ1wDLW8w0B62GqzeWvfRqqgnpv55gcR5mTNXuhKwqeBCbJPKVt7+ +bYQLCIt+jerXmCHG8+c8eS9enNFMFY3h7CI3zJpDC5fcgJCNs2ebb0gIFVbPv/Er +fF6adulZkMV8gzURZVE= +-----END CERTIFICATE-----'" +"Example CA Owner","Hellenic Academic and Research Institutions Cert. Authority","","Example Root 1","00","44B545AA8A25E65A73CA15DC27FC36D24C1CB9953A066539B11582DC487B4833","A67DFA3384ED2EBDB007AD5E6A9E9AD0CC730E5EF003ACB9D2BF6A8FDC0B62CA","2015.07.07","2040.06.30","EC secp384r1","ecdsaWithSHA256","Websites","","","","","","","https://haricaeccrootca2015-valid-ev.harica.gr/","https://haricaeccrootca2015-expired-ev.harica.gr/","https://haricaeccrootca2015-revoked-ev.harica.gr/","","","","","https://repo.harica.gr/documents/CPS-EN-4.0.pdf; https://repo.harica.gr/documents/CPS-EL-4.0.pdf","https://www.qmscert.com/share/HARICA_Audit_Attestation_E_V2.3_040620-01-AL_V1.0.pdf","https://www.qmscert.com/share/HARICA_Audit_Attestation_E_V2.3_040620-01-AL_V1.0.pdf","https://www.qmscert.com/share/HARICA_Audit_Attestation_E_V2.3_040620-01-AL_V1.0.pdf","QMSCERT","ETSI EN 319 411","2020.06.04","'-----BEGIN CERTIFICATE----- +MIICwzCCAkqgAwIBAgIBADAKBggqhkjOPQQDAjCBqjELMAkGA1UEBhMCR1IxDzAN +BgNVBAcTBkF0aGVuczFEMEIGA1UEChM7SGVsbGVuaWMgQWNhZGVtaWMgYW5kIFJl +c2VhcmNoIEluc3RpdHV0aW9ucyBDZXJ0LiBBdXRob3JpdHkxRDBCBgNVBAMTO0hl +bGxlbmljIEFjYWRlbWljIGFuZCBSZXNlYXJjaCBJbnN0aXR1dGlvbnMgRUNDIFJv +b3RDQSAyMDE1MB4XDTE1MDcwNzEwMzcxMloXDTQwMDYzMDEwMzcxMlowgaoxCzAJ +BgNVBAYTAkdSMQ8wDQYDVQQHEwZBdGhlbnMxRDBCBgNVBAoTO0hlbGxlbmljIEFj +YWRlbWljIGFuZCBSZXNlYXJjaCBJbnN0aXR1dGlvbnMgQ2VydC4gQXV0aG9yaXR5 +MUQwQgYDVQQDEztIZWxsZW5pYyBBY2FkZW1pYyBhbmQgUmVzZWFyY2ggSW5zdGl0 +dXRpb25zIEVDQyBSb290Q0EgMjAxNTB2MBAGByqGSM49AgEGBSuBBAAiA2IABJKg +QehLgoRc4vgxEZmGZE4JJS+dQS8KrjVPdJWyUWRrjWvmP3CV8AVER6ZyOFB2lQJa +jq4onvktTpnvLEhvTCUp6NFxW98dwXU3tNf6e3pCnGoKVlp8aQuqgAkkbH7BRqNC +MEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFLQi +C4KZJAEOnLvkDv2/+5cgk5kqMAoGCCqGSM49BAMCA2cAMGQCMGfOFmI4oqxiRaep +lSTAGiecMjvAwNW6qef4BENThe5SId6d9SWDPp5YSy/XZxMOIQIwBeF1Ad5o7Sof +TUwJCA3sS61kFyjndc5FZXIhF8siQQ6ME5g4mlRtm8rifOoCWCKR +-----END CERTIFICATE-----'" +"Example CA Owner","Hellenic Academic and Research Institutions Cert. Authority","","Example Root 2","00","A040929A02CE53B4ACF4F2FFC6981CE4496F755E6D45FE0B2A692BCD52523F36","3320D8C4A37FDAAA85D4E251A05D2EC661C6873AD437DAF892602E151A2DA6CF","2015.07.07","2040.06.30","RSA 4096 bits","SHA256WithRSA","Websites","","","","","","","https://haricarootca2015-valid-ev.harica.gr/","https://haricarootca2015-expired-ev.harica.gr/","https://haricarootca2015-revoked-ev.harica.gr/","","","","","https://repo.harica.gr/documents/CPS-EN-4.0.pdf; https://repo.harica.gr/documents/CPS-EL-4.0.pdf","https://www.qmscert.com/share/HARICA_Audit_Attestation_E_V2.3_040620-01-AL_V1.0.pdf","https://www.qmscert.com/share/HARICA_Audit_Attestation_E_V2.3_040620-01-AL_V1.0.pdf","https://www.qmscert.com/share/HARICA_Audit_Attestation_E_V2.3_040620-01-AL_V1.0.pdf","QMSCERT","ETSI EN 319 411","2020.06.04","'-----BEGIN CERTIFICATE----- +MIIGCzCCA/OgAwIBAgIBADANBgkqhkiG9w0BAQsFADCBpjELMAkGA1UEBhMCR1Ix +DzANBgNVBAcTBkF0aGVuczFEMEIGA1UEChM7SGVsbGVuaWMgQWNhZGVtaWMgYW5k +IFJlc2VhcmNoIEluc3RpdHV0aW9ucyBDZXJ0LiBBdXRob3JpdHkxQDA+BgNVBAMT +N0hlbGxlbmljIEFjYWRlbWljIGFuZCBSZXNlYXJjaCBJbnN0aXR1dGlvbnMgUm9v +dENBIDIwMTUwHhcNMTUwNzA3MTAxMTIxWhcNNDAwNjMwMTAxMTIxWjCBpjELMAkG +A1UEBhMCR1IxDzANBgNVBAcTBkF0aGVuczFEMEIGA1UEChM7SGVsbGVuaWMgQWNh +ZGVtaWMgYW5kIFJlc2VhcmNoIEluc3RpdHV0aW9ucyBDZXJ0LiBBdXRob3JpdHkx +QDA+BgNVBAMTN0hlbGxlbmljIEFjYWRlbWljIGFuZCBSZXNlYXJjaCBJbnN0aXR1 +dGlvbnMgUm9vdENBIDIwMTUwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoIC +AQDC+Kk/G4n8PDwEXT2QNrCROnk8ZlrvbTkBSRq0t89/TSNTt5AA4xMqKKYx8ZEA +4yjsriFBzh/a/X0SWwGDD7mwX5nh8hKDgE0GPt+sr+ehiGsxr/CL0BgzuNtFajT0 +AoAkKAoCFZVedioNmToUW/bLy1O8E00BiDeUJRtCvCLYjqOWXjrZMts+6PAQZe10 +4S+nfK8nNLspfZu2zwnI5dMK/IhlZXQK3HMcXM1AsRzUtoSMTFDPaI6oWa7CJ06C +ojXdFPQf/7J31Ycvqm59JCfnxssm5uX+Zwdj2EUN3TpZZTlYepKZcj2chF6IIbjV +9Cz82XBST3i4vTwri5WY9bPRaM8gFH5MXF/ni+X1NYEZN9cRCLdmvtNKzoNXADrD +gfgXy5I2XdGj2HUb4Ysn6npIQf1FGQatJ5lOwXBH3bWfgVMS5bGMSF0xQxfjjMZ6 +Y5ZLKTBOhE5iGV48zpeQpX8B653g+IuJ3SWYPZK2fu/Z8VFRfS0myGlZYeCsargq +NhEEelC9MoS+L9xy1dcdFkfkR2YgP/SWxa+OAXqlD3pk9Q0Yh9muiNX6hME6wGko +LfINaFGq46V3xqSQDqE3izEjR8EJCOtu93ib14L8hCCZSRm2Ekax+0VVFqmjZayc +Bw/qa9wfLgZy7IaIEuQt218FL+TwA9MmM+eAws1CoRc0CwIDAQABo0IwQDAPBgNV +HRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUcRVnyMjJvXVd +ctA4GGqd83EkVAswDQYJKoZIhvcNAQELBQADggIBAHW7bVRLqhBYRjTyYtcWNl0I +XtVsyIe9tC5G8jH4fOpCtZMWVdyhDBKg2mF+D1hYc2Ryx+hFjtyp8iY/xnmMsVMI +M4GwVhO+5lFc2JsKT0ucVlMC6U/2DWDqTUJV6HwbISHTGzrMd/K4kPFox/la/vot +9L/J9UUbzjgQKjeKeaO04wlshYaT/4mWJ3iBj2fjRnRUjtkNaeJK9E10A/+yd+2V +Z5fkscWrv2oj6NSU4kQoYsRL4vDY4ilrGnB+JGGTe08DMiUNRSQrlrRGar9KC/ea +j8GsGsVn82800vpzY4zvFrCopEYq+OsS7HK07/grfoxSwIuEVPkvPuNVqNxmsdnh +X9izjFk0WaSrT2y7HxjbdavYy5LNlDhhDgcGH0tGEPEVvo2FXDtKK4F5D7Rpn0lQ +l033DlZdwJVqwjbDG2jJ9SrcR5q+ss7FJej6A7na+RZukYT1HCjI/CbM1xyQVqdf +bzoEvM14iQuODy+jqk+iGxI9FghAD/FGTNeqewjBCvVtJ94Cj8rDtSvK6evIIVM4 +pcw72Hc3MKJP2W/R8kCtQXoXxdZKNYm3QdV8hn9VTYNKpXMgwDqvkPGaJI7ZjnHK +e7iG2rKPmT4dEw0SEe7Uq/DpFXYC5ODfqiAeW2GFZECpkJcNrVPSWh2HagCXZWK0 +vm9qp/UsQu0yrbYhnr68 +-----END CERTIFICATE-----'" +"Global Digital Cybersecurity Authority Co., Ltd. (Formerly Guang Dong Certificate Authority (GDCA))","GUANG DONG CERTIFICATE AUTHORITY CO.,LTD.","","GDCA TrustAUTH R5 ROOT","7D0997FEF047EA7A","BFFF8FD04433487D6A8AA60C1A29767A9FC2BBB05E420F713A13B992891D3893","F42B91CF3AEBD52131F0859008FC31D9DABFFE55CC4BCE9630B916E6F51B4ED3","2014.11.26","2040.12.31","RSA 4096 bits","SHA256WithRSA","Websites","","","1.2.156.112559.1.1.6.1","https://bugzilla.mozilla.org/show_bug.cgi?id=1128392","NSS 3.34","Firefox 58","https://ev-ssl-test-1.95105813.cn/","https://ev-ssl-test-3.95105813.cn/","https://ev-ssl-test-2.95105813.cn/","None","http://www.gdca.com.cn/","China","https://www.gdca.com.cn/cp/cp","https://www.gdca.com.cn/cps/cps","https://www.cpacanada.ca/generichandlers/CPACHandler.ashx?attachmentid=239786","https://www.cpacanada.ca/generichandlers/CPACHandler.ashx?attachmentid=239788","https://www.cpacanada.ca/generichandlers/CPACHandler.ashx?attachmentid=239789","Anthony Kam & Associates Ltd.","WebTrust","2020.04.28","'-----BEGIN CERTIFICATE----- +MIIFiDCCA3CgAwIBAgIIfQmX/vBH6nowDQYJKoZIhvcNAQELBQAwYjELMAkGA1UE +BhMCQ04xMjAwBgNVBAoMKUdVQU5HIERPTkcgQ0VSVElGSUNBVEUgQVVUSE9SSVRZ +IENPLixMVEQuMR8wHQYDVQQDDBZHRENBIFRydXN0QVVUSCBSNSBST09UMB4XDTE0 +MTEyNjA1MTMxNVoXDTQwMTIzMTE1NTk1OVowYjELMAkGA1UEBhMCQ04xMjAwBgNV +BAoMKUdVQU5HIERPTkcgQ0VSVElGSUNBVEUgQVVUSE9SSVRZIENPLixMVEQuMR8w +HQYDVQQDDBZHRENBIFRydXN0QVVUSCBSNSBST09UMIICIjANBgkqhkiG9w0BAQEF +AAOCAg8AMIICCgKCAgEA2aMW8Mh0dHeb7zMNOwZ+Vfy1YI92hhJCfVZmPoiC7XJj +Dp6L3TQsAlFRwxn9WVSEyfFrs0yw6ehGXTjGoqcuEVe6ghWinI9tsJlKCvLriXBj +TnnEt1u9ol2x8kECK62pOqPseQrsXzrj/e+APK00mxqriCZ7VqKChh/rNYmDf1+u +KU49tm7srsHwJ5uu4/Ts765/94Y9cnrrpftZTqfrlYwiOXnhLQiPzLyRuEH3FMEj +qcOtmkVEs7LXLM3GKeJQEK5cy4KOFxg2fZfmiJqwTTQJ9Cy5WmYqsBebnh52nUpm +MUHfP/vFBu8btn4aRjb3ZGM74zkYI+dndRTVdVeSN72+ahsmUPI2JgaQxXABZG12 +ZuGR224HwGGALrIuL4xwp9E7PLOR5G62xDtw8mySlwnNR30YwPO7ng/Wi64HtloP +zgsMR6flPri9fcebNaBhlzpBdRfMK5Z3KpIhHtmVdiBnaM8Nvd/WHwlqmuLMc3Gk +L30SgLdTMEZeS1SZD2fJpcjyIMGC7J0R38IC+xo70e0gmu9lZJIQDSri3nDxGGeC +jGHeuLzRL5z7D9Ar7Rt2ueQ5Vfj4oR24qoAATILnsn8JuLwwoC8N9VKejveSswoA +HQBUlwbgsQfZxw9cZX08bVlX5O2ljelAU58VS6Bx9hoh49pwBiFYFIeFd3mqgnkC +AwEAAaNCMEAwHQYDVR0OBBYEFOLJQJ9NzuiaoXzPDj9lxSmIahlRMA8GA1UdEwEB +/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgGGMA0GCSqGSIb3DQEBCwUAA4ICAQDRSVfg +p8xoWLoBDysZzY2wYUWsEe1jUGn4H3++Fo/9nesLqjJHdtJnJO29fDMylyrHBYZm +DRd9FBUb1Ov9H5r2XpdptxolpAqzkT9fNqyL7FeoPueBihhXOYV0GkLH6VsTX4/5 +COmSdI31R9KrO9b7eGZONn356ZLpBN79SWP8bfsUcZNnL0dKt7n/HipzcEYwv1ry +L3ml4Y0M2fmyYzeMN2WFcGpcWwlyua1jPLHd+PwyvzeG5LuOmCd+uh8W4XAR8gPf +JWIyJyYYMoSf/wA6E7qaTfRPuBRwIrHKK5DOKcFw9C+df/KQHtZa37dG/OaG+svg +IHZ6uqbL9XzeYqWxi+7egmaKTjowHz+Ay60nugxe19CxVsp3cbK1daFQqUBDF8Io +2c9Si1vIY9RCPqAzekYu9wogRlR+ak8x8YF+QnQ4ZXMn7sZ8uI7XpTrXmKGcjBBV +09tL7ECQ8s1uV9JiDnxXk7Gnbc2dg7sq5+W2O3FYrf3RRbxake5TFW/TRQl1brqQ +XR4EzzffHqhmsYzmIGrv/EhOdJhCrylvLmrH+33RZjEizIYAfmaDDEL0vTSSwxrq +T8p+ck0LcIymSLumoRT2+1hEmRSuqguTaaApJUqlyyvdimYHFngVV3Eb7PVHhPOe +MTd61X8kreS8/f3MboPoDKi3QWwH3b08hpcv0g== +-----END CERTIFICATE-----'" +"GlobalSign nv-sa","GlobalSign","GlobalSign ECC Root CA - R5","GlobalSign","605949E0262EBB55F90A778A71F94AD86C","179FBC148A3DD00FD24EA13458CC43BFA7F59C8182D783A513F6EBEC100C8924","A64AEFD1343767459314DFB5FA4B1F97B382C07EEB2D55C4194F91E127672520","2012.11.13","2038.01.19","EC secp384r1","ecdsaWithSHA384","Websites;Email","","","2.23.140.1.1","https://bugzilla.mozilla.org/show_bug.cgi?id=825954","NSS 3.17.3","Firefox 36","https://valid.r5.roots.globalsign.com","https://expired.r5.roots.globalsign.com","https://revoked.r5.roots.globalsign.com","None","https://www.globalsign.com","Belgium, Global","https://www.globalsign.com/en/repository/GlobalSign_CP_v6.3_final.pdf","https://www.globalsign.com/en/repository/GlobalSign_CPS_v9.3_final.pdf","https://www.cpacanada.ca/generichandlers/CPACHandler.ashx?attachmentid=240903","https://www.cpacanada.ca/generichandlers/CPACHandler.ashx?attachmentid=240904","https://www.cpacanada.ca/generichandlers/CPACHandler.ashx?attachmentid=240905","Ernst & Young, LLP","WebTrust","2020.06.29","'-----BEGIN CERTIFICATE----- +MIICHjCCAaSgAwIBAgIRYFlJ4CYuu1X5CneKcflK2GwwCgYIKoZIzj0EAwMwUDEk +MCIGA1UECxMbR2xvYmFsU2lnbiBFQ0MgUm9vdCBDQSAtIFI1MRMwEQYDVQQKEwpH +bG9iYWxTaWduMRMwEQYDVQQDEwpHbG9iYWxTaWduMB4XDTEyMTExMzAwMDAwMFoX +DTM4MDExOTAzMTQwN1owUDEkMCIGA1UECxMbR2xvYmFsU2lnbiBFQ0MgUm9vdCBD +QSAtIFI1MRMwEQYDVQQKEwpHbG9iYWxTaWduMRMwEQYDVQQDEwpHbG9iYWxTaWdu +MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAER0UOlvt9Xb/pOdEh+J8LttV7HpI6SFkc +8GIxLcB6KP4ap1yztsyX50XUWPrRd21DosCHZTQKH3rd6zwzocWdTaRvQZU4f8ke +hOvRnkmSh5SHDDqFSmafnVmTTZdhBoZKo0IwQDAOBgNVHQ8BAf8EBAMCAQYwDwYD +VR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUPeYpSJvqB8ohREom3m7e0oPQn1kwCgYI +KoZIzj0EAwMDaAAwZQIxAOVpEslu28YxuglB4Zf4+/2a4n0Sye18ZNPLBSWLVtmg +515dTguDnFt2KaAJJiFqYgIwcdK1j1zqO+F4CYWodZI7yFz9SO8NdCKoCOJuxUnO +xwy8p2Fp8fc74SrL+SvzZpA3 +-----END CERTIFICATE-----'" +"GlobalSign nv-sa","GlobalSign","GlobalSign Root CA - R3","GlobalSign","04000000000121585308A2","CBB522D7B7F127AD6A0113865BDF1CD4102E7D0759AF635A7CF4720DC963C53B","36E1C3DAD1E6E9545058867325C3CC79E4B9C70E41B86EAB1A550F7520C6D5D6","2009.03.18","2029.03.18","RSA 2048 bits","SHA256WithRSA","Websites;Email","","","2.23.140.1.1","https://bugzilla.mozilla.org/show_bug.cgi?id=507360","NSS 3.12.8","Firefox 3.6.12","https://valid.r3.roots.globalsign.com","https://expired.r3.roots.globalsign.com","https://revoked.r3.roots.globalsign.com","","https://www.globalsign.com","Belgium, Global","https://www.globalsign.com/en/repository/GlobalSign_CP_v6.3_final.pdf","https://www.globalsign.com/en/repository/GlobalSign_CPS_v9.3_final.pdf","https://www.cpacanada.ca/generichandlers/CPACHandler.ashx?attachmentid=240903","https://www.cpacanada.ca/generichandlers/CPACHandler.ashx?attachmentid=240904","https://www.cpacanada.ca/generichandlers/CPACHandler.ashx?attachmentid=240905","Ernst & Young, LLP","WebTrust","2020.06.29","'-----BEGIN CERTIFICATE----- +MIIDXzCCAkegAwIBAgILBAAAAAABIVhTCKIwDQYJKoZIhvcNAQELBQAwTDEgMB4G +A1UECxMXR2xvYmFsU2lnbiBSb290IENBIC0gUjMxEzARBgNVBAoTCkdsb2JhbFNp +Z24xEzARBgNVBAMTCkdsb2JhbFNpZ24wHhcNMDkwMzE4MTAwMDAwWhcNMjkwMzE4 +MTAwMDAwWjBMMSAwHgYDVQQLExdHbG9iYWxTaWduIFJvb3QgQ0EgLSBSMzETMBEG +A1UEChMKR2xvYmFsU2lnbjETMBEGA1UEAxMKR2xvYmFsU2lnbjCCASIwDQYJKoZI +hvcNAQEBBQADggEPADCCAQoCggEBAMwldpB5BngiFvXAg7aEyiie/QV2EcWtiHL8 +RgJDx7KKnQRfJMsuS+FggkbhUqsMgUdwbN1k0ev1LKMPgj0MK66X17YUhhB5uzsT +gHeMCOFJ0mpiLx9e+pZo34knlTifBtc+ycsmWQ1z3rDI6SYOgxXG71uL0gRgykmm +KPZpO/bLyCiR5Z2KYVc3rHQU3HTgOu5yLy6c+9C7v/U9AOEGM+iCK65TpjoWc4zd +QQ4gOsC0p6Hpsk+QLjJg6VfLuQSSaGjlOCZgdbKfd/+RFO+uIEn8rUAVSNECMWEZ +XriX7613t2Saer9fwRPvm2L7DWzgVGkWqQPabumDk3F2xmmFghcCAwEAAaNCMEAw +DgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFI/wS3+o +LkUkrk1Q+mOai97i3Ru8MA0GCSqGSIb3DQEBCwUAA4IBAQBLQNvAUKr+yAzv95ZU +RUm7lgAJQayzE4aGKAczymvmdLm6AC2upArT9fHxD4q/c2dKg8dEe3jgr25sbwMp +jjM5RcOO5LlXbKr8EpbsU8Yt5CRsuZRj+9xTaGdWPoO4zzUhw8lo/s7awlOqzJCK +6fBdRoyV3XpYKBovHd7NADdBj+1EbddTKJd+82cEHhXXipa0095MJ6RMG3NzdvQX +mcIfeg7jLQitChws/zyrVQ4PkX4268NXSb7hLi18YIvDQVETI53O9zJrlAGomecs +Mx86OyXShkDOOyyGeMlhLxS67ttVb9+E7gUJTb0o2HLO02JQZR7rkpeDMdmztcpH +WD9f +-----END CERTIFICATE-----'" +"GlobalSign nv-sa","GlobalSign","GlobalSign Root CA - R6","GlobalSign","45E6BB038333C3856548E6FF4551","2CABEAFE37D06CA22ABA7391C0033D25982952C453647349763A3AB5AD6CCF69","33FD5FC097D472DD50BBC47EDDE854E177CB33DFDBE53E419D632EAAFD61878C","2014.12.10","2034.12.10","RSA 4096 bits","SHA384WithRSA","Websites;Email","","","2.23.140.1.1","https://bugzilla.mozilla.org/show_bug.cgi?id=1390803","NSS 3.39","Firefox 63","https://valid.r6.roots.globalsign.com/","https://expired.r6.roots.globalsign.com/","https://revoked.r6.roots.globalsign.com/","","https://www.globalsign.com","Belgium, Global","https://www.globalsign.com/en/repository/GlobalSign_CP_v6.3_final.pdf","https://www.globalsign.com/en/repository/GlobalSign_CPS_v9.3_final.pdf","https://www.cpacanada.ca/generichandlers/CPACHandler.ashx?attachmentid=240903","https://www.cpacanada.ca/generichandlers/CPACHandler.ashx?attachmentid=240904","https://www.cpacanada.ca/generichandlers/CPACHandler.ashx?attachmentid=240905","Ernst & Young, LLP","WebTrust","2020.06.29","'-----BEGIN CERTIFICATE----- +MIIFgzCCA2ugAwIBAgIORea7A4Mzw4VlSOb/RVEwDQYJKoZIhvcNAQEMBQAwTDEg +MB4GA1UECxMXR2xvYmFsU2lnbiBSb290IENBIC0gUjYxEzARBgNVBAoTCkdsb2Jh +bFNpZ24xEzARBgNVBAMTCkdsb2JhbFNpZ24wHhcNMTQxMjEwMDAwMDAwWhcNMzQx +MjEwMDAwMDAwWjBMMSAwHgYDVQQLExdHbG9iYWxTaWduIFJvb3QgQ0EgLSBSNjET +MBEGA1UEChMKR2xvYmFsU2lnbjETMBEGA1UEAxMKR2xvYmFsU2lnbjCCAiIwDQYJ +KoZIhvcNAQEBBQADggIPADCCAgoCggIBAJUH6HPKZvnsFMp7PPcNCPG0RQssgrRI +xutbPK6DuEGSMxSkb3/pKszGsIhrxbaJ0cay/xTOURQh7ErdG1rG1ofuTToVBu1k +ZguSgMpE3nOUTvOniX9PeGMIyBJQbUJmL025eShNUhqKGoC3GYEOfsSKvGRMIRxD +aNc9PIrFsmbVkJq3MQbFvuJtMgamHvm566qjuL++gmNQ0PAYid/kD3n16qIfKtJw +LnvnvJO7bVPiSHyMEAc4/2ayd2F+4OqMPKq0pPbzlUoSB239jLKJz9CgYXfIWHSw +1CM69106yqLbnQneXUQtkPGBzVeS+n68UARjNN9rkxi+azayOeSsJDa38O+2HBNX +k7besvjihbdzorg1qkXy4J02oW9UivFyVm4uiMVRQkQVlO6jxTiWm05OWgtH8wY2 +SXcwvHE35absIQh1/OZhFj931dmRl4QKbNQCTXTAFO39OfuD8l4UoQSwC+n+7o/h +bguyCLNhZglqsQY6ZZZZwPA1/cnaKI0aEYdwgQqomnUdnjqGBQCe24DWJfncBZ4n +WUx2OVvq+aWh2IMP0f/fMBH5hc8zSPXKbWQULHpYT9NLCEnFlWQaYw55PfWzjMpY +rZxCRXluDocZXFSxZba/jJvcE+kNb7gu3GduyYsRtYQUigAZcIN5kZeR1Bonvzce +MgfYFGM8KEyvAgMBAAGjYzBhMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTAD +AQH/MB0GA1UdDgQWBBSubAWjkxPioufi1xzWx/B/yGdToDAfBgNVHSMEGDAWgBSu +bAWjkxPioufi1xzWx/B/yGdToDANBgkqhkiG9w0BAQwFAAOCAgEAgyXt6NH9lVLN +nsAEoJFp5lzQhN7craJP6Ed41mWYqVuoPId8AorRbrcWc+ZfwFSY1XS+wc3iEZGt +Ixg93eFyRJa0lV7Ae46ZeBZDE1ZXs6KzO7V33EByrKPrmzU+sQghoefEQzd5Mr61 +55wsTLxDKZmOMNOsIeDjHfrYBzN2VAAiKrlNIC5waNrlU/yDXNOd8v9EDERm8tLj +vUYAGm0CuiVdjaExUd1URhxN25mW7xocBFymFe944Hn+Xds+qkxV/ZoVqW/hpvvf +cDDpw+5CRu3CkwWJ+n1jez/QcYF8AOiYrg54NMMl+68KnyBr3TsTjxKM4kEaSHpz +oHdpx7Zcf4LIHv5YGygrqGytXm3ABdJ7t+uA/iU3/gKbaKxCXcPu9czc8FB10jZp +nOZ7BN9uBmm23goJSFmH63sUYHpkqmlD75HHTOwY3WzvUy2MmeFe8nI+z1TIvWfs +pA9MRf/TuTAjB0yPEL+GltmZWrSZVxykzLsViVO6LAUP5MSeGbEYNNVMnbrt9x+v +JJUEeKgDu+6B5dpffItKoZB0JaezPkvILFa9x8jvOOJckvB595yEunQtYQEgfn7R +8k8HWV+LLUNS60YMlOH1Zkd5d9VUWx+tJDfLRVpOoERIyNiwmcUVhAn21klJwGW4 +5hpxbqCo8YLoRT5s1gLXCmeDBVrJpBA= +-----END CERTIFICATE-----'" +"GlobalSign nv-sa","GlobalSign nv-sa","Root CA","GlobalSign Root CA","040000000001154B5AC394","EBD41040E4BB3EC742C9E381D31EF2A41A48B6685C96E7CEF3C1DF6CD4331C99","E2D61F4A55EA263BB9B6FD98A2625439E581FD543179ADE55F0A6F681786A5DF","1998.09.01","2028.01.28","RSA 2048 bits","SHA1WithRSA","Websites;Email","","","2.23.140.1.1","https://bugzilla.mozilla.org/show_bug.cgi?id=406794","NSS 3.11.10","Firefox 3.0.2","https://valid.r1.roots.globalsign.com","https://expired.r1.roots.globalsign.com","https://revoked.r1.roots.globalsign.com","","https://www.globalsign.com","Belgium, Global","https://www.globalsign.com/en/repository/GlobalSign_CP_v6.3_final.pdf","https://www.globalsign.com/en/repository/GlobalSign_CPS_v9.3_final.pdf","https://www.cpacanada.ca/generichandlers/CPACHandler.ashx?attachmentid=240903","https://www.cpacanada.ca/generichandlers/CPACHandler.ashx?attachmentid=240904","https://www.cpacanada.ca/generichandlers/CPACHandler.ashx?attachmentid=240905","Ernst & Young, LLP","WebTrust","2020.06.29","'-----BEGIN CERTIFICATE----- +MIIDdTCCAl2gAwIBAgILBAAAAAABFUtaw5QwDQYJKoZIhvcNAQEFBQAwVzELMAkG +A1UEBhMCQkUxGTAXBgNVBAoTEEdsb2JhbFNpZ24gbnYtc2ExEDAOBgNVBAsTB1Jv +b3QgQ0ExGzAZBgNVBAMTEkdsb2JhbFNpZ24gUm9vdCBDQTAeFw05ODA5MDExMjAw +MDBaFw0yODAxMjgxMjAwMDBaMFcxCzAJBgNVBAYTAkJFMRkwFwYDVQQKExBHbG9i +YWxTaWduIG52LXNhMRAwDgYDVQQLEwdSb290IENBMRswGQYDVQQDExJHbG9iYWxT +aWduIFJvb3QgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDaDuaZ +jc6j40+Kfvvxi4Mla+pIH/EqsLmVEQS98GPR4mdmzxzdzxtIK+6NiY6arymAZavp +xy0Sy6scTHAHoT0KMM0VjU/43dSMUBUc71DuxC73/OlS8pF94G3VNTCOXkNz8kHp +1Wrjsok6Vjk4bwY8iGlbKk3Fp1S4bInMm/k8yuX9ifUSPJJ4ltbcdG6TRGHRjcdG +snUOhugZitVtbNV4FpWi6cgKOOvyJBNPc1STE4U6G7weNLWLBYy5d4ux2x8gkasJ +U26Qzns3dLlwR5EiUWMWea6xrkEmCMgZK9FGqkjWZCrXgzT/LCrBbBlDSgeF59N8 +9iFo7+ryUp9/k5DPAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8E +BTADAQH/MB0GA1UdDgQWBBRge2YaRQ2XyolQL30EzTSo//z9SzANBgkqhkiG9w0B +AQUFAAOCAQEA1nPnfE920I2/7LqivjTFKDK1fPxsnCwrvQmeU79rXqoRSLblCKOz +yj1hTdNGCbM+w6DjY1Ub8rrvrTnhQ7k4o+YviiY776BQVvnGCv04zcQLcFGUl5gE +38NflNUVyRRBnMRddWQVDf9VMOyGj/8N7yy5Y0b2qvzfvGn9LhJIZJrglfCm7ymP +AbEVtQwdpf5pLGkkeB6zpxxxYu7KyJesF12KwvhHhm4qxFYxldBniYUr+WymXUad +DKqC5JlR3XC321Y9YeRq4VzW9v493kHMB65jUr9TU/Qr6cf9tveCX4XSQRjbgbME +HMUfpIBvFSDJ3gyICh3WZlXi/EjJKSZp4A== +-----END CERTIFICATE-----'" +"GoDaddy","The Go Daddy Group, Inc.","Go Daddy Class 2 Certification Authority","Go Daddy Class 2 CA","00","C3846BF24B9E93CA64274C0EC67C1ECC5E024FFCACD2D74019350E81FE546AE4","6CB777C3B2653371134AB578E0FE2E60F116CF56208C884E6540D10BECBCB671","2004.06.29","2034.06.29","RSA 2048 bits","SHA1WithRSA","Websites;Email","","","2.16.840.1.114413.1.7.23.3","https://bugzilla.mozilla.org/show_bug.cgi?id=284677","NSS 3.10","Firefox 1","https://valid.gdi.catest.godaddy.com/","https://expired.gdi.catest.godaddy.com/","https://revoked.gdi.catest.godaddy.com/","","http://www.godaddy.com/","USA, Global","","https://certs.godaddy.com/repository/certificate_practices/en/StarfieldCertificatePolicyandCertificationPracticeStatement.pdf","https://www.cpacanada.ca/generichandlers/CPACHandler.ashx?attachmentid=234200","https://www.cpacanada.ca/generichandlers/CPACHandler.ashx?attachmentid=234201","https://www.cpacanada.ca/generichandlers/CPACHandler.ashx?attachmentid=234202","Schellman & Company, LLC.","WebTrust","2019.08.14","'-----BEGIN CERTIFICATE----- +MIIEADCCAuigAwIBAgIBADANBgkqhkiG9w0BAQUFADBjMQswCQYDVQQGEwJVUzEh +MB8GA1UEChMYVGhlIEdvIERhZGR5IEdyb3VwLCBJbmMuMTEwLwYDVQQLEyhHbyBE +YWRkeSBDbGFzcyAyIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTA0MDYyOTE3 +MDYyMFoXDTM0MDYyOTE3MDYyMFowYzELMAkGA1UEBhMCVVMxITAfBgNVBAoTGFRo +ZSBHbyBEYWRkeSBHcm91cCwgSW5jLjExMC8GA1UECxMoR28gRGFkZHkgQ2xhc3Mg +MiBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTCCASAwDQYJKoZIhvcNAQEBBQADggEN +ADCCAQgCggEBAN6d1+pXGEmhW+vXX0iG6r7d/+TvZxz0ZWizV3GgXne77ZtJ6XCA +PVYYYwhv2vLM0D9/AlQiVBDYsoHUwHU9S3/Hd8M+eKsaA7Ugay9qK7HFiH7Eux6w +wdhFJ2+qN1j3hybX2C32qRe3H3I2TqYXP2WYktsqbl2i/ojgC95/5Y0V4evLOtXi +EqITLdiOr18SPaAIBQi2XKVlOARFmR6jYGB0xUGlcmIbYsUfb18aQr4CUWWoriMY +avx4A6lNf4DD+qta/KFApMoZFv6yyO9ecw3ud72a9nmYvLEHZ6IVDd2gWMZEewo+ +YihfukEHU1jPEX44dMX4/7VpkI+EdOqXG68CAQOjgcAwgb0wHQYDVR0OBBYEFNLE +sNKR1EwRcbNhyz2h/t2oatTjMIGNBgNVHSMEgYUwgYKAFNLEsNKR1EwRcbNhyz2h +/t2oatTjoWekZTBjMQswCQYDVQQGEwJVUzEhMB8GA1UEChMYVGhlIEdvIERhZGR5 +IEdyb3VwLCBJbmMuMTEwLwYDVQQLEyhHbyBEYWRkeSBDbGFzcyAyIENlcnRpZmlj +YXRpb24gQXV0aG9yaXR5ggEAMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQAD +ggEBADJL87LKPpH8EsahB4yOd6AzBhRckB4Y9wimPQoZ+YeAEW5p5JYXMP80kWNy +OO7MHAGjHZQopDH2esRU1/blMVgDoszOYtuURXO1v0XJJLXVggKtI3lpjbi2Tc7P +TMozI+gciKqdi0FuFskg5YmezTvacPd+mSYgFFQlq25zheabIZ0KbIIOqPjCDPoQ +HmyW74cNxA9hi63ugyuV+I6ShHI56yDqg+2DzZduCLzrTia2cyvk0/ZM/iZx4mER +dEr/VxqHD3VILs9RaRegAhJhldXRQLIQTO7ErBBDpqWeCtWVYpoNz4iCxTIM5Cuf +ReYNnyicsbkqWletNw+vHX/bvZ8= +-----END CERTIFICATE-----'" +"GoDaddy","GoDaddy.com, Inc.","","Go Daddy Root Certificate Authority - G2","00","45140B3247EB9CC8C5B4F0D7B53091F73292089E6E5A63E2749DD3ACA9198EDA","397DA2FAACAB0A2C3A4C4C92AF13361A64E69FDE24430200DADB150983FEB30A","2009.09.01","2037.12.31","RSA 2048 bits","SHA256WithRSA","Websites","","","2.16.840.1.114413.1.7.23.3","https://bugzilla.mozilla.org/show_bug.cgi?id=527056","NSS 3.12.10","Firefox 6.0","https://valid.gdig2.catest.godaddy.com/","https://expired.gdig2.catest.godaddy.com/","https://revoked.gdig2.catest.godaddy.com/","","http://www.godaddy.com/","USA, Global","","https://certs.godaddy.com/repository/certificate_practices/en/StarfieldCertificatePolicyandCertificationPracticeStatement.pdf","https://www.cpacanada.ca/generichandlers/CPACHandler.ashx?attachmentid=234200","https://www.cpacanada.ca/generichandlers/CPACHandler.ashx?attachmentid=234201","https://www.cpacanada.ca/generichandlers/CPACHandler.ashx?attachmentid=234202","Schellman & Company, LLC.","WebTrust","2019.08.14","'-----BEGIN CERTIFICATE----- +MIIDxTCCAq2gAwIBAgIBADANBgkqhkiG9w0BAQsFADCBgzELMAkGA1UEBhMCVVMx +EDAOBgNVBAgTB0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxGjAYBgNVBAoT +EUdvRGFkZHkuY29tLCBJbmMuMTEwLwYDVQQDEyhHbyBEYWRkeSBSb290IENlcnRp +ZmljYXRlIEF1dGhvcml0eSAtIEcyMB4XDTA5MDkwMTAwMDAwMFoXDTM3MTIzMTIz +NTk1OVowgYMxCzAJBgNVBAYTAlVTMRAwDgYDVQQIEwdBcml6b25hMRMwEQYDVQQH +EwpTY290dHNkYWxlMRowGAYDVQQKExFHb0RhZGR5LmNvbSwgSW5jLjExMC8GA1UE +AxMoR28gRGFkZHkgUm9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkgLSBHMjCCASIw +DQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAL9xYgjx+lk09xvJGKP3gElY6SKD +E6bFIEMBO4Tx5oVJnyfq9oQbTqC023CYxzIBsQU+B07u9PpPL1kwIuerGVZr4oAH +/PMWdYA5UXvl+TW2dE6pjYIT5LY/qQOD+qK+ihVqf94Lw7YZFAXK6sOoBJQ7Rnwy +DfMAZiLIjWltNowRGLfTshxgtDj6AozO091GB94KPutdfMh8+7ArU6SSYmlRJQVh +GkSBjCypQ5Yj36w6gZoOKcUcqeldHraenjAKOc7xiID7S13MMuyFYkMlNAJWJwGR +tDtwKj9useiciAF9n9T521NtYJ2/LOdYq7hfRvzOxBsDPAnrSTFcaUaz4EcCAwEA +AaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYE +FDqahQcQZyi27/a9BUFuIMGU2g/eMA0GCSqGSIb3DQEBCwUAA4IBAQCZ21151fmX +WWcDYfF+OwYxdS2hII5PZYe096acvNjpL9DbWu7PdIxztDhC2gV7+AJ1uP2lsdeu +9tfeE8tTEH6KRtGX+rcuKxGrkLAngPnon1rpN5+r5N9ss4UXnT3ZJE95kTXWXwTr +gIOrmgIttRD02JDHBHNA7XIloKmf7J6raBKZV8aPEjoJpL1E/QYVN8Gb5DKj7Tjo +2GTzLH4U/ALqn83/B2gX2yKQOC16jdFU8WnjXzPKej17CuPKf1855eJ1usV2GDPO +LPAvTK33sefOT6jEm0pUBsV/fdUID+Ic/n4XuKxe9tQWskMJDE32p2u0mYRlynqI +4uJEvlz36hz1 +-----END CERTIFICATE-----'" +"GoDaddy","Starfield Technologies, Inc.","Starfield Class 2 Certification Authority","Starfield Class 2 CA","00","1465FA205397B876FAA6F0A9958E5590E40FCC7FAA4FB7C2C8677521FB5FB658","75B917DBDFBE859F4E9BE41A26235727F59AA6DEBE65AAE116905F31739C68AF","2004.06.29","2034.06.29","RSA 2048 bits","SHA1WithRSA","Websites;Email","","","2.16.840.1.114414.1.7.23.3","https://bugzilla.mozilla.org/show_bug.cgi?id=284677","NSS 3.10","Firefox 1","https://valid.sfi.catest.starfieldtech.com/","https://expired.sfi.catest.starfieldtech.com/","https://revoked.sfi.catest.starfieldtech.com/","","http://www.godaddy.com/","USA, Global","","https://certs.godaddy.com/repository/certificate_practices/en/StarfieldCertificatePolicyandCertificationPracticeStatement.pdf","https://www.cpacanada.ca/generichandlers/CPACHandler.ashx?attachmentid=234200","https://www.cpacanada.ca/generichandlers/CPACHandler.ashx?attachmentid=234201","https://www.cpacanada.ca/generichandlers/CPACHandler.ashx?attachmentid=234202","Schellman & Company, LLC.","WebTrust","2019.08.14","'-----BEGIN CERTIFICATE----- +MIIEDzCCAvegAwIBAgIBADANBgkqhkiG9w0BAQUFADBoMQswCQYDVQQGEwJVUzEl +MCMGA1UEChMcU3RhcmZpZWxkIFRlY2hub2xvZ2llcywgSW5jLjEyMDAGA1UECxMp +U3RhcmZpZWxkIENsYXNzIDIgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMDQw +NjI5MTczOTE2WhcNMzQwNjI5MTczOTE2WjBoMQswCQYDVQQGEwJVUzElMCMGA1UE +ChMcU3RhcmZpZWxkIFRlY2hub2xvZ2llcywgSW5jLjEyMDAGA1UECxMpU3RhcmZp +ZWxkIENsYXNzIDIgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwggEgMA0GCSqGSIb3 +DQEBAQUAA4IBDQAwggEIAoIBAQC3Msj+6XGmBIWtDBFk385N78gDGIc/oav7PKaf +8MOh2tTYbitTkPskpD6E8J7oX+zlJ0T1KKY/e97gKvDIr1MvnsoFAZMej2YcOadN ++lq2cwQlZut3f+dZxkqZJRRU6ybH838Z1TBwj6+wRir/resp7defqgSHo9T5iaU0 +X9tDkYI22WY8sbi5gv2cOj4QyDvvBmVmepsZGD3/cVE8MC5fvj13c7JdBmzDI1aa +K4UmkhynArPkPw2vCHmCuDY96pzTNbO8acr1zJ3o/WSNF4Azbl5KXZnJHoe0nRrA +1W4TNSNe35tfPe/W93bC6j67eA0cQmdrBNj41tpvi/JEoAGrAgEDo4HFMIHCMB0G +A1UdDgQWBBS/X7fRzt0fhvRbVazc1xDCDqmI5zCBkgYDVR0jBIGKMIGHgBS/X7fR +zt0fhvRbVazc1xDCDqmI56FspGowaDELMAkGA1UEBhMCVVMxJTAjBgNVBAoTHFN0 +YXJmaWVsZCBUZWNobm9sb2dpZXMsIEluYy4xMjAwBgNVBAsTKVN0YXJmaWVsZCBD +bGFzcyAyIENlcnRpZmljYXRpb24gQXV0aG9yaXR5ggEAMAwGA1UdEwQFMAMBAf8w +DQYJKoZIhvcNAQEFBQADggEBAAWdP4id0ckaVaGsafPzWdqbAYcaT1epoXkJKtv3 +L7IezMdeatiDh6GX70k1PncGQVhiv45YuApnP+yz3SFmH8lU+nLMPUxA2IGvd56D +eruix/U0F47ZEUD0/CwqTRV/p2JdLiXTAAsgGh1o+Re49L2L7ShZ3U0WixeDyLJl +xy16paq8U4Zt3VekyvggQQto8PT7dL5WXXp59fkdheMtlb71cZBDzI0fmgAKhynp +VSJYACPq4xJDKVtHCN2MQWplBqjlIapBtJUhlbl90TSrE9atvNziPTnNvT51cKEY +WQPJIrSPnNVeKtelttQKbfi3QBFGmh95DmK/D5fs4C8fF5Q= +-----END CERTIFICATE-----'" +"GoDaddy","Starfield Technologies, Inc.","","Starfield Root Certificate Authority - G2","00","2CE1CB0BF9D2F9E102993FBE215152C3B2DD0CABDE1C68E5319B839154DBB7F5","2F0CDE81F2EEB640DA2990B73A31E2172FB59807966B593BB9F403E976B0F533","2009.09.01","2037.12.31","RSA 2048 bits","SHA256WithRSA","Websites","","","2.16.840.1.114414.1.7.23.3","https://bugzilla.mozilla.org/show_bug.cgi?id=527056","NSS 3.12.10","Firefox 6.0","https://valid.sfig2.catest.starfieldtech.com/","https://expired.sfig2.catest.starfieldtech.com/","https://revoked.sfig2.catest.starfieldtech.com/","","http://www.godaddy.com/","USA, Global","","https://certs.godaddy.com/repository/certificate_practices/en/StarfieldCertificatePolicyandCertificationPracticeStatement.pdf","https://www.cpacanada.ca/generichandlers/CPACHandler.ashx?attachmentid=234200","https://www.cpacanada.ca/generichandlers/CPACHandler.ashx?attachmentid=234201","https://www.cpacanada.ca/generichandlers/CPACHandler.ashx?attachmentid=234202","Schellman & Company, LLC.","WebTrust","2019.08.14","'-----BEGIN CERTIFICATE----- +MIID3TCCAsWgAwIBAgIBADANBgkqhkiG9w0BAQsFADCBjzELMAkGA1UEBhMCVVMx +EDAOBgNVBAgTB0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxJTAjBgNVBAoT +HFN0YXJmaWVsZCBUZWNobm9sb2dpZXMsIEluYy4xMjAwBgNVBAMTKVN0YXJmaWVs +ZCBSb290IENlcnRpZmljYXRlIEF1dGhvcml0eSAtIEcyMB4XDTA5MDkwMTAwMDAw +MFoXDTM3MTIzMTIzNTk1OVowgY8xCzAJBgNVBAYTAlVTMRAwDgYDVQQIEwdBcml6 +b25hMRMwEQYDVQQHEwpTY290dHNkYWxlMSUwIwYDVQQKExxTdGFyZmllbGQgVGVj +aG5vbG9naWVzLCBJbmMuMTIwMAYDVQQDEylTdGFyZmllbGQgUm9vdCBDZXJ0aWZp +Y2F0ZSBBdXRob3JpdHkgLSBHMjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC +ggEBAL3twQP89o/8ArFvW59I2Z154qK3A2FWGMNHttfKPTUuiUP3oWmb3ooa/RMg +nLRJdzIpVv257IzdIvpy3Cdhl+72WoTsbhm5iSzchFvVdPtrX8WJpRBSiUZV9Lh1 +HOZ/5FSuS/hVclcCGfgXcVnrHigHdMWdSL5stPSksPNkN3mSwOxGXn/hbVNMYq/N +Hwtjuzqd+/x5AJhhdM8mgkBj87JyahkNmcrUDnXMN/uLicFZ8WJ/X7NfZTD4p7dN +dloedl40wOiWVpmKs/B/pM293DIxfJHP4F8R+GuqSVzRmZTRouNjWwl2tVZi4Ut0 +HZbUJtQIBFnQmA4O5t78w+wfkPECAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAO +BgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFHwMMh+n2TB/xH1oo2Kooc6rB1snMA0G +CSqGSIb3DQEBCwUAA4IBAQARWfolTwNvlJk7mh+ChTnUdgWUXuEok21iXQnCoKjU +sHU48TRqneSfioYmUeYs0cYtbpUgSpIB7LiKZ3sx4mcujJUDJi5DnUox9g61DLu3 +4jd/IroAow57UvtruzvE03lRTs2Q9GcHGcg8RnoNAX3FWOdt5oUwF5okxBDgBPfg +8n/Uqgr/Qh037ZTlZFkSIHc40zI+OIF1lnP6aI+xy84fxez6nH7PfrHxBy22/L/K +pL/QlwVKvOoYKAKQvVR4CSFx09F9HdkWsKlhPdAKACL8x3vLCWRFCztAgfd9fDL1 +mMpYjn0q7pBZc2T5NnReJaH1ZgUufzkVqSr7UIuOhWn0 +-----END CERTIFICATE-----'" +"Google Trust Services LLC (GTS)","GlobalSign","GlobalSign ECC Root CA - R4","GlobalSign","2A38A41C960A04DE42B228A50BE8349802","BEC94911C2955676DB6C0A550986D76E3BA005667C442C9762B4FBB773DE228C","E7BE5BAB85BD4AF554B3C28287CEF885C92126334C0FFC85E6607461B815F162","2012.11.13","2038.01.19","EC secp256r1","ecdsaWithSHA256","Websites;Email","","","Not EV","https://bugzilla.mozilla.org/show_bug.cgi?id=825954","NSS 3.17.3","Firefox 36","https://good.gsr4demo.pki.goog/","https://expired.gsr4demo.pki.goog/","https://revoked.gsr4demo.pki.goog/","None","https://pki.goog","Global","https://static.googleusercontent.com/media/pki.goog/en//GTS-CP-1.9.pdf","https://static.googleusercontent.com/media/pki.goog/en//GTS-CPS-2.14.pdf","https://www.cpacanada.ca/generichandlers/CPACHandler.ashx?attachmentid=236832","https://www.cpacanada.ca/generichandlers/CPACHandler.ashx?attachmentid=236833","","Ernst & Young, LLP","WebTrust","2019.10.30","'-----BEGIN CERTIFICATE----- +MIIB4TCCAYegAwIBAgIRKjikHJYKBN5CsiilC+g0mAIwCgYIKoZIzj0EAwIwUDEk +MCIGA1UECxMbR2xvYmFsU2lnbiBFQ0MgUm9vdCBDQSAtIFI0MRMwEQYDVQQKEwpH +bG9iYWxTaWduMRMwEQYDVQQDEwpHbG9iYWxTaWduMB4XDTEyMTExMzAwMDAwMFoX +DTM4MDExOTAzMTQwN1owUDEkMCIGA1UECxMbR2xvYmFsU2lnbiBFQ0MgUm9vdCBD +QSAtIFI0MRMwEQYDVQQKEwpHbG9iYWxTaWduMRMwEQYDVQQDEwpHbG9iYWxTaWdu +MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEuMZ5049sJQ6fLjkZHAOkrprlOQcJ +FspjsbmG+IpXwVfOQvpzofdlQv8ewQCybnMO/8ch5RikqtlxP6jUuc6MHaNCMEAw +DgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFFSwe61F +uOJAf/sKbvu+M8k8o4TVMAoGCCqGSM49BAMCA0gAMEUCIQDckqGgE6bPA7DmxCGX +kPoUVy0D7O48027KqGx2vKLeuwIgJ6iFJzWbVsaj8kfSt24bAgAXqmemFZHe+pTs +ewv4n4Q= +-----END CERTIFICATE-----'" +"Google Trust Services LLC (GTS)","GlobalSign","GlobalSign Root CA - R2","GlobalSign","0400000000010F8626E60D","CA42DD41745FD0B81EB902362CF9D8BF719DA1BD1B1EFC946F5B4C99F42C1B9E","D3A1F647B28A974B318E60DFF310C76D7614C5C60F3F34CD0F7599D46D7DA0A9","2006.12.15","2021.12.15","RSA 2048 bits","SHA1WithRSA","Websites;Email","","","Not EV","https://bugzilla.mozilla.org/show_bug.cgi?id=367245","NSS 3.11.8","Firefox 2","https://good.gsr2demo.pki.goog/","https://expired.gsr2demo.pki.goog/","https://revoked.gsr2demo.pki.goog/","","https://pki.goog","Global","https://static.googleusercontent.com/media/pki.goog/en//GTS-CP-1.9.pdf","https://static.googleusercontent.com/media/pki.goog/en//GTS-CPS-2.14.pdf","https://www.cpacanada.ca/generichandlers/CPACHandler.ashx?attachmentid=236832","https://www.cpacanada.ca/generichandlers/CPACHandler.ashx?attachmentid=236833","","Ernst & Young, LLP","WebTrust","2019.10.30","'-----BEGIN CERTIFICATE----- +MIIDujCCAqKgAwIBAgILBAAAAAABD4Ym5g0wDQYJKoZIhvcNAQEFBQAwTDEgMB4G +A1UECxMXR2xvYmFsU2lnbiBSb290IENBIC0gUjIxEzARBgNVBAoTCkdsb2JhbFNp +Z24xEzARBgNVBAMTCkdsb2JhbFNpZ24wHhcNMDYxMjE1MDgwMDAwWhcNMjExMjE1 +MDgwMDAwWjBMMSAwHgYDVQQLExdHbG9iYWxTaWduIFJvb3QgQ0EgLSBSMjETMBEG +A1UEChMKR2xvYmFsU2lnbjETMBEGA1UEAxMKR2xvYmFsU2lnbjCCASIwDQYJKoZI +hvcNAQEBBQADggEPADCCAQoCggEBAKbPJA6+Lm8omUVCxKs+IVSbC9N/hHD6ErPL +v4dfxn+G07IwXNb9rfF73OX4YJYJkhD10FPe+3t+c4isUoh7SqbKSaZeqKeMWhG8 +eoLrvozps6yWJQeXSpkqBy+0Hne/ig+1AnwblrjFuTosvNYSuetZfeLQBoZfXklq +tTleiDTsvHgMCJiEbKjNS7SgfQx5TfC4LcshytVsW33hoCmEofnTlEnLJGKRILzd +C9XZzPnqJworc5HGnRusyMvo4KD0L5CLTfuwNhv2GXqF4G3yYROIXJ/gkwpRl4pa +zq+r1feqCapgvdzZX99yqWATXgAByUr6P6TqBwMhAo6CygPCm48CAwEAAaOBnDCB +mTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUm+IH +V2ccHsBqBt5ZtJot39wZhi4wNgYDVR0fBC8wLTAroCmgJ4YlaHR0cDovL2NybC5n +bG9iYWxzaWduLm5ldC9yb290LXIyLmNybDAfBgNVHSMEGDAWgBSb4gdXZxwewGoG +3lm0mi3f3BmGLjANBgkqhkiG9w0BAQUFAAOCAQEAmYFThxxol4aR7OBKuEQLq4Gs +J0/WwbgcQ3izDJr86iw8bmEbTUsp9Z8FHSbBuOmDAGJFtqkIk7mpM0sYmsL4h4hO +291xNBrBVNpGP+DTKqttVCL1OmLNIG+6KYnX3ZHu01yiPqFbQfXf5WRDLenVOavS +ot+3i9DAgBkcRcAtjOj4LaR0VknFBbVPFd5uRHg5h6h+u/N5GJG79G+dwfCMNYxd +AfvDbbnvRG15RjF+Cv6pgsH/76tuIMRQyV+dTZsXjAzlAcmgQWpzU/qlULRuJQ/7 +TBj0/VLZjmmx6BEP3ojY+x1J96relc8geMJgEtslQIxq/H5COEBkEveegeGTLg== +-----END CERTIFICATE-----'" +"Google Trust Services LLC (GTS)","Google Trust Services LLC","","GTS Root R1","6E47A9C54B470C0DEC33D089B91CF4E1","2A575471E31340BC21581CBD2CF13E158463203ECE94BCF9D3CC196BF09A5472","1AB88FE2C48A31F5435F3EE3A22F354379CC1E28BDEBB3D1E702ED4817441589","2016.06.22","2036.06.22","RSA 4096 bits","SHA384WithRSA","Websites","","","Not EV","https://bugzilla.mozilla.org/show_bug.cgi?id=1325532","NSS 3.41","Firefox 65","https://good.r1demo.pki.goog","https://expired.r1demo.pki.goog","https://revoked.r1demo.pki.goog","","https://pki.goog","Global","https://static.googleusercontent.com/media/pki.goog/en//GTS-CP-1.9.pdf","https://static.googleusercontent.com/media/pki.goog/en//GTS-CPS-2.14.pdf","https://www.cpacanada.ca/generichandlers/CPACHandler.ashx?attachmentid=236832","https://www.cpacanada.ca/generichandlers/CPACHandler.ashx?attachmentid=236833","","Ernst & Young, LLP","WebTrust","2019.10.30","'-----BEGIN CERTIFICATE----- +MIIFWjCCA0KgAwIBAgIQbkepxUtHDA3sM9CJuRz04TANBgkqhkiG9w0BAQwFADBH +MQswCQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExM +QzEUMBIGA1UEAxMLR1RTIFJvb3QgUjEwHhcNMTYwNjIyMDAwMDAwWhcNMzYwNjIy +MDAwMDAwWjBHMQswCQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNl +cnZpY2VzIExMQzEUMBIGA1UEAxMLR1RTIFJvb3QgUjEwggIiMA0GCSqGSIb3DQEB +AQUAA4ICDwAwggIKAoICAQC2EQKLHuOhd5s73L+UPreVp0A8of2C+X0yBoJx9vaM +f/vo27xqLpeXo4xL+Sv2sfnOhB2x+cWX3u+58qPpvBKJXqeqUqv4IyfLpLGcY9vX +mX7wCl7raKb0xlpHDU0QM+NOsROjyBhsS+z8CZDfnWQpJSMHobTSPS5g4M/SCYe7 +zUjwTcLCeoiKu7rPWRnWr4+wB7CeMfGCwcDfLqZtbBkOtdh+JhpFAz2weaSUKK0P +fyblqAj+lug8aJRT7oM6iCsVlgmy4HqMLnXWnOunVmSPlk9orj2XwoSPwLxAwAtc +vfaHszVsrBhQf4TgTM2S0yDpM7xSma8ytSmzJSq0SPly4cpk9+aCEI3oncKKiPo4 +Zor8Y/kB+Xj9e1x3+naH+uzfsQ55lVe0vSbv1gHR6xYKu44LtcXFilWr06zqkUsp +zBmkMiVOKvFlRNACzqrOSbTqn3yDsEB750Orp2yjj32JgfpMpf/VjsPOS+C12LOO +Rc92wO1AK/1TD7Cn1TsNsYqiA94xrcx36m97PtbfkSIS5r762DL8EGMUUXLeXdYW +k70paDPvOmbsB4om3xPXV2V4J95eSRQAogB/mqghtqmxlbCluQ0WEdrHbEg8QOB+ +DVrNVjzRlwW5y0vtOUucxD/SVRNuJLDWcfr0wbrM7Rv1/oFB2ACYPTrIrnqYNxgF +lQIDAQABo0IwQDAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNV +HQ4EFgQU5K8rJnEaK0gnhS9SZizv8IkTcT4wDQYJKoZIhvcNAQEMBQADggIBADiW +Cu49tJYeX++dnAsznyvgyv3SjgofQXSlfKqE1OXyHuY3UjKcC9FhHb8owbZEKTV1 +d5iyfNm9dKyKaOOpMQkpAWBz40d8U6iQSifvS9efk+eCNs6aaAyC58/UEBZvXw6Z +XPYfcX3v73svfuo21pdwCxXu11xWajOl40k4DLh9+42FpLFZXvRq4d2h9mREruZR +gyFmxhE+885H7pwoHyXa/6xmld01D1zvICxi/ZG6qcz8WpyTgYMpl0p8WnK0OdC3 +d8t5/Wk6kjftbjhlRn7pYL15iJdfOBL07q9bgsiG1eGZbYwE8na6SfZu6W0eX6Dv +J4J2QPim01hcDyxC2kLGe4g0x8HYRZvBPsVhHdljUEn2NIVq4BjFbkerQUIpm/Zg +DdIx02OYI5NaAIFItO/Nis3Jz5nu2Z6qNuFoS3FJFDYoOj0dzpqPJeaAcWErtXvM ++SUWgeExX6GjfhaknBZqlxi9dnKlC54dNuYvoS++cJEPqOba+MSSQGwlfnuzCdyy +F62ARPBopY+Udf90WuioAnwMCeKpSwughQtiue+hMZL77/ZRBIls6Kl0obsXs7X9 +SQ98POyDGCBDTtWTurQ0sR8WNh8M5mQ5Fkzc4P4dyKliPUDqysU0ArSuiYgzNdws +E3PYJ/HQcu51OyLemGhmW/HGY0dVHLqlCFF1pkgl +-----END CERTIFICATE-----'" +"Google Trust Services LLC (GTS)","Google Trust Services LLC","","GTS Root R2","6E47A9C65AB3E720C5309A3F6852F26F","C45D7BB08E6D67E62E4235110B564E5F78FD92EF058C840AEA4E6455D7585C60","0E5C2CB50C8CC27FF4E1C72805073A671BBC51763B8310735C6FEC3BDE93F9EB","2016.06.22","2036.06.22","RSA 4096 bits","SHA384WithRSA","Websites","","","Not EV","https://bugzilla.mozilla.org/show_bug.cgi?id=1325532","NSS 3.41","Firefox 65","https://good.r2demo.pki.goog","https://expired.r2demo.pki.goog","https://revoked.r2demo.pki.goog","","https://pki.goog","Global","https://static.googleusercontent.com/media/pki.goog/en//GTS-CP-1.9.pdf","https://static.googleusercontent.com/media/pki.goog/en//GTS-CPS-2.14.pdf","https://www.cpacanada.ca/generichandlers/CPACHandler.ashx?attachmentid=236832","https://www.cpacanada.ca/generichandlers/CPACHandler.ashx?attachmentid=236833","","Ernst & Young, LLP","WebTrust","2019.10.30","'-----BEGIN CERTIFICATE----- +MIIFWjCCA0KgAwIBAgIQbkepxlqz5yDFMJo/aFLybzANBgkqhkiG9w0BAQwFADBH +MQswCQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExM +QzEUMBIGA1UEAxMLR1RTIFJvb3QgUjIwHhcNMTYwNjIyMDAwMDAwWhcNMzYwNjIy +MDAwMDAwWjBHMQswCQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNl +cnZpY2VzIExMQzEUMBIGA1UEAxMLR1RTIFJvb3QgUjIwggIiMA0GCSqGSIb3DQEB +AQUAA4ICDwAwggIKAoICAQDO3v2m++zsFDQ8BwZabFn3GTXd98GdVarTzTukk3Lv +CvptnfbwhYBboUhSnznFt+4orO/LdmgUud+tAWyZH8QiHZ/+cnfgLFuv5AS/T3Kg +GjSY6Dlo7JUle3ah5mm5hRm9iYz+re026nO8/4Piy33B0s5Ks40FnotJk9/BW9Bu +XvAuMC6C/Pq8tBcKSOWIm8Wba96wyrQD8Nr0kLhlZPdcTK3ofmZemde4wj7I0BOd +re7kRXuJVfeKH2JShBKzwkCX44ofR5GmdFrS+LFjKBC4swm4VndAoiaYecb+3yXu +PuWgf9RhD1FLPD+M2uFwdNjCaKH5wQzpoeJ/u1U8dgbuak7MkogwTZq9TwtImoS1 +mKPV+3PBV2HdKFZ1E66HjucMUQkQdYhMvI35ezzUIkgfKtzra7tEscszcTJGr61K +8YzodDqs5xoic4DSMPclQsciOzsSrZYuxsN2B6ogtzVJV+mSSeh2FnIxZyuWfoqj +x5RWIr9qS34BIbIjMt/kmkRtWVtd9QCgHJvGeJeNkP+byKq0rxFROV7Z+2et1VsR +nTKaG73VululycslaVNVJ1zgyjbLiGH7HrfQy+4W+9OmTN6SpdTi3/UGVN4unUu0 +kzCqgc7dGtxRcw1PcOnlthYhGXmy5okLdWTK1au8CcEYof/UVKGFPP0UJAOyh9Ok +twIDAQABo0IwQDAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNV +HQ4EFgQUu//KjiOfT5nK2+JopqUVJxce2Q4wDQYJKoZIhvcNAQEMBQADggIBALZp +8KZ3/p7uC4Gt4cCpx/k1HUCCq+YEtN/L9x0Pg/B+E02NjO7jMyLDOfxA325BS0JT +vhaI8dI4XsRomRyYUpOM52jtG2pzegVATX9lO9ZY8c6DR2Dj/5epnGB3GFW1fgiT +z9D2PGcDFWEJ+YF59exTpJ/JjwGLc8R3dtyDovUMSRqodt6Sm2T4syzFJ9MHwAiA +pJiS4wGWAqoC7o87xdFtCjMwc3i5T1QWvwsHoaRc5svJXISPD+AVdyx+Jn7axEvb +pxZ3B7DNdehyQtaVhJ2Gg/LkkM0JR9SLA3DaWsYDQvTtN6LwG1BUSw7YhN4ZKJmB +R64JGz9I0cNv4rBgF/XuIwKl2gBbbZCr7qLpGzvpx0QnRY5rn/WkhLx3+WuXrD5R +RaIRpsyF7gpo8j5QOHokYh4XIDdtak23CZvJ/KRY9bb7nE4Yu5UC56GtmwfuNmsk +0jmGwZODUNKBRqhfYlcsu2xkiAhu7xNUX90txGdj08+JN7+dIPT7eoOboB6BAFDC +5AwiWVIQ7UNWhwD4FFKnHYuTjKJNRn8nxnGbJN7k2oaLDX5rIMHAnuFl2GqjpuiF +izoHCBy69Y9Vmhh1fuXsgWbRIXOhNUQLgD1bnF5vKheW0YMjiGZt5obicDIvUiLn +yOd/xCxgXS/Dr55FBcOEArf9LAhST4Ldo/DUhgkC +-----END CERTIFICATE-----'" +"Google Trust Services LLC (GTS)","Google Trust Services LLC","","GTS Root R3","6E47A9C76CA9732440890F0355DD8D1D","15D5B8774619EA7D54CE1CA6D0B0C403E037A917F131E8A04E1E6B7A71BABCE5","57D88B417FB78BE305558C964B3663661EFFAF2EB6829D1D317D92001BF66C79","2016.06.22","2036.06.22","EC secp384r1","ecdsaWithSHA384","Websites","","","Not EV","https://bugzilla.mozilla.org/show_bug.cgi?id=1325532","NSS 3.41","Firefox 65","https://good.r3demo.pki.goog","https://expired.r3demo.pki.goog","https://revoked.r3demo.pki.goog","","https://pki.goog","Global","https://static.googleusercontent.com/media/pki.goog/en//GTS-CP-1.9.pdf","https://static.googleusercontent.com/media/pki.goog/en//GTS-CPS-2.14.pdf","https://www.cpacanada.ca/generichandlers/CPACHandler.ashx?attachmentid=236832","https://www.cpacanada.ca/generichandlers/CPACHandler.ashx?attachmentid=236833","","Ernst & Young, LLP","WebTrust","2019.10.30","'-----BEGIN CERTIFICATE----- +MIICDDCCAZGgAwIBAgIQbkepx2ypcyRAiQ8DVd2NHTAKBggqhkjOPQQDAzBHMQsw +CQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExMQzEU +MBIGA1UEAxMLR1RTIFJvb3QgUjMwHhcNMTYwNjIyMDAwMDAwWhcNMzYwNjIyMDAw +MDAwWjBHMQswCQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZp +Y2VzIExMQzEUMBIGA1UEAxMLR1RTIFJvb3QgUjMwdjAQBgcqhkjOPQIBBgUrgQQA +IgNiAAQfTzOHMymKoYTey8chWEGJ6ladK0uFxh1MJ7x/JlFyb+Kf1qPKzEUURout +736GjOyxfi//qXGdGIRFBEFVbivqJn+7kAHjSxm65FSWRQmx1WyRRK2EE46ajA2A +DDL24CejQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MB0GA1Ud +DgQWBBTB8Sa6oC2uhYHP0/EqEr24Cmf9vDAKBggqhkjOPQQDAwNpADBmAjEAgFuk +fCPAlaUs3L6JbyO5o91lAFJekazInXJ0glMLfalAvWhgxeG4VDvBNhcl2MG9AjEA +njWSdIUlUfUk7GRSJFClH9voy8l27OyCbvWFGFPouOOaKaqW04MjyaR7YbPMAuhd +-----END CERTIFICATE-----'" +"Google Trust Services LLC (GTS)","Google Trust Services LLC","","GTS Root R4","6E47A9C88B94B6E8BB3B2AD8A2B2C199","71CCA5391F9E794B04802530B363E121DA8A3043BB26662FEA4DCA7FC951A4BD","20579A7FA60179758D7F5914C1EDCDA977B8FD70D1CA28A1613FD5FD37EA4591","2016.06.22","2036.06.22","EC secp384r1","ecdsaWithSHA384","Websites","","","Not EV","https://bugzilla.mozilla.org/show_bug.cgi?id=1325532","NSS 3.41","Firefox 65","https://good.r4demo.pki.goog","https://expired.r4demo.pki.goog","https://revoked.r4demo.pki.goog","","https://pki.goog","Global","https://static.googleusercontent.com/media/pki.goog/en//GTS-CP-1.9.pdf","https://static.googleusercontent.com/media/pki.goog/en//GTS-CPS-2.14.pdf","https://www.cpacanada.ca/generichandlers/CPACHandler.ashx?attachmentid=236832","https://www.cpacanada.ca/generichandlers/CPACHandler.ashx?attachmentid=236833","","Ernst & Young, LLP","WebTrust","2019.10.30","'-----BEGIN CERTIFICATE----- +MIICCjCCAZGgAwIBAgIQbkepyIuUtui7OyrYorLBmTAKBggqhkjOPQQDAzBHMQsw +CQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExMQzEU +MBIGA1UEAxMLR1RTIFJvb3QgUjQwHhcNMTYwNjIyMDAwMDAwWhcNMzYwNjIyMDAw +MDAwWjBHMQswCQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZp +Y2VzIExMQzEUMBIGA1UEAxMLR1RTIFJvb3QgUjQwdjAQBgcqhkjOPQIBBgUrgQQA +IgNiAATzdHOnaItgrkO4NcWBMHtLSZ37wWHO5t5GvWvVYRg1rkDdc/eJkTBa6zzu +hXyiQHY7qca4R9gq55KRanPpsXI5nymfopjTX15YhmUPoYRlBtHci8nHc8iMai/l +xKvRHYqjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MB0GA1Ud +DgQWBBSATNbrdP9JNqPV2Py1PsVq8JQdjDAKBggqhkjOPQQDAwNnADBkAjBqUFJ0 +CMRw3J5QdCHojXohw0+WbhXRIjVhLfoIN+4Zba3bssx9BzT1YBkstTTZbyACMANx +sbqjYAuG7ZoIapVon+Kz4ZNkfF6Tpt95LY2F45TPI11xzPKwTdb+mciUqXWi4w== +-----END CERTIFICATE-----'" +"Government of Hong Kong (SAR), Hongkong Post, Certizen","Hongkong Post","","Hongkong Post Root CA 1","03E8","F9E67D336C51002AC054C632022D66DDA2E7E3FFF10AD061ED31D8BBB410CFB2","12A9BFC9E69F56C0C99F97144D2FBFB0A30F135D4C184F5CC31988DC307AC096","2003.05.15","2023.05.15","RSA 2048 bits","SHA1WithRSA","Websites","","","Not EV","https://bugzilla.mozilla.org/show_bug.cgi?id=408949","NSS 3.12.6","Firefox 3.6.2","https://www.hongkongpost.gov.hk/","https://expired.hongkongpost.gov.hk/","https://revoked.hongkongpost.gov.hk/","","http://www.hongkongpost.gov.hk/index.html","Hong Kong (SAR), China","https://www.ecert.gov.hk/product/cps/ecert/img/server_cps_en6.pdf","https://www.ecert.gov.hk/ev/e-Cert%20(Server)%20CPS-Eng-1.7.4.pdf","https://www.cpacanada.ca/generichandlers/CPACHandler.ashx?attachmentid=238797","https://www.cpacanada.ca/generichandlers/CPACHandler.ashx?attachmentid=238798","","PwC - PricewaterhouseCoopers International Limited","WebTrust","2020.02.28","'-----BEGIN CERTIFICATE----- +MIIDMDCCAhigAwIBAgICA+gwDQYJKoZIhvcNAQEFBQAwRzELMAkGA1UEBhMCSEsx +FjAUBgNVBAoTDUhvbmdrb25nIFBvc3QxIDAeBgNVBAMTF0hvbmdrb25nIFBvc3Qg +Um9vdCBDQSAxMB4XDTAzMDUxNTA1MTMxNFoXDTIzMDUxNTA0NTIyOVowRzELMAkG +A1UEBhMCSEsxFjAUBgNVBAoTDUhvbmdrb25nIFBvc3QxIDAeBgNVBAMTF0hvbmdr +b25nIFBvc3QgUm9vdCBDQSAxMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC +AQEArP84tulmAknjorThkPlAj3n54r15/gK97iSSHSL22oVyaf7XPwnU3ZG1ApzQ +jVrhVcNQhrkpJsLj2aDxaQMoIIBFIi1WpztUlVYiWR8o3x8gPW2iNr4joLFutbEn +PzlTCeqrauh0ssJlXI6/fMN4hM2eFvz1Lk8gKgifd/PFHsSaUmYeSF7jEAaPIpjh +ZY4bXSNmO7ilMlHIhqqhqZ5/dpTCpmy3QfDVyAY45tQM4vM7TG1QjMSDJ8EThFk9 +nnV0ttgCXjqQesBCNnLsak3c78QA3xMYV18meMjWCnl3v/evt3a5pQuEF10Q6m/h +q5URX208o1xNg1vysxmKgIsLhwIDAQABoyYwJDASBgNVHRMBAf8ECDAGAQH/AgED +MA4GA1UdDwEB/wQEAwIBxjANBgkqhkiG9w0BAQUFAAOCAQEADkbVPK7ih9legYsC +mEEIjEy82tvuJxuC52pF7BaLT4Wg87JwvVqWuspube5Gi27nKi6Wsxkz67SfqLI3 +7piol7Yutmcn1KZJ/RyTZXaeQi/cImyaT/JaFTmxcdcrUehtHJjA2Sr0oYJ71clB +oiMBdDhViw+5LmeiIAQ32pwL0xch4I+XeTRvhEgCIDMb5jREn5Fw9IBehEPCKdJs +EhTkYY2sEJCehFC78JZvRZ+K88psT/oROhUVRsPNH4NbLUES7VBnQRM9IauUiqpO +fMGx+6fWtScvl6tu4B3i0RwsH0Ti/L6RoZz71ilTc4afU9hDDl3WY4JxHYB0yvbi +AmvZWg== +-----END CERTIFICATE-----'" +"Government of Hong Kong (SAR), Hongkong Post, Certizen","Hongkong Post","","Hongkong Post Root CA 3","08165F8A4CA5EC00C99340DFC4C6AE23B81C5AA4","5A2FC03F0C83B090BBFA40604B0988446C7636183DF9846E17101A447FB8EFD6","8ADF99FED163C7809331E00788A9311612373EE392E3E43D59628B50139E7127","2017.06.03","2042.06.03","RSA 4096 bits","SHA256WithRSA","Websites","","","2.23.140.1.1","https://bugzilla.mozilla.org/show_bug.cgi?id=1464306","NSS 3.43","Firefox 67","https://valid-ev.ecert.gov.hk/","https://expired-ev.ecert.gov.hk/","https://revoked-ev.ecert.gov.hk/","","http://www.hongkongpost.gov.hk/index.html","Hong Kong (SAR), China","https://www.ecert.gov.hk/product/cps/ecert/img/server_cps_en6.pdf","https://www.ecert.gov.hk/ev/e-Cert%20(Server)%20CPS-Eng-1.7.4.pdf","https://www.cpacanada.ca/generichandlers/CPACHandler.ashx?attachmentid=238797","https://www.cpacanada.ca/generichandlers/CPACHandler.ashx?attachmentid=238798","https://www.ecert.gov.hk/ev/Webtrust_EVSSL_2019.pdf","PwC - PricewaterhouseCoopers International Limited","WebTrust","2020.02.28","'-----BEGIN CERTIFICATE----- +MIIFzzCCA7egAwIBAgIUCBZfikyl7ADJk0DfxMauI7gcWqQwDQYJKoZIhvcNAQEL +BQAwbzELMAkGA1UEBhMCSEsxEjAQBgNVBAgTCUhvbmcgS29uZzESMBAGA1UEBxMJ +SG9uZyBLb25nMRYwFAYDVQQKEw1Ib25na29uZyBQb3N0MSAwHgYDVQQDExdIb25n +a29uZyBQb3N0IFJvb3QgQ0EgMzAeFw0xNzA2MDMwMjI5NDZaFw00MjA2MDMwMjI5 +NDZaMG8xCzAJBgNVBAYTAkhLMRIwEAYDVQQIEwlIb25nIEtvbmcxEjAQBgNVBAcT +CUhvbmcgS29uZzEWMBQGA1UEChMNSG9uZ2tvbmcgUG9zdDEgMB4GA1UEAxMXSG9u +Z2tvbmcgUG9zdCBSb290IENBIDMwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIK +AoICAQCziNfqzg8gTr7m1gNt7ln8wlffKWihgw4+aMdoWJwcYEuJQwy51BWy7sFO +dem1p+/l6TWZ5Mwc50tfjTMwIDNT2aa71T4Tjukfh0mtUC1Qyhi+AViiE3CWu4mI +VoBc+L0sPOFMV4i707mV78vH9toxdCim5lSJ9UExyuUmGs2C4HDaOym71QP1mbpV +9WTRYA6ziUm4ii8F0oRFKHyPaFASePwLtVPLwpgchKOesL4jpNrcyCse2m5FHomY +2vkALgbpDDtw1VAliJnLzXNg99X/NWfFobxeq81KuEXryGgeDQ0URhLj0mRiikKY +vLTGCAj4/ahMZJx2Ab0vqWwzD9g/KLg8aQFChn5pwckGyuV6RmXpwtZQQS4/t+Tt +bNe/JgERohYpSms0BpDsE9K2+2p20jzt8NYt3eEV7KObLyzJPivkaTv/ciWxNoZb +x39ri1UbSsUgYT2uy1DhCDq+sI9jQVMwCFk8mB13umOResoQUGC/8Ne8lYePl8X+ +l2oBlKN8W4UdKjk60FSh0Tlxnf0h+bV78OLgAo9uliQlLKAeLKjEiafv7ZkGL7YK +TE/bosw3Gq9HhS2KX8Q0NEwA/RiTZxPRN+ZItIsGxVd7GYYKecsAyVKvQv83j+Gj +Hno9UKtjBucVtT+2RTeUN7F+8kjDf8V1/peNRY8apxpyKBpADwIDAQABo2MwYTAP +BgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAfBgNVHSMEGDAWgBQXnc0e +i9Y5K3DTXNSguB+wAPzFYTAdBgNVHQ4EFgQUF53NHovWOStw01zUoLgfsAD8xWEw +DQYJKoZIhvcNAQELBQADggIBAFbVe27mIgHSQpsY1Q7XZiNc4/6gx5LS6ZStS6LG +7BJ8dNVI0lkUmcDrudHr9EgwW62nV3OZqdPlt9EuWSRY3GguLmLYauRwCy0gUCCk +MpXRAJi70/33MvJJrsZ64Ee+bs7Lo3I6LWldy8joRTnU+kLBEUx3XZL7av9YROXr +gZ6voJmtvqkBZss4HTzfQx/0TW60uhdG/H39h4F5ag0zD/ov+BS5gLNdTaqX4fnk +GMX41TiMJjz98iji7lpJiCzfeT2OnpA8vUFKOt1b9pq0zj8lMH8yfaIDlNDceqFS +3m6TjRgm/VWsvY+b0s+v54Ysyx8Jb6NvqYTUc79NoXQbTiNg8swOqn+knEwlqLJm +Ozj/2ZQw9nKEvmhVEA/GcywWaZMH/rFF7buiVWqw2rVKAiUnhde3t4ZEFolsgCs+ +l6mc1X5VTMbeRRAc6uk7nwNT7u56AQIWeNTowr5GdogTPyK7SBIdUgC0An4hGh6c +JfTzPV4e0hz5sy229zdcxsshTrD3mUcYhcErulWuBurQB7Lcq9CClnXO0lD+mefP +L5/ndtFhKvshuzHQqp9HpLIiyhY6UFfEW0NnxWViA0kB60PZ2Pierc+xYw5F9KBa +LJstxabArahH9CdMOA0uG0k7UvToiIMrVCjU8jVStDKDYmlkDJGcn5fqdBb9HxEG +mpv0 +-----END CERTIFICATE-----'" +"Government of Spain, Autoritat de Certificació de la Comunitat Valenciana (ACCV)","ACCV","PKIACCV","ACCVRAIZ1","5EC3B7A6437FA4E0","9A6EC012E1A7DA9DBE34194D478AD7C0DB1822FB071DF12981496ED104384113","F35C192B8FBF8CB909D2AA5DAF985C805162CC2B4329A6BC0790C9086EF170CC","2011.05.05","2030.12.31","RSA 4096 bits","SHA1WithRSA","Websites;Email","","","Not EV","https://bugzilla.mozilla.org/show_bug.cgi?id=811352","NSS 3.15.4","Firefox 27","https://activo.accv.es/test/hola.html","https://caducado.accv.es:444/test/hola.html","https://revocado.accv.es:442/test/hola.html","","http://www.pki.gva.es/","Valencia region of Spain","https://www.accv.es/fileadmin/Archivos/Politicas_pdf/ACCV-CP-3V4.0.4-EN-2020.pdf","https://www.accv.es/fileadmin/Archivos/Practicas_de_certificacion/ACCV-CPS-V4.0.7-EN-2020.pdf","https://www.cpacanada.ca/GenericHandlers/CPACHandler.ashx?AttachmentID=240927","https://www.cpacanada.ca/GenericHandlers/CPACHandler.ashx?AttachmentID=240935","","Auren","WebTrust","2020.07.17","'-----BEGIN CERTIFICATE----- +MIIH0zCCBbugAwIBAgIIXsO3pkN/pOAwDQYJKoZIhvcNAQEFBQAwQjESMBAGA1UE +AwwJQUNDVlJBSVoxMRAwDgYDVQQLDAdQS0lBQ0NWMQ0wCwYDVQQKDARBQ0NWMQsw +CQYDVQQGEwJFUzAeFw0xMTA1MDUwOTM3MzdaFw0zMDEyMzEwOTM3MzdaMEIxEjAQ +BgNVBAMMCUFDQ1ZSQUlaMTEQMA4GA1UECwwHUEtJQUNDVjENMAsGA1UECgwEQUND +VjELMAkGA1UEBhMCRVMwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCb +qau/YUqXry+XZpp0X9DZlv3P4uRm7x8fRzPCRKPfmt4ftVTdFXxpNRFvu8gMjmoY +HtiP2Ra8EEg2XPBjs5BaXCQ316PWywlxufEBcoSwfdtNgM3802/J+Nq2DoLSRYWo +G2ioPej0RGy9ocLLA76MPhMAhN9KSMDjIgro6TenGEyxCQ0jVn8ETdkXhBilyNpA +lHPrzg5XPAOBOp0KoVdDaaxXbXmQeOW1tDvYvEyNKKGno6e6Ak4l0Squ7a4DIrhr +IA8wKFSVf+DuzgpmndFALW4ir50awQUZ0m/A8p/4e7MCQvtQqR0tkw8jq8bBD5L/ +0KIV9VMJcRz/RROE5iZe+OCIHAr8Fraocwa48GOEAqDGWuzndN9wrqODJerWx5eH +k6fGioozl2A3ED6XPm4pFdahD9GILBKfb6qkxkLrQaLjlUPTAYVtjrs78yM2x/47 +4KElB0iryYl0/wiPgL/AlmXz7uxLaL2diMMxs0Dx6M/2OLuc5NF/1OVYm3z61PMO +m3WR5LpSLhl+0fXNWhn8ugb2+1KoS5kE3fj5tItQo05iifCHJPqDQsGH+tUtKSpa +cXpkatcnYGMN285J9Y0fkIkyF/hzQ7jSWpOGYdbhdQrqeWZ2iE9x6wQl1gpaepPl +uUsXQA+xtrn13k/c4LOsOxFwYIRKQ26ZIMApcQrAZQIDAQABo4ICyzCCAscwfQYI +KwYBBQUHAQEEcTBvMEwGCCsGAQUFBzAChkBodHRwOi8vd3d3LmFjY3YuZXMvZmls +ZWFkbWluL0FyY2hpdm9zL2NlcnRpZmljYWRvcy9yYWl6YWNjdjEuY3J0MB8GCCsG +AQUFBzABhhNodHRwOi8vb2NzcC5hY2N2LmVzMB0GA1UdDgQWBBTSh7Tj3zcnk1X2 +VuqB5TbMjB4/vTAPBgNVHRMBAf8EBTADAQH/MB8GA1UdIwQYMBaAFNKHtOPfNyeT +VfZW6oHlNsyMHj+9MIIBcwYDVR0gBIIBajCCAWYwggFiBgRVHSAAMIIBWDCCASIG +CCsGAQUFBwICMIIBFB6CARAAQQB1AHQAbwByAGkAZABhAGQAIABkAGUAIABDAGUA +cgB0AGkAZgBpAGMAYQBjAGkA8wBuACAAUgBhAO0AegAgAGQAZQAgAGwAYQAgAEEA +QwBDAFYAIAAoAEEAZwBlAG4AYwBpAGEAIABkAGUAIABUAGUAYwBuAG8AbABvAGcA +7QBhACAAeQAgAEMAZQByAHQAaQBmAGkAYwBhAGMAaQDzAG4AIABFAGwAZQBjAHQA +cgDzAG4AaQBjAGEALAAgAEMASQBGACAAUQA0ADYAMAAxADEANQA2AEUAKQAuACAA +QwBQAFMAIABlAG4AIABoAHQAdABwADoALwAvAHcAdwB3AC4AYQBjAGMAdgAuAGUA +czAwBggrBgEFBQcCARYkaHR0cDovL3d3dy5hY2N2LmVzL2xlZ2lzbGFjaW9uX2Mu +aHRtMFUGA1UdHwROMEwwSqBIoEaGRGh0dHA6Ly93d3cuYWNjdi5lcy9maWxlYWRt +aW4vQXJjaGl2b3MvY2VydGlmaWNhZG9zL3JhaXphY2N2MV9kZXIuY3JsMA4GA1Ud +DwEB/wQEAwIBBjAXBgNVHREEEDAOgQxhY2N2QGFjY3YuZXMwDQYJKoZIhvcNAQEF +BQADggIBAJcxAp/n/UNnSEQU5CmH7UwoZtCPNdpNYbdKl02125DgBS4OxnnQ8pdp +D70ER9m+27Up2pvZrqmZ1dM8MJP1jaGo/AaNRPTKFpV8M9xii6g3+CfYCS0b78gU +JyCpZET/LtZ1qmxNYEAZSUNUY9rizLpm5U9EelvZaoErQNV/+QEnWCzI7UiRfD+m +AM/EKXMRNt6GGT6d7hmKG9Ww7Y49nCrADdg9ZuM8Db3VlFzi4qc1GwQA9j9ajepD +vV+JHanBsMyZ4k0ACtrJJ1vnE5Bc5PUzolVt3OAJTS+xJlsndQAJxGJ3KQhfnlms +tn6tn1QwIgPBHnFk/vk4CpYY3QIUrCPLBhwepH2NDd4nQeit2hW3sCPdK6jT2iWH +7ehVRE2I9DZ+hJp4rPcOVkkO1jMl1oRQQmwgEh0q1b688nCBpHBgvgW1m54ERL5h +I6zppSSMEYCUWqKiuUnSwdzRp+0xESyeGabu4VXhwOrPDYTkF7eifKXeVSUG7szA +h1xA2syVP1XgNce4hL60Xc16gwFy7ofmXx2utYXGJt/mwZrpHgJHnyqobalbz+xF +d3+YJ5oyXSrjhO7FmGYvliAd3djDJ9ew+f7Zfc3Qn48LFFhRny+Lwzgt3uiP1o2H +pPVWQxaZLPSkVrQ0uGE3ycJYgBugl6H8WY3pEfbRD0tVNEYqi4Y7 +-----END CERTIFICATE-----'" +"Government of Spain, Fábrica Nacional de Moneda y Timbre (FNMT)","FNMT-RCM","AC RAIZ FNMT-RCM","FNMT-RCM - SHA256","5D938D306736C8061D1AC754846907","EBC5570C29018C4D67B1AA127BAF12F703B4611EBC17B7DAB5573894179B93FA","1B3CF7B332D65B1EF518CFA49F19B8548A0AAA1B0F8C337CE1C1C5ED1E536BF7","2008.10.29","2030.01.01","RSA 4096 bits","SHA256WithRSA","Websites","","","Not EV","https://bugzilla.mozilla.org/show_bug.cgi?id=435736","NSS 3.28.1","Firefox 51","https://www.sede.fnmt.gob.es","https://testexpired.cert.fnmt.es","https://testrevoked.cert.fnmt.es","None","http://www.cert.fnmt.es/","Spain","","https://www.sede.fnmt.gob.es/documents/10445900/10536309/dgpc_english.pdf","https://www.aenor.com/Certificacion_Documentos/eiDas/2020%20AENOR%20Anexo%202%20ETSI%20319%20411-1%20PSC-2019-003%20-%20FNMT-v2.pdf","https://www.aenor.com/Certificacion_Documentos/eiDas/2020%20AENOR%20Anexo%201%20ETSI%20319%20411-2%20PSC-2019-003%20-%20FNMT-v2.pdf","","AENOR INTERNACIONAL, S.A. (Unipersonal)","ETSI EN 319 411","2020.03.23","'-----BEGIN CERTIFICATE----- +MIIFgzCCA2ugAwIBAgIPXZONMGc2yAYdGsdUhGkHMA0GCSqGSIb3DQEBCwUAMDsx +CzAJBgNVBAYTAkVTMREwDwYDVQQKDAhGTk1ULVJDTTEZMBcGA1UECwwQQUMgUkFJ +WiBGTk1ULVJDTTAeFw0wODEwMjkxNTU5NTZaFw0zMDAxMDEwMDAwMDBaMDsxCzAJ +BgNVBAYTAkVTMREwDwYDVQQKDAhGTk1ULVJDTTEZMBcGA1UECwwQQUMgUkFJWiBG +Tk1ULVJDTTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBALpxgHpMhm5/ +yBNtwMZ9HACXjywMI7sQmkCpGreHiPibVmr75nuOi5KOpyVdWRHbNi63URcfqQgf +BBckWKo3Shjf5TnUV/3XwSyRAZHiItQDwFj8d0fsjz50Q7qsNI1NOHZnjrDIbzAz +WHFctPVrbtQBULgTfmxKo0nRIBnuvMApGGWn3v7v3QqQIecaZ5JCEJhfTzC8PhxF +tBDXaEAUwED653cXeuYLj2VbPNmaUtu1vZ5Gzz3rkQUCwJaydkxNEJY7kvqcfw+Z +374jNUUeAlz+taibmSXaXvMiwzn15Cou08YfxGyqxRxqAQVKL9LFwag0Jl1mpdIC +IfkYtwb1TplvqKtMUejPUBjFd8g5CSxJkjKZqLsXF3mwWsXmo8RZZUc1g16p6DUL +mbvkzSDGm0oGObVo/CK67lWMK07q87Hj/LaZmtVC+nFNCM+HHmpxffnTtOmlcYF7 +wk5HlqX2doWjKI/pgG6BU6VtX7hI+cL5NqYuSf+4lsKMB7ObiFj86xsc3i1w4peS +MKGJ47xVqCfWS+2QrYv6YyVZLag13cqXM7zlzced0ezvXg5KkAYmY6252TUtB7p2 +ZSysV4999AeU14ECll2jB0nVetBX+RvnU0Z1qrB5QstocQjpYL05ac70r8NWQMet +UqIJ5G+GR4of6ygnXYMgrwTJbFaai0b1AgMBAAGjgYMwgYAwDwYDVR0TAQH/BAUw +AwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFPd9xf3E6Jobd2Sn9R2gzL+H +YJptMD4GA1UdIAQ3MDUwMwYEVR0gADArMCkGCCsGAQUFBwIBFh1odHRwOi8vd3d3 +LmNlcnQuZm5tdC5lcy9kcGNzLzANBgkqhkiG9w0BAQsFAAOCAgEAB5BK3/MjTvDD +nFFlm5wioooMhfNzKWtN/gHiqQxjAb8EZ6WdmF/9ARP67Jpi6Yb+tmLSbkyU+8B1 +RXxlDPiyN8+sD8+Nb/kZ94/sHvJwnvDKuO+3/3Y3dlv2bojzr2IyIpMNOmqOFGYM +LVN0V2Ue1bLdI4E7pWYjJ2cJj+F3qkPNZVEI7VFY/uY5+ctHhKQV8Xa7pO6kO8Rf +77IzlhEYt8llvhjho6Tc+hj507wTmzl6NLrTQfv6MooqtyuGC2mDOL7Nii4LcK2N +JpLuHvUBKwrZ1pebbuCoGRw6IYsMHkCtA+fdZn71uSANA+iW+YJF1DngoABd15jm +fZ5nc8OaKveri6E6FO80vFIOiZiaBECEHX5FaZNXzuvO+FB8TxxuBEOb+dY7Ixjp +6o7RTUaN8Tvkasq6+yO3m/qZASlaWFot4/nUbQ4mrcFuNLwy+AwF+mWj2zs3gyLp +1txyM/1d8iC9djwj2ij3+RvrWWTV3F9yfiD8zYm1kGdNYno/Tq0dwzn+evQoFt9B +9kiABdcPUXmsEKvU7ANm5mqwujGSQkBqvjrTcuFqN1W8rB2Vt2lh8kORdOag0wok +RqEIr9baRRmW1FMdW4R58MD3R++Lj8UGrp1MYp3/RgT408m2ECVAdf4WqslKYIYv +uu8wd+RU4riEmViAqhOLUTpPSPaLtrM= +-----END CERTIFICATE-----'" +"Government of Taiwan, Government Root Certification Authority (GRCA)","Government Root Certification Authority","","Government Root Certification Authority - Taiwan","1F9D595AD72FC20644A5800869E35EF6","7600295EEFE85B9E1FD624DB76062AAAAE59818A54D2774CD4C0B2C01131E1B3","3CDFB2A99A19FFB3297BB68CE91BC6E1E8BDCA902134735A0931E712CFFD841F","2002.12.05","2032.12.05","RSA 4096 bits","SHA1WithRSA","Websites","","","Not EV","https://bugzilla.mozilla.org/show_bug.cgi?id=274106","NSS 3.11.4","Firefox 2","https://valid.gca.nat.gov.tw","https://expired.gca.nat.gov.tw","https://revoked.gca.nat.gov.tw","","http://grca.nat.gov.tw/01-01.html","Taiwan","http://grca.nat.gov.tw/download/GPKI_CP_eng_v2.0.pdf","http://grca.nat.gov.tw/download/GRCA_CPS_eng_v2.0.pdf","https://www.cpacanada.ca/generichandlers/CPACHandler.ashx?attachmentid=240756","https://www.cpacanada.ca/generichandlers/CPACHandler.ashx?attachmentid=240757","","KPMG","WebTrust","2020.05.25","'-----BEGIN CERTIFICATE----- +MIIFcjCCA1qgAwIBAgIQH51ZWtcvwgZEpYAIaeNe9jANBgkqhkiG9w0BAQUFADA/ +MQswCQYDVQQGEwJUVzEwMC4GA1UECgwnR292ZXJubWVudCBSb290IENlcnRpZmlj +YXRpb24gQXV0aG9yaXR5MB4XDTAyMTIwNTEzMjMzM1oXDTMyMTIwNTEzMjMzM1ow +PzELMAkGA1UEBhMCVFcxMDAuBgNVBAoMJ0dvdmVybm1lbnQgUm9vdCBDZXJ0aWZp +Y2F0aW9uIEF1dGhvcml0eTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIB +AJoluOzMonWoe/fOW1mKydGGEghU7Jzy50b2iPN86aXfTEc2pBsBHH8eV4qNw8XR +IePaJD9IK/ufLqGU5ywck9G/GwGHU5nOp/UKIXZ3/6m3xnOUT0b3EEk3+qhZSV1q +gQdW8or5BtD3cCJNtLdBuTK4sfCxw5w/cP1T3YGq2GN49thTbqGsaoQkclSGxtKy +yhwOeYHWtXBiCAEuTk8O1RGvqa/lmr/czIdtJuTJV6L7lvnM4T9TjGxMfptTCAts +F/tnyMKtsc2AtJfcdgEWFelq16TheEfOhtX7MfP6Mb40qij7cEwdScevLJ1tZqa2 +jWR+tSBqnTuBto9AAGdLiYa4zGX+FVPpBMHWXx1E1wovJ5pGfaENda1UhhXcSTvx +ls4Pm6Dso3pdvtUqdULle96ltqqvKKyskKw4t9VoNSZ63Pc78/1Fm9G7Q3hub/FC +VGqY8A2tl+lSXunVanLeavcbYBT0peS2cWeqH+riTcFCQP5nRhc4L0c/cZyu5SHK +YS1tB6iEfC3uUSXxY5Ce/eFXiGvviiNtsea9P63RPZYLhY3Naye7twWb7LuRqQoH +EgKXTiCQ8P8NHuJBO9NAOueNXdpm5AKwB1KYXA6OM5zCppX7VRluTI6uSw+9wThN +Xo+EHWbNxWCWtFJaBYmOlXqYwZE8lSOyDvR5tMl8wUohAgMBAAGjajBoMB0GA1Ud +DgQWBBTMzO/MKWCkO7GStjz6MmKPrCUVOzAMBgNVHRMEBTADAQH/MDkGBGcqBwAE +MTAvMC0CAQAwCQYFKw4DAhoFADAHBgVnKgMAAAQUA5vwIhP/lSg209yewDL7MTqK +UWUwDQYJKoZIhvcNAQEFBQADggIBAECASvomyc5eMN1PhnR2WPWus4MzeKR6dBcZ +TulStbngCnRiqmjKeKBMmo4sIy7VahIkv9Ro04rQ2JyftB8M3jh+Vzj8jeJPXgyf +qzvS/3WXy6TjZwj/5cAWtUgBfen5Cv8b5Wppv3ghqMKnI6mGq3ZW6A4M9hPdKmaK +ZEk9GhiHkASfQlK3T8v+R0F2Ne//AHY2RTKbxkaFXeIksB7jSJaYV0eUVXoPQbFE +JPPB/hprv4j9wabak2BegUqZIJxIZhm1AHlUD7gsL0u8qV1bYH+Mh6XgUmMqvtg7 +hUAV/h62ZT/FS9p+tXo1KaMuephgIqP0fSdOLeq0dDzpD6QzDxARvBMB1uUO07+1 +EqLhRSPAzAhuYbeJq4PjJB7mXQfnHyA+z2fI56wwbSdLaG5LKlwCCDTb+HbkZ6Mm +nD+iMsJKxYEYMRBWqoTvLQr/uB930r+lWKBi5NdLkXWNiYCYfm3LU05er/ayl4WX +udpVBrkk7tfGOB5jGxI7leFYrPLfhNVfmS8NVVvmONsuP3LpSIXLuykTjx44Vbnz +ssQwmSNOXfJIoRIM3BKQCZBUkQM8R+XVyWXgt0t97EfTsws+rZ7QdAAO671RrcDe +LMDDav7v3Aun+kbfYNucpllQdSNpc5Oy+fwC00fmcc4QAu4njIT/rEUNE1yDMuAl +pYYsfPQS +-----END CERTIFICATE-----'" +"Government of The Netherlands, PKIoverheid (Logius)","Staat der Nederlanden","","Staat der Nederlanden EV Root CA","0098968D","4D2491414CFE956746EC4CEFA6CF6F72E28A1329432F9D8A907AC4CB5DADC15A","E7DFDB853847525B956737CDF27C6BC6C2B87957605EEE3D0C48820560376D0B","2010.12.08","2022.12.08","RSA 4096 bits","SHA256WithRSA","Websites","","","2.16.528.1.1003.1.2.7","https://bugzilla.mozilla.org/show_bug.cgi?id=1016568","NSS 3.18","Firefox 38","https://roottest-ev.pkioverheid.nl/","https://roottest-ev-expired.pkioverheid.nl/","https://roottest-ev-revoked.pkioverheid.nl/","None","https://www.logius.nl/languages/english/pkioverheid/","Netherlands","","https://cps.pkioverheid.nl/CPS_PA_PKIoverheid_G2_G3_Root_v4.3.pdf","https://www.cpacanada.ca/generichandlers/CPACHandler.ashx?attachmentid=238851","https://www.cpacanada.ca/generichandlers/CPACHandler.ashx?attachmentid=238852","https://www.cpacanada.ca/generichandlers/CPACHandler.ashx?attachmentid=238853","KPMG","WebTrust","2020.03.12","'-----BEGIN CERTIFICATE----- +MIIFcDCCA1igAwIBAgIEAJiWjTANBgkqhkiG9w0BAQsFADBYMQswCQYDVQQGEwJO +TDEeMBwGA1UECgwVU3RhYXQgZGVyIE5lZGVybGFuZGVuMSkwJwYDVQQDDCBTdGFh +dCBkZXIgTmVkZXJsYW5kZW4gRVYgUm9vdCBDQTAeFw0xMDEyMDgxMTE5MjlaFw0y +MjEyMDgxMTEwMjhaMFgxCzAJBgNVBAYTAk5MMR4wHAYDVQQKDBVTdGFhdCBkZXIg +TmVkZXJsYW5kZW4xKTAnBgNVBAMMIFN0YWF0IGRlciBOZWRlcmxhbmRlbiBFViBS +b290IENBMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA48d+ifkkSzrS +M4M1LGns3Amk41GoJSt5uAg94JG6hIXGhaTK5skuU6TJJB79VWZxXSzFYGgEt9nC +UiY4iKTWO0Cmws0/zZiTs1QUWJZV1VD+hq2kY39ch/aO5ieSZxeSAgMs3NZmdO3d +Z//BYY1jTw+bbRcwJu+r0h8QoPnFfxZpgQNH7R5ojXKhTbImxrpsX23Wr9GxE46p +rfNeaXUmGD5BKyF/7otdBwadQ8QpCiv8Kj6GyzyDOvnJDdrFmeK8eEEzduG/L13l +pJhQDBXd4Pqcfzho0LKmeqfRMb1+ilgnQ7O6M5HTp5gVXJrm0w912fxBmJc+qiXb +j5IusHsMX/FjqTf5m3VpTCgmJdrV8hJwRVXj33NeN/UhbJCONVrJ0yPr08C+eKxC +KFhmpUZtcALXEPlLVPxdhkqHz3/KRawRWrUgUY0viEeXOcDPusBCAUCZSCELa6fS +/ZbV0b5GnUngC6agIk440ME8MLxwjyx1zNDFjFE7PZQIZCZhfbnDZY8UnCHQqv0X +cgOPvZuM5l5Tnrmd74K74bzickFbIZTTRTeU0d8JOV3nI6qaHcptqAqGhYqCvkIH +1vI4gnPah1vlPNOePqc7nvQDs/nxfRN0Av+7oeX6AHkcpmZBiFxgV6YuCcS6/ZrP +px9Aw7vMWgpVSzs4dlG4Y4uElBbmVvMCAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB +/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFP6rAJCYniT8qcwaivsnuL8wbqg7 +MA0GCSqGSIb3DQEBCwUAA4ICAQDPdyxuVr5Os7aEAJSrR8kN0nbHhp8dB9O2tLsI +eK9p0gtJ3jPFrK3CiAJ9Brc1AsFgyb/E6JTe1NOpEyVa/m6irn0F3H3zbPB+po3u +2dfOWBfoqSmuc0iH55vKbimhZF8ZE/euBhD/UcabTVUlT5OZEAFTdfETzsemQUHS +v4ilf0X8rLiltTMMgsT7B/Zq5SWEXwbKwYY5EdtYzXc7LMJMD16a4/CrPmEbUCTC +wPTxGfARKbalGAKb12NMcIxHowNDXLldRqANb/9Zjr7dn3LDWyvfjFvO5QxGbJKy +CqNMVEIYFRIYvdr8unRu/8G2oGTYqV9Vrp9canaW2HNnh/tNf1zuacpzEPuKqf2e +vTY4SUmH9A4U8OmHuD+nT3pajnnUk+S7aFKErGzp85hwVXIy+TSrK0m1zSBi5Dp6 +Z2Orltxtrpfs/J92VoguZs9btsmksNcFuuEnL5O7Jiqik7Ab846+HUCjuTaPPoIa +Gl6I6lD4WeKDRikL40Rc4ZW2aZCaFG+XroHPaO+Zmr615+F/+PoTRxZMzG0IQOeL +eG9QgkRQP2YGiqtDhFZKDyAthg710tvSeopLzaXoTvFeJiUBWSOgftL2fiFX1ye8 +FVdMpEbB4IMeDExNH08GGeL5qPQ6gqGyeUN51q1veieQA6TqJIc/2b3Z6fJfUEkc +7uzXLg== +-----END CERTIFICATE-----'" +"Government of The Netherlands, PKIoverheid (Logius)","Staat der Nederlanden","","Staat der Nederlanden Root CA - G3","0098A239","3C4FB0B95AB8B30032F432B86F535FE172C185D0FD39865837CF36187FA6F428","BBA5DEB8B63C0654BC3D5D680BF72BF2FABE87A6D53CE4EC7382F51DFE4E8790","2013.11.14","2028.11.13","RSA 4096 bits","SHA256WithRSA","Websites;Email","","","Not EV","https://bugzilla.mozilla.org/show_bug.cgi?id=1016568","NSS 3.18","Firefox 38","https://roottest-g3.pkioverheid.nl/","https://roottest-g3-expired.pkioverheid.nl/","https://roottest-g3-revoked.pkioverheid.nl/","None","https://www.logius.nl/languages/english/pkioverheid/","Netherlands","","https://cps.pkioverheid.nl/CPS_PA_PKIoverheid_G2_G3_Root_v4.3.pdf","https://www.cpacanada.ca/generichandlers/CPACHandler.ashx?attachmentid=238851","https://www.cpacanada.ca/generichandlers/CPACHandler.ashx?attachmentid=238852","","KPMG","WebTrust","2020.03.12","'-----BEGIN CERTIFICATE----- +MIIFdDCCA1ygAwIBAgIEAJiiOTANBgkqhkiG9w0BAQsFADBaMQswCQYDVQQGEwJO +TDEeMBwGA1UECgwVU3RhYXQgZGVyIE5lZGVybGFuZGVuMSswKQYDVQQDDCJTdGFh +dCBkZXIgTmVkZXJsYW5kZW4gUm9vdCBDQSAtIEczMB4XDTEzMTExNDExMjg0MloX +DTI4MTExMzIzMDAwMFowWjELMAkGA1UEBhMCTkwxHjAcBgNVBAoMFVN0YWF0IGRl +ciBOZWRlcmxhbmRlbjErMCkGA1UEAwwiU3RhYXQgZGVyIE5lZGVybGFuZGVuIFJv +b3QgQ0EgLSBHMzCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAL4yolQP +cPssXFnrbMSkUeiFKrPMSjTysF/zDsccPVMeiAho2G89rcKezIJnByeHaHE6n3WW +IkYFsO2tx1ueKt6c/DrGlaf1F2cY5y9JCAxcz+bMNO14+1Cx3Gsy8KL+tjzk7FqX +xz8ecAgwoNzFs21v0IJyEavSgWhZghe3eJJg+szeP4TrjTgzkApyI/o1zCZxMdFy +KJLZWyNtZrVtB0LrpjPOktvA9mxjeM3KTj215VKb8b475lRgsGYeCasH/lSJEULR +9yS6YHgamPfJEf0WwTUaVHXvQ9Plrk7O53vDxk5hUUurmkVLoR9BvUhTFXFkC4az +5S6+zqQbwSmEorXLCCN2QyIkHxcE1G6cxvx/K2Ya7Irl1s9N9WMJtxU51nus6+N8 +6U78dULI7ViVDAZCopz35HCz33JvWjdAidiFpNfxC95DGdRKWCyMijmev4SH8RY7 +Ngzp07TKbBlBUgmhHbBqv4LvcFEhMtwFdozL92TkA1CvjJFnq8Xy7ljY3r735zHP +bMk7ccHViLVlvMDoFxcHErVc0qsgk7TmgoNwNsXNo42ti+yjwUOH5kPiNL6VizXt +BznaqB16nzaeErAMZRKQFWDZJkBE41ZgpRDUajz9QdwOWke275dhdU/Z/seyHdTt +XUmzqWrLZoQT1Vyg3N9udwbRcXXIV2+vD3dbAgMBAAGjQjBAMA8GA1UdEwEB/wQF +MAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBRUrfrHkleuyjWcLhL75Lpd +INyUVzANBgkqhkiG9w0BAQsFAAOCAgEAMJmdBTLIXg47mAE6iqTnB/d6+Oea31BD +U5cqPco8R5gu4RV78ZLzYdqQJRZlwJ9UXQ4DO1t3ApyEtg2YXzTdO2PCwyiBwpwp +LiniyMMB8jPqKqrMCQj3ZWfGzd/TtiunvczRDnBfuCPRy5FOCvTIeuXZYzbB1N/8 +Ipf3YF3qKS9Ysr1YvY2WTxB1v0h7PVGHoTx0IsL8B3+A3MSs/mrBcDCw6Y5p4ixp +gZQJut3+TcCDjJRYwEYgr5wfAvg1VUkvRtTA8KCWAg8zxXHzniN9lLf9OtMJgwYh +/WA9rjLA0u6NpvDntIJ8CsxwyXmA+P5M9zWEGYox+wrZ13+b8KKaa8MFSu1BYBQw +0aoRQm7TIwIEC8Zl3d1Sd9qBa7Ko+gE4uZbqKmxnl4mUnrzhVNXkanjvSr0rmj1A +fsbAddJu+2gw7OyLnflJNZoaLNmzlTnVHpL3prllL+U9bTpITAjc5CgSKL59NVzq +4BZ+Extq1z7XnvwtdbLBFNUjA9tbbws+eC8N3jONFrdI54OagQ97wUNNVQQXOEpR +1VmiiXTTn74eS9fGbbeIJG9gkaSChVtWQbzQRKtqE77RLFi3EjNYsjdj3BP1lB0/ +QFH1T/U67cjF68IeHRaVesd+QnGTbksVtzDfqu1XhUisHWrdOWnk4Xl4vs4Fv6EM +94B7IWcnMFk= +-----END CERTIFICATE-----'" +"Government of Turkey, Kamu Sertifikasyon Merkezi (Kamu SM)","Turkiye Bilimsel ve Teknolojik Arastirma Kurumu - TUBITAK","Kamu Sertifikasyon Merkezi - Kamu SM","TUBITAK Kamu SM SSL Kok Sertifikasi - Surum 1","01","46EDC3689046D53A453FB3104AB80DCAEC658B2660EA1629DD7E867990648716","FC7E0F2A6965CFD6EECB4965EB14C6F9986BFC466CFDE9A4843B7CBD83BF770E","2013.11.25","2043.10.25","RSA 2048 bits","SHA256WithRSA","Websites","","","Not EV","https://bugzilla.mozilla.org/show_bug.cgi?id=1262809","NSS 3.30.2","Firefox 54","https://testssl.kamusm.gov.tr/","https://testsslexpired.kamusm.gov.tr/","https://testsslrevoked.kamusm.gov.tr/","*.gov.tr, *.k12.tr, *.pol.tr, *.mil.tr, *.tsk.tr, *.kep.tr,*.bel.tr,*.edu.tr, *.org.tr","http://www.kamusm.gov.tr/","Turkey","http://depo.kamusm.gov.tr/ilke/KamuSM_CP_En_1.0.1.pdf","http://depo.kamusm.gov.tr/ilke/KamuSM_CPS/KamuSM_CPS_En_3.3.1.pdf","https://bug1262809.bmoattachments.org/attachment.cgi?id=9110501","https://bug1262809.bmoattachments.org/attachment.cgi?id=9110501","","KIWA CERMET Italia S.p.A","ETSI EN 319 411","2019.10.24","'-----BEGIN CERTIFICATE----- +MIIEYzCCA0ugAwIBAgIBATANBgkqhkiG9w0BAQsFADCB0jELMAkGA1UEBhMCVFIx +GDAWBgNVBAcTD0dlYnplIC0gS29jYWVsaTFCMEAGA1UEChM5VHVya2l5ZSBCaWxp +bXNlbCB2ZSBUZWtub2xvamlrIEFyYXN0aXJtYSBLdXJ1bXUgLSBUVUJJVEFLMS0w +KwYDVQQLEyRLYW11IFNlcnRpZmlrYXN5b24gTWVya2V6aSAtIEthbXUgU00xNjA0 +BgNVBAMTLVRVQklUQUsgS2FtdSBTTSBTU0wgS29rIFNlcnRpZmlrYXNpIC0gU3Vy +dW0gMTAeFw0xMzExMjUwODI1NTVaFw00MzEwMjUwODI1NTVaMIHSMQswCQYDVQQG +EwJUUjEYMBYGA1UEBxMPR2ViemUgLSBLb2NhZWxpMUIwQAYDVQQKEzlUdXJraXll +IEJpbGltc2VsIHZlIFRla25vbG9qaWsgQXJhc3Rpcm1hIEt1cnVtdSAtIFRVQklU +QUsxLTArBgNVBAsTJEthbXUgU2VydGlmaWthc3lvbiBNZXJrZXppIC0gS2FtdSBT +TTE2MDQGA1UEAxMtVFVCSVRBSyBLYW11IFNNIFNTTCBLb2sgU2VydGlmaWthc2kg +LSBTdXJ1bSAxMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAr3UwM6q7 +a9OZLBI3hNmNe5eA027n/5tQlT6QlVZC1xl8JoSNkvoBHToP4mQ4t4y86Ij5iySr +LqP1N+RAjhgleYN1Hzv/bKjFxlb4tO2KRKOrbEz8HdDc72i9z+SqzvBV96I01INr +N3wcwv61A+xXzry0tcXtAA9TNypN9E8Mg/uGz8v+jE69h/mniyFXnHrfA2eJLJ2X +YacQuFWQfw4tJzh03+f92k4S400VIgLI4OD8D62K18lUUMw7D8oWgITQUVbDjlZ/ +iSIzL+aFCr2lqBs23tPcLG07xxO9WSMs5uWk99gL7eqQQESolbuT1dCANLZGeA4f +AJNG4e7p+exPFwIDAQABo0IwQDAdBgNVHQ4EFgQUZT/HiobGPN08VFw1+DrtUgxH +V8gwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEL +BQADggEBACo/4fEyjq7hmFxLXs9rHmoJ0iKpEsdeV31zVmSAhHqT5Am5EM2fKifh +AHe+SMg1qIGf5LgsyX8OsNJLN13qudULXjS99HMpw+0mFZx+CFOKWI3QSyjfwbPf +IPP54+M638yclNhOT8NrF7f3cuitZjO1JVOr4PhMqZ398g26rrnZqsZr+ZO7rqu4 +lzwDGrpDxpa5RXI4s6ehlj2Re37AIVNMh+3yC1SVUZPVIqUNivGTDj5UDrDYyU7c +8jEyVupk+eq1nRZmQnLzf9OxMUP8pI4X8W0jq5Rm+K37DwhuJi1/FwcJsoz7UMCf +lo3Ptv0AnVoUmr8CRPXBwp8iXqIPoeM= +-----END CERTIFICATE-----'" +"HARICA","Hellenic Academic and Research Institutions Cert. Authority","","Hellenic Academic and Research Institutions ECC RootCA 2015","00","44B545AA8A25E65A73CA15DC27FC36D24C1CB9953A066539B11582DC487B4833","A67DFA3384ED2EBDB007AD5E6A9E9AD0CC730E5EF003ACB9D2BF6A8FDC0B62CA","2015.07.07","2040.06.30","EC secp384r1","ecdsaWithSHA256","Websites;Email","","","Not EV","https://bugzilla.mozilla.org/show_bug.cgi?id=1201423","NSS 3.25","Firefox 49","https://haricaeccrootca2015-valid-ev.harica.gr","https://haricaeccrootca2015-expired-ev.harica.gr","https://haricaeccrootca2015-revoked-ev.harica.gr","None","http://www.harica.gr/","Greece, Greek Academic and Research Institutions","","https://repo.harica.gr/documents/CPS-EN.pdf","https://www.qmscert.com/share/HARICA_Audit_Attestation_E_V2.3_040620-01-AL_V1.0.pdf","https://www.qmscert.com/share/HARICA_Audit_Attestation_E_V2.3_040620-01-AL_V1.0.pdf","https://www.qmscert.com/share/HARICA_Audit_Attestation_E_V2.3_040620-01-AL_V1.0.pdf","QMSCERT","ETSI EN 319 411","2020.06.04","'-----BEGIN CERTIFICATE----- +MIICwzCCAkqgAwIBAgIBADAKBggqhkjOPQQDAjCBqjELMAkGA1UEBhMCR1IxDzAN +BgNVBAcTBkF0aGVuczFEMEIGA1UEChM7SGVsbGVuaWMgQWNhZGVtaWMgYW5kIFJl +c2VhcmNoIEluc3RpdHV0aW9ucyBDZXJ0LiBBdXRob3JpdHkxRDBCBgNVBAMTO0hl +bGxlbmljIEFjYWRlbWljIGFuZCBSZXNlYXJjaCBJbnN0aXR1dGlvbnMgRUNDIFJv +b3RDQSAyMDE1MB4XDTE1MDcwNzEwMzcxMloXDTQwMDYzMDEwMzcxMlowgaoxCzAJ +BgNVBAYTAkdSMQ8wDQYDVQQHEwZBdGhlbnMxRDBCBgNVBAoTO0hlbGxlbmljIEFj +YWRlbWljIGFuZCBSZXNlYXJjaCBJbnN0aXR1dGlvbnMgQ2VydC4gQXV0aG9yaXR5 +MUQwQgYDVQQDEztIZWxsZW5pYyBBY2FkZW1pYyBhbmQgUmVzZWFyY2ggSW5zdGl0 +dXRpb25zIEVDQyBSb290Q0EgMjAxNTB2MBAGByqGSM49AgEGBSuBBAAiA2IABJKg +QehLgoRc4vgxEZmGZE4JJS+dQS8KrjVPdJWyUWRrjWvmP3CV8AVER6ZyOFB2lQJa +jq4onvktTpnvLEhvTCUp6NFxW98dwXU3tNf6e3pCnGoKVlp8aQuqgAkkbH7BRqNC +MEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFLQi +C4KZJAEOnLvkDv2/+5cgk5kqMAoGCCqGSM49BAMCA2cAMGQCMGfOFmI4oqxiRaep +lSTAGiecMjvAwNW6qef4BENThe5SId6d9SWDPp5YSy/XZxMOIQIwBeF1Ad5o7Sof +TUwJCA3sS61kFyjndc5FZXIhF8siQQ6ME5g4mlRtm8rifOoCWCKR +-----END CERTIFICATE-----'" +"HARICA","Hellenic Academic and Research Institutions Cert. Authority","","Hellenic Academic and Research Institutions RootCA 2011","00","BC104F15A48BE709DCA542A7E1D4B9DF6F054527E802EAA92D595444258AFE71","1FC11D7838792D05CE76753F6DC70A7EADB890B0B03AAF45487CAE5CE35F59C4","2011.12.06","2031.12.01","RSA 2048 bits","SHA1WithRSA","Websites;Email","","","Not EV","https://bugzilla.mozilla.org/show_bug.cgi?id=581901","NSS 3.13.2","Firefox 11","https://haricarootca2011-valid.harica.gr","https://haricarootca2011-expired.harica.gr","https://haricarootca2011-revoked.harica.gr","","http://www.harica.gr/","Greece, Greek Academic and Research Institutions","","https://repo.harica.gr/documents/CPS-EN.pdf","https://www.qmscert.com/share/HARICA_Audit_Attestation_E_V2.3_040620-01-AL_V1.0.pdf","https://www.qmscert.com/share/HARICA_Audit_Attestation_E_V2.3_040620-01-AL_V1.0.pdf","https://www.qmscert.com/share/HARICA-AUDIT_ATTESTATION_W_ANNEX_290617-7-R2-AA.pdf","QMSCERT","ETSI EN 319 411","2020.06.04","'-----BEGIN CERTIFICATE----- +MIIEMTCCAxmgAwIBAgIBADANBgkqhkiG9w0BAQUFADCBlTELMAkGA1UEBhMCR1Ix +RDBCBgNVBAoTO0hlbGxlbmljIEFjYWRlbWljIGFuZCBSZXNlYXJjaCBJbnN0aXR1 +dGlvbnMgQ2VydC4gQXV0aG9yaXR5MUAwPgYDVQQDEzdIZWxsZW5pYyBBY2FkZW1p +YyBhbmQgUmVzZWFyY2ggSW5zdGl0dXRpb25zIFJvb3RDQSAyMDExMB4XDTExMTIw +NjEzNDk1MloXDTMxMTIwMTEzNDk1MlowgZUxCzAJBgNVBAYTAkdSMUQwQgYDVQQK +EztIZWxsZW5pYyBBY2FkZW1pYyBhbmQgUmVzZWFyY2ggSW5zdGl0dXRpb25zIENl +cnQuIEF1dGhvcml0eTFAMD4GA1UEAxM3SGVsbGVuaWMgQWNhZGVtaWMgYW5kIFJl +c2VhcmNoIEluc3RpdHV0aW9ucyBSb290Q0EgMjAxMTCCASIwDQYJKoZIhvcNAQEB +BQADggEPADCCAQoCggEBAKlTAOMupvaO+mDYLZU++CwqVE7NuYRhlFhPjz2L5EPz +dYmNUeTDN9KKiE15HrcS3UN4SoqS5tdI1Q+kOilENbgH9mgdVc04UfCMJDGFr4PJ +fel3r+0ae50X+bOdOFAPplp5kYCvN66m0zH7tSYJnTxa71HFK9+WXesyHgLacEns +bgzImjeN9/E2YEsmLIKe0HjzDQ9jpFEw4fkrJxIH2Oq9GGKYsFk3fb7u8yBRQlqD +75O6aRXxYp2fmTmCobd0LovUxQt7L/DICto9eQqakxylKHJzkUOap9FNhYS5qXSP +FEDH3N6sQWRstBmbAmNtJGSPRLIl6s5ddAxjMlyNh+UCAwEAAaOBiTCBhjAPBgNV +HRMBAf8EBTADAQH/MAsGA1UdDwQEAwIBBjAdBgNVHQ4EFgQUppFC/RNhSiOeCKQp +5dgTBCPuQSUwRwYDVR0eBEAwPqA8MAWCAy5ncjAFggMuZXUwBoIELmVkdTAGggQu +b3JnMAWBAy5ncjAFgQMuZXUwBoEELmVkdTAGgQQub3JnMA0GCSqGSIb3DQEBBQUA +A4IBAQAf73lB4XtuP7KMhjdCSk4cNx6NZrokgclPEg8hwAOXhiVtXdMiKahsog2p +6z0GW5k6x8zDmjR/qw7IThzh+uTczQ2+vyT+bOdrwg3IBp5OjWEopmr95fZi6hg8 +TqBTnbI6nOulnJEWtk2C4AwFSKls9cz4y51JtPACpf1wA+2KIaWuE4ZJwzNzvoc7 +dIsXRSZMFpGD/md9zU1jZ/rzAxKWeAaNsWftjj++n08C9bMJL/NMh98qy5V8Acys +Nnq/onN694/BtZqhFLKPM58N7yLcZnuEvUUXBj08yrl3NI/K6s8/MT7jiOOASSXI +l7WdmplNsDz4SgCbZN2fOUvRJ9e4 +-----END CERTIFICATE-----'" +"HARICA","Hellenic Academic and Research Institutions Cert. Authority","","Hellenic Academic and Research Institutions RootCA 2015","00","A040929A02CE53B4ACF4F2FFC6981CE4496F755E6D45FE0B2A692BCD52523F36","3320D8C4A37FDAAA85D4E251A05D2EC661C6873AD437DAF892602E151A2DA6CF","2015.07.07","2040.06.30","RSA 4096 bits","SHA256WithRSA","Websites;Email","","","Not EV","https://bugzilla.mozilla.org/show_bug.cgi?id=1201423","NSS 3.25","Firefox 49","https://haricarootca2015-valid-ev.harica.gr","https://haricarootca2015-expired-ev.harica.gr","https://haricarootca2015-revoked-ev.harica.gr","None","http://www.harica.gr/","Greece, Greek Academic and Research Institutions","","https://repo.harica.gr/documents/CPS-EN.pdf","https://www.qmscert.com/share/HARICA_Audit_Attestation_E_V2.3_040620-01-AL_V1.0.pdf","https://www.qmscert.com/share/HARICA_Audit_Attestation_E_V2.3_040620-01-AL_V1.0.pdf","https://www.qmscert.com/share/HARICA_Audit_Attestation_E_V2.3_040620-01-AL_V1.0.pdf","QMSCERT","ETSI EN 319 411","2020.06.04","'-----BEGIN CERTIFICATE----- +MIIGCzCCA/OgAwIBAgIBADANBgkqhkiG9w0BAQsFADCBpjELMAkGA1UEBhMCR1Ix +DzANBgNVBAcTBkF0aGVuczFEMEIGA1UEChM7SGVsbGVuaWMgQWNhZGVtaWMgYW5k +IFJlc2VhcmNoIEluc3RpdHV0aW9ucyBDZXJ0LiBBdXRob3JpdHkxQDA+BgNVBAMT +N0hlbGxlbmljIEFjYWRlbWljIGFuZCBSZXNlYXJjaCBJbnN0aXR1dGlvbnMgUm9v +dENBIDIwMTUwHhcNMTUwNzA3MTAxMTIxWhcNNDAwNjMwMTAxMTIxWjCBpjELMAkG +A1UEBhMCR1IxDzANBgNVBAcTBkF0aGVuczFEMEIGA1UEChM7SGVsbGVuaWMgQWNh +ZGVtaWMgYW5kIFJlc2VhcmNoIEluc3RpdHV0aW9ucyBDZXJ0LiBBdXRob3JpdHkx +QDA+BgNVBAMTN0hlbGxlbmljIEFjYWRlbWljIGFuZCBSZXNlYXJjaCBJbnN0aXR1 +dGlvbnMgUm9vdENBIDIwMTUwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoIC +AQDC+Kk/G4n8PDwEXT2QNrCROnk8ZlrvbTkBSRq0t89/TSNTt5AA4xMqKKYx8ZEA +4yjsriFBzh/a/X0SWwGDD7mwX5nh8hKDgE0GPt+sr+ehiGsxr/CL0BgzuNtFajT0 +AoAkKAoCFZVedioNmToUW/bLy1O8E00BiDeUJRtCvCLYjqOWXjrZMts+6PAQZe10 +4S+nfK8nNLspfZu2zwnI5dMK/IhlZXQK3HMcXM1AsRzUtoSMTFDPaI6oWa7CJ06C +ojXdFPQf/7J31Ycvqm59JCfnxssm5uX+Zwdj2EUN3TpZZTlYepKZcj2chF6IIbjV +9Cz82XBST3i4vTwri5WY9bPRaM8gFH5MXF/ni+X1NYEZN9cRCLdmvtNKzoNXADrD +gfgXy5I2XdGj2HUb4Ysn6npIQf1FGQatJ5lOwXBH3bWfgVMS5bGMSF0xQxfjjMZ6 +Y5ZLKTBOhE5iGV48zpeQpX8B653g+IuJ3SWYPZK2fu/Z8VFRfS0myGlZYeCsargq +NhEEelC9MoS+L9xy1dcdFkfkR2YgP/SWxa+OAXqlD3pk9Q0Yh9muiNX6hME6wGko +LfINaFGq46V3xqSQDqE3izEjR8EJCOtu93ib14L8hCCZSRm2Ekax+0VVFqmjZayc +Bw/qa9wfLgZy7IaIEuQt218FL+TwA9MmM+eAws1CoRc0CwIDAQABo0IwQDAPBgNV +HRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUcRVnyMjJvXVd +ctA4GGqd83EkVAswDQYJKoZIhvcNAQELBQADggIBAHW7bVRLqhBYRjTyYtcWNl0I +XtVsyIe9tC5G8jH4fOpCtZMWVdyhDBKg2mF+D1hYc2Ryx+hFjtyp8iY/xnmMsVMI +M4GwVhO+5lFc2JsKT0ucVlMC6U/2DWDqTUJV6HwbISHTGzrMd/K4kPFox/la/vot +9L/J9UUbzjgQKjeKeaO04wlshYaT/4mWJ3iBj2fjRnRUjtkNaeJK9E10A/+yd+2V +Z5fkscWrv2oj6NSU4kQoYsRL4vDY4ilrGnB+JGGTe08DMiUNRSQrlrRGar9KC/ea +j8GsGsVn82800vpzY4zvFrCopEYq+OsS7HK07/grfoxSwIuEVPkvPuNVqNxmsdnh +X9izjFk0WaSrT2y7HxjbdavYy5LNlDhhDgcGH0tGEPEVvo2FXDtKK4F5D7Rpn0lQ +l033DlZdwJVqwjbDG2jJ9SrcR5q+ss7FJej6A7na+RZukYT1HCjI/CbM1xyQVqdf +bzoEvM14iQuODy+jqk+iGxI9FghAD/FGTNeqewjBCvVtJ94Cj8rDtSvK6evIIVM4 +pcw72Hc3MKJP2W/R8kCtQXoXxdZKNYm3QdV8hn9VTYNKpXMgwDqvkPGaJI7ZjnHK +e7iG2rKPmT4dEw0SEe7Uq/DpFXYC5ODfqiAeW2GFZECpkJcNrVPSWh2HagCXZWK0 +vm9qp/UsQu0yrbYhnr68 +-----END CERTIFICATE-----'" +"IdenTrust Services, LLC","Digital Signature Trust Co.","","DST Root CA X3","44AFB080D6A327BA893039862EF8406B","0687260331A72403D909F105E69BCF0D32E1BD2493FFC6D9206D11BCD6770739","5A4004FA01EF95384A74FEE22977AF88E62E0FE13B6317E29E6586ECC0ED5010","2000.09.30","2021.09.30","RSA 2048 bits","SHA1WithRSA","Websites","","","Not EV","https://bugzilla.mozilla.org/show_bug.cgi?id=359069","NSS 3.11.9","Firefox 2","https://www.identrustssl.com/","https://expired.identrustssl.com/","https://revoked.identrustssl.com/","","http://www.identrust.com/","USA","https://www.identrust.com/sites/default/files/resources/TrustID_CP_V4.5_Published%209.27.2019.pdf","https://www.identrust.com/sites/default/files/resources/TrustID_CPS_v4.5_Published%209.27.2019.pdf","https://www.cpacanada.ca/generichandlers/CPACHandler.ashx?attachmentid=236834","https://www.cpacanada.ca/generichandlers/CPACHandler.ashx?attachmentid=236835","","Schellman & Company, LLC.","WebTrust","2019.11.04","'-----BEGIN CERTIFICATE----- +MIIDSjCCAjKgAwIBAgIQRK+wgNajJ7qJMDmGLvhAazANBgkqhkiG9w0BAQUFADA/ +MSQwIgYDVQQKExtEaWdpdGFsIFNpZ25hdHVyZSBUcnVzdCBDby4xFzAVBgNVBAMT +DkRTVCBSb290IENBIFgzMB4XDTAwMDkzMDIxMTIxOVoXDTIxMDkzMDE0MDExNVow +PzEkMCIGA1UEChMbRGlnaXRhbCBTaWduYXR1cmUgVHJ1c3QgQ28uMRcwFQYDVQQD +Ew5EU1QgUm9vdCBDQSBYMzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB +AN+v6ZdQCINXtMxiZfaQguzH0yxrMMpb7NnDfcdAwRgUi+DoM3ZJKuM/IUmTrE4O +rz5Iy2Xu/NMhD2XSKtkyj4zl93ewEnu1lcCJo6m67XMuegwGMoOifooUMM0RoOEq +OLl5CjH9UL2AZd+3UWODyOKIYepLYYHsUmu5ouJLGiifSKOeDNoJjj4XLh7dIN9b +xiqKqy69cK3FCxolkHRyxXtqqzTWMIn/5WgTe1QLyNau7Fqckh49ZLOMxt+/yUFw +7BZy1SbsOFU5Q9D8/RhcQPGX69Wam40dutolucbY38EVAjqr2m7xPi71XAicPNaD +aeQQmxkqtilX4+U9m5/wAl0CAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNV +HQ8BAf8EBAMCAQYwHQYDVR0OBBYEFMSnsaR7LHH62+FLkHX/xBVghYkQMA0GCSqG +SIb3DQEBBQUAA4IBAQCjGiybFwBcqR7uKGY3Or+Dxz9LwwmglSBd49lZRNI+DT69 +ikugdB/OEIKcdBodfpga3csTS7MgROSR6cz8faXbauX+5v3gTt23ADq1cEmv8uXr +AvHRAosZy5Q6XkjEGB5YGV8eAlrwDPGxrancWYaLbumR9YbK+rlmM6pZW87ipxZz +R8srzJmwN0jP41ZL9c8PDHIyh8bwRLtTcm1D9SZImlJnt1ir/md2cXjbDaJWFBM5 +JDGFoqgCWjBH4d1QB7wCCZAA62RjYJsWvIjJEubSfZGL+T0yjWW06XyxV3bqxbYo +Ob8VZRzI9neWagqNdwvYkQsEjgfbKbYK7p2CNTUQ +-----END CERTIFICATE-----'" +"IdenTrust Services, LLC","IdenTrust","","IdenTrust Commercial Root CA 1","0A0142800000014523C844B500000002","5D56499BE4D2E08BCFCAD08A3E38723D50503BDE706948E42F55603019E528AE","89B8F1171882FB89B23E8779EAC21869AC06C62183619A22340AC14D8BE58EEB","2014.01.16","2034.01.16","RSA 4096 bits","SHA256WithRSA","Websites;Email","","","Not EV","https://bugzilla.mozilla.org/show_bug.cgi?id=1037590","NSS 3.18","Firefox 38","https://sha2ssl-trustidvalid.identrustssl.com/","https://sha2ssl-trustidexpired.identrustssl.com/","https://sha2ssl-trustidrevoked.identrustssl.com/","None","http://www.identrust.com/","USA","https://www.identrust.com/sites/default/files/resources/identrust_trustid_cp_v4.7.2_05212020_0.pdf","https://www.identrust.com/sites/default/files/resources/identrust_trustid_cps_v4.7.2_05212020_0.pdf","https://www.cpacanada.ca/generichandlers/CPACHandler.ashx?attachmentid=236834","https://www.cpacanada.ca/generichandlers/CPACHandler.ashx?attachmentid=236835","https://www.cpacanada.ca/generichandlers/CPACHandler.ashx?attachmentid=234359","Schellman & Company, LLC.","WebTrust","2019.11.04","'-----BEGIN CERTIFICATE----- +MIIFYDCCA0igAwIBAgIQCgFCgAAAAUUjyES1AAAAAjANBgkqhkiG9w0BAQsFADBK +MQswCQYDVQQGEwJVUzESMBAGA1UEChMJSWRlblRydXN0MScwJQYDVQQDEx5JZGVu +VHJ1c3QgQ29tbWVyY2lhbCBSb290IENBIDEwHhcNMTQwMTE2MTgxMjIzWhcNMzQw +MTE2MTgxMjIzWjBKMQswCQYDVQQGEwJVUzESMBAGA1UEChMJSWRlblRydXN0MScw +JQYDVQQDEx5JZGVuVHJ1c3QgQ29tbWVyY2lhbCBSb290IENBIDEwggIiMA0GCSqG +SIb3DQEBAQUAA4ICDwAwggIKAoICAQCnUBneP5k91DNG8W9RYYKyqU+PZ4ldhNlT +3Qwo2dfw/66VQ3KZ+bVdfIrBQuExUHTRgQ18zZshq0PirK1ehm7zCYofWjK9ouuU ++ehcCuz/mNKvcbO0U59Oh++SvL3sTzIwiEsXXlfEU8L2ApeN2WIrvyQfYo3fw7gp +S0l4PJNgiCL8mdo2yMKi1CxUAGc1bnO/AljwpN3lsKImesrgNqUZFvX9t++uP0D1 +bVoE/c40yiTcdCMbXTMTEl3EASX2MN0CXZ/g1Ue9tOsbobtJSdifWwLziuQkkORi +T0/Br4sOdBeo0XKIanoBScy0RnnGF7HamB4HWfp1IYVl3ZBWzvurpWCdxJ35UrCL +vYf5jysjCiN2O/cz4ckA82n5S6LgTrx+kzmEB/dEcH7+B1rlsazRGMzyNeVJSQjK +Vsk9+w8YfYs7wRPCTY/JTw436R+hDmrfYi7LNQZReSzIJTj0+kuniVyc0uMNOYZK +dHzVWYfCP04MXFL0PfdSgvHqo6z9STQaKPNBiDoT7uje/5kdX7rL6B7yuVBgwDHT +c+XvvqDtMwt0viAgxGds8AgDelWAf0ZOlqf0Hj7h9tgJ4TNkK2PXMl6f+cB7D3hv +l7yTmvmcEpB4eoCHFddydJxVdHixuuFucAS6T6C6aMN7/zHwcz09lCqxC0EOoP5N +iGVreTO01wIDAQABo0IwQDAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB +/zAdBgNVHQ4EFgQU7UQZwNPwBovupHu+QucmVMiONnYwDQYJKoZIhvcNAQELBQAD +ggIBAA2ukDL2pkt8RHYZYR4nKM1eVO8lvOMIkPkp165oCOGUAFjvLi5+U1KMtlwH +6oi6mYtQlNeCgN9hCQCTrQ0U5s7B8jeUeLBfnLOic7iPBZM4zY0+sLj7wM+x8uwt +LRvM7Kqas6pgghstO8OEPVeKlh6cdbjTMM1gCIOQ045U8U1mwF10A0Cj7oV+wh93 +nAbowacYXVKV7cndJZ5t+qntozo00Fl72u1Q8zW/7esUTTHHYPTa8Yec4kjixsU3 ++wYQ+nVZZjFHKdp2mhzpgq7vmrlR94gjmmmVYjzlVYA211QC//G5Xc7UI2/YRYRK +W2XviQzdFKcgyxilJbQN+QHwotL0AMh0jqEqSI5l2xPE4iUXfeu+h1sXIFRRk0pT +AwvsXcoz7WL9RccvW9xYoIA55vrX/hMUpu09lEpCdNTDd1lzzY9GvlU47/rokTLq +l1gEIt44w8y8bckzOmoKaT+gyOpyj4xjhiO9bTyWnpXgSUyqorkqG5w2gXjtw+hG +4iZZRHUe2XWJUc0QhJ1hYMtd+ZciTY6Y5uN/9lu7rs3KSoFrXgvzUeF0K+l+J6fZ +mUlO+KWA2yUPHGNiiskzZ2s8EIPGrd6ozRaOjfAHN3Gf8qv8QfXBi+wAN10J5U6A +7/qxXDgGpRtK4dw4LTzcqx+QGtVKnO7RcGzM7vRX+Bi6hG6H +-----END CERTIFICATE-----'" +"IdenTrust Services, LLC","IdenTrust","","IdenTrust Public Sector Root CA 1","0A0142800000014523CF467C00000002","30D0895A9A448A262091635522D1F52010B5867ACAE12C78EF958FD4F4389F2F","961F12D77D4812E6F76FCC1E57681EBF94A6416F4B43699DCA0D91B7B7037DE6","2014.01.16","2034.01.16","RSA 4096 bits","SHA256WithRSA","Websites;Email","","","Not EV","https://bugzilla.mozilla.org/show_bug.cgi?id=1037590","NSS 3.18","Firefox 38","https://sha2ssl-acesvalid.identrust.com/","https://sha2ssl-acesexpired.identrust.com/","https://sha2ssl-acesrevoked.identrust.com/","None","http://www.identrust.com/","USA","https://www.identrust.com/sites/default/files/resources/identrust_trustid_cp_v4.7.2_05212020_0.pdf","https://www.identrust.com/sites/default/files/resources/identrust_trustid_cps_v4.7.2_05212020_0.pdf","https://www.cpacanada.ca/generichandlers/CPACHandler.ashx?attachmentid=236834","https://www.cpacanada.ca/generichandlers/CPACHandler.ashx?attachmentid=236835","","Schellman & Company, LLC.","WebTrust","2019.11.04","'-----BEGIN CERTIFICATE----- +MIIFZjCCA06gAwIBAgIQCgFCgAAAAUUjz0Z8AAAAAjANBgkqhkiG9w0BAQsFADBN +MQswCQYDVQQGEwJVUzESMBAGA1UEChMJSWRlblRydXN0MSowKAYDVQQDEyFJZGVu +VHJ1c3QgUHVibGljIFNlY3RvciBSb290IENBIDEwHhcNMTQwMTE2MTc1MzMyWhcN +MzQwMTE2MTc1MzMyWjBNMQswCQYDVQQGEwJVUzESMBAGA1UEChMJSWRlblRydXN0 +MSowKAYDVQQDEyFJZGVuVHJ1c3QgUHVibGljIFNlY3RvciBSb290IENBIDEwggIi +MA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC2IpT8pEiv6EdrCvsnduTyP4o7 +ekosMSqMjbCpwzFrqHd2hCa2rIFCDQjrVVi7evi8ZX3yoG2LqEfpYnYeEe4IFNGy +RBb06tD6Hi9e28tzQa68ALBKK0CyrOE7S8ItneShm+waOh7wCLPQ5CQ1B5+ctMlS +bdsHyo+1W/CD80/HLaXIrcuVIKQxKFdYWuSNG5qrng0M8gozOSI5Cpcu81N3uURF +/YTLNiCBWS2ab21ISGHKTN9T0a9SvESfqy9rg3LvdYDaBjMbXcjaY8ZNzaxmMc3R +3j6HEDbhuaR672BQssvKplbgN6+rNBM5Jeg5ZuSYeqoSmJxZZoY+rfGwyj4GD3vw +EUs3oERte8uojHH01bWRNszwFcYr3lEXsZdMUD2xlVl8BX0tIdUAvwFnol57plzy +9yLxkA2T26pEUWbMfXYD62qoKjgZl3YNa4ph+bz27nb9cCvdKTz4Ch5bQhyLVi9V +GxyhLrXHFub4qjySjmm2AcG1hp2JDws4lFTo6tyePSW8Uybt1as5qsVATFSrsrTZ +2fjXctscvG29ZV/viDUqZi/u9rNl8DONfJhBaUYPQxxp+pu10GFqzcpL2UyQRqsV +WaFHVCkugyhfHMKiq3IXAAaOReyL4jM9f9oZRORicsPfIsbyVtTdX5Vy7W1f90gD +W/3FKqD2cyOEEBsB5wIDAQABo0IwQDAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/ +BAUwAwEB/zAdBgNVHQ4EFgQU43HgntinQtnbcZFrlJPrw6PRFKMwDQYJKoZIhvcN +AQELBQADggIBAEf63QqwEZE4rU1d9+UOl1QZgkiHVIyqZJnYWv6IAcVYpZmxI1Qj +t2odIFflAWJBF9MJ23XLblSQdf4an4EKwt3X9wnQW3IV5B4Jaj0z8yGa5hV+rVHV +DRDtfULAj+7AmgjVQdZcDiFpboBhDhXAuM/FSRJSzL46zNQuOAXeNf0fb7iAaJg9 +TaDKQGXSc3z1i9kKlT/YPyNtGtEqJBnZhbMX73huqVjRI9PHE+1yJX9dsXNw0H8G +lwmEKYBhHfpe/3OsoOOJuBxxFcbeMX8S3OFtm6/n6J91eEyrRjuazr8FGF1NFTwW +mhlQBJqymm9li1JfPFgEKCXAZmExfrngdbkaqIHWchezxQMxNRF4eKLg6TCMf4Df +WN88uieW4oA0beOY02QnrEh+KHdcxiVhJfiFDGX6xDIvpZgF5PgLZxYWxoK4Mhn5 ++bl53B/N66+rDt0b20XkeucC4pVd/GnwU2lhlXV5C15V5jgclKlZM57IcXR5f1GJ +tshquDDIajjDbp7hNxbqBWJMWxJH7ae0s1hWx0nzfxJoCTFx8G34Tkf71oXuxVhA +GaQdp/lLQzfcaFpPz+vCZHTetBXZ9FRUGi8c15dxVJCO2SCdUyt/q4/i6jC8UDfv +8Ue1fXwsBOxonbRJRBD0ckscZOf85muQ3Wl9af0AVqW3rLatt8o+Ae+c +-----END CERTIFICATE-----'" +"Internet Security Research Group (ISRG)","Internet Security Research Group","","ISRG Root X1","008210CFB0D240E3594463E0BB63828B00","96BCEC06264976F37460779ACF28C5A7CFE8A3C0AAE11A8FFCEE05C0BDDF08C6","DA43F86604EB9619893C744D6AFBC37A7A57A0FBA3841E8D95488F5C798B150A","2015.06.04","2035.06.04","RSA 4096 bits","SHA256WithRSA","Websites","","","Not EV","https://bugzilla.mozilla.org/show_bug.cgi?id=1204656","NSS 3.26","Firefox 50","https://valid-isrgrootx1.letsencrypt.org/","https://expired-isrgrootx1.letsencrypt.org/","https://revoked-isrgrootx1.letsencrypt.org/","","https://letsencrypt.org/","Global","https://letsencrypt.org/documents/isrg-cp-v2.4/","https://letsencrypt.org/documents/isrg-cps-v2.7/","https://www.cpacanada.ca/generichandlers/CPACHandler.ashx?attachmentid=238186","https://www.cpacanada.ca/generichandlers/CPACHandler.ashx?attachmentid=238187","","Schellman & Company, LLC.","WebTrust","2019.11.14","'-----BEGIN CERTIFICATE----- +MIIFazCCA1OgAwIBAgIRAIIQz7DSQONZRGPgu2OCiwAwDQYJKoZIhvcNAQELBQAw +TzELMAkGA1UEBhMCVVMxKTAnBgNVBAoTIEludGVybmV0IFNlY3VyaXR5IFJlc2Vh +cmNoIEdyb3VwMRUwEwYDVQQDEwxJU1JHIFJvb3QgWDEwHhcNMTUwNjA0MTEwNDM4 +WhcNMzUwNjA0MTEwNDM4WjBPMQswCQYDVQQGEwJVUzEpMCcGA1UEChMgSW50ZXJu +ZXQgU2VjdXJpdHkgUmVzZWFyY2ggR3JvdXAxFTATBgNVBAMTDElTUkcgUm9vdCBY +MTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAK3oJHP0FDfzm54rVygc +h77ct984kIxuPOZXoHj3dcKi/vVqbvYATyjb3miGbESTtrFj/RQSa78f0uoxmyF+ +0TM8ukj13Xnfs7j/EvEhmkvBioZxaUpmZmyPfjxwv60pIgbz5MDmgK7iS4+3mX6U +A5/TR5d8mUgjU+g4rk8Kb4Mu0UlXjIB0ttov0DiNewNwIRt18jA8+o+u3dpjq+sW +T8KOEUt+zwvo/7V3LvSye0rgTBIlDHCNAymg4VMk7BPZ7hm/ELNKjD+Jo2FR3qyH +B5T0Y3HsLuJvW5iB4YlcNHlsdu87kGJ55tukmi8mxdAQ4Q7e2RCOFvu396j3x+UC +B5iPNgiV5+I3lg02dZ77DnKxHZu8A/lJBdiB3QW0KtZB6awBdpUKD9jf1b0SHzUv +KBds0pjBqAlkd25HN7rOrFleaJ1/ctaJxQZBKT5ZPt0m9STJEadao0xAH0ahmbWn +OlFuhjuefXKnEgV4We0+UXgVCwOPjdAvBbI+e0ocS3MFEvzG6uBQE3xDk3SzynTn +jh8BCNAw1FtxNrQHusEwMFxIt4I7mKZ9YIqioymCzLq9gwQbooMDQaHWBfEbwrbw +qHyGO0aoSCqI3Haadr8faqU9GY/rOPNk3sgrDQoo//fb4hVC1CLQJ13hef4Y53CI +rU7m2Ys6xt0nUW7/vGT1M0NPAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNV +HRMBAf8EBTADAQH/MB0GA1UdDgQWBBR5tFnme7bl5AFzgAiIyBpY9umbbjANBgkq +hkiG9w0BAQsFAAOCAgEAVR9YqbyyqFDQDLHYGmkgJykIrGF1XIpu+ILlaS/V9lZL +ubhzEFnTIZd+50xx+7LSYK05qAvqFyFWhfFQDlnrzuBZ6brJFe+GnY+EgPbk6ZGQ +3BebYhtF8GaV0nxvwuo77x/Py9auJ/GpsMiu/X1+mvoiBOv/2X/qkSsisRcOj/KK +NFtY2PwByVS5uCbMiogziUwthDyC3+6WVwW6LLv3xLfHTjuCvjHIInNzktHCgKQ5 +ORAzI4JMPJ+GslWYHb4phowim57iaztXOoJwTdwJx4nLCgdNbOhdjsnvzqvHu7Ur +TkXWStAmzOVyyghqpZXjFaH3pO3JLF+l+/+sKAIuvtd7u+Nxe5AW0wdeRlN8NwdC +jNPElpzVmbUq4JUagEiuTDkHzsxHpFKVK7q4+63SM1N95R1NbdWhscdCb+ZAJzVc +oyi3B43njTOQ5yOf+1CceWxG1bQVs5ZufpsMljq4Ui0/1lvh+wjChP4kqKOJ2qxq +4RgqsahDYVvTH9w7jXbyLeiNdd8XM2w9U/t7y0Ff/9yi0GE44Za4rF2LN9d11TPA +mRGunUHBcnWEvgJBQl9nJEiU0Zsnvgc/ubhPgXRR4Xq37Z0j4r7g1SgEEzwxA57d +emyPxgcYxn/eR44/KJ4EBs+lVDR3veyJm+kXQ99b21/+jh5Xos1AnX5iItreGCc= +-----END CERTIFICATE-----'" +"Izenpe S.A.","IZENPE S.A.","","Izenpe.com","00B0B75A16485FBFE1CBF58BD719E67D","2530CC8E98321502BAD96F9B1FBA1B099E2D299E0F4548BB914F363BC0D4531F","A2E476CF81D072DAA490850C466CD44A66F994CA38AEAC731A2D8F8385E9D090","2007.12.13","2037.12.13","RSA 4096 bits","SHA256WithRSA","Websites","","","1.3.6.1.4.1.14777.6.1.1, 1.3.6.1.4.1.14777.6.1.2","https://bugzilla.mozilla.org/show_bug.cgi?id=361957","NSS 3.12.9","Firefox 4.0","https://test-ev-qualified.izenpe.eus","https://test-expired-ev.izenpe.eus","https://test-revoked-ev.izenpe.eus","","http://www.izenpe.com","Basque Country, Spain","http://www.izenpe.eus/contenidos/informacion/doc_especifica/en_def/adjuntos/Izenpe_CP_website-certificates_v1.7_-06-2020-.pdf","https://www.izenpe.eus/contenidos/informacion/descarga_certificados/es_url/adjuntos/DOC_P_CPS_v6.5.pdf","https://www.aenor.com/Certificacion_Documentos/eiDas/2020%20AENOR%20Anexo%20ETSI%20319%20411-1-2%20PSC-IZENPE_v1.0%20(003).pdf","https://www.aenor.com/Certificacion_Documentos/eiDas/2020%20AENOR%20Anexo%20ETSI%20319%20411-1-2%20PSC-IZENPE_v1.0%20(003).pdf","https://www.aenor.com/Certificacion_Documentos/eiDas/2020%20AENOR%20Anexo%20ETSI%20319%20411-1-2%20PSC-IZENPE_v1.0%20(003).pdf","AENOR INTERNACIONAL, S.A. (Unipersonal)","ETSI EN 319 411","2020.07.23","'-----BEGIN CERTIFICATE----- +MIIF8TCCA9mgAwIBAgIQALC3WhZIX7/hy/WL1xnmfTANBgkqhkiG9w0BAQsFADA4 +MQswCQYDVQQGEwJFUzEUMBIGA1UECgwLSVpFTlBFIFMuQS4xEzARBgNVBAMMCkl6 +ZW5wZS5jb20wHhcNMDcxMjEzMTMwODI4WhcNMzcxMjEzMDgyNzI1WjA4MQswCQYD +VQQGEwJFUzEUMBIGA1UECgwLSVpFTlBFIFMuQS4xEzARBgNVBAMMCkl6ZW5wZS5j +b20wggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDJ03rKDx6sp4boFmVq +scIbRTJxldn+EFvMr+eleQGPicPK8lVx93e+d5TzcqQsRNiekpsUOqHnJJAKClaO +xdgmlOHZSOEtPtoKct2jmRXagaKH9HtuJneJWK3W6wyyQXpzbm3benhB6QiIEn6H +LmYRY2xU+zydcsC8Lv/Ct90NduM61/e0aL6i9eOBbsFGb12N4E3GVFWJGjMxCrFX +uaOKmMPsOzTFlUFpfnXCPCDFYbpRR6AgkJOhkEvzTnyFRVSa0QUmQbC1TR0zvsQD +yCV8wXDbO/QJLVQnSKwv4cSsPsjLkkxTOTcj7NMB+eAJRE1NZMDhDVqHIrytG6P+ +JrUV86f8hBnp7KGItERphIPzidF0BqnMC9bC3ieFUCbKF7jJeodWLBoBHmy+E60Q +rLUk9TiRodZL2vG70t5HtfG8gfZZa88ZU+mNFctKy6lvROUbQc/hhqfK0GqfvEyN +BjNaooXlkDWgYlwWTvDjovoDGrQscbNYLN57C9saD+veIR8GdwYDsMnvmfzAuU8L +hij+0rnq49qlw0dpEuDb8PYZi+17cNcC1u2HGCgsBCRMd+RIihrGO5rUD8r6ddIB +QFqNeb+Lz0vPqhbBleStTIo+F5HUsWLlguWABKQDfo2/2n+iD5dPDNMN+9fR5XJ+ +HMh3/1uaD7euBUbl8agW7EekFwIDAQABo4H2MIHzMIGwBgNVHREEgagwgaWBD2lu +Zm9AaXplbnBlLmNvbaSBkTCBjjFHMEUGA1UECgw+SVpFTlBFIFMuQS4gLSBDSUYg +QTAxMzM3MjYwLVJNZXJjLlZpdG9yaWEtR2FzdGVpeiBUMTA1NSBGNjIgUzgxQzBB +BgNVBAkMOkF2ZGEgZGVsIE1lZGl0ZXJyYW5lbyBFdG9yYmlkZWEgMTQgLSAwMTAx +MCBWaXRvcmlhLUdhc3RlaXowDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMC +AQYwHQYDVR0OBBYEFB0cZQ6o8iV7tJHP5LGx5r1VdGwFMA0GCSqGSIb3DQEBCwUA +A4ICAQB4pgwWSp9MiDrAyw6lFn2fuUhfGI8NYjb2zRlrrKvV9pF9rnHzP7MOeIWb +laQnIUdCSnxIOvVFfLMMjlF4rJUT3sb9fbgakEyrkgPH7UIBzg/YsfqikuFgba56 +awmqxinuaElnMIAkejEWOVt+8Rwu3WwJrfIxwYJOubv5vr8qhT/AQKM6WfxZSzwo +JNu0FXWuDYi6LnPAvViH5ULy617uHjAimcs30cQhbIHsvm0m5hzkQiCeR7Csg1lw +LDXWrzY0tM07+DKo7+N4ifuNRSzanLh+QBxh5z6ikixL8s36mLYp//Pye6kfLqCT +VyvehQP5aTfLnnhqBbTFMXiJ7HqnheG5ezzevh55hM6fcA5ZwjUukCox2eRFekGk +LhObNA5me0mrZJfQRsN5nXJQY6aYWwa9SG3YOYNw6DXwBdGqvOPbyALqfP2C2sJb +UjWumDqtujWTI6cfSN01RpiyEGjkpTHCClguGYEQyVB1/OpaFs4R1+7vUIgtYf8/ +QnMFlEPVjjxOAToZpR9GTnfQXeWBIiGH/pR9hNiTrdZoQ0iy2+tzJOeRf1SktoA+ +naM8THLCV8Sg1Mw4J87VBp6iSNnpn86CcDaTmjvfliHjWbcM2pE38P1ZWrOZyGls +QyYBNWNgVYkDOnXYukrZVP/u3oDYLdE41V4tC5h9Pmzb/CaIxw== +-----END CERTIFICATE-----'" +"Krajowa Izba Rozliczeniowa S.A. (KIR)","Krajowa Izba Rozliczeniowa S.A.","","SZAFIR ROOT CA2","3E8A5D07EC55D232D5B7E3B65F01EB2DDCE4D6E4","A1339D33281A0B56E557D3D32B1CE7F9367EB094BD5FA72A7E5004C8DED7CAFE","7E424C7C6EB92B46962CAF9AE6B4CAADF17FB0728382CF701F7B6FBDEDB13FDC","2015.10.19","2035.10.19","RSA 2048 bits","SHA256WithRSA","Websites;Email","","","Not EV","https://bugzilla.mozilla.org/show_bug.cgi?id=817994","NSS 3.23","Firefox 46","https://ssl.elektronicznypodpis.pl/","https://expired.elektronicznypodpis.pl/","https://revoked.elektronicznypodpis.pl/","None","http://www.kir.com.pl/","Poland","https://www.elektronicznypodpis.pl/gfx/elektronicznypodpis/userfiles/_public/information/legal_basis/20200326_certification_policy_kir_trusted_nq_certificates.pdf","https://www.elektronicznypodpis.pl/gfx/elektronicznypodpis/userfiles/_public/information/legal_basis/20200330_certification_practice_statement_kir_trusted_nq_certificates.pdf","https://www.cpacanada.ca/generichandlers/CPACHandler.ashx?attachmentid=238854","https://www.cpacanada.ca/generichandlers/CPACHandler.ashx?attachmentid=238855","","Ernst & Young, LLP","WebTrust","2020.03.09","'-----BEGIN CERTIFICATE----- +MIIDcjCCAlqgAwIBAgIUPopdB+xV0jLVt+O2XwHrLdzk1uQwDQYJKoZIhvcNAQEL +BQAwUTELMAkGA1UEBhMCUEwxKDAmBgNVBAoMH0tyYWpvd2EgSXpiYSBSb3psaWN6 +ZW5pb3dhIFMuQS4xGDAWBgNVBAMMD1NaQUZJUiBST09UIENBMjAeFw0xNTEwMTkw +NzQzMzBaFw0zNTEwMTkwNzQzMzBaMFExCzAJBgNVBAYTAlBMMSgwJgYDVQQKDB9L +cmFqb3dhIEl6YmEgUm96bGljemVuaW93YSBTLkEuMRgwFgYDVQQDDA9TWkFGSVIg +Uk9PVCBDQTIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC3vD5QqEvN +QLXOYeeWyrSh2gwisPq1e3YAd4wLz32ohswmUeQgPYUM1ljj5/QqGJ3a0a4m7utT +3PSQ1hNKDJA8w/Ta0o4NkjrcsbH/ON7Dui1fgLkCvUqdGw+0w8LBZwPd3BucPbOw +3gAeqDRHu5rr/gsUvTaE2g0gv/pby6kWIK05YO4vdbbnl5z5Pv1+TW9NL++IDWr6 +3fE9biCloBK0TXC5ztdyO4mTp4CEHCdJckm1/zuVnsHMyAHs6A6KCpbns6aH5db5 +BSsNl0BwPLqsdVqc1U2dAgrSS5tmS0YHF2Wtn2yIANwiieDhZNRnvDF5YTy7ykHN +XGoAyDw4jlivAgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQD +AgEGMB0GA1UdDgQWBBQuFqlKGLXLzPVvUPMjX/hd56zwyDANBgkqhkiG9w0BAQsF +AAOCAQEAtXP4A9xZWx126aMqe5Aosk3AM0+qmrHUuOQn/6mWmc5G4G18TKI4pAZw +8PRBEew/R40/cof5O/2kbytTAOD/OblqBw7rHRz2onKQy4I9EYKL0rufKq8h5mOG +nXkZ7/e7DDWQw4rtTw/1zBLZpD67oPwglV9PJi8RI4NOdQcPv5vRtB3pEAT+ymCP +oky4rc/hkA/NrgrHXXu3UNLUYfrVFdvXn4dRVOul4+vJhaAlIDf7js4MNIThPIGy +d05DpYhfhmehPea0XGG2Ptv+tyjFogeutcrKjSoS75ftwjCkySp6+/NNIxuZMzSg +LvWpCz/UXeHPhJ/iGcJfitYgHuNztw== +-----END CERTIFICATE-----'" +"Microsec Ltd.","Microsec Ltd.","","e-Szigno Root CA 2017","015448EF21FD97590DF5040A","BEB00B30839B9BC32C32E4447905950641F26421B15ED089198B518AE2EA1B99","CADE6C91BD5484A703610123F3FD944E860AAAC3774940A92E1EE58A2339845A","2017.08.22","2042.08.22","EC secp256r1","ecdsaWithSHA256","Websites;Email","","","Not EV","https://bugzilla.mozilla.org/show_bug.cgi?id=1445364","NSS 3.54","Firefox 79","https://eqtlsca2018-valid.e-szigno.hu/","https://eqtlsca2018-expired.e-szigno.hu/","https://eqtlsca2018-revoked.e-szigno.hu/","","https://e-szigno.hu/en/","Hungary, Europe","https://static.e-szigno.hu/docs/hr--min--ssl--EN--v2.16.pdf; https://static.e-szigno.hu/docs/hr--min--ssl--EN--v2.14.pdf","https://static.e-szigno.hu/docs/szsz--min--ssl--EN--v2.16.pdf; https://static.e-szigno.hu/docs/szsz--min--ssl--EN--v2.14.pdf","https://www.tuvit.de/fileadmin/Content/TUV_IT/zertifikate/en/AA2019121302_e-Szigno-Root-CA-2017_V1.1_s.pdf","https://www.tuvit.de/fileadmin/Content/TUV_IT/zertifikate/en/AA2019121302_e-Szigno-Root-CA-2017_V1.1_s.pdf","https://www.tuvit.de/fileadmin/Content/TUV_IT/zertifikate/en/AA2019121302_e-Szigno-Root-CA-2017_V1.1_s.pdf","TÜViT - TÜV Informationstechnik GmbH","ETSI EN 319 411","2019.12.13","'-----BEGIN CERTIFICATE----- +MIICQDCCAeWgAwIBAgIMAVRI7yH9l1kN9QQKMAoGCCqGSM49BAMCMHExCzAJBgNV +BAYTAkhVMREwDwYDVQQHDAhCdWRhcGVzdDEWMBQGA1UECgwNTWljcm9zZWMgTHRk +LjEXMBUGA1UEYQwOVkFUSFUtMjM1ODQ0OTcxHjAcBgNVBAMMFWUtU3ppZ25vIFJv +b3QgQ0EgMjAxNzAeFw0xNzA4MjIxMjA3MDZaFw00MjA4MjIxMjA3MDZaMHExCzAJ +BgNVBAYTAkhVMREwDwYDVQQHDAhCdWRhcGVzdDEWMBQGA1UECgwNTWljcm9zZWMg +THRkLjEXMBUGA1UEYQwOVkFUSFUtMjM1ODQ0OTcxHjAcBgNVBAMMFWUtU3ppZ25v +IFJvb3QgQ0EgMjAxNzBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABJbcPYrYsHtv +xie+RJCxs1YVe45DJH0ahFnuY2iyxl6H0BVIHqiQrb1TotreOpCmYF9oMrWGQd+H +Wyx7xf58etqjYzBhMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0G +A1UdDgQWBBSHERUI0arBeAyxr87GyZDvvzAEwDAfBgNVHSMEGDAWgBSHERUI0arB +eAyxr87GyZDvvzAEwDAKBggqhkjOPQQDAgNJADBGAiEAtVfd14pVCzbhhkT61Nlo +jbjcI4qKDdQvfepz7L9NbKgCIQDLpbQS+ue16M9+k/zzNY9vTlp8tLxOsvxyqltZ ++efcMQ== +-----END CERTIFICATE-----'" +"Microsec Ltd.","Microsec Ltd.","","Microsec e-Szigno Root CA 2009","00C27E43044E473F19","3C5F81FEA5FAB82C64BFA2EAECAFCDE8E077FC8620A7CAE537163DF36EDBF378","1F520FB57E00CA3E0EF4CE0704C8BA8934069066F88D4F48DDB9A1A04E60BF56","2009.06.16","2029.12.30","RSA 2048 bits","SHA256WithRSA","Websites;Email","","","Not EV","https://bugzilla.mozilla.org/show_bug.cgi?id=510506","NSS 3.12.8","Firefox 3.6.12","https://qtlsca2018-valid.e-szigno.hu/","https://qtlsca2018-expired.e-szigno.hu/","https://qtlsca2018-revoked.e-szigno.hu/","","https://e-szigno.hu/en/","Hungary, Europe","https://static.e-szigno.hu/docs/hr--min--ssl--EN--v2.16.pdf; https://static.e-szigno.hu/docs/hr--min--ssl--EN--v2.14.pdf","https://static.e-szigno.hu/docs/szsz--min--ssl--EN--v2.16.pdf; https://static.e-szigno.hu/docs/szsz--min--ssl--EN--v2.14.pdf","https://www.tuvit.de/fileadmin/Content/TUV_IT/zertifikate/en/AA2019121301_Microsec-eSzignoRoot-CA-2009_V1.2_s.pdf","https://www.tuvit.de/fileadmin/Content/TUV_IT/zertifikate/en/AA2019121301_Microsec-eSzignoRoot-CA-2009_V1.2_s.pdf","https://www.tuvit.de/fileadmin/Content/TUV_IT/zertifikate/en/AA2019121301_Microsec-eSzignoRoot-CA-2009_V1.2_s.pdf","TÜViT - TÜV Informationstechnik GmbH","ETSI EN 319 411","2019.12.13","'-----BEGIN CERTIFICATE----- +MIIECjCCAvKgAwIBAgIJAMJ+QwRORz8ZMA0GCSqGSIb3DQEBCwUAMIGCMQswCQYD +VQQGEwJIVTERMA8GA1UEBwwIQnVkYXBlc3QxFjAUBgNVBAoMDU1pY3Jvc2VjIEx0 +ZC4xJzAlBgNVBAMMHk1pY3Jvc2VjIGUtU3ppZ25vIFJvb3QgQ0EgMjAwOTEfMB0G +CSqGSIb3DQEJARYQaW5mb0BlLXN6aWduby5odTAeFw0wOTA2MTYxMTMwMThaFw0y +OTEyMzAxMTMwMThaMIGCMQswCQYDVQQGEwJIVTERMA8GA1UEBwwIQnVkYXBlc3Qx +FjAUBgNVBAoMDU1pY3Jvc2VjIEx0ZC4xJzAlBgNVBAMMHk1pY3Jvc2VjIGUtU3pp +Z25vIFJvb3QgQ0EgMjAwOTEfMB0GCSqGSIb3DQEJARYQaW5mb0BlLXN6aWduby5o +dTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAOn4j/NjrdqG2KfgQvvP +kd6mJviZpWNwrZuuyjNAfW2WbqEORO7hE52UQlKavXWFdCyoDh2Tthi3jCyoz/tc +cbna7P7ofo/kLx2yqHWH2Leh5TvPmUpG0IMZfcChEhyVbUr02MelTTMuhTlAdX4U +fIASmFDHQWe4oIBhVKZsTh/gnQ4H6cm6M+f+wFUoLAKApxn1ntxVUwOXewdI/5n7 +N4okxFnMUBBjjqqpGrCEGob5X7uxUG6k0QrM1XF+H6cbfPVTbiJfyyvm1HxdrtbC +xkzlBQHZ7Vf8wSN5/PrIJIOV87VqUQHQd9bpEqH5GoP7ghu5sJf0dgYzQ0mg/wu1 ++rUCAwEAAaOBgDB+MA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0G +A1UdDgQWBBTLD8bfQkPMPcu1SCOhGnqmKrs0aDAfBgNVHSMEGDAWgBTLD8bfQkPM +Pcu1SCOhGnqmKrs0aDAbBgNVHREEFDASgRBpbmZvQGUtc3ppZ25vLmh1MA0GCSqG +SIb3DQEBCwUAA4IBAQDJ0Q5eLtXMs3w+y/w9/w0olZMEyL/azXm4Q5DwpL7v8u8h +mLzU1F0G9u5C7DBsoKqpyvGvivo/C3NqPuouQH4frlRheesuCDfXI/OMn74dseGk +ddug4lQUsbocKaQY9hK6ohQU4zE1yED/t+AFdlfBHFny+L/k7SViXITwfn4fs775 +tyERzAMBVnCnEJIeGzSBHq2cGsMEPO0CYdYeBvNfOofyK/FFh+U9rNHHV4S9a67c +2Pm2G2JwCz02yULyMtd6YebS2z3PyKnJm9zbWETXbzivf3jTo60adbocwTZ8jx5t +HMN1Rq41Bab2XD0h7lbwyYIiLXpUq3DDfSJlgnCW +-----END CERTIFICATE-----'" +"Microsoft Corporation","Microsoft Corporation","","Microsoft ECC Root Certificate Authority 2017","66F23DAF87DE8BB14AEA0C573101C2EC","358DF39D764AF9E1B766E9C972DF352EE15CFAC227AF6AD1D70E8E4A6EDCBA02","9E1DF5CA54D3B67F982329387843DFEB63F0CEA067510D04879123AA9814BE87","2019.12.18","2042.07.18","EC secp384r1","ecdsaWithSHA384","Websites","","","Not EV","https://bugzilla.mozilla.org/show_bug.cgi?id=1448093","NSS 3.54","Firefox 79","https://acteccroot2017.pki.microsoft.com/","https://expeccroot2017.pki.microsoft.com/","https://rvkeccroot2017.pki.microsoft.com/","","https://www.microsoft.com/pkiops/docs/repository.htm","Global","https://www.microsoft.com/pkiops/Docs/Content/policy/Microsoft_PKI_Services_CP_v3.1.3.pdf","https://www.microsoft.com/pkiops/Docs/Content/policy/Microsoft_PKI_Services_CPS_v3.1.5.pdf","https://www.cpacanada.ca/generichandlers/CPACHandler.ashx?attachmentid=240887","https://www.cpacanada.ca/generichandlers/CPACHandler.ashx?attachmentid=240899","https://www.cpacanada.ca/generichandlers/CPACHandler.ashx?attachmentid=240900","BDO International Limited","WebTrust","2020.06.29","'-----BEGIN CERTIFICATE----- +MIICWTCCAd+gAwIBAgIQZvI9r4fei7FK6gxXMQHC7DAKBggqhkjOPQQDAzBlMQsw +CQYDVQQGEwJVUzEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMTYwNAYD +VQQDEy1NaWNyb3NvZnQgRUNDIFJvb3QgQ2VydGlmaWNhdGUgQXV0aG9yaXR5IDIw +MTcwHhcNMTkxMjE4MjMwNjQ1WhcNNDIwNzE4MjMxNjA0WjBlMQswCQYDVQQGEwJV +UzEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMTYwNAYDVQQDEy1NaWNy +b3NvZnQgRUNDIFJvb3QgQ2VydGlmaWNhdGUgQXV0aG9yaXR5IDIwMTcwdjAQBgcq +hkjOPQIBBgUrgQQAIgNiAATUvD0CQnVBEyPNgASGAlEvaqiBYgtlzPbKnR5vSmZR +ogPZnZH6thaxjG7efM3beaYvzrvOcS/lpaso7GMEZpn4+vKTEAXhgShC48Zo9OYb +hGBKia/teQ87zvH2RPUBeMCjVDBSMA4GA1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8E +BTADAQH/MB0GA1UdDgQWBBTIy5lycFIM+Oa+sgRXKSrPQhDtNTAQBgkrBgEEAYI3 +FQEEAwIBADAKBggqhkjOPQQDAwNoADBlAjBY8k3qDPlfXu5gKcs68tvWMoQZP3zV +L8KxzJOuULsJMsbG7X7JNpQS5GiFBqIb0C8CMQCZ6Ra0DvpWSNSkMBaReNtUjGUB +iudQZsIxtzm6uBoiB078a1QWIP8rtedMDE2mT3M= +-----END CERTIFICATE-----'" +"Microsoft Corporation","Microsoft Corporation","","Microsoft RSA Root Certificate Authority 2017","1ED397095FD8B4B347701EAABE7F45B3","C741F70F4B2A8D88BF2E71C14122EF53EF10EBA0CFA5E64CFA20F418853073E0","5131CFC5D520AD083F4F27CDE3EC234A0EF6355403E4ED5390E530B423E9BEB3","2019.12.18","2042.07.18","RSA 4096 bits","SHA384WithRSA","Websites","","","Not EV","https://bugzilla.mozilla.org/show_bug.cgi?id=1448093","NSS 3.54","Firefox 79","https://actrsaroot2017.pki.microsoft.com/","https://exprsaroot2017.pki.microsoft.com/","https://rvkrsaroot2017.pki.microsoft.com/","","https://www.microsoft.com/pkiops/docs/repository.htm","Global","https://www.microsoft.com/pkiops/Docs/Content/policy/Microsoft_PKI_Services_CP_v3.1.3.pdf","https://www.microsoft.com/pkiops/Docs/Content/policy/Microsoft_PKI_Services_CPS_v3.1.5.pdf","https://www.cpacanada.ca/generichandlers/CPACHandler.ashx?attachmentid=240887","https://www.cpacanada.ca/generichandlers/CPACHandler.ashx?attachmentid=240899","https://www.cpacanada.ca/generichandlers/CPACHandler.ashx?attachmentid=240900","BDO International Limited","WebTrust","2020.06.29","'-----BEGIN CERTIFICATE----- +MIIFqDCCA5CgAwIBAgIQHtOXCV/YtLNHcB6qvn9FszANBgkqhkiG9w0BAQwFADBl +MQswCQYDVQQGEwJVUzEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMTYw +NAYDVQQDEy1NaWNyb3NvZnQgUlNBIFJvb3QgQ2VydGlmaWNhdGUgQXV0aG9yaXR5 +IDIwMTcwHhcNMTkxMjE4MjI1MTIyWhcNNDIwNzE4MjMwMDIzWjBlMQswCQYDVQQG +EwJVUzEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMTYwNAYDVQQDEy1N +aWNyb3NvZnQgUlNBIFJvb3QgQ2VydGlmaWNhdGUgQXV0aG9yaXR5IDIwMTcwggIi +MA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDKW76UM4wplZEWCpW9R2LBifOZ +Nt9GkMml7Xhqb0eRaPgnZ1AzHaGm++DlQ6OEAlcBXZxIQIJTELy/xztokLaCLeX0 +ZdDMbRnMlfl7rEqUrQ7eS0MdhweSE5CAg2Q1OQT85elss7YfUJQ4ZVBcF0a5toW1 +HLUX6NZFndiyJrDKxHBKrmCk3bPZ7Pw71VdyvD/IybLeS2v4I2wDwAW9lcfNcztm +gGTjGqwu+UcF8ga2m3P1eDNbx6H7JyqhtJqRjJHTOoI+dkC0zVJhUXAoP8XFWvLJ +jEm7FFtNyP9nTUwSlq31/niol4fX/V4ggNyhSyL71Imtus5Hl0dVe49FyGcohJUc +aDDv70ngNXtk55iwlNpNhTs+VcQor1fznhPbRiefHqJeRIOkpcrVE7NLP8TjwuaG +YaRSMLl6IE9vDzhTyzMMEyuP1pq9KsgtsRx9S1HKR9FIJ3Jdh+vVReZIZZ2vUpC6 +W6IYZVcSn2i51BVrlMRpIpj0M+Dt+VGOQVDJNE92kKz8OMHY4Xu54+OU4UZpyw4K +UGsTuqwPN1q3ErWQgR5WrlcihtnJ0tHXUeOrO8ZV/R4O03QK0dqq6mm4lyiPSMQH ++FJDOvTKVTUssKZqwJz58oHhEmrARdlns87/I6KJClTUFLkqqNfs+avNJVgyeY+Q +W5g5xAgGwax/Dj0ApQIDAQABo1QwUjAOBgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/ +BAUwAwEB/zAdBgNVHQ4EFgQUCctZf4aycI8awznjwNnpv7tNsiMwEAYJKwYBBAGC +NxUBBAMCAQAwDQYJKoZIhvcNAQEMBQADggIBAKyvPl3CEZaJjqPnktaXFbgToqZC +LgLNFgVZJ8og6Lq46BrsTaiXVq5lQ7GPAJtSzVXNUzltYkyLDVt8LkS/gxCP81OC +gMNPOsduET/m4xaRhPtthH80dK2Jp86519efhGSSvpWhrQlTM93uCupKUY5vVau6 +tZRGrox/2KJQJWVggEbbMwSubLWYdFQl3JPk+ONVFT24bcMKpBLBaYVu32TxU5nh +SnUgnZUP5NbcA/FZGOhHibJXWpS2qdgXKxdJ5XbLwVaZOjex/2kskZGT4d9Mozd2 +TaGf+G0eHdP67Pv0RR0Tbc/3WeUiJ3IrhvNXuzDtJE3cfVa7o7P4NHmJweDyAmH3 +pvwPuxwXC65B2Xy9J6P9LjrRk5Sxcx0ki69bIImtt2dmefU6xqaWM/5TkshGsRGR +xpl/j8nWZjEgQRCHLQzWwa80mMpkg/sTV9HB8Dx6jKXB/ZUhoHHBk2dxEuqPiApp +GWSZI1b7rCoucL5mxAyE7+WL85MB+GqQk2dLsmijtWKP6T+MejteD+eMuMZ87zf9 +dOLITzNy4ZQ5bb0Sr74MTnB8G2+NszKTc0QWbej09+CVgI+WXTik9KveCjCHk9hN +AHFiRSdLOkKEW39lt2c0Ui2cFmuqqNh7o0JMcccMyj6D5KbvtwEwXlGjefVwaaZB +RA+GsCyRxj3qrg+E +-----END CERTIFICATE-----'" +"NetLock Ltd.","NetLock Kft.","Tanúsítványkiadók (Certification Services)","NetLock Arany (Class Gold) Főtanúsítvány","49412CE40010","6C61DAC3A2DEF031506BE036D2A6FE401994FBD13DF9C8D466599274C446EC98","420DB8024F846B2FC1243244BE1114BC9625CD88E88B9F163E8D5FF71E0E4A84","2008.12.11","2028.12.06","RSA 2048 bits","SHA256WithRSA","Websites;Email","","","Not EV","https://bugzilla.mozilla.org/show_bug.cgi?id=480966","NSS 3.12.6","Firefox 3.6.2","https://valid.qev.tanusitvany.hu","https://expired.qev.tanusitvany.hu","https://revoked.qev.tanusitvany.hu","","http://www.netlock.hu/USEREN/index.html","Hungary","https://netlock.hu/download/sp-qc-en-draft/?wpdmdl=59471","https://netlock.hu/download/sps-qc-en-draft/?wpdmdl=59472","http://eng.matrix-tanusito.hu/wp-content/uploads/2019/11/I-NL19T2_TAN.EN_TAN.ME-01_signed.pdf","http://eng.matrix-tanusito.hu/wp-content/uploads/2019/11/I-NL19T2_TAN.EN_TAN.ME-01_signed.pdf","http://eng.matrix-tanusito.hu/wp-content/uploads/2019/11/I-NL19T2_TAN.EN_TAN.ME-01_signed.pdf","MATRIX Ltd.","ETSI EN 319 411","2019.10.25","'-----BEGIN CERTIFICATE----- +MIIEFTCCAv2gAwIBAgIGSUEs5AAQMA0GCSqGSIb3DQEBCwUAMIGnMQswCQYDVQQG +EwJIVTERMA8GA1UEBwwIQnVkYXBlc3QxFTATBgNVBAoMDE5ldExvY2sgS2Z0LjE3 +MDUGA1UECwwuVGFuw7pzw610dsOhbnlraWFkw7NrIChDZXJ0aWZpY2F0aW9uIFNl +cnZpY2VzKTE1MDMGA1UEAwwsTmV0TG9jayBBcmFueSAoQ2xhc3MgR29sZCkgRsWR +dGFuw7pzw610dsOhbnkwHhcNMDgxMjExMTUwODIxWhcNMjgxMjA2MTUwODIxWjCB +pzELMAkGA1UEBhMCSFUxETAPBgNVBAcMCEJ1ZGFwZXN0MRUwEwYDVQQKDAxOZXRM +b2NrIEtmdC4xNzA1BgNVBAsMLlRhbsO6c8OtdHbDoW55a2lhZMOzayAoQ2VydGlm +aWNhdGlvbiBTZXJ2aWNlcykxNTAzBgNVBAMMLE5ldExvY2sgQXJhbnkgKENsYXNz +IEdvbGQpIEbFkXRhbsO6c8OtdHbDoW55MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A +MIIBCgKCAQEAxCRec75LbRTDofTjl5Bu0jBFHjzuZ9lk4BqKf8owyoPjIMHj9DrT +lF8afFttvzBPhCf2nx9JvMaZCpDyD/V/Q4Q3Y1GLeqVw/HpYzY6b7cNGbIRwXdrz +AZAj/E4wqX7hJ2Pn7WQ8oLjJM2P+FpD/sLj916jAwJRDC7bVWaaeVtAkH3B5r9s5 +VA1lddkVQZQBr17s9o3x/61k/iCa11zr/qYfCGSji3ZVrR47KGAuhyXoqq8fxmRG +ILdwfzzeSNuWU7c5d+Qa4scWhHaXWy+7GRWF+GmF9ZmnqfI0p6m2pgP8b4Y9VHx2 +BJtr+UBdADTHLpl1neWIA6pN+APSQnbAGwIDAKiLo0UwQzASBgNVHRMBAf8ECDAG +AQH/AgEEMA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUzPpnk/C2uNClwB7zU/2M +U9+D15YwDQYJKoZIhvcNAQELBQADggEBAKt/7hwWqZw8UQCgwBEIBaeZ5m8BiFRh +bvG5GK1Krf6BQCOUL/t1fC8oS2IkgYIL9WHxHG64YTjrgfpioTtaYtOUZcTh5m2C ++C8lcLIhJsFyUR+MLMOEkMNaj7rP9KdlpeuY0fsFskZ1FSNqb4VjMIDw1Z4fKRzC +bLBQWV2QWzuoDTDPv31/zvGdg73JRm4gpvlhUbohL3u+pRVjodSVh/GeufOJ8z2F +uLjbvrW5KfnaNwUASZQDhETnv0Mxz3WLJdH0pmT1kvarBes96aULNmLazAZfNou2 +XjG4Kvte9nHfRCaexOYNkbQudZWAUWpLMKawYqGT8ZvYzsRjdT9ZR7E= +-----END CERTIFICATE-----'" +"OISTE","WISeKey","Copyright (c) 2005, OISTE Foundation Endorsed","OISTE WISeKey Global Root GA CA","413D72C7F46B1F81437DF1D22854DF9A","41C923866AB4CAD6B7AD578081582E020797A6CBDF4FFF78CE8396B38937D7F5","C8FEACC9989817A040D25A231120934A5152EFA47B9E696B412D4B51D46D6111","2005.12.11","2037.12.11","RSA 2048 bits","SHA1WithRSA","Websites;Email","","","Not EV","https://bugzilla.mozilla.org/show_bug.cgi?id=371362","NSS 3.12.4","Firefox 3.5","https://gavalidssl.hightrusted.com","https://gaexpiredssl.hightrusted.com","https://garevokedssl.hightrusted.com","","https://www.wisekey.com/","Switzerland, Global","https://oiste.org/wp-content/uploads/OGTM-CP-SSL-Certificates.v1.0.pdf","https://cdn.wisekey.com/wp-content/uploads/2020/05/OGTM-OISTE-Foundation-CPS.v3.1-CLEAN-1.pdf","https://www.cpacanada.ca/generichandlers/CPACHandler.ashx?attachmentid=240761","https://www.cpacanada.ca/generichandlers/CPACHandler.ashx?attachmentid=240762","https://www.cpacanada.ca/generichandlers/CPACHandler.ashx?attachmentid=240763","Auren","WebTrust","2020.06.19","'-----BEGIN CERTIFICATE----- +MIID8TCCAtmgAwIBAgIQQT1yx/RrH4FDffHSKFTfmjANBgkqhkiG9w0BAQUFADCB +ijELMAkGA1UEBhMCQ0gxEDAOBgNVBAoTB1dJU2VLZXkxGzAZBgNVBAsTEkNvcHly +aWdodCAoYykgMjAwNTEiMCAGA1UECxMZT0lTVEUgRm91bmRhdGlvbiBFbmRvcnNl +ZDEoMCYGA1UEAxMfT0lTVEUgV0lTZUtleSBHbG9iYWwgUm9vdCBHQSBDQTAeFw0w +NTEyMTExNjAzNDRaFw0zNzEyMTExNjA5NTFaMIGKMQswCQYDVQQGEwJDSDEQMA4G +A1UEChMHV0lTZUtleTEbMBkGA1UECxMSQ29weXJpZ2h0IChjKSAyMDA1MSIwIAYD +VQQLExlPSVNURSBGb3VuZGF0aW9uIEVuZG9yc2VkMSgwJgYDVQQDEx9PSVNURSBX +SVNlS2V5IEdsb2JhbCBSb290IEdBIENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A +MIIBCgKCAQEAy0+zAJs9Nt350UlqaxBJH+zYK7LG+DKBKUOVTJoZIyEVRd7jyBxR +VVuuk+g3/ytr6dTqvirdqFEr12bDYVxgAsj1znJ7O7jyTmUIms2kahnBAbtzptf2 +w93NvKSLtZlhuAGio9RN1AU9ka34tAhxZK9w8RxrfvbDd50kc3vkDIzh2TbhmYsF +mQvtRTEJysIA2/dyoJaqlYfQjse2YXMNdmaM3Bu0Y6Kff5MTMPGhJ9vZ/yxViJGg +4E8HsChWjBgbl0SOid3gF27nKu+POQoxhILYQBRJLnpB5Kf+42TMwVlxSywhp1t9 +4B3RLoGbw9ho972WG6xwsRYUC9tguSYBBQIDAQABo1EwTzALBgNVHQ8EBAMCAYYw +DwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUswN+rja8sHnR3JQmthG+IbJphpQw +EAYJKwYBBAGCNxUBBAMCAQAwDQYJKoZIhvcNAQEFBQADggEBAEuh/wuHbrP5wUOx +SPMowB0uyQlB+pQAHKSkq0lPjz0e701vvbyk9vImMMkQyh2I+3QZH4VFvbBsUfk2 +ftv1TDI6QU9bR8/oCy22xBmddMVHxjtqD6wU2zz0c5ypBd8A3HR4+vg1YFkCExh8 +vPtNsCBtQ7tgMHpnM1zFmdH4LTlSc/uMqpclXHLZCB6rTjzjgTGfA6b7wP4piFXa +hNVQA7bihKOmNqoROgHhGEvWRGizPflTdISzRpFGlgC3gCy24eMQ4tui5yiPAZZi +Fj4A4xylNoEYokxSdsARo27mHbrjWr42U8U+dY+GaSlYU7Wcu2+fXMUY7N0v4ZjJ +/L7fCg0= +-----END CERTIFICATE-----'" +"OISTE","WISeKey","OISTE Foundation Endorsed","OISTE WISeKey Global Root GB CA","76B1205274F0858746B3F8231AF6C2C0","6B9C08E86EB0F767CFAD65CD98B62149E5494A67F5845E7BD1ED019F27B86BD6","DA8BF275BF433360CAB959340EF5E8DA9C20C66A9C578C187F56952804407321","2014.12.01","2039.12.01","RSA 2048 bits","SHA256WithRSA","Websites;Email","","","2.16.756.5.14.7.4.8","https://bugzilla.mozilla.org/show_bug.cgi?id=1172819","NSS 3.21","Firefox 44","https://gbvalidssl.hightrusted.com/","https://gbexpiredssl.hightrusted.com/","https://gbrevokedssl.hightrusted.com/","None","https://www.wisekey.com/","Switzerland, Global","https://oiste.org/wp-content/uploads/OGTM-CP-SSL-Certificates.v1.0.pdf","https://cdn.wisekey.com/wp-content/uploads/2020/05/OGTM-OISTE-Foundation-CPS.v3.1-CLEAN-1.pdf","https://www.cpacanada.ca/generichandlers/CPACHandler.ashx?attachmentid=240761","https://www.cpacanada.ca/generichandlers/CPACHandler.ashx?attachmentid=240762","https://www.cpacanada.ca/generichandlers/CPACHandler.ashx?attachmentid=240763","Auren","WebTrust","2020.06.19","'-----BEGIN CERTIFICATE----- +MIIDtTCCAp2gAwIBAgIQdrEgUnTwhYdGs/gjGvbCwDANBgkqhkiG9w0BAQsFADBt +MQswCQYDVQQGEwJDSDEQMA4GA1UEChMHV0lTZUtleTEiMCAGA1UECxMZT0lTVEUg +Rm91bmRhdGlvbiBFbmRvcnNlZDEoMCYGA1UEAxMfT0lTVEUgV0lTZUtleSBHbG9i +YWwgUm9vdCBHQiBDQTAeFw0xNDEyMDExNTAwMzJaFw0zOTEyMDExNTEwMzFaMG0x +CzAJBgNVBAYTAkNIMRAwDgYDVQQKEwdXSVNlS2V5MSIwIAYDVQQLExlPSVNURSBG +b3VuZGF0aW9uIEVuZG9yc2VkMSgwJgYDVQQDEx9PSVNURSBXSVNlS2V5IEdsb2Jh +bCBSb290IEdCIENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA2Be3 +HEokKtaXscriHvt9OO+Y9bI5mE4nuBFde9IllIiCFSZqGzG7qFshISvYD06fWvGx +WuR51jIjK+FTzJlFXHtPrby/h0oLS5daqPZI7H17Dc0hBt+eFf1Biki3IPShehtX +1F1Q/7pn2COZH8g/497/b1t3sWtuuMlk9+HKQUYOKXHQuSP8yYFfTvdv37+ErXNk +u7dCjmn21HYdfp2nuFeKUWdy19SouJVUQHMD9ur06/4oQnc/nSMbsrY9gBQHTC5P +99UKFg29ZkM3fiNDecNAhvVMKdqOmq0NpQSHiB6F4+lT1ZvIiwNjeOvgGUpuuy9r +M2RYk61pv48b74JIxwIDAQABo1EwTzALBgNVHQ8EBAMCAYYwDwYDVR0TAQH/BAUw +AwEB/zAdBgNVHQ4EFgQUNQ/INmNe4qPs+TtmFc5RUuORmj0wEAYJKwYBBAGCNxUB +BAMCAQAwDQYJKoZIhvcNAQELBQADggEBAEBM+4eymYGQfp3FsLAmzYh7KzKNbrgh +cViXfa43FK8+5/ea4n32cZiZBKpDdHij40lhPnOMTZTg+XHEthYOU3gf1qKHLwI5 +gSk8rxWYITD+KJAAjNHhy/peyP34EEY7onhCkRd0VQreUGdNZtGn//3ZwLWoo4rO +ZvUPQ82nK1d7Y0Zqqi5S2PTt4W2tKZB4SLrhI6qjiey1q5bAtEuiHZeeevJuQHHf +aPFlTc58Bd9TZaml8LGXBHAVRgOY1NK/VLSgWH1Sb9pWJmLU2NuJMW8c8CLC02Ic +Nc1MaRVUGpCY3useX8p3x8uOPUNpnJpY0CQ73xtAln41rYHHTnG6iBM= +-----END CERTIFICATE-----'" +"OISTE","WISeKey","OISTE Foundation Endorsed","OISTE WISeKey Global Root GC CA","212A560CAEDA0CAB4045BF2BA22D3AEA","8560F91C3624DABA9570B5FEA0DBE36FF11A8323BE9486854FB3F34A5571198D","7AFC854B656E7DF8E105EA76A50126BAA4E0BAE4C8C1100C4EB12F8CA84F9FA3","2017.05.09","2042.05.09","EC secp384r1","ecdsaWithSHA384","Websites;Email","","","Not EV","https://bugzilla.mozilla.org/show_bug.cgi?id=1403591","NSS 3.39","Firefox 63","https://gcvalidssl.hightrusted.com/","https://gcexpiredssl.hightrusted.com/","https://gcrevokedssl.hightrusted.com/","","https://www.wisekey.com/","Switzerland, Global","https://oiste.org/wp-content/uploads/OGTM-CP-SSL-Certificates.v1.0.pdf","https://cdn.wisekey.com/wp-content/uploads/2020/05/OGTM-OISTE-Foundation-CPS.v3.1-CLEAN-1.pdf","https://www.cpacanada.ca/generichandlers/CPACHandler.ashx?attachmentid=240761","https://www.cpacanada.ca/generichandlers/CPACHandler.ashx?attachmentid=240762","https://www.cpacanada.ca/generichandlers/CPACHandler.ashx?attachmentid=240763","Auren","WebTrust","2020.06.19","'-----BEGIN CERTIFICATE----- +MIICaTCCAe+gAwIBAgIQISpWDK7aDKtARb8roi066jAKBggqhkjOPQQDAzBtMQsw +CQYDVQQGEwJDSDEQMA4GA1UEChMHV0lTZUtleTEiMCAGA1UECxMZT0lTVEUgRm91 +bmRhdGlvbiBFbmRvcnNlZDEoMCYGA1UEAxMfT0lTVEUgV0lTZUtleSBHbG9iYWwg +Um9vdCBHQyBDQTAeFw0xNzA1MDkwOTQ4MzRaFw00MjA1MDkwOTU4MzNaMG0xCzAJ +BgNVBAYTAkNIMRAwDgYDVQQKEwdXSVNlS2V5MSIwIAYDVQQLExlPSVNURSBGb3Vu +ZGF0aW9uIEVuZG9yc2VkMSgwJgYDVQQDEx9PSVNURSBXSVNlS2V5IEdsb2JhbCBS +b290IEdDIENBMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAETOlQwMYPchi82PG6s4ni +eUqjFqdrVCTbUf/q9Akkwwsin8tqJ4KBDdLArzHkdIJuyiXZjHWd8dvQmqJLIX4W +p2OQ0jnUsYd4XxiWD1AbNTcPasbc2RNNpI6QN+a9WzGRo1QwUjAOBgNVHQ8BAf8E +BAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUSIcUrOPDnpBgOtfKie7T +rYy0UGYwEAYJKwYBBAGCNxUBBAMCAQAwCgYIKoZIzj0EAwMDaAAwZQIwJsdpW9zV +57LnyAyMjMPdeYwbY9XJUpROTYJKcx6ygISpJcBMWm1JKWB4E+J+SOtkAjEA2zQg +Mgj/mkkCtojeFK9dbJlxjRo/i9fgojaGHAeCOnZT/cKi7e97sIBPWA9LUzm9 +-----END CERTIFICATE-----'" +"QuoVadis","QuoVadis Limited","","QuoVadis Root CA 1 G3","78585F2EAD2C194BE3370735341328B596D46593","8A866FD1B276B57E578E921C65828A2BED58E9F2F288054134B7F1F4BFC9CC74","7521FA2485299C38CAD326A675563D4F9877F018941ABEC7E59AA8233EA25076","2012.01.12","2042.01.12","RSA 4096 bits","SHA256WithRSA","Websites;Email","","","Not EV","https://bugzilla.mozilla.org/show_bug.cgi?id=926541","NSS 3.16.3","Firefox 32","https://qvsslrca1g3-ssl-v.quovadisglobal.com","https://qvsslrca1g3-ssl-e.quovadisglobal.com","https://qvsslrca1g3-ssl-r.quovadisglobal.com","","http://www.quovadisglobal.com","Bermuda, Global","https://www.quovadisglobal.com/wp-content/uploads/2020/03/QV_RCA2_CPCPS_v2.8.pdf","https://www.quovadisglobal.com/wp-content/uploads/2020/03/QV_RCA1_RCA3_CPCPS_V4_29.pdf","https://www.cpacanada.ca/generichandlers/CPACHandler.ashx?attachmentid=239021","https://www.cpacanada.ca/generichandlers/CPACHandler.ashx?attachmentid=239022","","Ernst & Young, LLP","WebTrust","2020.03.31","'-----BEGIN CERTIFICATE----- +MIIFYDCCA0igAwIBAgIUeFhfLq0sGUvjNwc1NBMotZbUZZMwDQYJKoZIhvcNAQEL +BQAwSDELMAkGA1UEBhMCQk0xGTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxHjAc +BgNVBAMTFVF1b1ZhZGlzIFJvb3QgQ0EgMSBHMzAeFw0xMjAxMTIxNzI3NDRaFw00 +MjAxMTIxNzI3NDRaMEgxCzAJBgNVBAYTAkJNMRkwFwYDVQQKExBRdW9WYWRpcyBM +aW1pdGVkMR4wHAYDVQQDExVRdW9WYWRpcyBSb290IENBIDEgRzMwggIiMA0GCSqG +SIb3DQEBAQUAA4ICDwAwggIKAoICAQCgvlAQjunybEC0BJyFuTHK3C3kEakEPBtV +wedYMB0ktMPvhd6MLOHBPd+C5k+tR4ds7FtJwUrVu4/sh6x/gpqG7D0DmVIB0jWe +rNrwU8lmPNSsAgHaJNM7qAJGr6Qc4/hzWHa39g6QDbXwz8z6+cZM5cOGMAqNF341 +68Xfuw6cwI2H44g4hWf6Pser4BOcBRiYz5P1sZK0/CPTz9XEJ0ngnjybCKOLXSoh +4Pw5qlPafX7PGglTvF0FBM+hSo+LdoINofjSxxR3W5A2B4GbPgb6Ul5jxaYA/qXp +UhtStZI5cgMJYr2wYBZupt0lwgNm3fME0UDiTouG9G/lg6AnhF4EwfWQvTA9xO+o +abw4m6SkltFi2mnAAZauy8RRNOoMqv8hjlmPSlzkYZqn0ukqeI1RPToV7qJZjqlc +3sX5kCLliEVx3ZGZbHqfPT2YfF72vhZooF6uCyP8Wg+qInYtyaEQHeTTRCOQiJ/G +KubX9ZqzWB4vMIkIG1SitZgj7Ah3HJVdYdHLiZxfokqRmu8hqkkWCKi9YSgxyXSt +hfbZxbGL0eUQMk1fiyA6PEkfM4VZDdvLCXVDaXP7a3F98N/ETH3Goy7IlXnLc6KO +Tk0k+17kBL5yG6YnLUlamXrXXAkgt3+UuU/xDRxeiEIbEbfnkduebPRq34wGmAOt +zCjvpUfzUwIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIB +BjAdBgNVHQ4EFgQUo5fW816iEOGrRZ88F2Q87gFwnMwwDQYJKoZIhvcNAQELBQAD +ggIBABj6W3X8PnrHX3fHyt/PX8MSxEBd1DKquGrX1RUVRpgjpeaQWxiZTOOtQqOC +MTaIzen7xASWSIsBx40Bz1szBpZGZnQdT+3Btrm0DWHMY37XLneMlhwqI2hrhVd2 +cDMT/uFPpiN3GPoajOi9ZcnPP/TJF9zrx7zABC4tRi9pZsMbj/7sPtPKlL92CiUN +qXsCHKnQO18LwIE6PWThv6ctTr1NxNgpxiIY0MWscgKCP6o6ojoilzHdCGPDdRS5 +YCgtW2jgFqlmgiNR9etT2DGbe+m3nUvriBbP+V04ikkwj+3x6xn0dxoxGE1nVGwv +b2X52z3sIexe9PSLymBlVNFxZPT5pqOBMzYzcfCkeF9OrYMh3jRJjehZrJ3ydlo2 +8hP0r+AJx2EqbPfgna67hkooby7utHnNkDPDs3b69fBsnQGQ+p6Q9pxyz0fawx/k +NSBT8lTR32GDpgLiJTjehTItXnOQUl1CxM49S+H5GYQd1aJQzEH7QRTDvdbJWqNj +ZgKAvQU6O0ec7AAmTPWIUb+oI38YB7AL7YsmoWTTYUrrXJ/es69nA7Mf3W1daWhp +q1467HxpvMc7hU6eFbm0FU/DlXpY18ls6Wy58yljXrQs8C097Vpl4KlbQMJImYFt +nh8GKjwStIsPm6Ik8KaN1nrgS7ZklmOVhMJKzRwuJIczYOXD +-----END CERTIFICATE-----'" +"QuoVadis","QuoVadis Limited","","QuoVadis Root CA 2","0509","85A0DD7DD720ADB7FF05F83D542B209DC7FF4528F7D677B18389FEA5E5C49E86","3BE6F14E3FB7C64FA06002587411FE388E935C5B924A39010103989EC1CC5C47","2006.11.24","2031.11.24","RSA 4096 bits","SHA1WithRSA","Websites;Email","","","1.3.6.1.4.1.8024.0.2.100.1.2","https://bugzilla.mozilla.org/show_bug.cgi?id=365281","NSS 3.11.8","Firefox 2","https://qvsslrca2-ev-v.quovadisglobal.com","https://qvsslrca2-ev-e.quovadisglobal.com","https://qvsslrca2-ev-r.quovadisglobal.com","","http://www.quovadisglobal.com","Bermuda, Global","https://www.quovadisglobal.com/wp-content/uploads/2020/03/QV_RCA2_CPCPS_v2.8.pdf","https://www.quovadisglobal.com/wp-content/uploads/2020/03/QV_RCA1_RCA3_CPCPS_V4_29.pdf","https://www.cpacanada.ca/generichandlers/CPACHandler.ashx?attachmentid=239021","https://www.cpacanada.ca/generichandlers/CPACHandler.ashx?attachmentid=239022","https://www.cpacanada.ca/generichandlers/CPACHandler.ashx?attachmentid=239023","Ernst & Young, LLP","WebTrust","2020.03.31","'-----BEGIN CERTIFICATE----- +MIIFtzCCA5+gAwIBAgICBQkwDQYJKoZIhvcNAQEFBQAwRTELMAkGA1UEBhMCQk0x +GTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxGzAZBgNVBAMTElF1b1ZhZGlzIFJv +b3QgQ0EgMjAeFw0wNjExMjQxODI3MDBaFw0zMTExMjQxODIzMzNaMEUxCzAJBgNV +BAYTAkJNMRkwFwYDVQQKExBRdW9WYWRpcyBMaW1pdGVkMRswGQYDVQQDExJRdW9W +YWRpcyBSb290IENBIDIwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCa +GMpLlA0ALa8DKYrwD4HIrkwZhR0In6spRIXzL4GtMh6QRr+jhiYaHv5+HBg6XJxg +Fyo6dIMzMH1hVBHL7avg5tKifvVrbxi3Cgst/ek+7wrGsxDp3MJGF/hd/aTa/55J +WpzmM+Yklvc/ulsrHHo1wtZn/qtmUIttKGAr79dgw8eTvI02kfN/+NsRE8Scd3bB +rrcCaoF6qUWD4gXmuVbBlDePSHFjIuwXZQeVikvfj8ZaCuWw419eaxGrDPmF60Tp ++ARz8un+XJiM9XOva7R+zdRcAitMOeGylZUtQofX1bOQQ7dsE/He3fbE+Ik/0XX1 +ksOR1YqI0JDs3G3eicJlcZaLDQP9nL9bFqyS2+r+eXyt66/3FsvbzSUr5R/7mp/i +Ucw6UwxI5g69ybR2BlLmEROFcmMDBOAENisgGQLodKcftslWZvB1JdxnwQ5hYIiz +PtGo/KPaHbDRsSNU30R2be1B2MGyIrZTHN81Hdyhdyox5C315eXbyOD/5YDXC2Og +/zOhD7osFRXql7PSorW+8oyWHhqPHWykYTe5hnMz15eWniN9gqRMgeKh0bpnX5UH +oycR7hYQe7xFSkyyBNKr79X9DFHOUGoIMfmR2gyPZFwDwzqLID9ujWc9Otb+fVuI +yV77zGHcizN300QyNQliBJIWENieJ0f7OyHj+OsdWwIDAQABo4GwMIGtMA8GA1Ud +EwEB/wQFMAMBAf8wCwYDVR0PBAQDAgEGMB0GA1UdDgQWBBQahGK8SEwzJQTU7tD2 +A8QZRtGUazBuBgNVHSMEZzBlgBQahGK8SEwzJQTU7tD2A8QZRtGUa6FJpEcwRTEL +MAkGA1UEBhMCQk0xGTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxGzAZBgNVBAMT +ElF1b1ZhZGlzIFJvb3QgQ0EgMoICBQkwDQYJKoZIhvcNAQEFBQADggIBAD4KFk2f +BluornFdLwUvZ+YTRYPENvbzwCYMDbVHZF34tHLJRqUDGCdViXh9duqWNIAXINzn +g/iN/Ae42l9NLmeyhP3ZRPx3UIHmfLTJDQtyU/h2BwdBR5YM++CCJpNVjP4iH2Bl +fF/nJrP3MpCYUNQ3cVX2kiF495V5+vgtJodmVjB3pjd4M1IQWK4/YY7yarHvGH5K +WWPKjaJW1acvvFYfzznB4vsKqBUsfU16Y8Zsl0Q80m/DShcK+JDSV6IZUaUtl0Ha +B0+pUNqQjZRG4T7wlP0QADj1O+hA4bRuVhogzG9Yje0uRY/W6ZM/57Es3zrWIozc +hLsib9D45MY56QSIPMO661V6bYCZJPVsAfv4l7CUW+v90m/xd2gNNWQjrLhVoQPR +TUIZ3Ph1WVaj+ahJefivDrkRoHy3au000LYmYjgahwz46P0u05B/B5EqHdZ+XIWD +mbA4CD/pXvk1B+TJYm5Xf6dQlfe6yJvmjqIBxdZmv3lh8zwc4bmCXF2gw+nYSL0Z +ohEUGW6yhhtoPkg3Goi3XZZenMfvJ2II4pEZXNLxId26F0KCl3GBUzGpn/Z9Yr9y +4aOTHcyKJloJONDO1w2AFrR4pTqHTI2KpdVGl/IsELm8VCLAAVBpQ570su9t+Oza +8eOx79+Rj1QqCyXBJhnEUhAFZdWCEOrCMc0u +-----END CERTIFICATE-----'" +"QuoVadis","QuoVadis Limited","","QuoVadis Root CA 2 G3","445734245B81899B35F2CEB82B3B5BA726F07528","8FE4FB0AF93A4D0D67DB0BEBB23E37C71BF325DCBCDD240EA04DAF58B47E1840","D619C138A5452CF1B46D565FC37116923B5FFA8495FEF580A9910609A1F2D374","2012.01.12","2042.01.12","RSA 4096 bits","SHA256WithRSA","Websites","","","1.3.6.1.4.1.8024.0.2.100.1.2","https://bugzilla.mozilla.org/show_bug.cgi?id=926541","NSS 3.16.3","Firefox 32","https://qvsslrca2g3-ev-v.quovadisglobal.com","https://qvsslrca2g3-ev-e.quovadisglobal.com","https://qvsslrca2g3-ev-r.quovadisglobal.com","","http://www.quovadisglobal.com","Bermuda, Global","https://www.quovadisglobal.com/wp-content/uploads/2020/03/QV_RCA2_CPCPS_v2.8.pdf","https://www.quovadisglobal.com/wp-content/uploads/2020/03/QV_RCA1_RCA3_CPCPS_V4_29.pdf","https://www.cpacanada.ca/generichandlers/CPACHandler.ashx?attachmentid=239021","https://www.cpacanada.ca/generichandlers/CPACHandler.ashx?attachmentid=239022","https://www.cpacanada.ca/generichandlers/CPACHandler.ashx?attachmentid=239023","Ernst & Young, LLP","WebTrust","2020.03.31","'-----BEGIN CERTIFICATE----- +MIIFYDCCA0igAwIBAgIURFc0JFuBiZs18s64KztbpybwdSgwDQYJKoZIhvcNAQEL +BQAwSDELMAkGA1UEBhMCQk0xGTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxHjAc +BgNVBAMTFVF1b1ZhZGlzIFJvb3QgQ0EgMiBHMzAeFw0xMjAxMTIxODU5MzJaFw00 +MjAxMTIxODU5MzJaMEgxCzAJBgNVBAYTAkJNMRkwFwYDVQQKExBRdW9WYWRpcyBM +aW1pdGVkMR4wHAYDVQQDExVRdW9WYWRpcyBSb290IENBIDIgRzMwggIiMA0GCSqG +SIb3DQEBAQUAA4ICDwAwggIKAoICAQChriWyARjcV4g/Ruv5r+LrI3HimtFhZiFf +qq8nUeVuGxbULX1QsFN3vXg6YOJkApt8hpvWGo6t/x8Vf9WVHhLL5hSEBMHfNrMW +n4rjyduYNM7YMxcoRvynyfDStNVNCXJJ+fKH46nafaF9a7I6JaltUkSs+L5u+9ym +c5GQYaYDFCDy54ejiK2toIz/pgslUiXnFgHVy7g1gQyjO/Dh4fxaXc6AcW34Sas+ +O7q414AB+6XrW7PFXmAqMaCvN+ggOp+oMiwMzAkd056OXbxMmO7FGmh77FOm6RQ1 +o9/NgJ8MSPsc9PG/Srj61YxxSscfrf5BmrODXfKEVu+lV0POKa2Mq1W/xPtbAd0j +IaFYAI7D0GoT7RPjEiuA3GfmlbLNHiJuKvhB1PLKFAeNilUSxmn1uIZoL1NesNKq +IcGY5jDjZ1XHm26sGahVpkUG0CM62+tlXSoREfA7T8pt9DTEceT/AFr2XK4jYIVz +8eQQsSWu1ZK7E8EM4DnatDlXtas1qnIhO4M15zHfeiFuuDIIfR0ykRVKYnLP43eh +vNURG3YBZwjgQQvD6xVu+KQZ2aKrr+InUlYrAoosFCT5v0ICvybIxo/gbjh9Uy3l +7ZizlWNof/k19N+IxWA1ksB8aRxhlRbQ694Lrz4EEEVlWFA4r0jyWbYW8jwNkALG +cC4BrTwV1wIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIB +BjAdBgNVHQ4EFgQU7edvdlq/YOxJW8ald7tyFnGbxD0wDQYJKoZIhvcNAQELBQAD +ggIBAJHfgD9DCX5xwvfrs4iP4VGyvD11+ShdyLyZm3tdquXK4Qr36LLTn91nMX66 +AarHakE7kNQIXLJgapDwyM4DYvmL7ftuKtwGTTwpD4kWilhMSA/ohGHqPHKmd+RC +roijQ1h5fq7KpVMNqT1wvSAZYaRsOPxDMuHBR//47PERIjKWnML2W2mWeyAMQ0Ga +W/ZZGYjeVYg3UQt4XAoeo0L9x52ID8DyeAIkVJOviYeIyUqAHerQbj5hLja7NQ4n +lv1mNDthcnPxFlxHBlRJAHpYErAK74X9sbgzdWqTHBLmYF5vHX/JHyPLhGGfHoJE ++V+tYlUkmlKY7VHnoX6XOuYvHxHaU4AshZ6rNRDbIl9qxV6XU/IyAgkwo1jwDQHV +csaxfGl7w/U2Rcxhbl5MlMVerugOXou/983g7aEOGzPuVBj+D77vfoRrQ+NwmNtd +dbINWQeFFSM51vHfqSYP1kjHs6Yi9TM3WpVHn3u6GBVv/9YUZINJ0gpnIdsPNWNg +KCLjsZWDzYWm3S8P52dSbrsvhXz1SnPnxT7AvSESBT/8twNJAlvIJebiVDj1eYeM +HVOyToV7BjjHLPj4sHKNJeV3UvQDHEimUF+IIDBu8oJDqz2XhOdT+yHBTw8imoa4 +WSr2Rz0ZiC3oheGe7IUIarFsNMkd7EgrO3jtZsSOeWmD3n+M +-----END CERTIFICATE-----'" +"QuoVadis","QuoVadis Limited","","QuoVadis Root CA 3","05C6","18F1FC7F205DF8ADDDEB7FE007DD57E3AF375A9C4D8D73546BF4F1FED1E18D35","E55B359CC1370DBBFEE0017590B6E4CBCC41E9C313D0DA7EF29CC0C5CBBCC9F3","2006.11.24","2031.11.24","RSA 4096 bits","SHA1WithRSA","Websites;Email","","","Not EV","https://bugzilla.mozilla.org/show_bug.cgi?id=365281","NSS 3.11.8","Firefox 2","https://qvsslrca3-ssl-v.quovadisglobal.com","https://qvsslrca3-ssl-e.quovadisglobal.com","https://qvsslrca3-ssl-r.quovadisglobal.com","","http://www.quovadisglobal.com","Bermuda, Global","https://www.quovadisglobal.com/wp-content/uploads/2020/03/QV_RCA2_CPCPS_v2.8.pdf","https://www.quovadisglobal.com/wp-content/uploads/2020/03/QV_RCA1_RCA3_CPCPS_V4_29.pdf","https://www.cpacanada.ca/generichandlers/CPACHandler.ashx?attachmentid=239021","https://www.cpacanada.ca/generichandlers/CPACHandler.ashx?attachmentid=239022","","Ernst & Young, LLP","WebTrust","2020.03.31","'-----BEGIN CERTIFICATE----- +MIIGnTCCBIWgAwIBAgICBcYwDQYJKoZIhvcNAQEFBQAwRTELMAkGA1UEBhMCQk0x +GTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxGzAZBgNVBAMTElF1b1ZhZGlzIFJv +b3QgQ0EgMzAeFw0wNjExMjQxOTExMjNaFw0zMTExMjQxOTA2NDRaMEUxCzAJBgNV +BAYTAkJNMRkwFwYDVQQKExBRdW9WYWRpcyBMaW1pdGVkMRswGQYDVQQDExJRdW9W +YWRpcyBSb290IENBIDMwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDM +V0IWVJzmmNPTTe7+7cefQzlKZbPoFog02w1ZkXTPkrgEQK0CSzGrvI2RaNggDhoB +4hp7Thdd4oq3P5kazethq8Jlph+3t723j/z9cI8LoGe+AaJZz3HmDyl2/7FWeUUr +H556VOijKTVopAFPD6QuN+8bv+OPEKhyq1hX51SGyMnzW9os2l2ObjyjPtr7guXd +8lyyBTNvijbO0BNO/79KDDRMpsMhvVAEVeuxu537RR5kFd5VAYwCdrXLoT9Cabwv +vWhDFlaJKjdhkf2mrk7AyxRllDdLkgbvBNDInIjbC3uBr7E9KsRlOni27tyAsdLT +mZw67mtaa7ONt9XOnMK+pUsvFrGeaDsGb659n/je7Mwpp5ijJUMv7/FfJuGITfhe +btfZFG4ZM2mnO4SJk8RTVROhUXhA+LjJou57ulJCg54U7QVSWllWp5f8nT8KKdjc +T5EOE7zelaTfi5m+rJsziO+1ga8bxiJTyPbH7pcUsMV8eFLI8M5ud2CEpukqdiDt +WAEXMJPpGovgc2PZapKUSU60rUqFxKMiMPwJ7Wgic6aIDFUhWMXhOp8q3crhkODZ +c6tsgLjoC2SToJyMGf+z0gzskSaHirOi4XCPLArlzW1oUevaPwV/izLmE1xr/l9A +4iLItLRkT9a6fUg+qGkM17uGcclzuD87nSVL2v9A6wIDAQABo4IBlTCCAZEwDwYD +VR0TAQH/BAUwAwEB/zCB4QYDVR0gBIHZMIHWMIHTBgkrBgEEAb5YAAMwgcUwgZMG +CCsGAQUFBwICMIGGGoGDQW55IHVzZSBvZiB0aGlzIENlcnRpZmljYXRlIGNvbnN0 +aXR1dGVzIGFjY2VwdGFuY2Ugb2YgdGhlIFF1b1ZhZGlzIFJvb3QgQ0EgMyBDZXJ0 +aWZpY2F0ZSBQb2xpY3kgLyBDZXJ0aWZpY2F0aW9uIFByYWN0aWNlIFN0YXRlbWVu +dC4wLQYIKwYBBQUHAgEWIWh0dHA6Ly93d3cucXVvdmFkaXNnbG9iYWwuY29tL2Nw +czALBgNVHQ8EBAMCAQYwHQYDVR0OBBYEFPLAE+CCQz777i9nMpY1XNu4ywLQMG4G +A1UdIwRnMGWAFPLAE+CCQz777i9nMpY1XNu4ywLQoUmkRzBFMQswCQYDVQQGEwJC +TTEZMBcGA1UEChMQUXVvVmFkaXMgTGltaXRlZDEbMBkGA1UEAxMSUXVvVmFkaXMg +Um9vdCBDQSAzggIFxjANBgkqhkiG9w0BAQUFAAOCAgEAT62gLEz6wPJv92ZVqyM0 +7ucp2sNbtrCD2dDQ4iH782CnO11gUyeim/YIIirnv6By5ZwkajGxkHon24QRiSem +d1o417+shvzuXYO8BsbRd2sPbSQvS3pspweWyuOEn62Iix2rFo1bZhfZFvSLgNLd ++LJ2w/w4E6oM3kJpK27zPOuAJ9v1pkQNn1pVWQvVDVJIxa6f8i+AxeoyUDUSly7B +4f/xI4hROJ/yZlZ25w9Rl6VSDE1JUZU2Pb+iSwwQHYaZTKrzchGT5Or2m9qoXadN +t54CrnMAyNojA+j56hl0YgCUyyIgvpSnWbWCar6ZeXqp8kokUvd0/bpO5qgdAm6x +DYBEwa7TIzdfu4V8K5Iu6H6li92Z4b8nby1dqnuH/grdS/yO9SbkbnBCbjPsMZ57 +k8HkyWkaPcBrTiJt7qtYTcbQQcEr6k8Sh17rRdhs9ZgC06DYVYoGmRmioHfRMJ6s +zHXug/WwYjnPbFfiTNKRCw51KBuav/0aQ/HKd/s7j2G4aSgWQgRecCocIdiP4b0j +Wy10QJLZYxkNc91pvGJHvOB0K7Lrfb5BG7XARsWhIstfTsEokt4YutUqKLsRixeT +mJlglFwjz1onl14LBQaTNx47aTbrqZ5hHY8y2o4M1nQ+ewkk2gF3R8Q7zTSMmfXK +4SVhM7JZG+Ju1zdXtg2pEto= +-----END CERTIFICATE-----'" +"QuoVadis","QuoVadis Limited","","QuoVadis Root CA 3 G3","2EF59B0228A7DB7AFFD5A3A9EEBD03A0CF126A1D","88EF81DE202EB018452E43F864725CEA5FBD1FC2D9D205730709C5D8B8690F46","053274EB4FE13F809374AF7879284A03678F4042E6E94D254E2F6D4A748E1B04","2012.01.12","2042.01.12","RSA 4096 bits","SHA256WithRSA","Websites;Email","","","Not EV","https://bugzilla.mozilla.org/show_bug.cgi?id=926541","NSS 3.16.3","Firefox 32","https://qvsslrca3g3-ssl-v.quovadisglobal.com","https://qvsslrca3g3-ssl-e.quovadisglobal.com","https://qvsslrca3g3-ssl-r.quovadisglobal.com","","http://www.quovadisglobal.com","Bermuda, Global","https://www.quovadisglobal.com/wp-content/uploads/2020/03/QV_RCA2_CPCPS_v2.8.pdf","https://www.quovadisglobal.com/wp-content/uploads/2020/03/QV_RCA1_RCA3_CPCPS_V4_29.pdf","https://www.cpacanada.ca/generichandlers/CPACHandler.ashx?attachmentid=239021","https://www.cpacanada.ca/generichandlers/CPACHandler.ashx?attachmentid=239022","","Ernst & Young, LLP","WebTrust","2020.03.31","'-----BEGIN CERTIFICATE----- +MIIFYDCCA0igAwIBAgIULvWbAiin23r/1aOp7r0DoM8Sah0wDQYJKoZIhvcNAQEL +BQAwSDELMAkGA1UEBhMCQk0xGTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxHjAc +BgNVBAMTFVF1b1ZhZGlzIFJvb3QgQ0EgMyBHMzAeFw0xMjAxMTIyMDI2MzJaFw00 +MjAxMTIyMDI2MzJaMEgxCzAJBgNVBAYTAkJNMRkwFwYDVQQKExBRdW9WYWRpcyBM +aW1pdGVkMR4wHAYDVQQDExVRdW9WYWRpcyBSb290IENBIDMgRzMwggIiMA0GCSqG +SIb3DQEBAQUAA4ICDwAwggIKAoICAQCzyw4QZ47qFJenMioKVjZ/aEzHs286IxSR +/xl/pcqs7rN2nXrpixurazHb+gtTTK/FpRp5PIpM/6zfJd5O2YIyC0TeytuMrKNu +FoM7pmRLMon7FhY4futD4tN0SsJiCnMK3UmzV9KwCoWdcTzeo8vAMvMBOSBDGzXR +U7Ox7sWTaYI+FrUoRqHe6okJ7UO4BUaKhvVZR74bbwEhELn9qdIoyhA5CcoTNs+c +ra1AdHkrAj80//ogaX3T7mH1urPnMNA3I4ZyYUUpSFlob3emLoG+B01vr87ERROR +FHAGjx+f+IdpsQ7vw4kZ6+ocYfx6bIrc1gMLnia6Et3UVDmrJqMz6nWB2i3ND0/k +A9HvFZcba5DFApCTZgIhsUfei5pKgLlVj7WiL8DWM2fafsSntARE60f75li59wzw +eyuxwHApw0BiLTtIadwjPEjrewl5qW3aqDCYz4ByA4imW0aucnl8CAMhZa634Ryl +sSqiMd5mBPfAdOhx3v89WcyWJhKLhZVXGqtrdQtEPREoPHtht+KPZ0/l7DxMYIBp +VzgeAVuNVejH38DMdyM0SXV89pgR6y3e7UEuFAUCf+D+IOs15xGsIs5XPd7JMG0Q +A4XN8f+MFrXBsj6IbGB/kE+V9/YtrQE5BwT6dYB9v0lQ7e/JxHwc64B+27bQ3RP+ +ydOc17KXqQIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIB +BjAdBgNVHQ4EFgQUxhfQvKjqAkPyGwaZXSuQILnXnOQwDQYJKoZIhvcNAQELBQAD +ggIBADRh2Va1EodVTd2jNTFGu6QHcrxfYWLopfsLN7E8trP6KZ1/AvWkyaiTt3px +KGmPc+FSkNrVvjrlt3ZqVoAh313m6Tqe5T72omnHKgqwGEfcIHB9UqM+WXzBusnI +FUBhynLWcKzSt/Ac5IYp8M7vaGPQtSCKFWGafoaYtMnCdvvMujAWzKNhxnQT5Wvv +oxXqA/4Ti2Tk08HS6IT7SdEQTXlm66r99I0xHnAUrdzeZxNMgRVhvLfZkXdxGYFg +u/BYpbWcC/ePIlUnwEsBbTuZDdQdm2NnL9DuDcpmvJRPpq3t/O5jrFc/ZSXPsoaP +0Aj/uHYUbt7lJ+yreLVTubY/6CD50qi+YUbKh4yE8/nxoGibIh6BJpsQBJFxwAYf +3KDTuVan45gtf4Od34wrnDKOMpTwATwiKp9Dwi7DmDkHOHv8XgBCH/MyJnmDhPbl +8MFREsALHgQjDFSlTC9JxUrRtm5gDWv8a4uFJGS3iQ6rJUdbPM9+Sb3H6QrG2vd+ +DhcI00iX0HGS8A85PjRqHH3Y8iKuu2n0M7SmSFXRDw4m6Oy2Cy2nhTXN/VnIn9HN +PlopNLk9hM6xZdRZkZFWdSHBd575euFgndOtBBj0fOtek49TSiIp+EgrPk2GrFt/ +ywaZWWDYWGWVjUTR939+J399roD1B0y2PpxxVJkES/1Y+Zj0 +-----END CERTIFICATE-----'" +"QuoVadis","QuoVadis Limited","Root Certification Authority","QuoVadis Root Certification Authority","3AB6508B","A45EDE3BBBF09C8AE15C72EFC07268D693A21C996FD51E67CA079460FD6D8873","0BF1DADC2186727D782B630CE0AAEE79A716F54EC1261524A44E27EE2BE8DC14","2001.03.19","2021.03.17","RSA 2048 bits","SHA1WithRSA","Websites;Email","","","Not EV","https://bugzilla.mozilla.org/show_bug.cgi?id=238381","NSS 3.9.6","Firefox 1","https://qvsslrca-ssl-v.quovadisglobal.com","https://qvsslrca-ssl-e.quovadisglobal.com","https://qvsslrca-ssl-r.quovadisglobal.com","","http://www.quovadisglobal.com","Bermuda, Global","https://www.quovadisglobal.com/wp-content/uploads/2020/03/QV_RCA2_CPCPS_v2.8.pdf","https://www.quovadisglobal.com/wp-content/uploads/2020/03/QV_RCA1_RCA3_CPCPS_V4_29.pdf","https://www.cpacanada.ca/generichandlers/CPACHandler.ashx?attachmentid=239021","https://www.cpacanada.ca/generichandlers/CPACHandler.ashx?attachmentid=239022","","Ernst & Young, LLP","WebTrust","2020.03.31","'-----BEGIN CERTIFICATE----- +MIIF0DCCBLigAwIBAgIEOrZQizANBgkqhkiG9w0BAQUFADB/MQswCQYDVQQGEwJC +TTEZMBcGA1UEChMQUXVvVmFkaXMgTGltaXRlZDElMCMGA1UECxMcUm9vdCBDZXJ0 +aWZpY2F0aW9uIEF1dGhvcml0eTEuMCwGA1UEAxMlUXVvVmFkaXMgUm9vdCBDZXJ0 +aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0wMTAzMTkxODMzMzNaFw0yMTAzMTcxODMz +MzNaMH8xCzAJBgNVBAYTAkJNMRkwFwYDVQQKExBRdW9WYWRpcyBMaW1pdGVkMSUw +IwYDVQQLExxSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MS4wLAYDVQQDEyVR +dW9WYWRpcyBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIIBIjANBgkqhkiG +9w0BAQEFAAOCAQ8AMIIBCgKCAQEAv2G1lVO6V/z68mcLOhrfEYBklbTRvM16z/Yp +li4kVEAkOPcahdxYTMukJ0KX0J+DisPkBgNbAKVRHnAEdOLB1Dqr1607BxgFjv2D +rOpm2RgbaIr1VxqYuvXtdj182d6UajtLF8HVj71lODqV0D1VNk7feVcxKh7YWWVJ +WCCYfqtffp/p1k3sg3Spx2zY7ilKhSoGFPlU5tPaZQeLYzcS19Dsw3sgQUSj7cug +F+FxZc4dZjH3dgEZyH0DWLaVSR2mEiboxgx24ONmy+pdpibu5cxfvWenAScOospU +xbF6lR1xHkopigPcakXBpBlebzbNw6Kwt/5cOOJSvPhEQ+aQuwIDAQABo4ICUjCC +Ak4wPQYIKwYBBQUHAQEEMTAvMC0GCCsGAQUFBzABhiFodHRwczovL29jc3AucXVv +dmFkaXNvZmZzaG9yZS5jb20wDwYDVR0TAQH/BAUwAwEB/zCCARoGA1UdIASCAREw +ggENMIIBCQYJKwYBBAG+WAABMIH7MIHUBggrBgEFBQcCAjCBxxqBxFJlbGlhbmNl +IG9uIHRoZSBRdW9WYWRpcyBSb290IENlcnRpZmljYXRlIGJ5IGFueSBwYXJ0eSBh +c3N1bWVzIGFjY2VwdGFuY2Ugb2YgdGhlIHRoZW4gYXBwbGljYWJsZSBzdGFuZGFy +ZCB0ZXJtcyBhbmQgY29uZGl0aW9ucyBvZiB1c2UsIGNlcnRpZmljYXRpb24gcHJh +Y3RpY2VzLCBhbmQgdGhlIFF1b1ZhZGlzIENlcnRpZmljYXRlIFBvbGljeS4wIgYI +KwYBBQUHAgEWFmh0dHA6Ly93d3cucXVvdmFkaXMuYm0wHQYDVR0OBBYEFItLbe3T +KbkGGew5Oanwl4Rqy+/fMIGuBgNVHSMEgaYwgaOAFItLbe3TKbkGGew5Oanwl4Rq +y+/foYGEpIGBMH8xCzAJBgNVBAYTAkJNMRkwFwYDVQQKExBRdW9WYWRpcyBMaW1p +dGVkMSUwIwYDVQQLExxSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MS4wLAYD +VQQDEyVRdW9WYWRpcyBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5ggQ6tlCL +MA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQUFAAOCAQEAitQUtf70mpKnGdSk +fnIYj9lofFIk3WdvOXrEql494liwTXCYhGHoG+NpGA7O+0dQoE7/8CQfvbLO9Sf8 +7C9TqnN7Az10buYWnuulLsS/VidQK2K6vkscPFVcQR0kvoIgR13VRH56FmjffU1R +cHhXHTMe/QKZnAzNCgVPx7uOpHX6Sm2xgI4JVrmcGmD+XcHXetwReNDWXcG31a0y +mQM6isxUJTkxgXsTIlG6Rmyhu576BGxJJnSP0nPrzDCi5upZIof4l/UO/erMkqQW +xFIY6iHOsfHmhIHluqmGKPJDWl0Snawe2ajlCmqnf6CHKc/yiU3U7MXi5nrQNiOK +SnQ2+Q== +-----END CERTIFICATE-----'" +"SECOM Trust Systems CO., LTD.","SECOM Trust.net","Security Communication RootCA1","SECOM Trust.net - Security Communication RootCA1","00","E75E72ED9F560EEC6EB4800073A43FC3AD19195A392282017895974A99026B6C","8E2707510EF1957F0E67838AC4EC0BD20D1D8320164BFF44F16D60DCAA789B00","2003.09.30","2023.09.30","RSA 2048 bits","SHA1WithRSA","Websites;Email","","","Not EV","https://bugzilla.mozilla.org/show_bug.cgi?id=260259","NSS 3.9.5","Firefox 1","https://pfwtest.secomtrust.net/","https://xev2e.secomtrust.net/","https://xev2r.secomtrust.net/","","http://www.secomtrust.net/","Japan","https://repository.secomtrust.net/SC-Root/SCRootCP1-EN.pdf","https://repository.secomtrust.net/SC-Root/SCRootCPS-EN.pdf","https://www.cpacanada.ca/generichandlers/CPACHandler.ashx?attachmentid=234693","https://www.cpacanada.ca/generichandlers/CPACHandler.ashx?attachmentid=234694","https://www.cpacanada.ca/generichandlers/CPACHandler.ashx?attachmentid=234695","KPMG","WebTrust","2019.08.29","'-----BEGIN CERTIFICATE----- +MIIDWjCCAkKgAwIBAgIBADANBgkqhkiG9w0BAQUFADBQMQswCQYDVQQGEwJKUDEY +MBYGA1UEChMPU0VDT00gVHJ1c3QubmV0MScwJQYDVQQLEx5TZWN1cml0eSBDb21t +dW5pY2F0aW9uIFJvb3RDQTEwHhcNMDMwOTMwMDQyMDQ5WhcNMjMwOTMwMDQyMDQ5 +WjBQMQswCQYDVQQGEwJKUDEYMBYGA1UEChMPU0VDT00gVHJ1c3QubmV0MScwJQYD +VQQLEx5TZWN1cml0eSBDb21tdW5pY2F0aW9uIFJvb3RDQTEwggEiMA0GCSqGSIb3 +DQEBAQUAA4IBDwAwggEKAoIBAQCzs/5/022x7xZ8V6UMbXaKL0u/ZPtM7orw8yl8 +9f/uKuDp6bpbZCKamm8sOiZpUQWZJtzVHGpxxpp9Hp3dfGzGjGdnSj74cbAZJ6kJ +DKaVv0uMDPpVmDvY6CKhS3E4eayXkmmziX7qIWgGmBSWh9JhNrxtJ1aeV+7AwFb9 +Ms+k2Y7CI9eNqPPYJayX5HA49LY6tJ07lyZDo6G8SVlyTCMwhwFY9k6+HGhWZq/N +QV3Is00qVUarH9oe4kA92819uZKAnDfdDJZkndwi92SL32HeFZRSFaB9UslLqCHJ +xrHty8OVYNEP8Ktw+N/LTX7s1vqr2b1/VPKl6Xn62dZ2JChzAgMBAAGjPzA9MB0G +A1UdDgQWBBSgc0mZaNyFW2XjmygvV5+9M7wHSDALBgNVHQ8EBAMCAQYwDwYDVR0T +AQH/BAUwAwEB/zANBgkqhkiG9w0BAQUFAAOCAQEAaECpqLvkT115swW1F7NgE+vG +kl3g0dNq/vu+m22/xwVtWSDEHPC32oRYAmP6SBbvT6UL90qY8j+eG61Ha2POCEfr +Uj94nK9NrvjVT8+amCoQQTlSxN3Zmw7vkwGusi7KaEIkQmywszo+zenaSMQVy+n5 +Bw+SUEmK3TGXX8npN6o7WWWXlDLJs58+OmJYxUmtYg5xpTKqL8aJdkNAExNnPaJU +JRDL8Try2frbSVa7pv6nQTXD4IhhyYjH3zYQIphZ6rBK+1YWc26sTfcioU+tHXot +RSflMMFe8toTyyVCUZVHA4xsIcx0Qu1T/zOLjw9XARYvz6buyXAiFL39vmwLAw== +-----END CERTIFICATE-----'" +"SECOM Trust Systems CO., LTD.","SECOM Trust Systems CO.,LTD.","Security Communication RootCA2","Security Communication RootCA2","00","513B2CECB810D4CDE5DD85391ADFC6C2DD60D87BB736D2B521484AA47A0EBEF6","DC3155F3F25CC4EAF8D8E8DACBD3E1CC224E00D4CCB304DE9EF8BA3595AE7183","2009.05.29","2029.05.29","RSA 2048 bits","SHA256WithRSA","Websites;Email","","","1.2.392.200091.100.721.1","https://bugzilla.mozilla.org/show_bug.cgi?id=1096205","NSS 3.13.2","Firefox 11","https://ev2v.secomtrust.net/","https://ev2e.secomtrust.net/","https://ev2r.secomtrust.net/","None","http://www.secomtrust.net/","Japan","https://repository.secomtrust.net/SC-Root/SCRootCP1-EN.pdf","https://repository.secomtrust.net/SC-Root/SCRootCPS-EN.pdf","https://www.cpacanada.ca/generichandlers/CPACHandler.ashx?attachmentid=234693","https://www.cpacanada.ca/generichandlers/CPACHandler.ashx?attachmentid=234694","https://www.cpacanada.ca/generichandlers/CPACHandler.ashx?attachmentid=234695","KPMG","WebTrust","2019.08.29","'-----BEGIN CERTIFICATE----- +MIIDdzCCAl+gAwIBAgIBADANBgkqhkiG9w0BAQsFADBdMQswCQYDVQQGEwJKUDEl +MCMGA1UEChMcU0VDT00gVHJ1c3QgU3lzdGVtcyBDTy4sTFRELjEnMCUGA1UECxMe +U2VjdXJpdHkgQ29tbXVuaWNhdGlvbiBSb290Q0EyMB4XDTA5MDUyOTA1MDAzOVoX +DTI5MDUyOTA1MDAzOVowXTELMAkGA1UEBhMCSlAxJTAjBgNVBAoTHFNFQ09NIFRy +dXN0IFN5c3RlbXMgQ08uLExURC4xJzAlBgNVBAsTHlNlY3VyaXR5IENvbW11bmlj +YXRpb24gUm9vdENBMjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANAV +OVKxUrO6xVmCxF1SrjpDZYBLx/KWvNs2l9amZIyoXvDjChz335c9S672XewhtUGr +zbl+dp+++T42NKA7wfYxEUV0kz1XgMX5iZnK5atq1LXaQZAQwdbWQonCv/Q4EpVM +VAX3NuRFg3sUZdbcDE3R3n4MqzvEFb46VqZab3ZpUql6ucjrappdUtAtCms1FgkQ +hNBqyjoGADdH5H5XTz+L62e4iKrFvlNVspHEfbmwhRkGeC7bYRr6hfVKkaHnFtWO +ojnflLhwHyg/i/xAXmODPIMqGplrz95Zajv8bxbXH/1KEOtOghY6rCcMU/Gt1SSw +awNQwS08Ft1ENCcadfsCAwEAAaNCMEAwHQYDVR0OBBYEFAqFqXdlBZh8QIH4D5cs +OPEK7DzPMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3 +DQEBCwUAA4IBAQBMOqNErLlFsceTfsgLCkLfZOoc7llsCLqJX2rKSpWeeo8HxdpF +coJxDjrSzG+ntKEju/Ykn8sX/oymzsLS28yN/HH8AynBbF0zX2S2ZTuJbxh2ePXc +okgfGT+Ok+vx+hfuzU7jBBJV1uXk3fs+BXziHV7Gp7yXT2g69ekuCkO2r1dcYmh8 +t/2jioSgrGK+KwmHNPBqAbubKVY8/gA3zyNs8U6qtnRGEmyR7jTV7JqR50S+kDFy +1UkC9gLl9B/rfNmWVan/7Ir5mUf/NVoCqgTLiluHcSmRvaS0eg29mvVXIwAHIRc/ +SjnRBUkLp7Y3gaVdjKozXoEofKd9J+sAro03 +-----END CERTIFICATE-----'" +"Sectigo","Comodo CA Limited","","AAA Certificate Services","01","D7A7A0FB5D7E2731D771E9484EBCDEF71D5F0C3E0A2948782BC83EE0EA699EF4","4216F920B2A81EC8F89BCCD93195B5CC05A6A121E269310BFF0A37722F13C553","2004.01.01","2028.12.31","RSA 2048 bits","SHA1WithRSA","Websites;Email","","","Not EV","https://bugzilla.mozilla.org/show_bug.cgi?id=249710","","Firefox 1","https://aaacertificateservices.comodoca.com/","https://aaacertificateservices.comodoca.com:442/","https://aaacertificateservices.comodoca.com:444/","","https://sectigo.com/","USA, UK, Global","https://sectigo.com/uploads/files/WebPKI-COP-v1.0.pdf","https://sectigo.com/uploads/files/Sectigo-CPS-v5.1.2.pdf","https://bug1472993.bmoattachments.org/attachment.cgi?id=9078178","https://www.cpacanada.ca/generichandlers/CPACHandler.ashx?attachmentid=231163","https://www.cpacanada.ca/generichandlers/CPACHandler.ashx?attachmentid=231164","Ernst & Young, LLP","WebTrust","2019.06.27","'-----BEGIN CERTIFICATE----- +MIIEMjCCAxqgAwIBAgIBATANBgkqhkiG9w0BAQUFADB7MQswCQYDVQQGEwJHQjEb +MBkGA1UECAwSR3JlYXRlciBNYW5jaGVzdGVyMRAwDgYDVQQHDAdTYWxmb3JkMRow +GAYDVQQKDBFDb21vZG8gQ0EgTGltaXRlZDEhMB8GA1UEAwwYQUFBIENlcnRpZmlj +YXRlIFNlcnZpY2VzMB4XDTA0MDEwMTAwMDAwMFoXDTI4MTIzMTIzNTk1OVowezEL +MAkGA1UEBhMCR0IxGzAZBgNVBAgMEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UE +BwwHU2FsZm9yZDEaMBgGA1UECgwRQ29tb2RvIENBIExpbWl0ZWQxITAfBgNVBAMM +GEFBQSBDZXJ0aWZpY2F0ZSBTZXJ2aWNlczCCASIwDQYJKoZIhvcNAQEBBQADggEP +ADCCAQoCggEBAL5AnfRu4ep2hxxNRUSOvkbIgwadwSr+GB+O5AL686tdUIoWMQua +BtDFcCLNSS1UY8y2bmhGC1Pqy0wkwLxyTurxFa70VJoSCsN6sjNg4tqJVfMiWPPe +3M/vg4aijJRPn2jymJBGhCfHdr/jzDUsi14HZGWCwEiwqJH5YZ92IFCokcdmtet4 +YgNW8IoaE+oxox6gmf049vYnMlhvB/VruPsUK6+3qszWY19zjNoFmag4qMsXeDZR +rOme9Hg6jc8P2ULimAyrL58OAd7vn5lJ8S3frHRNG5i1R8XlKdH5kBjHYpy+g8cm +ez6KJcfA3Z3mNWgQIJ2P2N7Sw4ScDV7oL8kCAwEAAaOBwDCBvTAdBgNVHQ4EFgQU +oBEKIz6W8Qfs4q8p74Klf9AwpLQwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQF +MAMBAf8wewYDVR0fBHQwcjA4oDagNIYyaHR0cDovL2NybC5jb21vZG9jYS5jb20v +QUFBQ2VydGlmaWNhdGVTZXJ2aWNlcy5jcmwwNqA0oDKGMGh0dHA6Ly9jcmwuY29t +b2RvLm5ldC9BQUFDZXJ0aWZpY2F0ZVNlcnZpY2VzLmNybDANBgkqhkiG9w0BAQUF +AAOCAQEACFb8AvCb6P+k+tZ7xkSAzk/ExfYAWMymtrwUSWgEdujm7l3sAg9g1o1Q +GE8mTgHj5rCl7r+8dFRBv/38ErjHT1r0iWAFf2C3BUrz9vHCv8S5dIa2LX1rzNLz +Rt0vxuBqw8M0Ayx9lt1awg6nCpnBBYurDC/zXDrPbDdVCYfeU0BsWO/8tqtlbgT2 +G9w84FoVxp7Z8VlIMCFlA2zs6SFz7JsDoeA3raAVGI/6ugLOpyypEBMs1OUIJqsi +l2D4kF501KKaU73yqWjgom7C12yxow+ev+to51byrvLjKzg6CYG1a4XXvi3tPxq3 +smPi9WIsgtRqAEFQ8TmDn5XpNpaYbg== +-----END CERTIFICATE-----'" +"Sectigo","COMODO CA Limited","","COMODO Certification Authority","4E812D8A8265E00B02EE3E350246E53D","0C2CD63DF7806FA399EDE809116B575BF87989F06518F9808C860503178BAF66","54BAEAD2D52D6D8AD6B2A2F4A037C8F383C91C4930D6B2AE7F8ACC381EE1DA18","2006.12.01","2029.12.31","RSA 2048 bits","SHA1WithRSA","Websites;Email","","","1.3.6.1.4.1.6449.1.2.1.5.1","https://bugzilla.mozilla.org/show_bug.cgi?id=401587","NSS 3.11.10","Firefox 3.0.2","https://comodocertificationauthority-ev.comodoca.com/","https://comodocertificationauthority-ev.comodoca.com:442/","https://comodocertificationauthority-ev.comodoca.com:444/","","https://sectigo.com/","USA, UK, Global","https://sectigo.com/uploads/files/WebPKI-COP-v1.0.pdf","https://sectigo.com/uploads/files/Sectigo-CPS-v5.1.2.pdf","https://bug1472993.bmoattachments.org/attachment.cgi?id=9078178","https://www.cpacanada.ca/generichandlers/CPACHandler.ashx?attachmentid=231163","https://www.cpacanada.ca/generichandlers/CPACHandler.ashx?attachmentid=231164","Ernst & Young, LLP","WebTrust","2019.06.27","'-----BEGIN CERTIFICATE----- +MIIEHTCCAwWgAwIBAgIQToEtioJl4AsC7j41AkblPTANBgkqhkiG9w0BAQUFADCB +gTELMAkGA1UEBhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4G +A1UEBxMHU2FsZm9yZDEaMBgGA1UEChMRQ09NT0RPIENBIExpbWl0ZWQxJzAlBgNV +BAMTHkNPTU9ETyBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0wNjEyMDEwMDAw +MDBaFw0yOTEyMzEyMzU5NTlaMIGBMQswCQYDVQQGEwJHQjEbMBkGA1UECBMSR3Jl +YXRlciBNYW5jaGVzdGVyMRAwDgYDVQQHEwdTYWxmb3JkMRowGAYDVQQKExFDT01P +RE8gQ0EgTGltaXRlZDEnMCUGA1UEAxMeQ09NT0RPIENlcnRpZmljYXRpb24gQXV0 +aG9yaXR5MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA0ECLi3LjkRv3 +UcEbVASY06m/weaKXTuH+7uIzg3jLz8GlvCiKVCZrts7oVewdFFxze1CkU1B/qnI +2GqGd0S7WWaXUF601CxwRM/aN5VCaTwwxHGzUvAhTaHYujl8HJ6jJJ3ygxaYqhZ8 +Q5sVW7euNJH+1GImGEaaP+vB+fGQV+useg2L23IwambV4EajcNxo2f8ESIl33rXp ++2dtQem8Ob0y2WIC8bGoPW43nOIv4tOiJovGuFVDiOEjPqXSJDlqR6sA1KGzqSX+ +DT+nHbrTUcELpNqsOO9VUCQFZUaTNE8tja3G1CEZ0o7KBWFxB3NH5YoZEr0ETc5O +nKVIrLsm9wIDAQABo4GOMIGLMB0GA1UdDgQWBBQLWOWLxkwVN6RAqTCpIb5HNlpW +/zAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zBJBgNVHR8EQjBAMD6g +PKA6hjhodHRwOi8vY3JsLmNvbW9kb2NhLmNvbS9DT01PRE9DZXJ0aWZpY2F0aW9u +QXV0aG9yaXR5LmNybDANBgkqhkiG9w0BAQUFAAOCAQEAPpiem/Yb6dc5t3iuHXIY +SdOH5EOC6z/JqvWote9VfCFSZfnVDeFs9D6Mk3ORLgLETgdxb8CPOGEIqB6BCsAv +IC9Bi5HcSEW88cbeunZrM8gALTFGTO3nnc+IlP8zwFboJIYmuNg4ON8qa90SzMc/ +RxdMosIGlgnW2/4/PEZB31jiVg88O8EckzXZOFKs7sjsLjBOlDW0JB9LeGna8gI4 +zJVSk/BwJVmcIGfE7vmLV2H0knZ9P4SNVbfo5azV8fUZVqZa+5Acr5Pr5RzUZ5dd +BA6+C4OmF4O5MBKgxTMVBbkN+8cFduPYSo38NBejxiEovjBFMR7HeL5YYTisO+IB +ZQ== +-----END CERTIFICATE-----'" +"Sectigo","COMODO CA Limited","","COMODO ECC Certification Authority","1F47AFAA62007050544C019E9B63992A","1793927A0614549789ADCE2F8F34F7F0B66D0F3AE3A3B84D21EC15DBBA4FADC7","96018C01276E7AB9236A6409175A7FB894B397580F0E86235D795818BFEC6C88","2008.03.06","2038.01.18","EC secp384r1","ecdsaWithSHA384","Websites;Email","","","1.3.6.1.4.1.6449.1.2.1.5.1","https://bugzilla.mozilla.org/show_bug.cgi?id=421946","NSS 3.12.1","Firefox 3.0.2","https://comodoecccertificationauthority-ev.comodoca.com/","https://comodoecccertificationauthority-ev.comodoca.com:442/","https://comodoecccertificationauthority-ev.comodoca.com:444/","","https://sectigo.com/","USA, UK, Global","https://sectigo.com/uploads/files/WebPKI-COP-v1.0.pdf","https://sectigo.com/uploads/files/Sectigo-CPS-v5.1.2.pdf","https://bug1472993.bmoattachments.org/attachment.cgi?id=9078178","https://www.cpacanada.ca/generichandlers/CPACHandler.ashx?attachmentid=231163","https://www.cpacanada.ca/generichandlers/CPACHandler.ashx?attachmentid=231164","Ernst & Young, LLP","WebTrust","2019.06.27","'-----BEGIN CERTIFICATE----- +MIICiTCCAg+gAwIBAgIQH0evqmIAcFBUTAGem2OZKjAKBggqhkjOPQQDAzCBhTEL +MAkGA1UEBhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UE +BxMHU2FsZm9yZDEaMBgGA1UEChMRQ09NT0RPIENBIExpbWl0ZWQxKzApBgNVBAMT +IkNPTU9ETyBFQ0MgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMDgwMzA2MDAw +MDAwWhcNMzgwMTE4MjM1OTU5WjCBhTELMAkGA1UEBhMCR0IxGzAZBgNVBAgTEkdy +ZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UEBxMHU2FsZm9yZDEaMBgGA1UEChMRQ09N +T0RPIENBIExpbWl0ZWQxKzApBgNVBAMTIkNPTU9ETyBFQ0MgQ2VydGlmaWNhdGlv +biBBdXRob3JpdHkwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAAQDR3svdcmCFYX7deSR +FtSrYpn1PlILBs5BAH+X4QokPB0BBO490o0JlwzgdeT6+3eKKvUDYEs2ixYjFq0J +cfRK9ChQtP6IHG4/bC8vCVlbpVsLM5niwz2J+Wos77LTBumjQjBAMB0GA1UdDgQW +BBR1cacZSBm8nZ3qQUfflMRId5nTeTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/ +BAUwAwEB/zAKBggqhkjOPQQDAwNoADBlAjEA7wNbeqy3eApyt4jf/7VGFAkK+qDm +fQjGGoe9GKhzvSbKYAydzpmfz1wPMOG+FDHqAjAU9JM8SaczepBGR7NjfRObTrdv +GDeAU/7dIOA1mjbRxwG55tzd8/8dLDoWV9mSOdY= +-----END CERTIFICATE-----'" +"Sectigo","COMODO CA Limited","","COMODO RSA Certification Authority","4CAAF9CADB636FE01FF74ED85B03869D","52F0E1C4E58EC629291B60317F074671B85D7EA80D5B07273463534B32B40234","27F1002A447C5BA03C4EB9053FD514E8EB88E5873415ABC4D66DF060634DFD57","2010.01.19","2038.01.18","RSA 4096 bits","SHA384WithRSA","Websites;Email","","","1.3.6.1.4.1.6449.1.2.1.5.1","https://bugzilla.mozilla.org/show_bug.cgi?id=606947","NSS 3.17.3","Firefox 36","https://comodorsacertificationauthority-ev.comodoca.com/","https://comodorsacertificationauthority-ev.comodoca.com:442/","https://comodorsacertificationauthority-ev.comodoca.com:444/","None","https://sectigo.com/","USA, UK, Global","https://sectigo.com/uploads/files/WebPKI-COP-v1.0.pdf","https://sectigo.com/uploads/files/Sectigo-CPS-v5.1.2.pdf","https://bug1472993.bmoattachments.org/attachment.cgi?id=9078178","https://www.cpacanada.ca/generichandlers/CPACHandler.ashx?attachmentid=231163","https://www.cpacanada.ca/generichandlers/CPACHandler.ashx?attachmentid=231164","Ernst & Young, LLP","WebTrust","2019.06.27","'-----BEGIN CERTIFICATE----- +MIIF2DCCA8CgAwIBAgIQTKr5yttjb+Af907YWwOGnTANBgkqhkiG9w0BAQwFADCB +hTELMAkGA1UEBhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4G +A1UEBxMHU2FsZm9yZDEaMBgGA1UEChMRQ09NT0RPIENBIExpbWl0ZWQxKzApBgNV +BAMTIkNPTU9ETyBSU0EgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMTAwMTE5 +MDAwMDAwWhcNMzgwMTE4MjM1OTU5WjCBhTELMAkGA1UEBhMCR0IxGzAZBgNVBAgT +EkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UEBxMHU2FsZm9yZDEaMBgGA1UEChMR +Q09NT0RPIENBIExpbWl0ZWQxKzApBgNVBAMTIkNPTU9ETyBSU0EgQ2VydGlmaWNh +dGlvbiBBdXRob3JpdHkwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCR +6FSS0gpWsawNJN3Fz0RndJkrN6N9I3AAcbxT38T6KhKPS38QVr2fcHK3YX/JSw8X +pz3jsARh7v8Rl8f0hj4K+j5c+ZPmNHrZFGvnnLOFoIJ6dq9xkNfs/Q36nGz637CC +9BR++b7Epi9Pf5l/tfxnQ3K9DADWietrLNPtj5gcFKt+5eNu/Nio5JIk2kNrYrhV +/erBvGy2i/MOjZrkm2xpmfh4SDBF1a3hDTxFYPwyllEnvGfDyi62a+pGx8cgoLEf +Zd5ICLqkTqnyg0Y3hOvozIFIQ2dOciqbXL1MGyiKXCJ7tKuY2e7gUYPDCUZObT6Z ++pUX2nwzV0E8jVHtC7ZcryxjGt9XyD+86V3Em69FmeKjWiS0uqlWPc9vqv9JWL7w +qP/0uK3pN/u6uPQLOvnoQ0IeidiEyxPx2bvhiWC4jChWrBQdnArncevPDt09qZah +SL0896+1DSJMwBGB7FY79tOi4lu3sgQiUpWAk2nojkxl8ZEDLXB0AuqLZxUpaVIC +u9ffUGpVRr+goyhhf3DQw6KqLCGqR84onAZFdr+CGCe01a60y1Dma/RMhnEw6abf +Fobg2P9A3fvQQoh/ozM6LlweQRGBY84YcWsr7KaKtzFcOmpH4MN5WdYgGq/yapiq +crxXStJLnbsQ/LBMQeXtHT1eKJ2czL+zUdqnR+WEUwIDAQABo0IwQDAdBgNVHQ4E +FgQUu69+Aj36pvE8hI6t7jiY7NkyMtQwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB +/wQFMAMBAf8wDQYJKoZIhvcNAQEMBQADggIBAArx1UaEt65Ru2yyTUEUAJNMnMvl +wFTPoCWOAvn9sKIN9SCYPBMtrFaisNZ+EZLpLrqeLppysb0ZRGxhNaKatBYSaVqM +4dc+pBroLwP0rmEdEBsqpIt6xf4FpuHA1sj+nq6PK7o9mfjYcwlYRm6mnPTXJ9OV +2jeDchzTc+CiR5kDOF3VSXkAKRzH7JsgHAckaVd4sjn8OoSgtZx8jb8uk2Intzna +FxiuvTwJaP+EmzzV1gsD41eeFPfR60/IvYcjt7ZJQ3mFXLrrkguhxuhoqEwWsRqZ +CuhTLJK7oQkYdQxlqHvLI7cawiiFwxv/0Cti76R7CZGYZ4wUAc1oBmpjIXUDgIiK +boHGhfKppC3n9KUkEEeDys30jXlYsQab5xoq2Z0B15R97QNKyvDb6KkBPvVWmcke +jkk9u+UJueBPSZI9FoJAzMxZxuY67RIuaTxslbH9qh17f4a+Hg4yRvv7E491f0yL +S0Zj/gA0QHDBw7mh3aZw4gSzQbzpgJHqZJx64SIDqZxubw5lT2yHh17zbqD5daWb +QOhTsiedSrnAdyGN/4fy3ryM7xfft0kL0fJuMAsaDk527RH89elWsn2/x20Kk4yl +0MC2Hb46TpSi125sC8KKfPog88Tk5c0NqMuRkrF8hey1FGlmDoLnzc7ILaZRfyHB +NVOFBkpdn627G190 +-----END CERTIFICATE-----'" +"Sectigo","The USERTRUST Network","","USERTrust ECC Certification Authority","5C8B99C55A94C5D27156DECD8980CC26","4FF460D54B9C86DABFBCFC5712E0400D2BED3FBC4D4FBDAA86E06ADCD2A9AD7A","BD4673B81A34DDAF33BD8B31AECBBC59F08E3D238B0738F4F4F2468D81AADDD8","2010.02.01","2038.01.18","EC secp384r1","ecdsaWithSHA384","Websites;Email","","","1.3.6.1.4.1.6449.1.2.1.5.1","https://bugzilla.mozilla.org/show_bug.cgi?id=606947","NSS 3.17.3","Firefox 36","https://usertrustecccertificationauthority-ev.comodoca.com/","https://usertrustecccertificationauthority-ev.comodoca.com:442/","https://usertrustecccertificationauthority-ev.comodoca.com:444/","None","https://sectigo.com/","USA, UK, Global","https://sectigo.com/uploads/files/WebPKI-COP-v1.0.pdf","https://sectigo.com/uploads/files/Sectigo-CPS-v5.1.2.pdf","https://bug1472993.bmoattachments.org/attachment.cgi?id=9078178","https://www.cpacanada.ca/generichandlers/CPACHandler.ashx?attachmentid=231163","https://www.cpacanada.ca/generichandlers/CPACHandler.ashx?attachmentid=231164","Ernst & Young, LLP","WebTrust","2019.06.27","'-----BEGIN CERTIFICATE----- +MIICjzCCAhWgAwIBAgIQXIuZxVqUxdJxVt7NiYDMJjAKBggqhkjOPQQDAzCBiDEL +MAkGA1UEBhMCVVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0plcnNl +eSBDaXR5MR4wHAYDVQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNVBAMT +JVVTRVJUcnVzdCBFQ0MgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMTAwMjAx +MDAwMDAwWhcNMzgwMTE4MjM1OTU5WjCBiDELMAkGA1UEBhMCVVMxEzARBgNVBAgT +Ck5ldyBKZXJzZXkxFDASBgNVBAcTC0plcnNleSBDaXR5MR4wHAYDVQQKExVUaGUg +VVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNVBAMTJVVTRVJUcnVzdCBFQ0MgQ2VydGlm +aWNhdGlvbiBBdXRob3JpdHkwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAAQarFRaqflo +I+d61SRvU8Za2EurxtW20eZzca7dnNYMYf3boIkDuAUU7FfO7l0/4iGzzvfUinng +o4N+LZfQYcTxmdwlkWOrfzCjtHDix6EznPO/LlxTsV+zfTJ/ijTjeXmjQjBAMB0G +A1UdDgQWBBQ64QmG1M8ZwpZ2dEl23OA1xmNjmjAOBgNVHQ8BAf8EBAMCAQYwDwYD +VR0TAQH/BAUwAwEB/zAKBggqhkjOPQQDAwNoADBlAjA2Z6EWCNzklwBBHU6+4WMB +zzuqQhFkoJ2UOQIReVx7Hfpkue4WQrO/isIJxOzksU0CMQDpKmFHjFJKS04YcPbW +RNZu9YO6bVi9JNlWSOrvxKJGgYhqOkbRqZtNyWHa0V1Xahg= +-----END CERTIFICATE-----'" +"Sectigo","The USERTRUST Network","","USERTrust RSA Certification Authority","01FD6D30FCA3CA51A81BBC640E35032D","E793C9B02FD8AA13E21C31228ACCB08119643B749C898964B1746D46C3D4CBD2","B42A394214C81E41F0B38102B01511D9FCAAAAB1FB32678C4944CE8E31837DB6","2010.02.01","2038.01.18","RSA 4096 bits","SHA384WithRSA","Websites;Email","","","1.3.6.1.4.1.6449.1.2.1.5.1","https://bugzilla.mozilla.org/show_bug.cgi?id=606947","NSS 3.17.3","Firefox 36","https://usertrustrsacertificationauthority-ev.comodoca.com/","https://usertrustrsacertificationauthority-ev.comodoca.com:442/","https://usertrustrsacertificationauthority-ev.comodoca.com:444/","None","https://sectigo.com/","USA, UK, Global","https://sectigo.com/uploads/files/WebPKI-COP-v1.0.pdf","https://sectigo.com/uploads/files/Sectigo-CPS-v5.1.2.pdf","https://bug1472993.bmoattachments.org/attachment.cgi?id=9078178","https://www.cpacanada.ca/generichandlers/CPACHandler.ashx?attachmentid=231163","https://www.cpacanada.ca/generichandlers/CPACHandler.ashx?attachmentid=231164","Ernst & Young, LLP","WebTrust","2019.06.27","'-----BEGIN CERTIFICATE----- +MIIF3jCCA8agAwIBAgIQAf1tMPyjylGoG7xkDjUDLTANBgkqhkiG9w0BAQwFADCB +iDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0pl +cnNleSBDaXR5MR4wHAYDVQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNV +BAMTJVVTRVJUcnVzdCBSU0EgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMTAw +MjAxMDAwMDAwWhcNMzgwMTE4MjM1OTU5WjCBiDELMAkGA1UEBhMCVVMxEzARBgNV +BAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0plcnNleSBDaXR5MR4wHAYDVQQKExVU +aGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNVBAMTJVVTRVJUcnVzdCBSU0EgQ2Vy +dGlmaWNhdGlvbiBBdXRob3JpdHkwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIK +AoICAQCAEmUXNg7D2wiz0KxXDXbtzSfTTK1Qg2HiqiBNCS1kCdzOiZ/MPans9s/B +3PHTsdZ7NygRK0faOca8Ohm0X6a9fZ2jY0K2dvKpOyuR+OJv0OwWIJAJPuLodMkY +tJHUYmTbf6MG8YgYapAiPLz+E/CHFHv25B+O1ORRxhFnRghRy4YUVD+8M/5+bJz/ +Fp0YvVGONaanZshyZ9shZrHUm3gDwFA66Mzw3LyeTP6vBZY1H1dat//O+T23LLb2 +VN3I5xI6Ta5MirdcmrS3ID3KfyI0rn47aGYBROcBTkZTmzNg95S+UzeQc0PzMsNT +79uq/nROacdrjGCT3sTHDN/hMq7MkztReJVni+49Vv4M0GkPGw/zJSZrM233bkf6 +c0Plfg6lZrEpfDKEY1WJxA3Bk1QwGROs0303p+tdOmw1XNtB1xLaqUkL39iAigmT +Yo61Zs8liM2EuLE/pDkP2QKe6xJMlXzzawWpXhaDzLhn4ugTncxbgtNMs+1b/97l +c6wjOy0AvzVVdAlJ2ElYGn+SNuZRkg7zJn0cTRe8yexDJtC/QV9AqURE9JnnV4ee +UB9XVKg+/XRjL7FQZQnmWEIuQxpMtPAlR1n6BB6T1CZGSlCBst6+eLf8ZxXhyVeE +Hg9j1uliutZfVS7qXMYoCAQlObgOK6nyTJccBz8NUvXt7y+CDwIDAQABo0IwQDAd +BgNVHQ4EFgQUU3m/WqorSs9UgOHYm8Cd8rIDZsswDgYDVR0PAQH/BAQDAgEGMA8G +A1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEMBQADggIBAFzUfA3P9wF9QZllDHPF +Up/L+M+ZBn8b2kMVn54CVVeWFPFSPCeHlCjtHzoBN6J2/FNQwISbxmtOuowhT6KO +VWKR82kV2LyI48SqC/3vqOlLVSoGIG1VeCkZ7l8wXEskEVX/JJpuXior7gtNn3/3 +ATiUFJVDBwn7YKnuHKsSjKCaXqeYalltiz8I+8jRRa8YFWSQEg9zKC7F4iRO/Fjs +8PRF/iKz6y+O0tlFYQXBl2+odnKPi4w2r78NBc5xjeambx9spnFixdjQg3IM8WcR +iQycE0xyNN+81XHfqnHd4blsjDwSXWXavVcStkNr/+XeTWYRUc+ZruwXtuhxkYze +Sf7dNXGiFSeUHM9h4ya7b6NnJSFd5t0dCy5oGzuCr+yDZ4XUmFF0sbmZgIn/f3gZ +XHlKYC6SQK5MNyosycdiyA5d9zZbyuAlJQG03RoHnHcAP9Dc1ew91Pq7P8yF1m9/ +qS3fuQL39ZeatTXaw2ewh0qpKJ4jjv9cJ2vhsE/zB+4ALtRZh8tSQZXq9EfX7mRB +VXyNWQKV3WKdwrnuWih0hKWbt5DHDAff9Yk2dDLWKMGwsAvgnEzDHNb842m1R0aB +L6KCq9NjRHDEjf8tM7qtj3u1cIiuPhnPQCjY/MiQu12ZIvVS5ljFH4gxQ+6IHdfG +jjxDah2nGN59PRbxYvnKkKj9 +-----END CERTIFICATE-----'" +"SecureTrust","SecureTrust Corporation","","Secure Global CA","075622A4E8D48A894DF413C8F0F8EAA5","4200F5043AC8590EBB527D209ED1503029FBCBD41CA1B506EC27F15ADE7DAC69","BD488A94F09E6F46DEADC161D664E57FA2F797CF6AFCBF7856DFE7B08B3B3473","2006.11.07","2029.12.31","RSA 2048 bits","SHA1WithRSA","Websites;Email","","","2.16.840.1.114404.1.1.2.4.1","https://bugzilla.mozilla.org/show_bug.cgi?id=409838","NSS 3.11.10","Firefox 3.0.2","https://sgcatest.trustwave.com","https://sgcatest-expired.trustwave.com","https://sgcatest-revoked.trustwave.com","","http://www.trustwave.com/","USA, Global","","https://certs.securetrust.com/CA/SecureTrustCPS_61.pdf","https://www.cpacanada.ca/generichandlers/CPACHandler.ashx?attachmentid=237400","https://certs.securetrust.com/CA/2%20-%20SecureTrust%202019%20SSL%20BL%20Report.pdf","https://www.cpacanada.ca/generichandlers/CPACHandler.ashx?attachmentid=237401","BDO International Limited","WebTrust","2019.11.19","'-----BEGIN CERTIFICATE----- +MIIDvDCCAqSgAwIBAgIQB1YipOjUiolN9BPI8PjqpTANBgkqhkiG9w0BAQUFADBK +MQswCQYDVQQGEwJVUzEgMB4GA1UEChMXU2VjdXJlVHJ1c3QgQ29ycG9yYXRpb24x +GTAXBgNVBAMTEFNlY3VyZSBHbG9iYWwgQ0EwHhcNMDYxMTA3MTk0MjI4WhcNMjkx +MjMxMTk1MjA2WjBKMQswCQYDVQQGEwJVUzEgMB4GA1UEChMXU2VjdXJlVHJ1c3Qg +Q29ycG9yYXRpb24xGTAXBgNVBAMTEFNlY3VyZSBHbG9iYWwgQ0EwggEiMA0GCSqG +SIb3DQEBAQUAA4IBDwAwggEKAoIBAQCvNS7YrGxVaQZx5RNoJLNP2MwhR/jxYDiJ +iQPpvepeRlMJ3Fz1Wuj3RSoC6zFh1ykzTM7HfAo3fg+6MpjhHZevj8fcyTiW89sa +/FHtaMbQbqR8JNGuQsiWUGMu4P51/pinX0kuleM5M2SOHqRfkNJnPLLZ/kG5VacJ +jnIFHovdRIWCQtBJwB1g8NEXLJXr9qXBkqPFwqcIYA1gBBCWeZ4WNOaptvolRTnI +HmX5k/Wq8VLcmZg9pYYaDDUz+kulBAYVHDGA76oYa8J719rO+TMg1fW9ajMtgQT7 +sFzUnKPiXB3jqUJ1XnvUd+85VLrJChgbEplJL4hL/VBi0XPnj3pDAgMBAAGjgZ0w +gZowEwYJKwYBBAGCNxQCBAYeBABDAEEwCwYDVR0PBAQDAgGGMA8GA1UdEwEB/wQF +MAMBAf8wHQYDVR0OBBYEFK9EBMJBfkiD2045AuzshHrmzsmkMDQGA1UdHwQtMCsw +KaAnoCWGI2h0dHA6Ly9jcmwuc2VjdXJldHJ1c3QuY29tL1NHQ0EuY3JsMBAGCSsG +AQQBgjcVAQQDAgEAMA0GCSqGSIb3DQEBBQUAA4IBAQBjGghAfaReUw132HquHw0L +URYD7xh8yOOvaliTFGCRsoTciE6+OYo68+aCiV0BN7OrJKQVDpI1WkpEXk5X+nXO +H0jOZvQ8QCaSmGwb7iRGDBezUqXbpZGRzzfTb+cnCDpOGR86p1hcF895P4vkp9Mm +I50mD1hp/Ed+stCNi5O/KU9DaXR2Z0vPB4zmAve14bRDtUstFJ/53CYNv6ZHdAbY +iNE6KTCEztI5gGIbqMdXSbxqVVFnFUq+NQfk1XWYN3kwFNspnWzFacxHVaIw98xc +f8LDmBxrThaA63p4ZUWiABqvDA1VZDRIuJK58bRQKfJPIx/abKwfROHdI3hRW8cW +-----END CERTIFICATE-----'" +"SecureTrust","SecureTrust Corporation","","SecureTrust CA","0CF08E5C0816A5AD427FF0EB271859D0","F1C1B50AE5A20DD8030EC9F6BC24823DD367B5255759B4E71B61FCE9F7375D73","662D9472BD6377EEE1EB5ACBE4306B73AF05681963716E28C49F7F456EB3025D","2006.11.07","2029.12.31","RSA 2048 bits","SHA1WithRSA","Websites","","","2.16.840.1.114404.1.1.2.4.1","https://bugzilla.mozilla.org/show_bug.cgi?id=409837","NSS 3.11.10","Firefox 3.0.2","https://stcatest.trustwave.com","https://stcatest-expired.trustwave.com","https://stcatest-revoked.trustwave.com","","http://www.trustwave.com/","USA, Global","","https://certs.securetrust.com/CA/SecureTrustCPS_61.pdf","https://www.cpacanada.ca/generichandlers/CPACHandler.ashx?attachmentid=237400","https://certs.securetrust.com/CA/2%20-%20SecureTrust%202019%20SSL%20BL%20Report.pdf","https://www.cpacanada.ca/generichandlers/CPACHandler.ashx?attachmentid=237401","BDO International Limited","WebTrust","2019.11.19","'-----BEGIN CERTIFICATE----- +MIIDuDCCAqCgAwIBAgIQDPCOXAgWpa1Cf/DrJxhZ0DANBgkqhkiG9w0BAQUFADBI +MQswCQYDVQQGEwJVUzEgMB4GA1UEChMXU2VjdXJlVHJ1c3QgQ29ycG9yYXRpb24x +FzAVBgNVBAMTDlNlY3VyZVRydXN0IENBMB4XDTA2MTEwNzE5MzExOFoXDTI5MTIz +MTE5NDA1NVowSDELMAkGA1UEBhMCVVMxIDAeBgNVBAoTF1NlY3VyZVRydXN0IENv +cnBvcmF0aW9uMRcwFQYDVQQDEw5TZWN1cmVUcnVzdCBDQTCCASIwDQYJKoZIhvcN +AQEBBQADggEPADCCAQoCggEBAKukgeWVzfX2FI7CT8rU4niVWJxB4Q2ZQCQXOZEz +Zum+4YOvYlyJ0fwkW2Gz4BERQRwdbvC4u/jep4G6pkjGnx29vo6pQT64lO0pGtSO +0gMdA+9tDWccV9cGrcrI9f4Or2YlSASWC12juhbDCE/RRvgUXPLIXgGZbf2IzIao +wW8xQmxSPmjL8xk037uHGFaAJsTQ3MBv396gwpEWoGQRS0S8Hvbn+mPeZqx2pHGj +7DaUaHp3pLHnDi+BeuK1cobvomuL8A/b01k/unK8RCSc43Oz969XL0Imnal0ugBS +8kvNU3xHCzaFDmapCJcWNFfBZveA4+1wVMeT4C4oFVmHursCAwEAAaOBnTCBmjAT +BgkrBgEEAYI3FAIEBh4EAEMAQTALBgNVHQ8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB +/zAdBgNVHQ4EFgQUQjK2FvoE/f5dS3rD/fdMQB1aQ68wNAYDVR0fBC0wKzApoCeg +JYYjaHR0cDovL2NybC5zZWN1cmV0cnVzdC5jb20vU1RDQS5jcmwwEAYJKwYBBAGC +NxUBBAMCAQAwDQYJKoZIhvcNAQEFBQADggEBADDtT0rhWDpSclu1pqNlGKa7UTt3 +6Z3q059c4EVlew3KW+JwULKUBRSuSceNQQcSc5R+DCMh/bwQf2AQWnL1mA6s7Ll/ +3XpvXdMc9P+IBWlCqQVxyLesJugutIxq/3HcuLHfmbx8IVQr5Fiiu1cprp6poxkm +D5kuCLDv/WnPmRoJjeOnnyvJNjR7JLN4TJUXpAYmHrZkUjZfYGfZnMUFdAvnZyPS +CPyI6a6Lf+Ew9Dd+/cYy2i2eRDAwbO4H3tI0/NL/QPZL9GZGBlSm8jIKYyYwa5vR +3ItHuuG51WLQoqD0ZwV4KWMabwTW+MZMo5qxN7SN5ShLHZ4swrhovO0C7jE= +-----END CERTIFICATE-----'" +"SecureTrust","XRamp Security Services Inc","www.xrampsecurity.com","XRamp Global Certification Authority","50946CEC18EAD59C4DD597EF758FA0AD","CECDDC905099D8DADFC5B1D209B737CBE2C18CFB2C10C0FF0BCF0D3286FC1AA2","9CDCC89B2E898E537BB02FFB25A47FCD52D3BD37601B7D2124D2B8948651A707","2004.11.01","2035.01.01","RSA 2048 bits","SHA1WithRSA","Websites;Email","","","2.16.840.1.114404.1.1.2.4.1","https://bugzilla.mozilla.org/show_bug.cgi?id=273189","NSS 3.10","Firefox 1","https://xgcatest.trustwave.com","https://xgcatest-expired.trustwave.com","https://xgcatest-revoked.trustwave.com","","http://www.trustwave.com/","USA, Global","","https://certs.securetrust.com/CA/SecureTrustCPS_61.pdf","https://www.cpacanada.ca/generichandlers/CPACHandler.ashx?attachmentid=237400","https://certs.securetrust.com/CA/2%20-%20SecureTrust%202019%20SSL%20BL%20Report.pdf","https://www.cpacanada.ca/generichandlers/CPACHandler.ashx?attachmentid=237401","BDO International Limited","WebTrust","2019.11.19","'-----BEGIN CERTIFICATE----- +MIIEMDCCAxigAwIBAgIQUJRs7Bjq1ZxN1ZfvdY+grTANBgkqhkiG9w0BAQUFADCB +gjELMAkGA1UEBhMCVVMxHjAcBgNVBAsTFXd3dy54cmFtcHNlY3VyaXR5LmNvbTEk +MCIGA1UEChMbWFJhbXAgU2VjdXJpdHkgU2VydmljZXMgSW5jMS0wKwYDVQQDEyRY +UmFtcCBHbG9iYWwgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMDQxMTAxMTcx +NDA0WhcNMzUwMTAxMDUzNzE5WjCBgjELMAkGA1UEBhMCVVMxHjAcBgNVBAsTFXd3 +dy54cmFtcHNlY3VyaXR5LmNvbTEkMCIGA1UEChMbWFJhbXAgU2VjdXJpdHkgU2Vy +dmljZXMgSW5jMS0wKwYDVQQDEyRYUmFtcCBHbG9iYWwgQ2VydGlmaWNhdGlvbiBB +dXRob3JpdHkwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCYJB69FbS6 +38eMpSe2OAtp87ZOqCwuIR1cRN8hXX4jdP5efrRKt6atH67gBhbim1vZZ3RrXYCP +KZ2GG9mcDZhtdhAoWORlsH9KmHmf4MMxfoArtYzAQDsRhtDLooY2YKTVMIJt2W7Q +DxIEM5dfT2Fa8OT5kavnHTu86M/0ay00fOJIYRyO82FEzG+gSqmUsE3a56k0enI4 +qEHMPJQRfevIpoy3hsvKMzvZPTeL+3o+hiznc9cKV6xkmxnr9A8ECIqsAxcZZPRa +JSKNNCyy9mgdEm3Tih4U2sSPpuIjhdV6Db1q4Ons7Be7QhtnqiXtRYMh/MHJfNVi +PvryxS3T/dRlAgMBAAGjgZ8wgZwwEwYJKwYBBAGCNxQCBAYeBABDAEEwCwYDVR0P +BAQDAgGGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFMZPoj0GY4QJnM5i5ASs +jVy16bYbMDYGA1UdHwQvMC0wK6ApoCeGJWh0dHA6Ly9jcmwueHJhbXBzZWN1cml0 +eS5jb20vWEdDQS5jcmwwEAYJKwYBBAGCNxUBBAMCAQEwDQYJKoZIhvcNAQEFBQAD +ggEBAJEVOQMBG2f7Shz5CmBbodpNl2L5JFMn14JkTpAuw0kbK5rc/Kh4ZzXxHfAR +vbdI4xD2Dd8/0sm2qlWkSLoC295ZLhVbO50WfUfXN+pfTXYSNrsf16GBBEYgoyxt +qZ4Bfj8pzgCT3/3JknOJiWSe5yvkHJEs0rnOfc5vMZnT5r7SHpDwCRR5XCOrTdLa +IR9NmXmd4c8nnxCbHIgNsIpkQTG4DmyQJKSbXHGPurt+HBvbaoAPIbzp26a3QPSy +i6mx5O+aGtA9aZnuqCij4Tyz8LIRnM98QObd50N9otg6tamN8jSZxNQQ4Qb9CYQQ +O+7ETPTsJ3xCwnR8gooJybQDJbw= +-----END CERTIFICATE-----'" +"Shanghai Electronic Certification Authority Co., Ltd. (SHECA)","UniTrust","","UCA Extended Validation Root","4FD22B8FF564C8339E4F345866237060","D43AF9B35473755C9684FC06D7D8CB70EE5C28E773FB294EB41EE71722924D24","FDEED5B2F5818F96D79C0E6AFDBBB6902B5EE6E38838626AE63D0D9E4F1F3C05","2015.03.13","2038.12.31","RSA 4096 bits","SHA256WithRSA","Websites","","","2.23.140.1.1","https://bugzilla.mozilla.org/show_bug.cgi?id=1309797","NSS 3.41","Firefox 65","https://rsaevg1.good.sheca.com/","https://rsaevg1.expired.sheca.com/","https://rsaevg1.revoked.sheca.com/","","https://www.sheca.com/repository","China","https://assets-cdn.sheca.com/documents/unitrust-certificate-policy-en-v1.4.5.pdf","https://assets-cdn.sheca.com/documents/sheca-certification-practice-statement-en-v3.6.7.pdf","https://www.cpacanada.ca/generichandlers/CPACHandler.ashx?attachmentid=240437","https://www.cpacanada.ca/generichandlers/CPACHandler.ashx?attachmentid=240438","https://www.cpacanada.ca/generichandlers/CPACHandler.ashx?attachmentid=240439","PwC - PricewaterhouseCoopers International Limited","WebTrust","2020.06.12","'-----BEGIN CERTIFICATE----- +MIIFWjCCA0KgAwIBAgIQT9Irj/VkyDOeTzRYZiNwYDANBgkqhkiG9w0BAQsFADBH +MQswCQYDVQQGEwJDTjERMA8GA1UECgwIVW5pVHJ1c3QxJTAjBgNVBAMMHFVDQSBF +eHRlbmRlZCBWYWxpZGF0aW9uIFJvb3QwHhcNMTUwMzEzMDAwMDAwWhcNMzgxMjMx +MDAwMDAwWjBHMQswCQYDVQQGEwJDTjERMA8GA1UECgwIVW5pVHJ1c3QxJTAjBgNV +BAMMHFVDQSBFeHRlbmRlZCBWYWxpZGF0aW9uIFJvb3QwggIiMA0GCSqGSIb3DQEB +AQUAA4ICDwAwggIKAoICAQCpCQcoEwKwmeBkqh5DFnpzsZGgdT6o+uM4AHrsiWog +D4vFsJszA1qGxliG1cGFu0/GnEBNyr7uaZa4rYEwmnySBesFK5pI0Lh2PpbIILvS +sPGP2KxFRv+qZ2C0d35qHzwaUnoEPQc8hQ2E0B92CvdqFN9y4zR8V05WAT558aop +O2z6+I9tTcg1367r3CTueUWnhbYFiN6IXSV8l2RnCdm/WhUFhvMJHuxYMjMR83dk +sHYf5BA1FxvyDrFspCqjc/wJHx4yGVMR59mzLC52LqGj3n5qiAno8geK+LLNEOfi +c0CTuwjRP+H8C5SzJe98ptfRr5//lpr1kXuYC3fUfugH0mK1lTnj8/FtDw5lhIpj +VMWAtuCeS31HJqcBCF3RiJ7XwzJE+oJKCmhUfzhTA8ykADNkUVkLo4KRel7sFsLz +KuZi2irbWWIQJUoqgQtHB0MGcIfS+pMRKXpITeuUx3BNr2fVUbGAIAEBtHoIppB/ +TuDvB0GHr2qlXov7z1CymlSvw4m6WC31MJixNnI5fkkE/SmnTHnkBVfblLkWU41G +sx2VYVdWf6/wFlthWG82UBEL2KwrlRYaDh8IzTY0ZRBiZtWAXxQgXy0MoHgKaNYs +1+lvK9JKBZP8nm9rZ/+I8U6laUpSNwXqxhaN0sSZ0YIrO7o1dfdRUVjzyAfd5LQD +fwIDAQABo0IwQDAdBgNVHQ4EFgQU2XQ65DA9DfcS3H5aBZ8eNJr34RQwDwYDVR0T +AQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAYYwDQYJKoZIhvcNAQELBQADggIBADaN +l8xCFWQpN5smLNb7rhVpLGsaGvdftvkHTFnq88nIua7Mui563MD1sC3AO6+fcAUR +ap8lTwEpcOPlDOHqWnzcSbvBHiqB9RZLcpHIojG5qtr8nR/zXUACE/xOHAbKsxSQ +VBcZEhrxH9cMaVr2cXj0lH2RC47skFSOvG+hTKv8dGT9cZr4QQehzZHkPJrgmzI5 +c6sq1WnIeJEmMX3ixzDx/BR4dxIOE/TdFpS/S2d7cFOFyrC78zhNLJA5wA3CXWvp +4uXViI3WLL+rG761KIcSF3Ru/H38j9CHJrAb+7lsq+KePRXBOy5nAliRn+/4Qh8s +t2j1da3Ptfb/EX3C8CSlrdP6oDyp+l3cpaDvRKS+1ujl5BOWF3sGPjLtx7dCvHaj +2GU4Kzg1USEODm8uNBNA4StnDG1KQTAYI1oyVZnJF+A83vbsea0rWBmirSwiGpWO +vpaQXUJXxPkUAzUrHC1RVwinOt4/5Mi0A3PCwSaAuwtCH60NryZy2sy+s6ODWA2C +xR9GUeOcGMyNm43sSet1UNWMKFnKdDTajAshqx7qG+XH/RU+wBeq+yNuJkbL+vmx +cmtpzyKEC2IPrNkZAJSidjzULZrtBJ4tBmIQN1IchXIbJ+XMxjHsN+xjWZsLHXbM +fjKaiJUINlK73nZfdklJrX+9ZSCyycErdhh2n1ax +-----END CERTIFICATE-----'" +"Shanghai Electronic Certification Authority Co., Ltd. (SHECA)","UniTrust","","UCA Global G2 Root","5DDFB1DA5AA3ED5DBE5A6520650390EF","9BEA11C976FE014764C1BE56A6F914B5A560317ABD9988393382E5161AA0493C","32B915B58CBF59C721C68E35BCD237F543020BA7576D272E5232221EEEA12172","2016.03.11","2040.12.31","RSA 4096 bits","SHA256WithRSA","Websites;Email","","","Not EV","https://bugzilla.mozilla.org/show_bug.cgi?id=1309797","NSS 3.41","Firefox 65","https://rsaovg3.good.sheca.com/","https://rsaovg3.expired.sheca.com/","https://rsaovg3.revoked.sheca.com/","None","https://www.sheca.com/repository","China","https://assets-cdn.sheca.com/documents/unitrust-certificate-policy-en-v1.4.5.pdf","https://assets-cdn.sheca.com/documents/sheca-certification-practice-statement-en-v3.6.7.pdf","https://www.cpacanada.ca/generichandlers/CPACHandler.ashx?attachmentid=240437","https://www.cpacanada.ca/generichandlers/CPACHandler.ashx?attachmentid=240438","https://www.cpacanada.ca/generichandlers/CPACHandler.ashx?attachmentid=240439","PwC - PricewaterhouseCoopers International Limited","WebTrust","2020.06.12","'-----BEGIN CERTIFICATE----- +MIIFRjCCAy6gAwIBAgIQXd+x2lqj7V2+WmUgZQOQ7zANBgkqhkiG9w0BAQsFADA9 +MQswCQYDVQQGEwJDTjERMA8GA1UECgwIVW5pVHJ1c3QxGzAZBgNVBAMMElVDQSBH +bG9iYWwgRzIgUm9vdDAeFw0xNjAzMTEwMDAwMDBaFw00MDEyMzEwMDAwMDBaMD0x +CzAJBgNVBAYTAkNOMREwDwYDVQQKDAhVbmlUcnVzdDEbMBkGA1UEAwwSVUNBIEds +b2JhbCBHMiBSb290MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAxeYr +b3zvJgUno4Ek2m/LAfmZmqkywiKHYUGRO8vDaBsGxUypK8FnFyIdK+35KYmToni9 +kmugow2ifsqTs6bRjDXVdfkX9s9FxeV67HeToI8jrg4aA3++1NDtLnurRiNb/yzm +VHqUwCoV8MmNsHo7JOHXaOIxPAYzRrZUEaalLyJUKlgNAQLx+hVRZ2zA+te2G3/R +VogvGjqNO7uCEeBHANBSh6v7hn4PJGtAnTRnvI3HLYZveT6OqTwXS3+wmeOwcWDc +C/Vkw85DvG1xudLeJ1uK6NjGruFZfc8oLTW4lVYa8bJYS7cSN8h8s+1LgOGN+jIj +tm+3SJUIsUROhYw6AlQgL9+/V087OpAh18EmNVQg7Mc/R+zvWr9LesGtOxdQXGLY +D0tK3Cv6brxzks3sx1DoQZbXqX5t2Okdj4q1uViSukqSKwxW/YDrCPBeKW4bHAyv +j5OJrdu9o54hyokZ7N+1wxrrFv54NkzWbtA+FxyQF2smuvt6L78RHBgOLXMDj6Dl +NaBa4kx1HXHhOThTeEDMg5PXCp6dW4+K5OXgSORIskfNTip1KnvyIvbJvgmRlld6 +iIis7nCs+dwp4wwcOxJORNanTrAmyPPZGpeRaOrvjUYG0lZFWJo8DA+DuAUlwznP +O6Q0ibd5Ei9Hxeepl2n8pndntd978XplFeRhVmUCAwEAAaNCMEAwDgYDVR0PAQH/ +BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFIHEjMz15DD/pQwIX4wV +ZyF0Ad/fMA0GCSqGSIb3DQEBCwUAA4ICAQATZSL1jiutROTL/7lo5sOASD0Ee/oj +L3rtNtqyzm325p7lX1iPyzcyochltq44PTUbPrw7tgTQvPlJ9Zv3hcU2tsu8+Mg5 +1eRfB70VVJd0ysrtT7q6ZHafgbiERUlMjW+i67HM0cOU2kTC5uLqGOiiHycFutfl +1qnN3e92mI0ADs0b+gO3joBYDic/UvuUospeZcnWhNq5NXHzJsBPd+aBJ9J3O5oU +b3n09tDh05S60FdRvScFDcH9yBIw7m+NESsIndTUv4BFFJqIRNow6rSn4+7vW4LV +PtateJLbXDzz2K36uGt/xDYotgIVilQsnLAXc47QN6MUPJiVAAwpBVueSUmxX8fj +y88nZY41F7dXyDDZQVu5FLbowg+UMaeUmMxq67XhJ/UQqAHojhJi6IjMtX9Gl8Cb +EGY4GjZGXyJoPd/JxhMnq1MGrKI8hgZlb7F+sSlEmqO6SWkoaY/X5V+tBIZkbxqg +DMUIYs6Ao9Dz7GjevjPHF1t/gMRMTLGmhIrDO7gJzRSBuhjjVFc2/tsvfEehOjPI ++Vg7RE+xygKJBJYoaMVLuCaJu9YzL1DV/pqJuhgyklTGW+Cd+V7lDSKb9triyCGy +YiGqhkCyLmTTX8jjfhFnRR8F/uOi77Oos/N9j/gMHyIfLXC0uAE0djAA5SN4p1bX +UB+K+wb1whnw0A== +-----END CERTIFICATE-----'" +"SK ID Solutions AS","AS Sertifitseerimiskeskus","","EE Certification Centre Root CA","5480F9A073ED3F004CCA89D8E371E64A","3E84BA4342908516E77573C0992F0979CA084E4685681FF195CCBA8A229B8A76","676F5DB3D8D0D3AD707AAA869FADEE0ECAC44A5D9AF7CD8DDAC3A35BE9AFE52B","2010.10.30","2030.12.17","RSA 2048 bits","SHA1WithRSA","Websites","","","Not EV","https://bugzilla.mozilla.org/show_bug.cgi?id=624356","NSS 3.14","Firefox 18","https://sk.ee/en/repository/certs/","https://expired.tls.sk.ee/","https://revoked.tls.sk.ee/","","http://www.sk.ee/","Baltic region (Estonia, Lithuania, Latvia)","https://www.skidsolutions.eu/upload/files/SK-CP-TLS-EN-v7_0-20200410.pdf","https://www.skidsolutions.eu/upload/files/SK-CPS-KLASS3-EN-v9_0-20200410.pdf","https://it-tuv.com/en/wp-content/uploads/sites/10/2020/05/AA2020052001_Audit_Attestation_TA_CERT__SK_EE-Certification-Centre-Root-CA.pdf","https://it-tuv.com/en/wp-content/uploads/sites/10/2020/05/AA2020052001_Audit_Attestation_TA_CERT__SK_EE-Certification-Centre-Root-CA.pdf","https://it-tuv.com/en/wp-content/uploads/sites/10/2020/05/AA2020052001_Audit_Attestation_TA_CERT__SK_EE-Certification-Centre-Root-CA.pdf","TÜViT - TÜV Informationstechnik GmbH","ETSI EN 319 411","2020.05.20","'-----BEGIN CERTIFICATE----- +MIIEAzCCAuugAwIBAgIQVID5oHPtPwBMyonY43HmSjANBgkqhkiG9w0BAQUFADB1 +MQswCQYDVQQGEwJFRTEiMCAGA1UECgwZQVMgU2VydGlmaXRzZWVyaW1pc2tlc2t1 +czEoMCYGA1UEAwwfRUUgQ2VydGlmaWNhdGlvbiBDZW50cmUgUm9vdCBDQTEYMBYG +CSqGSIb3DQEJARYJcGtpQHNrLmVlMCIYDzIwMTAxMDMwMTAxMDMwWhgPMjAzMDEy +MTcyMzU5NTlaMHUxCzAJBgNVBAYTAkVFMSIwIAYDVQQKDBlBUyBTZXJ0aWZpdHNl +ZXJpbWlza2Vza3VzMSgwJgYDVQQDDB9FRSBDZXJ0aWZpY2F0aW9uIENlbnRyZSBS +b290IENBMRgwFgYJKoZIhvcNAQkBFglwa2lAc2suZWUwggEiMA0GCSqGSIb3DQEB +AQUAA4IBDwAwggEKAoIBAQDIIMDs4MVLqwd4lfNE7vsLDP90jmG7sWLqI9iroWUy +euuOF0+W2Ap7kaJjbMeMTC55v6kF/GlclY1i+blw7cNRfdCT5mzrMEvhvH2/UpvO +bntl8jixwKIy72KyaOBhU8E2lf/slLo2rpwcpzIP5Xy0xm90/XsY6KxX7QYgSzIw +WFv9zajmofxwvI6Sc9uXp3whrj3B9UiHbCe9nyV0gVWw93X2PaRka9ZP585ArQ/d +MtO8ihJTmMmJ+xAdTX7Nfh9WDSFwhfYggx/2uh8Ej+p3iDXE/+pOoYtNP2MbRMNE +1CV2yreN1x5KZmTNXMWcg+HCCIia7E6j8T4cLNlsHaFLAgMBAAGjgYowgYcwDwYD +VR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFBLyWj7qVhy/ +zQas8fElyalL1BSZMEUGA1UdJQQ+MDwGCCsGAQUFBwMCBggrBgEFBQcDAQYIKwYB +BQUHAwMGCCsGAQUFBwMEBggrBgEFBQcDCAYIKwYBBQUHAwkwDQYJKoZIhvcNAQEF +BQADggEBAHv25MANqhlHt01Xo/6tu7Fq1Q+e2+RjxY6hUFaTlrg4wCQiZrxTFGGV +v9DHKpY5P30osxBAIWrEr7BSdxjhlthWXePdNl4dp1BUoMUq5KqMlIpPnTX/dqQG +E5Gion0ARD9V04I8GtVbvFZMIi5GQ4okQC3zErg7cBqklrkar4dBGmoYDQZPxz5u +uSlNDUmJEYcyW+ZLBMjkXOZ0c5RdFpgTlf7727FE5TpwrDdr5rMzcijJs1eg9gIW +iAYLtqZLICjU3j2LrTcFU3T+bsy8QxdxXvnFzBqpYe73dgzzcvRyrc9yAjYHR8/v +GVCJYMzpJJUPwssd8m92kMfMdcGWxZ0= +-----END CERTIFICATE-----'" +"SSL.com","SSL Corporation","","SSL.com EV Root Certification Authority ECC","2C299C5B16ED0595","22A2C1F7BDED704CC1E701B5F408C310880FE956B5DE2A4A44F99C873A25A7C8","8733B45ABC0458A8C549F543580C96AD198CA0ED99056511558685220D49BA8C","2016.02.12","2041.02.12","EC secp384r1","ecdsaWithSHA256","Websites","","","2.23.140.1.1","https://bugzilla.mozilla.org/show_bug.cgi?id=1277336","NSS 3.34","Firefox 58","https://test-ev-ecc.ssl.com/","https://expired-ecc-ev.ssl.com","https://revoked-ecc-ev.ssl.com","No","https://www.ssl.com/","USA, Global","","https://www.ssl.com/app/uploads/2019/06/SSLcom_CP_CPS_Version_1_6.pdf","https://cdn.ssl.com/app/uploads/2020/02/SSLcom-2019-WTCA-Indp-Acct-Report-and-Mgmt-Assertion-June-2019-REVISED-FINAL.pdf","https://cdn.ssl.com/app/uploads/2020/02/SSLcom-2019-WTBR-Indp-Acct-Report-and-Mgmt-Assertion-June-2019-REVISED-FINAL.pdf","https://cdn.ssl.com/app/uploads/2020/02/SSLcom-2019-WTEV-SSL-Indp-Acct-Report-and-Mgmt-Assertion-June-2019-REVISED-FINAL.pdf","BDO International Limited","WebTrust","2020.02.12","'-----BEGIN CERTIFICATE----- +MIIClDCCAhqgAwIBAgIILCmcWxbtBZUwCgYIKoZIzj0EAwIwfzELMAkGA1UEBhMC +VVMxDjAMBgNVBAgMBVRleGFzMRAwDgYDVQQHDAdIb3VzdG9uMRgwFgYDVQQKDA9T +U0wgQ29ycG9yYXRpb24xNDAyBgNVBAMMK1NTTC5jb20gRVYgUm9vdCBDZXJ0aWZp +Y2F0aW9uIEF1dGhvcml0eSBFQ0MwHhcNMTYwMjEyMTgxNTIzWhcNNDEwMjEyMTgx +NTIzWjB/MQswCQYDVQQGEwJVUzEOMAwGA1UECAwFVGV4YXMxEDAOBgNVBAcMB0hv +dXN0b24xGDAWBgNVBAoMD1NTTCBDb3Jwb3JhdGlvbjE0MDIGA1UEAwwrU1NMLmNv +bSBFViBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IEVDQzB2MBAGByqGSM49 +AgEGBSuBBAAiA2IABKoSR5CYG/vvw0AHgyBO8TCCogbR8pKGYfL2IWjKAMTH6kMA +VIbc/R/fALhBYlzccBYy3h+Z1MzFB8gIH2EWB1E9fVwHU+M1OIzfzZ/ZLg1Kthku +WnBaBu2+8KGwytAJKaNjMGEwHQYDVR0OBBYEFFvKXuXe0oGqzagtZFG22XKbl+ZP +MA8GA1UdEwEB/wQFMAMBAf8wHwYDVR0jBBgwFoAUW8pe5d7SgarNqC1kUbbZcpuX +5k8wDgYDVR0PAQH/BAQDAgGGMAoGCCqGSM49BAMCA2gAMGUCMQCK5kCJN+vp1RPZ +ytRrJPOwPYdGWBrssd9v+1a6cGvHOMzosYxPD/fxZ3YOg9AeUY8CMD32IygmTMZg +h5Mmm7I1HrrW9zzRHM76JTymGoEVW/MSD2zuZYrJh6j5B+BimoxcSg== +-----END CERTIFICATE-----'" +"SSL.com","SSL Corporation","","SSL.com EV Root Certification Authority RSA R2","56B629CD34BC78F6","2E7BF16CC22485A7BBE2AA8696750761B0AE39BE3B2FE9D0CC6D4EF73491425C","99C0B11A1CAAB0880079E929C0AE65A135624FA93D3FFAC24117DEAF338C8A40","2017.05.31","2042.05.30","RSA 4096 bits","SHA256WithRSA","Websites","","","2.23.140.1.1","https://bugzilla.mozilla.org/show_bug.cgi?id=1277336","NSS 3.34","Firefox 58","https://test-ev-rsa.ssl.com","https://expired-rsa-ev.ssl.com","https://revoked-rsa-ev.ssl.com/","No","https://www.ssl.com/","USA, Global","","https://www.ssl.com/app/uploads/2019/06/SSLcom_CP_CPS_Version_1_6.pdf","https://cdn.ssl.com/app/uploads/2020/02/SSLcom-2019-WTCA-Indp-Acct-Report-and-Mgmt-Assertion-June-2019-REVISED-FINAL.pdf","https://cdn.ssl.com/app/uploads/2020/02/SSLcom-2019-WTBR-Indp-Acct-Report-and-Mgmt-Assertion-June-2019-REVISED-FINAL.pdf","https://cdn.ssl.com/app/uploads/2020/02/SSLcom-2019-WTEV-SSL-Indp-Acct-Report-and-Mgmt-Assertion-June-2019-REVISED-FINAL.pdf","BDO International Limited","WebTrust","2020.02.12","'-----BEGIN CERTIFICATE----- +MIIF6zCCA9OgAwIBAgIIVrYpzTS8ePYwDQYJKoZIhvcNAQELBQAwgYIxCzAJBgNV +BAYTAlVTMQ4wDAYDVQQIDAVUZXhhczEQMA4GA1UEBwwHSG91c3RvbjEYMBYGA1UE +CgwPU1NMIENvcnBvcmF0aW9uMTcwNQYDVQQDDC5TU0wuY29tIEVWIFJvb3QgQ2Vy +dGlmaWNhdGlvbiBBdXRob3JpdHkgUlNBIFIyMB4XDTE3MDUzMTE4MTQzN1oXDTQy +MDUzMDE4MTQzN1owgYIxCzAJBgNVBAYTAlVTMQ4wDAYDVQQIDAVUZXhhczEQMA4G +A1UEBwwHSG91c3RvbjEYMBYGA1UECgwPU1NMIENvcnBvcmF0aW9uMTcwNQYDVQQD +DC5TU0wuY29tIEVWIFJvb3QgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgUlNBIFIy +MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAjzZlQOHWTcDXtOlG2mvq +M0fNTPl9fb69LT3w23jhhqXZuglXaO1XPqDQCEGD5yhBJB/jchXQARr7XnAjssuf +OePPxU7Gkm0mxnu7s9onnQqG6YE3Bf7wcXHswxzpY6IXFJ3vG2fThVUCAtZJycxa +4bH3bzKfydQ7iEGonL3Lq9ttewkfokxykNorCPzPPFTOZw+oz12WGQvE43LrrdF9 +HSfvkusQv1vrO6/PgN3B0pYEW3p+pKk8OHakYo6gOV7qd89dAFmPZiw+B6KjBSYR +aZfqhbcPlgtLyEDhULouisv3D5oi53+aNxPN8k0TayHRwMwi8qFG9kRpnMphNQcA +b9ZhCBHqurj26bNg5U257J8UZslXWNvNh2n4ioYSA0e/ZhN2rHd9NCSFg83XqpyQ +Gp8hLH94t2S42Oim9HizVcuE0jLEeK6jj2HdzghTreyI/BXkmg3mnxp3zkyPuBQV +PWKchjgGAGYS5Fl2WlPAApiiECtoRHuOec4zSnaqW4EWG7WK2NAAe15itAnWhmMO +pgWVSbooi4iTsjQc2KRVbrcc0N6ZVTsj9CLg+SlmJuwgUHfbSguPvuUCYHBBXtSu +UDkiFCbLsjtzdFVHB3mBOagwE0TlBIqulhMlQg+5U8Sb/M3kHN48+qvWBkofZ6aY +MBzdLNvcGJVXZsb/XItW9XcCAwEAAaNjMGEwDwYDVR0TAQH/BAUwAwEB/zAfBgNV +HSMEGDAWgBT5YLvU49U09rj1BoAlp3PbRmmonjAdBgNVHQ4EFgQU+WC71OPVNPa4 +9QaAJadz20ZpqJ4wDgYDVR0PAQH/BAQDAgGGMA0GCSqGSIb3DQEBCwUAA4ICAQBW +s47LCp1Jjr+kxJG7ZhcFUZh1++VQLHqe8RT6q9OKPv+RKY9ji9i0qVQBDb6Thi/5 +Sm3HXvVX+cpVHBK+Rw82xd9qt9t1wkclf7nxY/hoLVUE0fKNsKTPvDxeH3jnpaAg +cLAExbf3cqfeIg29MyVGjGSSJuM+LmOW2puMPfgYCdcDzH2GguDKBAdRUNf/ktUM +79qGn5nX67evaOI5JpS6aLe/g9Pqemc9YmeuJeVy6OLk7K4S9ksrPJ/psEDzOFSz +/bdoyNrGj1E8svuR3Bznm53htw1yj+KkxKl4+esUrMZDBcJlOSgYAsOCsp0FvmXt +ll9ldDz7CTUue5wT/RsPXcdtgTpWD8w74a8CLyKsRspGPKAcTNZEtF4uXBVmCeEm +Kf7GUmG6sXP/wwyc5WxqlD8UykAWlYTzWamsX0xhk23RO8yilQwipmdnRC652dKK +QbNmC1r7fSOl8hqw/96bg5Qu0T/fkreRrwU7ZcegbLHNYhLDkBvjJc40vG93drEQ +w/cFGsDWr3RiSBd3kmmQYRzelYB0VI8YHMPzA9C/pEN1hlMYegouCRw2n5H9gooi +S9EOUCXdywMMF8mDAAhONU2Ki+3wApRmLER/y5UnlhetCTCstnEXbosX9hwJ1C07 +mKVx01QT2WDz9UtmT/rx7iASjbSsV7FFY6GsdqnC+w== +-----END CERTIFICATE-----'" +"SSL.com","SSL Corporation","","SSL.com Root Certification Authority ECC","75E6DFCBC1685BA8","3417BB06CC6007DA1B961C920B8AB4CE3FAD820E4AA30B9ACBC4A74EBDCEBC65","EDF7703BAE9BC0A42010AB9EF4A92E88B44FF37F1E6810AE1E610AABECB501F3","2016.02.12","2041.02.12","EC secp384r1","ecdsaWithSHA256","Websites;Email","","","Not EV","https://bugzilla.mozilla.org/show_bug.cgi?id=1277336","NSS 3.34","Firefox 58","https://test-dv-ecc.ssl.com","https://expired-ecc-dv.ssl.com","https://revoked-ecc-dv.ssl.com","No","https://www.ssl.com/","USA, Global","","https://www.ssl.com/app/uploads/2019/06/SSLcom_CP_CPS_Version_1_6.pdf","https://cdn.ssl.com/app/uploads/2020/02/SSLcom-2019-WTCA-Indp-Acct-Report-and-Mgmt-Assertion-June-2019-REVISED-FINAL.pdf","https://cdn.ssl.com/app/uploads/2020/02/SSLcom-2019-WTBR-Indp-Acct-Report-and-Mgmt-Assertion-June-2019-REVISED-FINAL.pdf","https://www.cpacanada.ca/generichandlers/CPACHandler.ashx?attachmentid=233836","BDO International Limited","WebTrust","2020.02.12","'-----BEGIN CERTIFICATE----- +MIICjTCCAhSgAwIBAgIIdebfy8FoW6gwCgYIKoZIzj0EAwIwfDELMAkGA1UEBhMC +VVMxDjAMBgNVBAgMBVRleGFzMRAwDgYDVQQHDAdIb3VzdG9uMRgwFgYDVQQKDA9T +U0wgQ29ycG9yYXRpb24xMTAvBgNVBAMMKFNTTC5jb20gUm9vdCBDZXJ0aWZpY2F0 +aW9uIEF1dGhvcml0eSBFQ0MwHhcNMTYwMjEyMTgxNDAzWhcNNDEwMjEyMTgxNDAz +WjB8MQswCQYDVQQGEwJVUzEOMAwGA1UECAwFVGV4YXMxEDAOBgNVBAcMB0hvdXN0 +b24xGDAWBgNVBAoMD1NTTCBDb3Jwb3JhdGlvbjExMC8GA1UEAwwoU1NMLmNvbSBS +b290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IEVDQzB2MBAGByqGSM49AgEGBSuB +BAAiA2IABEVuqVDEpiM2nl8ojRfLliJkP9x6jh3MCLOicSS6jkm5BBtHllirLZXI +7Z4INcgn64mMU1jrYor+8FsPazFSY0E7ic3s7LaNGdM0B9y7xgZ/wkWV7Mt/qCPg +CemB+vNH06NjMGEwHQYDVR0OBBYEFILRhXMw5zUE044CkvvlpNHEIejNMA8GA1Ud +EwEB/wQFMAMBAf8wHwYDVR0jBBgwFoAUgtGFczDnNQTTjgKS++Wk0cQh6M0wDgYD +VR0PAQH/BAQDAgGGMAoGCCqGSM49BAMCA2cAMGQCMG/n61kRpGDPYbCWe+0F+S8T +kdzt5fxQaxFGRrMcIQBiu77D5+jNB5n5DQtdcj7EqgIwH7y6C+IwJPt8bYBVCpk+ +gA0z5Wajs6O7pdWLjwkspl1+4vAHCGht0nxpbl/f5Wpl +-----END CERTIFICATE-----'" +"SSL.com","SSL Corporation","","SSL.com Root Certification Authority RSA","7B2C9BD316803299","85666A562EE0BE5CE925C1D8890A6F76A87EC16D4D7D5F29EA7419CF20123B69","D28ECE720292F9E756C0FF66730ED98496ECE7F2FF408836E8F2899ADADE2B10","2016.02.12","2041.02.12","RSA 4096 bits","SHA256WithRSA","Websites;Email","","","Not EV","https://bugzilla.mozilla.org/show_bug.cgi?id=1277336","NSS 3.34","Firefox 58","https://test-dv-rsa.ssl.com","https://expired-rsa-dv.ssl.com","https://revoked-rsa-dv.ssl.com","No","https://www.ssl.com/","USA, Global","","https://www.ssl.com/app/uploads/2019/06/SSLcom_CP_CPS_Version_1_6.pdf","https://cdn.ssl.com/app/uploads/2020/02/SSLcom-2019-WTCA-Indp-Acct-Report-and-Mgmt-Assertion-June-2019-REVISED-FINAL.pdf","https://cdn.ssl.com/app/uploads/2020/02/SSLcom-2019-WTBR-Indp-Acct-Report-and-Mgmt-Assertion-June-2019-REVISED-FINAL.pdf","https://www.cpacanada.ca/generichandlers/CPACHandler.ashx?attachmentid=233836","BDO International Limited","WebTrust","2020.02.12","'-----BEGIN CERTIFICATE----- +MIIF3TCCA8WgAwIBAgIIeyyb0xaAMpkwDQYJKoZIhvcNAQELBQAwfDELMAkGA1UE +BhMCVVMxDjAMBgNVBAgMBVRleGFzMRAwDgYDVQQHDAdIb3VzdG9uMRgwFgYDVQQK +DA9TU0wgQ29ycG9yYXRpb24xMTAvBgNVBAMMKFNTTC5jb20gUm9vdCBDZXJ0aWZp +Y2F0aW9uIEF1dGhvcml0eSBSU0EwHhcNMTYwMjEyMTczOTM5WhcNNDEwMjEyMTcz +OTM5WjB8MQswCQYDVQQGEwJVUzEOMAwGA1UECAwFVGV4YXMxEDAOBgNVBAcMB0hv +dXN0b24xGDAWBgNVBAoMD1NTTCBDb3Jwb3JhdGlvbjExMC8GA1UEAwwoU1NMLmNv +bSBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IFJTQTCCAiIwDQYJKoZIhvcN +AQEBBQADggIPADCCAgoCggIBAPkP3aMrfcvQKv7sZ4Wm5y4bunfh4/WvpOz6Sl2R +xFdHaxh3a3by/ZPkPQ/CFp4LZsNWlJ4Xg4XOVu/yFv0AYvUiCVToZRdOQbngT0aX +qhvIuG5iXmmxX9sqAn78bMrzQdjt0Oj8P2FI7bADFB0QDksZ4LtO7IZl/zbzXmcC +C52GVWH9ejjt/uIZALdvoVBidXQ8oPrIJZK0bnoix/geoeOy3ZExqysdBP+lSgQ3 +6YWkMyv94tZVNHwZpEpox7Ko07fKoZOI68GXvIz5HdkihCR0xwQ9aqkpk8zruFvh +/l8lqjRYyMEjVJ0bmBHDOJx+PYZspQ9AhnwC9FwCTyjLrnGfDzrIM/4RJTXq/LrF +YD3ZfBjVsqnTdXgDciLKOsMf7yzlLqn6niy2UUb9rwPW6mBo6oUWNmuF6R7As93E +JNyAKoFBbZQ+yODJgUEAnl6/f8UImKIYLEJAs/lvOCdLToD0PYFH4Ih86hzOtXVc +US4cK38acijnALXRdMbX5J+tB5O2UzU1/Dfkw/ZdFr4hc96SCvigY2q8lpJqPvi8 +ZVWb3vUNiSYE/CUapiVpy8JtynziWV+XrOvvLsi81xtZPCvM8hnIk2snYxnP/Okm ++Mpxm3+T/jRnhE6Z6/yzeAkzcLpmpnbtG3PrGqUNxCITIJRWCk4sbE6x/c+cCbqi +M+2HAgMBAAGjYzBhMB0GA1UdDgQWBBTdBAkHovV6fVJTEpKV7jiAJQ2mWTAPBgNV +HRMBAf8EBTADAQH/MB8GA1UdIwQYMBaAFN0ECQei9Xp9UlMSkpXuOIAlDaZZMA4G +A1UdDwEB/wQEAwIBhjANBgkqhkiG9w0BAQsFAAOCAgEAIBgRlCn7Jp0cHh5wYfGV +cpNxJK1ok1iOMq8bs3AD/CUrdIWQPXhq9LmLpZc7tRiRux6n+UBbkflVma8eEdBc +Hadm47GUBwwyOabqG7B52B2ccETjit3E+ZUfijhDPwGFpUenPUayvOUiaPd7nNgs +PgohyC0zrL/FgZkxdMF1ccW+sfAjRfSda/wZY52jvATGGAslu1OJD7OAUN5F7kR/ +q5R4ZJjT9ijdh9hwZXT7DrkT66cPYakylszeu+1jTBi7qUD3oFRuIIhxdRjqerQ0 +cuAjJ3dctpDqhiVAq+8zD8ufgr6iIPv2tS0a5sKFsXQP+8hlAqRSAUfdSSLBv9jr +a6x+3uxjMxW3IwiPxg+NQVrdjsW5j+VFP3jbutIbQLH+cU0/4IGiul607BXgk90I +H37hVZkLId6Tngr75qNJvTYw/ud3sqB1l7UtgYgXZSD32pAAn8lSzDLKNXz1PQ/Y +K9f1JmzJBjSWFupwWRoyeXkLtoh/D1JIPb9s2KJELtFOt3JY04kTlf5Eq/jXixtu +nLwsoFvVagCvXzfh1foQC5ichucmj87w7G6KVwuA406ywKBjYZC6VWg3dGq2ktuf +oYYitmUnDuy2n0Jg5GfCtdpBC8TTi2EbvPofkSvXRAdeuims2cXp71NIWuuA8ShY +Ic2wBlX7Jz9TkHCpBB5XJ7k= +-----END CERTIFICATE-----'" +"SwissSign AG","SwissSign AG","","SwissSign Gold CA - G2","00BB401C43F55E4FB0","62DD0BE9B9F50A163EA0F8E75C053B1ECA57EA55C8688F647C6881F2C8357B95","5EFB7FBB95DA42E3C24458E0A670A05D99BEF6B05F6674F34983F5BD70C64988","2006.10.25","2036.10.25","RSA 4096 bits","SHA1WithRSA","Websites;Email","","","2.16.756.1.89.1.2.1.1","https://bugzilla.mozilla.org/show_bug.cgi?id=343756","NSS 3.11.9","Firefox 2","https://ev-g2-valid-cert-demo.swisssign.net/","https://ev-g2-expired-cert-demo.swisssign.net/","https://ev-g2-revoked-cert-demo.swisssign.net/","","http://www.swisssign.com/","Switzerland","","http://repository.swisssign.com/SwissSign-Gold-CP-CPS.pdf","https://it-tuv.com/wp-content/uploads/2019/12/AA2019121902_Audit_Attestation_TA_CERT__SwissSign_Gold_G2.pdf","https://it-tuv.com/wp-content/uploads/2019/12/AA2019121902_Audit_Attestation_TA_CERT__SwissSign_Gold_G2.pdf","https://it-tuv.com/wp-content/uploads/2019/12/AA2019121902_Audit_Attestation_TA_CERT__SwissSign_Gold_G2.pdf","TÜV Austria","ETSI EN 319 411","2019.12.19","'-----BEGIN CERTIFICATE----- +MIIFujCCA6KgAwIBAgIJALtAHEP1Xk+wMA0GCSqGSIb3DQEBBQUAMEUxCzAJBgNV +BAYTAkNIMRUwEwYDVQQKEwxTd2lzc1NpZ24gQUcxHzAdBgNVBAMTFlN3aXNzU2ln +biBHb2xkIENBIC0gRzIwHhcNMDYxMDI1MDgzMDM1WhcNMzYxMDI1MDgzMDM1WjBF +MQswCQYDVQQGEwJDSDEVMBMGA1UEChMMU3dpc3NTaWduIEFHMR8wHQYDVQQDExZT +d2lzc1NpZ24gR29sZCBDQSAtIEcyMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIIC +CgKCAgEAr+TufoskDhJuqVAtFkQ7kpJcyrhdhJJCEyq8ZVeCQD5XJM1QiyUqt2/8 +76LQwB8CJEoTlo8jE+YoWACjR8cGp4QjK7u9lit/VcyLwVcfDmJlD909Vopz2q5+ +bbqBHH5CjCA12UNNhPqE21Is8w4ndwtrvxEvcnifLtg+5hg3Wipy+dpikJKVyh+c +6bM8K8vzARO/Ws/BtQpgvd21mWRTuKCWs2/iJneRjOBiEAKfNA+k1ZIzUd6+jbqE +emA8atufK+ze3gE/bk3lUIbLtK/tREDFylqM2tIrfKjuvqblCqoOpd8FUrdVxyJd +MmqXl2MT28nbeTZ7hTpKxVKJ+STnnXepgv9VHKVxaSvRAiTysybUa9oEVeXBCsdt +MDeQKuSeFDNeFhdVxVu1yzSJkvGdJo+hB9TGsnhQ2wwMC3wLjEHXuendjIj3o02y +MszYF9rNt85mndT9Xv+9lz4pded+p2JYryU0pUHHPbwNUMoDAw8IWh+Vc3hiv69y +FGkOpeUDDniOJihC8AcLYiAQZzlG+qkDzAQ4embvIIO1jEpWjpEA/I5cgt6IoMPi +aG59je883WX0XaxR7ySArqpWl2/5rX3aYT+YdzylkbYcjCbaZaIJbcHiVOO5ykxM +gI93e2CaHt+28kgeDrpOVG2Y4OGiGqJ3UM/EY5LsRxmd6+ZrzsECAwEAAaOBrDCB +qTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUWyV7 +lqRlUX64OfPAeGZe6Drn8O4wHwYDVR0jBBgwFoAUWyV7lqRlUX64OfPAeGZe6Drn +8O4wRgYDVR0gBD8wPTA7BglghXQBWQECAQEwLjAsBggrBgEFBQcCARYgaHR0cDov +L3JlcG9zaXRvcnkuc3dpc3NzaWduLmNvbS8wDQYJKoZIhvcNAQEFBQADggIBACe6 +45R88a7A3hfm5djV9VSwg/S7zV4Fe0+fdWavPOhWfvxyeDgD2StiGwC5+OlgzczO +UYrHUDFu4Up+GC9pWbY9ZIEr44OE5iKHjn3g7gKZYbge9LgriBIWhMIxkziWMaa5 +O1M/wySTVltpkuzFwbs4AOPsF6m43Md8AYOfMke6UiI0HTJ6CVanfCU2qT1L2sCC +bwq7EsiHSycR+R4tx5M/nttfJmtS2S6K8RTGRI0Vqbe/vd6mGu6uLftIdxf+u+yv +GPUqUfA5hJeVbG4bwyvEdGB5JbAKJ9/fXtI5z0V9QkvfsywexcZdylU6oJxpmo/a +77KwPJ+HbBIrZXAVUjEaJM9vMSNQH4xPjyPDdEFjHFWoFN0+4FFQz/EbMFYOkrCC +hdiDyyJkvC24JdVUorgG6q2SpCSgwYa1ShNqR88uC1aVVMvOmttqtKay20EIhid3 +92qgQmwLOM7XdVAyksLfKzAiSNDVQTglXaTpXZ/GlHXQRf0wl0OPkKsKx4ZzYEpp +Ld6leNcG2mqeSz53OiATIgHQv2ieY2BrNU0LbbqhPcCT4H8js1WtciVORvnSFu+w +ZMEBnunKoGqYDs/YYPIvSbjkQuE4NRb0yG5P94FW6LqjviOvrv1vA+ACOzB2+htt +Qc8Bsem4yWb02ybzOqR08kkkW8mw0FfB+j564ZfJ +-----END CERTIFICATE-----'" +"SwissSign AG","SwissSign AG","","SwissSign Platinum CA - G2","4EB200670C035D4F","3B222E566711E992300DC0B15AB9473DAFDEF8C84D0CEF7D3317B4C1821D1436","E11C7F6B3B396261B347D5BD64B823BD0363D1A40C3F0D471A988143ACFC1CF3","2006.10.25","2036.10.25","RSA 4096 bits","SHA1WithRSA","Email","","","Not EV","https://bugzilla.mozilla.org/show_bug.cgi?id=343756","NSS 3.11.9","Firefox 2","","","","","http://www.swisssign.com/","Switzerland","","http://repository.swisssign.com/SwissSign-Platinum-CP-CPS.pdf","https://it-tuv.com/wp-content/uploads/2020/01/AA2019121901_Audit_Attestation_TA_CERT__SwissSign_Platinum_G2.pdf","","","TÜV Austria","ETSI EN 319 411","2019.12.19","'-----BEGIN CERTIFICATE----- +MIIFwTCCA6mgAwIBAgIITrIAZwwDXU8wDQYJKoZIhvcNAQEFBQAwSTELMAkGA1UE +BhMCQ0gxFTATBgNVBAoTDFN3aXNzU2lnbiBBRzEjMCEGA1UEAxMaU3dpc3NTaWdu +IFBsYXRpbnVtIENBIC0gRzIwHhcNMDYxMDI1MDgzNjAwWhcNMzYxMDI1MDgzNjAw +WjBJMQswCQYDVQQGEwJDSDEVMBMGA1UEChMMU3dpc3NTaWduIEFHMSMwIQYDVQQD +ExpTd2lzc1NpZ24gUGxhdGludW0gQ0EgLSBHMjCCAiIwDQYJKoZIhvcNAQEBBQAD +ggIPADCCAgoCggIBAMrfogLi2vj8Bxax3mCq3pZcZB/HL37PZ/pEQtZ2Y5Wu669y +IIpFR4ZieIbWIDkm9K6j/SPnpZy1IiEZtzeTIsBQnIJ71NUERFzLtMKfkr4k2Htn +IuJpX+UFeNSH2XFwMyVTtIc7KZAoNppVRDBopIOXfw0enHb/FZ1glwCNioUD7IC+ +6ixuEFGSzH7VozPY1kneWCqv9hbrS3uQMpe5up1Y8fhXSQQeol0GcN1x2/ndi5ob +jM89o03Oy3z2u5yg+gnOI2Ky6Q0f4nIoj5+saCB9bzuohTEJfwvH6GXp43gOCWcw +izSC+13gzJ2BbWLuCB4ELE6b7P6pT1/9aXjvCR+htL/68++QHkwFix7qepF6w9fl ++zC8bBsQWJj3Gl/QKTIDE0ZNYWqFTFJ0LwYfexHihJfGmfNtf9dng34TaNhxKFrY +zt3oEBSa/m0jh26OWnA81Y0JAKeqvLAxN23IhBQeW71FYyBrS3SMvds6DsHPWhaP +pZjydomyExI7C3d3rLvlPClKknLKYRorXkzig3R3+jVIeoVNjZpTxN94ypeRSCtF +KwH3HBqi7Ri6Cr2D+m+8jVeTO9TUps4e8aCxzqv9KyiaTxvXw3LbpMS/XUz13XuW +ae5ogObnmLo2t/5u7Su9IPhlGdpVCX4l3P5hYnL5fhgC72O00Puv5TtjjGePAgMB +AAGjgawwgakwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0O +BBYEFFCvzAeHFUdvOMW0ZdHelarp35zMMB8GA1UdIwQYMBaAFFCvzAeHFUdvOMW0 +ZdHelarp35zMMEYGA1UdIAQ/MD0wOwYJYIV0AVkBAQEBMC4wLAYIKwYBBQUHAgEW +IGh0dHA6Ly9yZXBvc2l0b3J5LnN3aXNzc2lnbi5jb20vMA0GCSqGSIb3DQEBBQUA +A4ICAQAIhab1Fgz8RBrBY+D5VUYI/HAcQiiWjrfFwUF1TglxeeVtlspLpYhg0DB0 +uMoI3LQwnkAHFmtllXcBrqS3NQuB2nEVqXQXOHtYyvkv+8Bldo1bAbl93oI9ZLi+ +FHSjClTTLJUYFzX1UWs/j6KWYTl4a0vlpqD4U99REJNi54Av4tHgvI42Rncz7Lj7 +jposiU0xEQ8mngS7twSNC/K5/FqdOxa3L8iYq/6KUFkuozv8KV2LwUvJ4ooTHbG/ +u0IdUt1O2BReEMYxB+9xJ/cbOQncguqLs5WGXv312l0xpuAxtpTmREl0xRbl9x8D +YSjFyMsSoEJL+WuICI20MhjzdZ/EfwBPBZWcoxcCw7NTm6ogOSkrZvqdr16zktK1 +puEa+S1BaYEUtLS17Yk9zvupnTVCRLEcFHOBzyoBNZox1S2PbYTfgE1X4z/FhHXa +icYwu+uPyyIIoK6q8QNsOktNCaUOcsZWayFCTiMlFGiudgp8DAdwZPmaL/YFOSbG +DI8Zf0NebvRbFS/bYV3mZy8/CJT5YLSYMdp08YSTcU1f+2BY0fvEwW2JorsgH51x +kcsymxM9Pn2SUjWskpSi0xjCfMfqr3YFFt1nJ8J+HAciIfNAChs0B0QTwoRqjt8Z +Wr9/6x3iGjjRXK9HkmuAtTClyY3YqzGBH9/CZjfTk6mFhnll0g== +-----END CERTIFICATE-----'" +"SwissSign AG","SwissSign AG","","SwissSign Silver CA - G2","4F1BD42F54BB2F4B","BE6C4DA2BBB9BA59B6F3939768374246C3C005993FA98F020D1DEDBED48A81D5","0E9EF07B096E0E474D06339130CC51C51356BFBF882AE684C43AB5CAAE9371B1","2006.10.25","2036.10.25","RSA 4096 bits","SHA1WithRSA","Websites;Email","","","Not EV","https://bugzilla.mozilla.org/show_bug.cgi?id=343756","NSS 3.11.9","Firefox 2","https://silver-g2-valid-cert-demo.swisssign.net/","https://silver-g2-expired-cert-demo.swisssign.net/","https://silver-g2-revoked-cert-demo.swisssign.net/","","http://www.swisssign.com/","Switzerland","","http://repository.swisssign.com/SwissSign-Silver-CP-CPS.pdf","https://it-tuv.com/wp-content/uploads/2020/01/AA2019121903_Audit_Attestation_TA_CERT__SwissSign_Silver_G2.pdf","https://it-tuv.com/wp-content/uploads/2020/01/AA2019121903_Audit_Attestation_TA_CERT__SwissSign_Silver_G2.pdf","","TÜV Austria","ETSI EN 319 411","2019.12.19","'-----BEGIN CERTIFICATE----- +MIIFvTCCA6WgAwIBAgIITxvUL1S7L0swDQYJKoZIhvcNAQEFBQAwRzELMAkGA1UE +BhMCQ0gxFTATBgNVBAoTDFN3aXNzU2lnbiBBRzEhMB8GA1UEAxMYU3dpc3NTaWdu +IFNpbHZlciBDQSAtIEcyMB4XDTA2MTAyNTA4MzI0NloXDTM2MTAyNTA4MzI0Nlow +RzELMAkGA1UEBhMCQ0gxFTATBgNVBAoTDFN3aXNzU2lnbiBBRzEhMB8GA1UEAxMY +U3dpc3NTaWduIFNpbHZlciBDQSAtIEcyMIICIjANBgkqhkiG9w0BAQEFAAOCAg8A +MIICCgKCAgEAxPGHf9N4Mfc4yfjDmUO8x/e8N+dOcbpLj6VzHVxumK4DV644N0Mv +Fz0fyM5oEMF4rhkDKxD6LHmD9ui5aLlV8gREpzn5/ASLHvGiTSf5YXu6t+WiE7br +YT7QbNHm+/pe7R20nqA1W6GSy/BJkv6FCgU+5tkL4k+73JU3/JHpMjUi0R86TieF +nbAVlDLaYQ1HTWBCrpJH6INaUFjpiou5XaHc3ZlKHzZnu0jkg7Y360g6rw9njxcH +6ATK72oxh9TAtvmUcXtnZLi2kUpCe2UuMGoM9ZDulebyzYLs2aFK7PayS+VFheZt +eJMELpyCbTapxDFkH4aDCyr0NQp4yVXPQbBH6TCfmb5hqAaEuSh6XzjZG6k4sIN/ +c8HDO0gqgg8hm7jMqDXDhBuDsz6+pJVpATqJAHgE2cn0mRmrVn5bi4Y5FZGkECwJ +MoBgs5PAKrYYC51+jUnyEEp/+dVGLxmSo5mnJqy7jDzmDrxHB9xzUfFwZC8I+bRH +HTBsROopN4WSaGa8gzj+ezku01DwH/teYLappvonQfGbGHLy9YR0SslnxFSuSGTf +jNFusB3hB48IHpmccelM2KX3RxIfdNFRnobzwqIjQAtz20um53MGjMGg6cFZrEb6 +5i/4z3GcRm25xBWNOHkDRUjvxF3XCO6HOSKGsg0PWEP3calILv3q1h8CAwEAAaOB +rDCBqTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQU +F6DNweRBtjpbO8tFnb0cwpj6hlgwHwYDVR0jBBgwFoAUF6DNweRBtjpbO8tFnb0c +wpj6hlgwRgYDVR0gBD8wPTA7BglghXQBWQEDAQEwLjAsBggrBgEFBQcCARYgaHR0 +cDovL3JlcG9zaXRvcnkuc3dpc3NzaWduLmNvbS8wDQYJKoZIhvcNAQEFBQADggIB +AHPGgeAn0i0P4JUw4ppBf1AsX19iYamGamkYDHRJ1l2E6kFSGG9YrVBWIGrGvShp +WJHckRE1qTodvBqlYJ7YH39FkWnZfrt4csEGDyrOj4VwYaygzQu4OSlWhDJOhrs9 +xCrZ1x9y7v5RoSJBsXECYxqCsGKrXlcSH9/L3XWgwF15kIwb4FDm3jH+mHtwX6WQ +2K34ArZv02DdQEsixT2tOnqfGhpHkXkzuoLcMmkDlm4fS/Bx/uNncqCxv1yL5PqZ +IseEuRuNI5c/7SXgz2W79WEE790eslpBIlqhn10s6FvJbakMDHiqYMZWjwFaDGi8 +aRl5xB9+lwW/xekkUV7U1UtT7dkjWjYDZaPBA61BMPNGG4WQr2W11bHkFlt4dR2X +em1ZqSqPe97Dh4kQmUlzeMg9vVE1dCrV8X5pGyq7O70luJpaPXJhkGaH7gzWTdQR +dAtq/gsD/KNVV4n+SsuuWxcFyPKNIzFTONItaj+CuY0IavdeQXRuwxF+B6wpYJE/ +OMpXEA29MC/HpeZBoNquBYeaoKRlbEwJDIm6uNO5wJOKMPqN5ZprFQFOZ6raYlY+ +hAhm0sQ2fac+EPyI4NSA5QC9qvNOBqN6avlicuMJT+ubDgEj8Z+7fNzcbBGXJbLy +tGMU0gYqZ4yD9c7qB9iaah7s5Aq7KkzrCWA5zspi2C5u +-----END CERTIFICATE-----'" +"Taiwan-CA Inc. (TWCA)","TAIWAN-CA","Root CA","TWCA Global Root CA","0CBE","59769007F7685D0FCD50872F9F95D5755A5B2B457D81F3692B610A98672F0E1B","ACFC9A26907167C54724AEC55BEF48A122E021EBA22DB83D9B65DD41EBBED1F8","2012.06.27","2030.12.31","RSA 4096 bits","SHA256WithRSA","Websites;Email","","","1.3.6.1.4.1.40869.1.1.22.3","https://bugzilla.mozilla.org/show_bug.cgi?id=810133","NSS 3.15.4","Firefox 27","https://evssldemo3.twca.com.tw/index.html","https://evssldemo5.twca.com.tw/","https://evssldemo4.twca.com.tw/","","http://www.twca.com.tw/Portal/english/coporate_profile/mission.html","Taiwan","https://www.twca.com.tw/picture/file/05311613-TWCA-CP-EN.pdf","https://www.twca.com.tw/picture/file/08141820-TWCAGLOBALCPSV141EN.pdf +https://www.twca.com.tw/picture/file/08141818-TWCAEVSSLCPSV141EN%20.pdf +https://www.twca.com.tw/picture/file/05311616-TWCA-RCA-CPS-EN(V1.3draft).pdf","https://www.cpacanada.ca/generichandlers/cpachandler.ashx?AttachmentID=238799","https://www.cpacanada.ca/generichandlers/cpachandler.ashx?AttachmentID=238800","https://www.cpacanada.ca/generichandlers/cpachandler.ashx?AttachmentID=238801","KPMG","WebTrust","2020.02.24","'-----BEGIN CERTIFICATE----- +MIIFQTCCAymgAwIBAgICDL4wDQYJKoZIhvcNAQELBQAwUTELMAkGA1UEBhMCVFcx +EjAQBgNVBAoTCVRBSVdBTi1DQTEQMA4GA1UECxMHUm9vdCBDQTEcMBoGA1UEAxMT +VFdDQSBHbG9iYWwgUm9vdCBDQTAeFw0xMjA2MjcwNjI4MzNaFw0zMDEyMzExNTU5 +NTlaMFExCzAJBgNVBAYTAlRXMRIwEAYDVQQKEwlUQUlXQU4tQ0ExEDAOBgNVBAsT +B1Jvb3QgQ0ExHDAaBgNVBAMTE1RXQ0EgR2xvYmFsIFJvb3QgQ0EwggIiMA0GCSqG +SIb3DQEBAQUAA4ICDwAwggIKAoICAQCwBdvI64zEbooh745NnHEKH1Jw7W2CnJfF +10xORUnLQEK1EjRsGcJ0pDFfhQKX7EMzClPSnIyOt7h52yvVavKOZsTuKwEHktSz +0ALfUPZVr2YOy+BHYC8rMjk1Ujoog/h7FsYYuGLWRyWRzvAZEk2tY/XTP3VfKfCh +MBwqoJimFb3u/Rk28OKRQ4/6ytYQJ0lM793B8YVwm8rqqFpD/G2Gb3PpN0Wp8DbH +zIh1HrtsBv+baz4X7GGqcXzGHaL3SekVtTzWoWH1EfcFbx39Eb7QMAfCKbAJTibc +46KokWofwpFFiFzlmLhxpRUZyXx1EcxwdE8tmx2RRP1WKKD+u4ZqyPpcC1jcxkt2 +yKsi2XMPpfRaAok/T54igu6idFMqPVMnaR1sjjIsZAAmY2E2TqNGtz99sy2sbZCi +laLOz9qC5wc0GZbpuCGqKX6mOL6OKUohZnkfs8O1CWfe1tQHRvMq2uYiN2DLgbYP +oA/pyJV/v1WRBXrPPRXAb94JlAGD1zQbzECl8LibZ9WYkTunhHiVJqRaCPgrdLQA +BDzfuBSO6N+pjWxnkjMdwLfS7JLIvgm/LCkFbwJrnu+8vyq8W8BQj0FwcYeyTbcE +qYSjMq+u7msXi7Kx/mzhkIyIqJdIzshNy/MGz19qCkKxHh53L46g5pIOBvwFItIm +4TFRfTLcDwIDAQABoyMwITAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB +/zANBgkqhkiG9w0BAQsFAAOCAgEAXzSBdu+WHdXltdkCY4QWwa6gcFGn90xHNcgL +1yg9iXHZqjNB6hQbbCEAwGxCGX6faVsgQt+i0trEfJdLjbDorMjupWkEmQqSpqsn +LhpNgb+E1HAerUf+/UqdM+DyucRFCCEK2mlpc3INvjT+lIutwx4116KD7+U4x6WF +H6vPNOw/KP4M8VeGTslV9xzU2KV9Bnpv1d8Q34FOIWWxtuEXeZVFBs5fzNxGiWNo +RI2T9GRwoD2dKAXDOXC4Ynsg/eTb6QihuJ49CcdP+yz4k3ZB3lLg4VfSnQO8d57+ +nile98FRYB/e2guyLXW3Q0iT5/Z5xoRdgFlglPx4mI88k1HtQJAH32RjJMtOcQWh +15QaiDLxInQirqWm2BJpTGCjAu4r7NRjkgtevi92a6O2JryPA9gK8kxkRr05YuWW +6zRjESjMlfGt7+/cgFhI6Uu46mWs6fyAtbXIRfmswZ/ZuepiiI7E8UuDEq3mi4TW +nsLrgxifarsbJGAzcMzs9zLzXNl5fe+epP7JI8Mk7hWSsT2RTyaGvWZzJBPqpK5j +wa19hAM8EHiGG3njxPPyBJUgriOCxLM6AGK/5jYk4Ve6xx6QddVfP5VhK8E7zeWz +aGHQRiapIVJpLesux+t3zqY6tQMzT3bR51xUAV3LePTJDL/PEo4XLSNolOer/qmy +KwbQBM0= +-----END CERTIFICATE-----'" +"Taiwan-CA Inc. (TWCA)","TAIWAN-CA","Root CA","TWCA Root Certification Authority","01","BFD88FE1101C41AE3E801BF8BE56350EE9BAD1A6B9BD515EDC5C6D5B8711AC44","47434CAA89E03EFA5781EEFB30976AB539E435330C9746C115B8B1E0FB28B3FE","2008.08.28","2030.12.31","RSA 2048 bits","SHA1WithRSA","Websites;Email","","","1.3.6.1.4.1.40869.1.1.22.3","https://bugzilla.mozilla.org/show_bug.cgi?id=518503","NSS 3.12.11","Firefox 6.0.2","https://evssldemo3.twca.com.tw/index.html","https://evssldemo5.twca.com.tw/","https://evssldemo4.twca.com.tw/","","http://www.twca.com.tw/Portal/english/coporate_profile/mission.html","Taiwan","https://www.twca.com.tw/picture/file/05311613-TWCA-CP-EN.pdf","https://www.twca.com.tw/picture/file/08141820-TWCAGLOBALCPSV141EN.pdf +https://www.twca.com.tw/picture/file/08141818-TWCAEVSSLCPSV141EN%20.pdf +https://www.twca.com.tw/picture/file/05311616-TWCA-RCA-CPS-EN(V1.3draft).pdf","https://www.cpacanada.ca/generichandlers/cpachandler.ashx?AttachmentID=238799","https://www.cpacanada.ca/generichandlers/cpachandler.ashx?AttachmentID=238800","https://www.cpacanada.ca/generichandlers/cpachandler.ashx?AttachmentID=238801","KPMG","WebTrust","2020.02.24","'-----BEGIN CERTIFICATE----- +MIIDezCCAmOgAwIBAgIBATANBgkqhkiG9w0BAQUFADBfMQswCQYDVQQGEwJUVzES +MBAGA1UECgwJVEFJV0FOLUNBMRAwDgYDVQQLDAdSb290IENBMSowKAYDVQQDDCFU +V0NBIFJvb3QgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMDgwODI4MDcyNDMz +WhcNMzAxMjMxMTU1OTU5WjBfMQswCQYDVQQGEwJUVzESMBAGA1UECgwJVEFJV0FO +LUNBMRAwDgYDVQQLDAdSb290IENBMSowKAYDVQQDDCFUV0NBIFJvb3QgQ2VydGlm +aWNhdGlvbiBBdXRob3JpdHkwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIB +AQCwfnK4pAOU5qfeCTiRShFAh6d8WWQUe7UREN3+v9XAu1bihSX0NXIP+FPQQeFE +AcK0HMMxQhZHhTMidrIKbw/lJVBPhYa+v5guEGcevhEFhgWQxFnQfHgQsIBct+HH +K3XLfJ+utdGdIzdjp9xCoi2SBBtQwXu4PhvJVgSLL1KbralW6cH/ralYhzC2gfeX +RfwZVzsrb+RH9JlF/h3x+JejiB03HFyP4HYlmlD4oFT/RJB2I9IyxsOrBr/8+7/z +rX2SYgJbKdM1o5OaQ2RgXbL6Mv87BK9NQGr5x+PvI/1ry+UPizgN7gr8/g+YnzAx +3WxSZfmLgb4i4RxYA7qRG4kHAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNV +HRMBAf8EBTADAQH/MB0GA1UdDgQWBBRqOFsmjd6LWvJPelSDGRjjCDWmujANBgkq +hkiG9w0BAQUFAAOCAQEAPNV3PdrfibqHDAhUaiBQkr6wQT25JmSDCi/oQMCXKCeC +MErJk/9q56YAf4lCmtYR5VPOL8zy2gXE/uJQxDqGfczafhAJO5I1KlOy/usrBdls +XebQ79NqZp4VKIV66IIArB6nCWlWQtNoURi+VJq/REG6Sb4gumlc7rh3zc5sH62D +lhh9DrUUOYTxKOkto557HnpyWoOzeW/vtPzQCqVYT0bf+215WfKEIlKuD8z7fDvn +aspHYcN6+NOSBB+4IIThNlQWx0DeO4pz3N/GCUzf7Nr/1FNCocnyYh0igzyXxfkZ +YiesZSLX0zzG5Y6yU8xJzrww/nsOM5D77dIUkR8Hrw== +-----END CERTIFICATE-----'" +"Telia Company (formerly TeliaSonera)","Sonera","","Sonera Class2 CA","1D","7908B40314C138100B518D0735807FFBFCF8518A0095337105BA386B153DD927","304CBA5DA8347B16C2B94BDA9278D3DDD2A0203F3A93C562F59C0BB44B438B41","2001.04.06","2021.04.06","RSA 2048 bits","SHA1WithRSA","Websites;Email","","","Not EV","https://bugzilla.mozilla.org/show_bug.cgi?id=258416","NSS 3.9.6","Firefox 1","https://juolukka.cover.sonera.net:10443/","https://juolukka.cover.sonera.net:10445/","https://juolukka.cover.sonera.net:10444/","","http://www.teliasonera.com","Finland, Europe, Sweden","","https://cps.trust.telia.com/Telia_Root_CPS_v2.5.pdf","https://www.cpacanada.ca/generichandlers/CPACHandler.ashx?attachmentid=240923","https://support.trust.telia.com/download/CA/Telia-2019-2020-WebTrust%20Report-WTBR-20200626.pdf","","KPMG","WebTrust","2020.06.26","'-----BEGIN CERTIFICATE----- +MIIDIDCCAgigAwIBAgIBHTANBgkqhkiG9w0BAQUFADA5MQswCQYDVQQGEwJGSTEP +MA0GA1UEChMGU29uZXJhMRkwFwYDVQQDExBTb25lcmEgQ2xhc3MyIENBMB4XDTAx +MDQwNjA3Mjk0MFoXDTIxMDQwNjA3Mjk0MFowOTELMAkGA1UEBhMCRkkxDzANBgNV +BAoTBlNvbmVyYTEZMBcGA1UEAxMQU29uZXJhIENsYXNzMiBDQTCCASIwDQYJKoZI +hvcNAQEBBQADggEPADCCAQoCggEBAJAXSjWdyvANlsdE+hY3/Ei9vX+ALTU74W+o +Z6m/AxxNjG8yR9VBaKQTBME1DJqEQ/xcHf+Js+gXGM2RX/uJ4+q/Tl18GybTdXnt +5oTjV+WtKcT0OijnpXuENmmz/V52vaMtmdOQTiMofRhj8VQ7Jp12W5dCsv+u8E7s +3TmVToMGf+dJQMjFAbJUWmYdPfz56TwKnoG4cPABi+QjVHzIrviQHgCWctRUz2Ej +vOr7nQKV0ba5cTppCD8PtOFCx4j1P5iop7oc4HFx71hXgVB6XGt0Rg6DA5jDjqhu +8nYybieDwnPz3BjotJPqdURrBGAgcVeHnfO+oJAjPYok4doh28MCAwEAAaMzMDEw +DwYDVR0TAQH/BAUwAwEB/zARBgNVHQ4ECgQISqCqWITTXjwwCwYDVR0PBAQDAgEG +MA0GCSqGSIb3DQEBBQUAA4IBAQBazof5FnIVV0sd2ZvnoiYw7JNn39Yt0jSv9zil +zqsWuasvfDXLrNAPtEwr/IDva4yRXzZ299uzGxnq9LIR/WFxRL8oszodv7ND6J+/ +3DEIcbCdjdY0RzKQxmUk96BKfARzjzlvF4xytb1LyHr4e4PDKE6cCepnP7JnBBvD +FNr450kkkdAdavphOe9r5yF1BgfYErQhIHBCcYHaPJo2vqZbDWpsmh+Re/n570K6 +Tk6ezAyNlNzZRZxe7EJQY670XcSxEtzKO6gunRRaBXW37Ndj4ro1tgQIkejanZz2 +ZrUYrAqmVCY0M9IbwdR/GjqOC6oybtv8TyWf2TLHllpwrN9M +-----END CERTIFICATE-----'" +"Telia Company (formerly TeliaSonera)","TeliaSonera","","TeliaSonera Root CA v1","0095BE16A0F72E46F17B398272FA8BCD96","DD6936FE21F8F077C123A1A521C12224F72255B73E03A7260693E8A24B0FA389","2102FDA7BB10BDD1CCA494A2BE66E32E15572CC73730736E82421FD39C9E26F5","2007.10.18","2032.10.18","RSA 4096 bits","SHA1WithRSA","Websites;Email","","","Not EV","https://bugzilla.mozilla.org/show_bug.cgi?id=539924","NSS 3.16","Firefox 29","https://juolukka.cover.sonera.net:10447/","https://juolukka.cover.sonera.net:10449/","https://juolukka.cover.sonera.net:10448/","","http://www.teliasonera.com","Finland, Europe, Sweden","","https://cps.trust.telia.com/Telia_Root_CPS_v2.5.pdf","https://www.cpacanada.ca/generichandlers/CPACHandler.ashx?attachmentid=240923","https://support.trust.telia.com/download/CA/Telia-2019-2020-WebTrust%20Report-WTBR-20200626.pdf","https://support.trust.telia.com/download/CA/TeliaEVWebTrustReport2018.pdf","KPMG","WebTrust","2020.06.26","'-----BEGIN CERTIFICATE----- +MIIFODCCAyCgAwIBAgIRAJW+FqD3LkbxezmCcvqLzZYwDQYJKoZIhvcNAQEFBQAw +NzEUMBIGA1UECgwLVGVsaWFTb25lcmExHzAdBgNVBAMMFlRlbGlhU29uZXJhIFJv +b3QgQ0EgdjEwHhcNMDcxMDE4MTIwMDUwWhcNMzIxMDE4MTIwMDUwWjA3MRQwEgYD +VQQKDAtUZWxpYVNvbmVyYTEfMB0GA1UEAwwWVGVsaWFTb25lcmEgUm9vdCBDQSB2 +MTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMK+6yfwIaPzaSZVfp3F +VRaRXP3vIb9TgHot0pGMYzHw7CTww6XScnwQbfQ3t+XmfHnqjLWCi65ItqwA3GV1 +7CpNX8GH9SBlK4GoRz6JI5UwFpB/6FcHSOcZrr9FZ7E3GwYq/t75rH2D+1665I+X +Z75Ljo1kB1c4VWk0Nj0TSO9P4tNmHqTPGrdeNjPUtAa9GAH9d4RQAEX1jF3oI7x+ +/jXh7VB7qTCNGdMJjmhnXb88lxhTuylixcpecsHHltTbLaC0H2kD7OriUPEMPPCs +81Mt8Bz17Ww5OXOAFshSsCPN4D7c3TxHoLs1iuKYaIu+5b9y7tL6pe0S7fyYGKkm +dtwoSxAgHNN/Fnct7W+A90m7UwW7XWjH1Mh1Fj+JWov3F0fUTPHSiXk+TT2YqGHe +Oh7S+F4D4MHJHIzTjU3TlTazN19jY5szFPAtJmtTfImMMsJu7D0hADnJoWjiUIMu +sDor8zagrC/kb2HCUQk5PotTubtn2txTuXZZNp1D5SDgPTJghSJRt8czu90VL6R4 +pgd7gUY2BIbdeTXHlSw7sKMXNeVzH7RcWe/a6hBle3rQf5+ztCo3O3CLm1u5K7fs +slESl1MpWtTwEhDcTwK7EpIvYtQ/aUN8Ddb8WHUBiJ1YFkveupD/RwGJBmr2X7KQ +arMCpgKIv7NHfirZ1fpoeDVNAgMBAAGjPzA9MA8GA1UdEwEB/wQFMAMBAf8wCwYD +VR0PBAQDAgEGMB0GA1UdDgQWBBTwj1k4ALP1j5qWDNXr+nuqF+gTEjANBgkqhkiG +9w0BAQUFAAOCAgEAvuRcYk4k9AwI//DTDGjkk0kiP0Qnb7tt3oNmzqjMDfz1mgbl +dxSR651Be5kqhOX//CHBXfDkH1e3damhXwIm/9fH907eT/j3HEbAek9ALCI18Bmx +0GtnLLCo4MBANzX2hFxc469CeP6nyQ1Q6g2EdvZR74NTxnr/DlZJLo961gzmJ1Tj +TQpgcmLNkQfWpb/ImWvtxBnmq0wROMVvMeJuScg/doAmAyYp4Db29iBT4xdwNBed +Y2gea+zDTYa4EzAvXUYNR0PVG6pZDrlcjQZIrXSHX8f8MVRBE+LHIQ6e4B4N4cB7 +Q4WQxYpYxmUKeFfyxiMPAdkgS94P+5KFdSpcc41teyWRyu5FrgZLAMzTsVlQ2jqI +OylDRl6XK1TOU2+NSueW+r9xDkKLfP0ooNBIytrEgUy7onOTJsjrDNYmiLbAJM+7 +vVvrdX3pCI6GMyx5dwlppYn8s3CQh3aP0yK7Qs69cwsgJirQmz1wHiRszYd2qReW +t88NkvuOGKmYSdGe/mBEciG5Ge3C9THxOUiIkCR1VBatzvT4aRRkOfujuLpwQMcn +HL/EVlP6Y2XQ8xwOFvVrhlhNGNTkDY6lnVuR3HYkUD/GKvvZt5y11ubQ2egZixVx +SK236thZiNSQvxaz2emsWWFUyBy6ysHK4bkgTI86k4mloMy/0/Z1pHWWbVY= +-----END CERTIFICATE-----'" +"TrustCor Systems","TrustCor Systems S. de R.L.","TrustCor Certificate Authority","TrustCor ECA-1","0084822C5F1C62D040","5A885DB19C01D912C5759388938CAFBBDF031AB2D48E91EE15589B42971D039C","76C969C4BA3E3C6D056EB708CB6CCF1A1DB9AC3D437309B747B5297BABC31636","2016.02.04","2029.12.31","RSA 2048 bits","SHA256WithRSA","Websites;Email","","","Not EV","https://bugzilla.mozilla.org/show_bug.cgi?id=1231853","NSS 3.34","Firefox 58","https://valid.epki.external.trustcor.ca/","https://expired.epki.external.trustcor.ca/","https://revoked.epki.external.trustcor.ca/","None","http://www.trustcorsystems.com","Canada, Global","https://www.trustcor.com/static/webtrust/TrustCorCA-CP-1.6.0.pdf","https://www.trustcor.com/static/webtrust/TrustCorCA-CPS-1.6.0.pdf","https://www.cpacanada.ca/generichandlers/CPACHandler.ashx?attachmentid=237407","https://www.cpacanada.ca/generichandlers/CPACHandler.ashx?attachmentid=237408","","PAG - Princeton Audit Group","WebTrust","2019.11.15","'-----BEGIN CERTIFICATE----- +MIIEIDCCAwigAwIBAgIJAISCLF8cYtBAMA0GCSqGSIb3DQEBCwUAMIGcMQswCQYD +VQQGEwJQQTEPMA0GA1UECAwGUGFuYW1hMRQwEgYDVQQHDAtQYW5hbWEgQ2l0eTEk +MCIGA1UECgwbVHJ1c3RDb3IgU3lzdGVtcyBTLiBkZSBSLkwuMScwJQYDVQQLDB5U +cnVzdENvciBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkxFzAVBgNVBAMMDlRydXN0Q29y +IEVDQS0xMB4XDTE2MDIwNDEyMzIzM1oXDTI5MTIzMTE3MjgwN1owgZwxCzAJBgNV +BAYTAlBBMQ8wDQYDVQQIDAZQYW5hbWExFDASBgNVBAcMC1BhbmFtYSBDaXR5MSQw +IgYDVQQKDBtUcnVzdENvciBTeXN0ZW1zIFMuIGRlIFIuTC4xJzAlBgNVBAsMHlRy +dXN0Q29yIENlcnRpZmljYXRlIEF1dGhvcml0eTEXMBUGA1UEAwwOVHJ1c3RDb3Ig +RUNBLTEwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDPj+ARtZ+odnbb +3w9U73NjKYKtR8aja+3+XzP4Q1HpGjORMRegdMTUpwHmspI+ap3tDvl0mEDTPwOA +BoJA6LHip1GnHYMma6ve+heRK9jGrB6xnhkB1Zem6g23xFUfJ3zSCNV2HykVh0A5 +3ThFEXXQmqc04L/NyFIduUd+Dbi7xgz2c1cWWn5DkR9VOsZtRASqnKmcp0yJF4Ou +owReUoCLHhIlERnXDH19MURB6tuvsBzvgdAsxZohmz3tQjtQJvLsznFhBmIhVE5/ +wZ0+fyCMgMsq2JdiyIMzkX2woloPV+g7zPIlstR8L+xNxqE6FXrntl019fZISjZF +ZtS6mFjBAgMBAAGjYzBhMB0GA1UdDgQWBBREnkj1zG1I1KBLf/5ZJC+Dl5mahjAf +BgNVHSMEGDAWgBREnkj1zG1I1KBLf/5ZJC+Dl5mahjAPBgNVHRMBAf8EBTADAQH/ +MA4GA1UdDwEB/wQEAwIBhjANBgkqhkiG9w0BAQsFAAOCAQEABT41XBVwm8nHc2Fv +civUwo/yQ10CzsSUuZQRg2dd4mdsdXa/uwyqNsatR5Nj3B5+1t4u/ukZMjgDfxT2 +AHMsWbEhBuH7rBiVDKP/mZb3Kyeb1STMHd3BOuCYRLDE5D53sXOpZCz2HAF8P11F +hcCF5yWPldwX8zyfGm6wyuMdKulMY/okYWLW2n62HGz1Ah3UKt1VkOsqEUc8Ll50 +soIipX1TH0XsJ5F95yIW6MBoNtjG8U+ARDL54dHRHareqKucBK+tIA5kmE2la8BI +WJZpTdwHjFGTot+fDz2LYLSCjaoITmJF4PkL0uDgPFveXHEnJcLmA4GLEFPjx1Wi +tJ/X5g== +-----END CERTIFICATE-----'" +"TrustCor Systems","TrustCor Systems S. de R.L.","TrustCor Certificate Authority","TrustCor RootCert CA-1","00DA9BEC71F303B019","D40E9C86CD8FE468C1776959F49EA774FA548684B6C406F3909261F4DCE2575C","EB38B702A2D8DD36CCC99E8A513384F9C4C104E2AECCE771757E1038B02476CE","2016.02.04","2029.12.31","RSA 2048 bits","SHA256WithRSA","Websites;Email","","","Not EV","https://bugzilla.mozilla.org/show_bug.cgi?id=1231853","NSS 3.34","Firefox 58","https://catest1.trustcor.ca/","https://catest1-expire.trustcor.ca/","https://catest1-revoke.trustcor.ca/","None","http://www.trustcorsystems.com","Canada, Global","https://www.trustcor.com/static/webtrust/TrustCorCA-CP-1.6.0.pdf","https://www.trustcor.com/static/webtrust/TrustCorCA-CPS-1.6.0.pdf","https://www.cpacanada.ca/generichandlers/CPACHandler.ashx?attachmentid=237407","https://www.cpacanada.ca/generichandlers/CPACHandler.ashx?attachmentid=237408","","PAG - Princeton Audit Group","WebTrust","2019.11.15","'-----BEGIN CERTIFICATE----- +MIIEMDCCAxigAwIBAgIJANqb7HHzA7AZMA0GCSqGSIb3DQEBCwUAMIGkMQswCQYD +VQQGEwJQQTEPMA0GA1UECAwGUGFuYW1hMRQwEgYDVQQHDAtQYW5hbWEgQ2l0eTEk +MCIGA1UECgwbVHJ1c3RDb3IgU3lzdGVtcyBTLiBkZSBSLkwuMScwJQYDVQQLDB5U +cnVzdENvciBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkxHzAdBgNVBAMMFlRydXN0Q29y +IFJvb3RDZXJ0IENBLTEwHhcNMTYwMjA0MTIzMjE2WhcNMjkxMjMxMTcyMzE2WjCB +pDELMAkGA1UEBhMCUEExDzANBgNVBAgMBlBhbmFtYTEUMBIGA1UEBwwLUGFuYW1h +IENpdHkxJDAiBgNVBAoMG1RydXN0Q29yIFN5c3RlbXMgUy4gZGUgUi5MLjEnMCUG +A1UECwweVHJ1c3RDb3IgQ2VydGlmaWNhdGUgQXV0aG9yaXR5MR8wHQYDVQQDDBZU +cnVzdENvciBSb290Q2VydCBDQS0xMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB +CgKCAQEAv463leLCJhJrMxnHQFgKq1mqjQCj/IDHUHuO1CAmujIS2CNUSSUQIpid +RtLByZ5OGy4sDjjzGiVoHKZaBeYei0i/mJZ0PmnK6bV4pQa81QBeCQryJ3pS/C3V +seq0iWEk8xoT26nPUu0MJLq5nux+AHT6k61sKZKuUbS701e/s/OojZz0JEsq1pme +9J7+wH5COucLlVPat2gOkEz7cD+PSiyU8ybdY2mplNgQTsVHCJCZGxdNuWxu72CV +EY4hgLW9oHPY0LJ3xEXqWib7ZnZ2+AYfYW0PVcWDtxBWcgYHpfOxGgMFZA6dWorW +hnAbJN7+KIor0Gqw/Hqi3LJ5DotlDwIDAQABo2MwYTAdBgNVHQ4EFgQU7mtJPHo/ +DeOxCbeKyKsZn3MzUOcwHwYDVR0jBBgwFoAU7mtJPHo/DeOxCbeKyKsZn3MzUOcw +DwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAYYwDQYJKoZIhvcNAQELBQAD +ggEBACUY1JGPE+6PHh0RU9otRCkZoB5rMZ5NDp6tPVxBb5UrJKF5mDo4Nvu7Zp5I +/5CQ7z3UuJu0h3U/IJvOcs+hVcFNZKIZBqEHMwwLKeXx6quj7LUKdJDHfXLy11yf +ke+Ri7fc7Waiz45mO7yfOgLgJ90WmMCV1Aqk5IGadZQ1nJBfiDcGrVmVCrDRZ9MZ +yonnMlo2HD6CqFqTvsbQZJG2z9m2GM/bftJlo6bEjhcxwft+dtvTheNYsnd6djts +L1Ac59v2Z3kf9YKVmgenFK+P3CghZwnS1k1aHBkcjndcw5QkPTJrS37UeJSDvjdN +zl/HHk484IkzlQsPpTLWPFp5LBk= +-----END CERTIFICATE-----'" +"TrustCor Systems","TrustCor Systems S. de R.L.","TrustCor Certificate Authority","TrustCor RootCert CA-2","25A1DFCA33CB5902","0753E940378C1BD5E3836E395DAEA5CB839E5046F1BD0EAE1951CF10FEC7C965","93E4635F1277A2CCAB309F141517C773AF4355FCF2FDE8BCF4501943CC005E59","2016.02.04","2034.12.31","RSA 4096 bits","SHA256WithRSA","Websites;Email","","","Not EV","https://bugzilla.mozilla.org/show_bug.cgi?id=1231853","NSS 3.34","Firefox 58","https://catest2.trustcor.ca/","https://catest2-expire.trustcor.ca/","https://catest2-revoke.trustcor.ca","None","http://www.trustcorsystems.com","Canada, Global","https://www.trustcor.com/static/webtrust/TrustCorCA-CP-1.6.0.pdf","https://www.trustcor.com/static/webtrust/TrustCorCA-CPS-1.6.0.pdf","https://www.cpacanada.ca/generichandlers/CPACHandler.ashx?attachmentid=237407","https://www.cpacanada.ca/generichandlers/CPACHandler.ashx?attachmentid=237408","","PAG - Princeton Audit Group","WebTrust","2019.11.15","'-----BEGIN CERTIFICATE----- +MIIGLzCCBBegAwIBAgIIJaHfyjPLWQIwDQYJKoZIhvcNAQELBQAwgaQxCzAJBgNV +BAYTAlBBMQ8wDQYDVQQIDAZQYW5hbWExFDASBgNVBAcMC1BhbmFtYSBDaXR5MSQw +IgYDVQQKDBtUcnVzdENvciBTeXN0ZW1zIFMuIGRlIFIuTC4xJzAlBgNVBAsMHlRy +dXN0Q29yIENlcnRpZmljYXRlIEF1dGhvcml0eTEfMB0GA1UEAwwWVHJ1c3RDb3Ig +Um9vdENlcnQgQ0EtMjAeFw0xNjAyMDQxMjMyMjNaFw0zNDEyMzExNzI2MzlaMIGk +MQswCQYDVQQGEwJQQTEPMA0GA1UECAwGUGFuYW1hMRQwEgYDVQQHDAtQYW5hbWEg +Q2l0eTEkMCIGA1UECgwbVHJ1c3RDb3IgU3lzdGVtcyBTLiBkZSBSLkwuMScwJQYD +VQQLDB5UcnVzdENvciBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkxHzAdBgNVBAMMFlRy +dXN0Q29yIFJvb3RDZXJ0IENBLTIwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIK +AoICAQCnIG7CKqJiJJWQdsg4foDSq8GbZQWU9MEKENUCrO2fk8eHyLAnK0IMPQo+ +QVqedd2NyuCb7GgypGmSaIwLgQ5WoD4a3SwlFIIvl9NkRvRUqdw6VC0xK5mC8tkq +1+9xALgxpL56JAfDQiDyitSSBBtlVkxs1Pu2YVpHI7TYabS3OtB0PAx1oYxOdqHp +2yqlO/rOsP9+aij9JxzIsekp8VduZLTQwRVtDr4uDkbIXvRR/u8OYzo7cbrPb1nK +DOObXUm4TOJXsZiKQlecdu/vvdFoqNL0Cbt3Nb4lggjEFixEIFapRBF37120Hape +az6LMvYHL1cEksr1/p3C6eizjkxLAjHZ5DxIgif3GIJ2SDpxsROhOdUuxTTCHWKF +3wP+TfSvPd9cW436cOGlfifHhi5qjxLGhF5DUVCcGZt45vz27Ud+ez1m7xMTiF88 +oWP7+ayHNZ/zgp6kPwqcMWmLmaSISo5uZk3vFsQPeSghYA2FFn3XVDjxklb9tTNM +g9zXEJ9L/cb4Qr26fHMC4P99zVvh1Kxhe1fVSntb1IVYJ12/+CtgrKAmrhQhJ8Z3 +mjOAPF5GP/fDsaOGM8boXg25NSyqRsGFAnWAoOsk+xWq5Gd/bnc/9ASKL3x74xdh +8N0JqSDIvgmk0H5Ew7IwSjiqqewYmgeCK9u4nBit2uBGF6zPXQIDAQABo2MwYTAd +BgNVHQ4EFgQU2f4hQG6UnrybPZx9mCAZ5YwwYrIwHwYDVR0jBBgwFoAU2f4hQG6U +nrybPZx9mCAZ5YwwYrIwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAYYw +DQYJKoZIhvcNAQELBQADggIBAJ5Fngw7tu/hOsh80QA9z+LqBrWyOrsGS2h60COX +dKcs8AjYeVrXWoSK2BKaG9l9XE1wxaX5q+WjiYndAfrs3fnpkpfbsEZC89NiqpX+ +MWcUaViQCqoL7jcjx1BRtPV+nuN79+TMQjItSQzL/0kMmx40/W5ulop5A7Zv2wnL +/V9lFDfhOPXzYRZY5LVtDQsEGz9QLX+zx3oaFoBg+Iof6Rsqxvm6ARppv9JYx1RX +CI/hOWB3S6xZhBqI8d3LT3jX5+EzLfzuQfogsL7L9ziUwOHQhQ+77Sxzq+3+knYa +ZH9bDTMJBzN7Bj8RpFxwPIXAz+OQqIN3+tvmxYxoZxBnpVIt8MSZj3+/0WvitUfW +2dCFmU2Umw9Lje4AWkcdEQOsQRivh7dvDDqPys/cA8GiCcjl/YBeyGBCARsaU1q7 +N6a3vLqE6R5sGtRk2tRD/pOLS/IseRYQ1JMLiI+h2IYURpFHmygk71dSTlxCnKr3 +Sewn6EAes6aJInKc9Q0ztFijMDvd1GpUk74aTfOTlPf8hAs/hCBcNANExdqtvArB +As8e5ZTZ845b2EzwnexhF7sUMlQMAimTHpKG9n/v55IFDlndmQguLvqcAFLTxWYp +5KeXRKQOKIETNcX2b2TmQcTVL8w0RSXPQQCWPUouwpaYT05KnJe32x+SMsj/D1Fu +1uwJ +-----END CERTIFICATE-----'" +"Trustis","Trustis Limited","Trustis FPS Root CA","Trustis Limited - Trustis FPS Root CA","1B1FADB620F924D3366BF7C7F18CA059","C1B48299ABA5208FE9630ACE55CA68A03EDA5A519C8802A0D3A673BE8F8E557D","EAACB5A71E029ED27FBAC478BCE300DA9DAE8CFEED2F428BC1DAFFA5A133D10A","2003.12.23","2024.01.21","RSA 2048 bits","SHA1WithRSA","Websites;Email","","","Not EV","https://bugzilla.mozilla.org/show_bug.cgi?id=577665","NSS 3.13.6","Firefox 16","https://etsi-411-test-active.trustis.com/","https://etsi-411-test-expired.trustis.com/","https://etsi-411-test-revoked.trustis.com/","","http://www.trustis.com/","UK and Europe","","http://www.trustis.com/pki/fpsia/policy/Trustis-FPS-CPS-v2.0.pdf","https://bug1360184.bmoattachments.org/attachment.cgi?id=9146189","https://bug1360184.bmoattachments.org/attachment.cgi?id=9146189","","LRQA - Lloyds Register Quality Assurance","ETSI EN 319 411","2020.03.30","'-----BEGIN CERTIFICATE----- +MIIDZzCCAk+gAwIBAgIQGx+ttiD5JNM2a/fH8YygWTANBgkqhkiG9w0BAQUFADBF +MQswCQYDVQQGEwJHQjEYMBYGA1UEChMPVHJ1c3RpcyBMaW1pdGVkMRwwGgYDVQQL +ExNUcnVzdGlzIEZQUyBSb290IENBMB4XDTAzMTIyMzEyMTQwNloXDTI0MDEyMTEx +MzY1NFowRTELMAkGA1UEBhMCR0IxGDAWBgNVBAoTD1RydXN0aXMgTGltaXRlZDEc +MBoGA1UECxMTVHJ1c3RpcyBGUFMgUm9vdCBDQTCCASIwDQYJKoZIhvcNAQEBBQAD +ggEPADCCAQoCggEBAMVQe547NdDfxIzNjpvto8A2mfRC6qc+gIMPpqdZh8mQRUN+ +AOqGeSoDvT03mYlmt+WKVoaTnGhLaASMk5MCPjDSNzoiYYkchU59j9WvezX2fihH +iTHcDnlkH5nSW7r+f2C/revnPDgpai/lkQtV/+xvWNUtyd5MZnGPDNcE2gfmHhjj +vSkCqPoc4Vu5g6hBSLwacY3nYuUtsuvffM/bq1rKMfFMIvMFE/eC+XN5DL7XSxzA +0RU8k0Fk0ea+IxciAIleH2ulrG6nS4zto3Lmr2NNL4XSFDWaLk6M6jKYKIahkQlB +OrTh4/L68MkKokHdqeMDx4gVOxzUGpTXn2RZEm0CAwEAAaNTMFEwDwYDVR0TAQH/ +BAUwAwEB/zAfBgNVHSMEGDAWgBS6+nEleYtXQSUhhgtx67JkDoshZzAdBgNVHQ4E +FgQUuvpxJXmLV0ElIYYLceuyZA6LIWcwDQYJKoZIhvcNAQEFBQADggEBAH5Y//01 +GX2cGE+esCu8jowU/yyg2kdbw++BLa8F6nRIW/M+TgfHbcWzk88iNVy2P3UnXwmW +zaD+vkAMXBJV+JOCyinpXj9WV4s4NvdFGkwozZ5BuO1WTISkQMi4sKUraXAEasP4 +1BIy+Q7DsdwyhEQsb8tGD+pmQQ9P8Vilpg0ND2HepZ5dfWWhPBfnqFVO76DH7cZE +f1T1o+CP8HxVIo8ptoGj4W1OLBuAZ+ytIJ8MYmHVl/9D7S3B2l0pKoU/rGXuhg8F +jZBf3+6f9L/uHfuY5H+QK4R4EA5sSVPvFVtlRkpdr7r7OnIdzfYliB6XzCGcKQEN +ZetX2fNXlrtIzYE= +-----END CERTIFICATE-----'" +"Web.com","Network Solutions L.L.C.","","Network Solutions Certificate Authority","57CB336FC25C16E6471617E3903168E0","15F0BA00A3AC7AF3AC884C072B1011A077BD77C097F40164B2F8598ABD83860C","6CA3676B176E34DC6D4B3D352CAC6793C93A6B311646AC0173E050D00A43CCA2","2006.12.01","2029.12.31","RSA 2048 bits","SHA1WithRSA","Websites","","","1.3.6.1.4.1.782.1.2.1.8.1","https://bugzilla.mozilla.org/show_bug.cgi?id=403915","NSS 3.11.10","Firefox 3.0.2","https://networksolutionscertificateauthority-2011.netsolssl.com","https://networksolutionscertificateauthority-2011.netsolssl.com:442","https://networksolutionscertificateauthority-2011.netsolssl.com:444","","http://www.networksolutions.com/","USA, UK","","https://assets.web.com/legal/English/CertificationPracticeStatement.pdf","https://www.cpacanada.ca/generichandlers/CPACHandler.ashx?attachmentid=240874","https://www.cpacanada.ca/generichandlers/CPACHandler.ashx?attachmentid=240873","https://www.cpacanada.ca/generichandlers/CPACHandler.ashx?attachmentid=240874","Ernst & Young, LLP","WebTrust","2020.07.01","'-----BEGIN CERTIFICATE----- +MIID5jCCAs6gAwIBAgIQV8szb8JcFuZHFhfjkDFo4DANBgkqhkiG9w0BAQUFADBi +MQswCQYDVQQGEwJVUzEhMB8GA1UEChMYTmV0d29yayBTb2x1dGlvbnMgTC5MLkMu +MTAwLgYDVQQDEydOZXR3b3JrIFNvbHV0aW9ucyBDZXJ0aWZpY2F0ZSBBdXRob3Jp +dHkwHhcNMDYxMjAxMDAwMDAwWhcNMjkxMjMxMjM1OTU5WjBiMQswCQYDVQQGEwJV +UzEhMB8GA1UEChMYTmV0d29yayBTb2x1dGlvbnMgTC5MLkMuMTAwLgYDVQQDEydO +ZXR3b3JrIFNvbHV0aW9ucyBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkwggEiMA0GCSqG +SIb3DQEBAQUAA4IBDwAwggEKAoIBAQDkvH6SMG3G2I4rC7xGzuAnlt7e+foS0zwz +c7MEL7xxjOWftiJgPl9dzgn/ggwbmlFQGiaJ3dVhXRncEg8tCqJDXRfQNJIg6nPP +OCwGJgl6cvf6UDL4wpPTaaIjzkGxzOTVHzbRijr4jGPiFFlp7Q3Tf2vouAPlT2rl +mGNpSAW+Lv8ztumXWWn4Zxmuk2GWRBXTcrA/vGp97Eh/jcOrqnErU2lBUzS1sLnF +BgrEsEX1QV1uiUV7PTsmjHTC5dLRfbIR1PtYMiKagMnc/Qzpf14Dl847ABSHJ3A4 +qY5usyd2mFHgBeMhqxrVhSI8KbWaFsWAqPS7azCPL0YCorEMIuDTAgMBAAGjgZcw +gZQwHQYDVR0OBBYEFCEwyfsA106Y2oeqKtCnLrFAMadMMA4GA1UdDwEB/wQEAwIB +BjAPBgNVHRMBAf8EBTADAQH/MFIGA1UdHwRLMEkwR6BFoEOGQWh0dHA6Ly9jcmwu +bmV0c29sc3NsLmNvbS9OZXR3b3JrU29sdXRpb25zQ2VydGlmaWNhdGVBdXRob3Jp +dHkuY3JsMA0GCSqGSIb3DQEBBQUAA4IBAQC7rkvnt1frf6ott3NHhWrB5KUd5Oc8 +6fRZZXe1eltajSU24HqXLjjAV2CDmAaDn7l2em5Q4LqILPxFzBiwmZVRDuwduIj/ +h1AcgsLj4DKAv6ALR8jDMe+ZZzKATxcheQxpXN5eNK4CtSbqUN9/GGUsyfJj4akH +/nxxH2szJGoeBfcFaMBqEssuXmHLrijTfsK0ZpEmXzwuJF/LWA/rKOyvEZbz3Htv +wKeI8lN3s2Berq4o2jUsbzRF0ybh3uxbTydrFny9RAQYgrOJeRcQcT16ohZO9QHN +pGxlaKFJdlxDydi8NmdspZS11My5vWo1ViHe2MPr+8ukYEywVaCge1ey +-----END CERTIFICATE-----'" diff --git a/core/third-party/chacha.js b/core/third-party/chacha.js new file mode 100644 index 0000000..4fa0294 --- /dev/null +++ b/core/third-party/chacha.js @@ -0,0 +1,76 @@ +/* This is free and unencumbered software released into the public domain. */ +"use strict"; +const CHACHA_ROUNDS = 20; +const CHACHA_KEYSIZE = 32; +const CHACHA_IVSIZE = 8; + +/** + * Create a new ChaCha generator seeded from the given KEY and IV. + * Both KEY and IV must be ArrayBuffer objects of at least the + * appropriate byte lengths (CHACHA_KEYSIZE, CHACHA_IVSIZE). Bytes + * beyond the specified length are ignored. + * + * Returns a closure that takes no arguments. This closure, when + * invoked, returns a 64-byte ArrayBuffer of the next 64 bytes of + * output. Note: This buffer object is "owned" by the closure, and + * the same buffer object is always returned, each time filled with + * fresh output. + */ +function ChaCha(key, iv) { + if (key.byteLength < CHACHA_KEYSIZE) + throw new Error('key too short'); + if (iv.byteLength < CHACHA_IVSIZE) + throw new Error('IV too short'); + const state = new Uint32Array(16); + let view = new DataView(key); + state[ 0] = 0x61707865; // "expand 32-byte k" + state[ 1] = 0x3320646e; // + state[ 2] = 0x79622d32; // + state[ 3] = 0x6b206574; // + state[ 4] = view.getUint32( 0, true); + state[ 5] = view.getUint32( 4, true); + state[ 6] = view.getUint32( 8, true); + state[ 7] = view.getUint32(12, true); + state[ 8] = view.getUint32(16, true); + state[ 9] = view.getUint32(20, true); + state[10] = view.getUint32(24, true); + state[11] = view.getUint32(28, true); + view = new DataView(iv); + state[14] = view.getUint32( 0, true); + state[15] = view.getUint32( 4, true); + + /* Generator */ + const output = new Uint32Array(16); + const outview = new DataView(output.buffer); + return function() { + function quarterround(x, a, b, c, d) { + function rotate(v, n) { return (v << n) | (v >>> (32 - n)); } + x[a] += x[b]; x[d] = rotate(x[d] ^ x[a], 16); + x[c] += x[d]; x[b] = rotate(x[b] ^ x[c], 12); + x[a] += x[b]; x[d] = rotate(x[d] ^ x[a], 8); + x[c] += x[d]; x[b] = rotate(x[b] ^ x[c], 7); + } + output.set(state); + for (let i = 0; i < CHACHA_ROUNDS; i += 2) { + quarterround(output, 0, 4, 8, 12); + quarterround(output, 1, 5, 9, 13); + quarterround(output, 2, 6, 10, 14); + quarterround(output, 3, 7, 11, 15); + quarterround(output, 0, 5, 10, 15); + quarterround(output, 1, 6, 11, 12); + quarterround(output, 2, 7, 8, 13); + quarterround(output, 3, 4, 9, 14); + } + for (let i = 0; i < 16; i++) + outview.setUint32(i * 4, output[i] + state[i], true); + state[12]++; + if (state[12] == 0) { + state[13]++; + if (state[13] == 0) { + /* One zebibyte of output reached! */ + throw new Error('output exhausted'); + } + } + return output.buffer; + } +} diff --git a/core/third-party/cose.js b/core/third-party/cose.js new file mode 100644 index 0000000..4e7d27f --- /dev/null +++ b/core/third-party/cose.js @@ -0,0 +1,36781 @@ +(function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.COSE = f()}})(function(){var define,module,exports;return (function(){function r(e,n,t){function o(i,f){if(!n[i]){if(!e[i]){var c="function"==typeof require&&require;if(!f&&c)return c(i,!0);if(u)return u(i,!0);var a=new Error("Cannot find module '"+i+"'");throw a.code="MODULE_NOT_FOUND",a}var p=n[i]={exports:{}};e[i][0].call(p.exports,function(r){var n=e[i][1][r];return o(n||r)},p,p.exports,r,e,n,t)}return n[i].exports}for(var u="function"==typeof require&&require,i=0;i> 6]; + const primitive = (tag & 0x20) === 0; + + // Multi-octet tag - load + if ((tag & 0x1f) === 0x1f) { + let oct = tag; + tag = 0; + while ((oct & 0x80) === 0x80) { + oct = buf.readUInt8(fail); + if (buf.isError(oct)) + return oct; + + tag <<= 7; + tag |= oct & 0x7f; + } + } else { + tag &= 0x1f; + } + const tagStr = der.tag[tag]; + + return { + cls: cls, + primitive: primitive, + tag: tag, + tagStr: tagStr + }; +} + +function derDecodeLen(buf, primitive, fail) { + let len = buf.readUInt8(fail); + if (buf.isError(len)) + return len; + + // Indefinite form + if (!primitive && len === 0x80) + return null; + + // Definite form + if ((len & 0x80) === 0) { + // Short form + return len; + } + + // Long form + const num = len & 0x7f; + if (num > 4) + return buf.error('length octect is too long'); + + len = 0; + for (let i = 0; i < num; i++) { + len <<= 8; + const j = buf.readUInt8(fail); + if (buf.isError(j)) + return j; + len |= j; + } + + return len; +} + +},{"../base/buffer":3,"../base/node":5,"../constants/der":7,"bn.js":15,"inherits":143}],10:[function(require,module,exports){ +'use strict'; + +const decoders = exports; + +decoders.der = require('./der'); +decoders.pem = require('./pem'); + +},{"./der":9,"./pem":11}],11:[function(require,module,exports){ +'use strict'; + +const inherits = require('inherits'); +const Buffer = require('safer-buffer').Buffer; + +const DERDecoder = require('./der'); + +function PEMDecoder(entity) { + DERDecoder.call(this, entity); + this.enc = 'pem'; +} +inherits(PEMDecoder, DERDecoder); +module.exports = PEMDecoder; + +PEMDecoder.prototype.decode = function decode(data, options) { + const lines = data.toString().split(/[\r\n]+/g); + + const label = options.label.toUpperCase(); + + const re = /^-----(BEGIN|END) ([^-]+)-----$/; + let start = -1; + let end = -1; + for (let i = 0; i < lines.length; i++) { + const match = lines[i].match(re); + if (match === null) + continue; + + if (match[2] !== label) + continue; + + if (start === -1) { + if (match[1] !== 'BEGIN') + break; + start = i; + } else { + if (match[1] !== 'END') + break; + end = i; + break; + } + } + if (start === -1 || end === -1) + throw new Error('PEM section not found for: ' + label); + + const base64 = lines.slice(start + 1, end).join(''); + // Remove excessive symbols + base64.replace(/[^a-z0-9+/=]+/gi, ''); + + const input = Buffer.from(base64, 'base64'); + return DERDecoder.prototype.decode.call(this, input, options); +}; + +},{"./der":9,"inherits":143,"safer-buffer":180}],12:[function(require,module,exports){ +'use strict'; + +const inherits = require('inherits'); +const Buffer = require('safer-buffer').Buffer; +const Node = require('../base/node'); + +// Import DER constants +const der = require('../constants/der'); + +function DEREncoder(entity) { + this.enc = 'der'; + this.name = entity.name; + this.entity = entity; + + // Construct base tree + this.tree = new DERNode(); + this.tree._init(entity.body); +} +module.exports = DEREncoder; + +DEREncoder.prototype.encode = function encode(data, reporter) { + return this.tree._encode(data, reporter).join(); +}; + +// Tree methods + +function DERNode(parent) { + Node.call(this, 'der', parent); +} +inherits(DERNode, Node); + +DERNode.prototype._encodeComposite = function encodeComposite(tag, + primitive, + cls, + content) { + const encodedTag = encodeTag(tag, primitive, cls, this.reporter); + + // Short form + if (content.length < 0x80) { + const header = Buffer.alloc(2); + header[0] = encodedTag; + header[1] = content.length; + return this._createEncoderBuffer([ header, content ]); + } + + // Long form + // Count octets required to store length + let lenOctets = 1; + for (let i = content.length; i >= 0x100; i >>= 8) + lenOctets++; + + const header = Buffer.alloc(1 + 1 + lenOctets); + header[0] = encodedTag; + header[1] = 0x80 | lenOctets; + + for (let i = 1 + lenOctets, j = content.length; j > 0; i--, j >>= 8) + header[i] = j & 0xff; + + return this._createEncoderBuffer([ header, content ]); +}; + +DERNode.prototype._encodeStr = function encodeStr(str, tag) { + if (tag === 'bitstr') { + return this._createEncoderBuffer([ str.unused | 0, str.data ]); + } else if (tag === 'bmpstr') { + const buf = Buffer.alloc(str.length * 2); + for (let i = 0; i < str.length; i++) { + buf.writeUInt16BE(str.charCodeAt(i), i * 2); + } + return this._createEncoderBuffer(buf); + } else if (tag === 'numstr') { + if (!this._isNumstr(str)) { + return this.reporter.error('Encoding of string type: numstr supports ' + + 'only digits and space'); + } + return this._createEncoderBuffer(str); + } else if (tag === 'printstr') { + if (!this._isPrintstr(str)) { + return this.reporter.error('Encoding of string type: printstr supports ' + + 'only latin upper and lower case letters, ' + + 'digits, space, apostrophe, left and rigth ' + + 'parenthesis, plus sign, comma, hyphen, ' + + 'dot, slash, colon, equal sign, ' + + 'question mark'); + } + return this._createEncoderBuffer(str); + } else if (/str$/.test(tag)) { + return this._createEncoderBuffer(str); + } else if (tag === 'objDesc') { + return this._createEncoderBuffer(str); + } else { + return this.reporter.error('Encoding of string type: ' + tag + + ' unsupported'); + } +}; + +DERNode.prototype._encodeObjid = function encodeObjid(id, values, relative) { + if (typeof id === 'string') { + if (!values) + return this.reporter.error('string objid given, but no values map found'); + if (!values.hasOwnProperty(id)) + return this.reporter.error('objid not found in values map'); + id = values[id].split(/[\s.]+/g); + for (let i = 0; i < id.length; i++) + id[i] |= 0; + } else if (Array.isArray(id)) { + id = id.slice(); + for (let i = 0; i < id.length; i++) + id[i] |= 0; + } + + if (!Array.isArray(id)) { + return this.reporter.error('objid() should be either array or string, ' + + 'got: ' + JSON.stringify(id)); + } + + if (!relative) { + if (id[1] >= 40) + return this.reporter.error('Second objid identifier OOB'); + id.splice(0, 2, id[0] * 40 + id[1]); + } + + // Count number of octets + let size = 0; + for (let i = 0; i < id.length; i++) { + let ident = id[i]; + for (size++; ident >= 0x80; ident >>= 7) + size++; + } + + const objid = Buffer.alloc(size); + let offset = objid.length - 1; + for (let i = id.length - 1; i >= 0; i--) { + let ident = id[i]; + objid[offset--] = ident & 0x7f; + while ((ident >>= 7) > 0) + objid[offset--] = 0x80 | (ident & 0x7f); + } + + return this._createEncoderBuffer(objid); +}; + +function two(num) { + if (num < 10) + return '0' + num; + else + return num; +} + +DERNode.prototype._encodeTime = function encodeTime(time, tag) { + let str; + const date = new Date(time); + + if (tag === 'gentime') { + str = [ + two(date.getUTCFullYear()), + two(date.getUTCMonth() + 1), + two(date.getUTCDate()), + two(date.getUTCHours()), + two(date.getUTCMinutes()), + two(date.getUTCSeconds()), + 'Z' + ].join(''); + } else if (tag === 'utctime') { + str = [ + two(date.getUTCFullYear() % 100), + two(date.getUTCMonth() + 1), + two(date.getUTCDate()), + two(date.getUTCHours()), + two(date.getUTCMinutes()), + two(date.getUTCSeconds()), + 'Z' + ].join(''); + } else { + this.reporter.error('Encoding ' + tag + ' time is not supported yet'); + } + + return this._encodeStr(str, 'octstr'); +}; + +DERNode.prototype._encodeNull = function encodeNull() { + return this._createEncoderBuffer(''); +}; + +DERNode.prototype._encodeInt = function encodeInt(num, values) { + if (typeof num === 'string') { + if (!values) + return this.reporter.error('String int or enum given, but no values map'); + if (!values.hasOwnProperty(num)) { + return this.reporter.error('Values map doesn\'t contain: ' + + JSON.stringify(num)); + } + num = values[num]; + } + + // Bignum, assume big endian + if (typeof num !== 'number' && !Buffer.isBuffer(num)) { + const numArray = num.toArray(); + if (!num.sign && numArray[0] & 0x80) { + numArray.unshift(0); + } + num = Buffer.from(numArray); + } + + if (Buffer.isBuffer(num)) { + let size = num.length; + if (num.length === 0) + size++; + + const out = Buffer.alloc(size); + num.copy(out); + if (num.length === 0) + out[0] = 0; + return this._createEncoderBuffer(out); + } + + if (num < 0x80) + return this._createEncoderBuffer(num); + + if (num < 0x100) + return this._createEncoderBuffer([0, num]); + + let size = 1; + for (let i = num; i >= 0x100; i >>= 8) + size++; + + const out = new Array(size); + for (let i = out.length - 1; i >= 0; i--) { + out[i] = num & 0xff; + num >>= 8; + } + if(out[0] & 0x80) { + out.unshift(0); + } + + return this._createEncoderBuffer(Buffer.from(out)); +}; + +DERNode.prototype._encodeBool = function encodeBool(value) { + return this._createEncoderBuffer(value ? 0xff : 0); +}; + +DERNode.prototype._use = function use(entity, obj) { + if (typeof entity === 'function') + entity = entity(obj); + return entity._getEncoder('der').tree; +}; + +DERNode.prototype._skipDefault = function skipDefault(dataBuffer, reporter, parent) { + const state = this._baseState; + let i; + if (state['default'] === null) + return false; + + const data = dataBuffer.join(); + if (state.defaultBuffer === undefined) + state.defaultBuffer = this._encodeValue(state['default'], reporter, parent).join(); + + if (data.length !== state.defaultBuffer.length) + return false; + + for (i=0; i < data.length; i++) + if (data[i] !== state.defaultBuffer[i]) + return false; + + return true; +}; + +// Utility methods + +function encodeTag(tag, primitive, cls, reporter) { + let res; + + if (tag === 'seqof') + tag = 'seq'; + else if (tag === 'setof') + tag = 'set'; + + if (der.tagByName.hasOwnProperty(tag)) + res = der.tagByName[tag]; + else if (typeof tag === 'number' && (tag | 0) === tag) + res = tag; + else + return reporter.error('Unknown tag: ' + tag); + + if (res >= 0x1f) + return reporter.error('Multi-octet tag encoding unsupported'); + + if (!primitive) + res |= 0x20; + + res |= (der.tagClassByName[cls || 'universal'] << 6); + + return res; +} + +},{"../base/node":5,"../constants/der":7,"inherits":143,"safer-buffer":180}],13:[function(require,module,exports){ +'use strict'; + +const encoders = exports; + +encoders.der = require('./der'); +encoders.pem = require('./pem'); + +},{"./der":12,"./pem":14}],14:[function(require,module,exports){ +'use strict'; + +const inherits = require('inherits'); + +const DEREncoder = require('./der'); + +function PEMEncoder(entity) { + DEREncoder.call(this, entity); + this.enc = 'pem'; +} +inherits(PEMEncoder, DEREncoder); +module.exports = PEMEncoder; + +PEMEncoder.prototype.encode = function encode(data, options) { + const buf = DEREncoder.prototype.encode.call(this, data); + + const p = buf.toString('base64'); + const out = [ '-----BEGIN ' + options.label + '-----' ]; + for (let i = 0; i < p.length; i += 64) + out.push(p.slice(i, i + 64)); + out.push('-----END ' + options.label + '-----'); + return out.join('\n'); +}; + +},{"./der":12,"inherits":143}],15:[function(require,module,exports){ +(function (module, exports) { + 'use strict'; + + // Utils + function assert (val, msg) { + if (!val) throw new Error(msg || 'Assertion failed'); + } + + // Could use `inherits` module, but don't want to move from single file + // architecture yet. + function inherits (ctor, superCtor) { + ctor.super_ = superCtor; + var TempCtor = function () {}; + TempCtor.prototype = superCtor.prototype; + ctor.prototype = new TempCtor(); + ctor.prototype.constructor = ctor; + } + + // BN + + function BN (number, base, endian) { + if (BN.isBN(number)) { + return number; + } + + this.negative = 0; + this.words = null; + this.length = 0; + + // Reduction context + this.red = null; + + if (number !== null) { + if (base === 'le' || base === 'be') { + endian = base; + base = 10; + } + + this._init(number || 0, base || 10, endian || 'be'); + } + } + if (typeof module === 'object') { + module.exports = BN; + } else { + exports.BN = BN; + } + + BN.BN = BN; + BN.wordSize = 26; + + var Buffer; + try { + if (typeof window !== 'undefined' && typeof window.Buffer !== 'undefined') { + Buffer = window.Buffer; + } else { + Buffer = require('buffer').Buffer; + } + } catch (e) { + } + + BN.isBN = function isBN (num) { + if (num instanceof BN) { + return true; + } + + return num !== null && typeof num === 'object' && + num.constructor.wordSize === BN.wordSize && Array.isArray(num.words); + }; + + BN.max = function max (left, right) { + if (left.cmp(right) > 0) return left; + return right; + }; + + BN.min = function min (left, right) { + if (left.cmp(right) < 0) return left; + return right; + }; + + BN.prototype._init = function init (number, base, endian) { + if (typeof number === 'number') { + return this._initNumber(number, base, endian); + } + + if (typeof number === 'object') { + return this._initArray(number, base, endian); + } + + if (base === 'hex') { + base = 16; + } + assert(base === (base | 0) && base >= 2 && base <= 36); + + number = number.toString().replace(/\s+/g, ''); + var start = 0; + if (number[0] === '-') { + start++; + this.negative = 1; + } + + if (start < number.length) { + if (base === 16) { + this._parseHex(number, start, endian); + } else { + this._parseBase(number, base, start); + if (endian === 'le') { + this._initArray(this.toArray(), base, endian); + } + } + } + }; + + BN.prototype._initNumber = function _initNumber (number, base, endian) { + if (number < 0) { + this.negative = 1; + number = -number; + } + if (number < 0x4000000) { + this.words = [ number & 0x3ffffff ]; + this.length = 1; + } else if (number < 0x10000000000000) { + this.words = [ + number & 0x3ffffff, + (number / 0x4000000) & 0x3ffffff + ]; + this.length = 2; + } else { + assert(number < 0x20000000000000); // 2 ^ 53 (unsafe) + this.words = [ + number & 0x3ffffff, + (number / 0x4000000) & 0x3ffffff, + 1 + ]; + this.length = 3; + } + + if (endian !== 'le') return; + + // Reverse the bytes + this._initArray(this.toArray(), base, endian); + }; + + BN.prototype._initArray = function _initArray (number, base, endian) { + // Perhaps a Uint8Array + assert(typeof number.length === 'number'); + if (number.length <= 0) { + this.words = [ 0 ]; + this.length = 1; + return this; + } + + this.length = Math.ceil(number.length / 3); + this.words = new Array(this.length); + for (var i = 0; i < this.length; i++) { + this.words[i] = 0; + } + + var j, w; + var off = 0; + if (endian === 'be') { + for (i = number.length - 1, j = 0; i >= 0; i -= 3) { + w = number[i] | (number[i - 1] << 8) | (number[i - 2] << 16); + this.words[j] |= (w << off) & 0x3ffffff; + this.words[j + 1] = (w >>> (26 - off)) & 0x3ffffff; + off += 24; + if (off >= 26) { + off -= 26; + j++; + } + } + } else if (endian === 'le') { + for (i = 0, j = 0; i < number.length; i += 3) { + w = number[i] | (number[i + 1] << 8) | (number[i + 2] << 16); + this.words[j] |= (w << off) & 0x3ffffff; + this.words[j + 1] = (w >>> (26 - off)) & 0x3ffffff; + off += 24; + if (off >= 26) { + off -= 26; + j++; + } + } + } + return this.strip(); + }; + + function parseHex4Bits (string, index) { + var c = string.charCodeAt(index); + // 'A' - 'F' + if (c >= 65 && c <= 70) { + return c - 55; + // 'a' - 'f' + } else if (c >= 97 && c <= 102) { + return c - 87; + // '0' - '9' + } else { + return (c - 48) & 0xf; + } + } + + function parseHexByte (string, lowerBound, index) { + var r = parseHex4Bits(string, index); + if (index - 1 >= lowerBound) { + r |= parseHex4Bits(string, index - 1) << 4; + } + return r; + } + + BN.prototype._parseHex = function _parseHex (number, start, endian) { + // Create possibly bigger array to ensure that it fits the number + this.length = Math.ceil((number.length - start) / 6); + this.words = new Array(this.length); + for (var i = 0; i < this.length; i++) { + this.words[i] = 0; + } + + // 24-bits chunks + var off = 0; + var j = 0; + + var w; + if (endian === 'be') { + for (i = number.length - 1; i >= start; i -= 2) { + w = parseHexByte(number, start, i) << off; + this.words[j] |= w & 0x3ffffff; + if (off >= 18) { + off -= 18; + j += 1; + this.words[j] |= w >>> 26; + } else { + off += 8; + } + } + } else { + var parseLength = number.length - start; + for (i = parseLength % 2 === 0 ? start + 1 : start; i < number.length; i += 2) { + w = parseHexByte(number, start, i) << off; + this.words[j] |= w & 0x3ffffff; + if (off >= 18) { + off -= 18; + j += 1; + this.words[j] |= w >>> 26; + } else { + off += 8; + } + } + } + + this.strip(); + }; + + function parseBase (str, start, end, mul) { + var r = 0; + var len = Math.min(str.length, end); + for (var i = start; i < len; i++) { + var c = str.charCodeAt(i) - 48; + + r *= mul; + + // 'a' + if (c >= 49) { + r += c - 49 + 0xa; + + // 'A' + } else if (c >= 17) { + r += c - 17 + 0xa; + + // '0' - '9' + } else { + r += c; + } + } + return r; + } + + BN.prototype._parseBase = function _parseBase (number, base, start) { + // Initialize as zero + this.words = [ 0 ]; + this.length = 1; + + // Find length of limb in base + for (var limbLen = 0, limbPow = 1; limbPow <= 0x3ffffff; limbPow *= base) { + limbLen++; + } + limbLen--; + limbPow = (limbPow / base) | 0; + + var total = number.length - start; + var mod = total % limbLen; + var end = Math.min(total, total - mod) + start; + + var word = 0; + for (var i = start; i < end; i += limbLen) { + word = parseBase(number, i, i + limbLen, base); + + this.imuln(limbPow); + if (this.words[0] + word < 0x4000000) { + this.words[0] += word; + } else { + this._iaddn(word); + } + } + + if (mod !== 0) { + var pow = 1; + word = parseBase(number, i, number.length, base); + + for (i = 0; i < mod; i++) { + pow *= base; + } + + this.imuln(pow); + if (this.words[0] + word < 0x4000000) { + this.words[0] += word; + } else { + this._iaddn(word); + } + } + + this.strip(); + }; + + BN.prototype.copy = function copy (dest) { + dest.words = new Array(this.length); + for (var i = 0; i < this.length; i++) { + dest.words[i] = this.words[i]; + } + dest.length = this.length; + dest.negative = this.negative; + dest.red = this.red; + }; + + BN.prototype.clone = function clone () { + var r = new BN(null); + this.copy(r); + return r; + }; + + BN.prototype._expand = function _expand (size) { + while (this.length < size) { + this.words[this.length++] = 0; + } + return this; + }; + + // Remove leading `0` from `this` + BN.prototype.strip = function strip () { + while (this.length > 1 && this.words[this.length - 1] === 0) { + this.length--; + } + return this._normSign(); + }; + + BN.prototype._normSign = function _normSign () { + // -0 = 0 + if (this.length === 1 && this.words[0] === 0) { + this.negative = 0; + } + return this; + }; + + BN.prototype.inspect = function inspect () { + return (this.red ? ''; + }; + + /* + + var zeros = []; + var groupSizes = []; + var groupBases = []; + + var s = ''; + var i = -1; + while (++i < BN.wordSize) { + zeros[i] = s; + s += '0'; + } + groupSizes[0] = 0; + groupSizes[1] = 0; + groupBases[0] = 0; + groupBases[1] = 0; + var base = 2 - 1; + while (++base < 36 + 1) { + var groupSize = 0; + var groupBase = 1; + while (groupBase < (1 << BN.wordSize) / base) { + groupBase *= base; + groupSize += 1; + } + groupSizes[base] = groupSize; + groupBases[base] = groupBase; + } + + */ + + var zeros = [ + '', + '0', + '00', + '000', + '0000', + '00000', + '000000', + '0000000', + '00000000', + '000000000', + '0000000000', + '00000000000', + '000000000000', + '0000000000000', + '00000000000000', + '000000000000000', + '0000000000000000', + '00000000000000000', + '000000000000000000', + '0000000000000000000', + '00000000000000000000', + '000000000000000000000', + '0000000000000000000000', + '00000000000000000000000', + '000000000000000000000000', + '0000000000000000000000000' + ]; + + var groupSizes = [ + 0, 0, + 25, 16, 12, 11, 10, 9, 8, + 8, 7, 7, 7, 7, 6, 6, + 6, 6, 6, 6, 6, 5, 5, + 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5 + ]; + + var groupBases = [ + 0, 0, + 33554432, 43046721, 16777216, 48828125, 60466176, 40353607, 16777216, + 43046721, 10000000, 19487171, 35831808, 62748517, 7529536, 11390625, + 16777216, 24137569, 34012224, 47045881, 64000000, 4084101, 5153632, + 6436343, 7962624, 9765625, 11881376, 14348907, 17210368, 20511149, + 24300000, 28629151, 33554432, 39135393, 45435424, 52521875, 60466176 + ]; + + BN.prototype.toString = function toString (base, padding) { + base = base || 10; + padding = padding | 0 || 1; + + var out; + if (base === 16 || base === 'hex') { + out = ''; + var off = 0; + var carry = 0; + for (var i = 0; i < this.length; i++) { + var w = this.words[i]; + var word = (((w << off) | carry) & 0xffffff).toString(16); + carry = (w >>> (24 - off)) & 0xffffff; + if (carry !== 0 || i !== this.length - 1) { + out = zeros[6 - word.length] + word + out; + } else { + out = word + out; + } + off += 2; + if (off >= 26) { + off -= 26; + i--; + } + } + if (carry !== 0) { + out = carry.toString(16) + out; + } + while (out.length % padding !== 0) { + out = '0' + out; + } + if (this.negative !== 0) { + out = '-' + out; + } + return out; + } + + if (base === (base | 0) && base >= 2 && base <= 36) { + // var groupSize = Math.floor(BN.wordSize * Math.LN2 / Math.log(base)); + var groupSize = groupSizes[base]; + // var groupBase = Math.pow(base, groupSize); + var groupBase = groupBases[base]; + out = ''; + var c = this.clone(); + c.negative = 0; + while (!c.isZero()) { + var r = c.modn(groupBase).toString(base); + c = c.idivn(groupBase); + + if (!c.isZero()) { + out = zeros[groupSize - r.length] + r + out; + } else { + out = r + out; + } + } + if (this.isZero()) { + out = '0' + out; + } + while (out.length % padding !== 0) { + out = '0' + out; + } + if (this.negative !== 0) { + out = '-' + out; + } + return out; + } + + assert(false, 'Base should be between 2 and 36'); + }; + + BN.prototype.toNumber = function toNumber () { + var ret = this.words[0]; + if (this.length === 2) { + ret += this.words[1] * 0x4000000; + } else if (this.length === 3 && this.words[2] === 0x01) { + // NOTE: at this stage it is known that the top bit is set + ret += 0x10000000000000 + (this.words[1] * 0x4000000); + } else if (this.length > 2) { + assert(false, 'Number can only safely store up to 53 bits'); + } + return (this.negative !== 0) ? -ret : ret; + }; + + BN.prototype.toJSON = function toJSON () { + return this.toString(16); + }; + + BN.prototype.toBuffer = function toBuffer (endian, length) { + assert(typeof Buffer !== 'undefined'); + return this.toArrayLike(Buffer, endian, length); + }; + + BN.prototype.toArray = function toArray (endian, length) { + return this.toArrayLike(Array, endian, length); + }; + + BN.prototype.toArrayLike = function toArrayLike (ArrayType, endian, length) { + var byteLength = this.byteLength(); + var reqLength = length || Math.max(1, byteLength); + assert(byteLength <= reqLength, 'byte array longer than desired length'); + assert(reqLength > 0, 'Requested array length <= 0'); + + this.strip(); + var littleEndian = endian === 'le'; + var res = new ArrayType(reqLength); + + var b, i; + var q = this.clone(); + if (!littleEndian) { + // Assume big-endian + for (i = 0; i < reqLength - byteLength; i++) { + res[i] = 0; + } + + for (i = 0; !q.isZero(); i++) { + b = q.andln(0xff); + q.iushrn(8); + + res[reqLength - i - 1] = b; + } + } else { + for (i = 0; !q.isZero(); i++) { + b = q.andln(0xff); + q.iushrn(8); + + res[i] = b; + } + + for (; i < reqLength; i++) { + res[i] = 0; + } + } + + return res; + }; + + if (Math.clz32) { + BN.prototype._countBits = function _countBits (w) { + return 32 - Math.clz32(w); + }; + } else { + BN.prototype._countBits = function _countBits (w) { + var t = w; + var r = 0; + if (t >= 0x1000) { + r += 13; + t >>>= 13; + } + if (t >= 0x40) { + r += 7; + t >>>= 7; + } + if (t >= 0x8) { + r += 4; + t >>>= 4; + } + if (t >= 0x02) { + r += 2; + t >>>= 2; + } + return r + t; + }; + } + + BN.prototype._zeroBits = function _zeroBits (w) { + // Short-cut + if (w === 0) return 26; + + var t = w; + var r = 0; + if ((t & 0x1fff) === 0) { + r += 13; + t >>>= 13; + } + if ((t & 0x7f) === 0) { + r += 7; + t >>>= 7; + } + if ((t & 0xf) === 0) { + r += 4; + t >>>= 4; + } + if ((t & 0x3) === 0) { + r += 2; + t >>>= 2; + } + if ((t & 0x1) === 0) { + r++; + } + return r; + }; + + // Return number of used bits in a BN + BN.prototype.bitLength = function bitLength () { + var w = this.words[this.length - 1]; + var hi = this._countBits(w); + return (this.length - 1) * 26 + hi; + }; + + function toBitArray (num) { + var w = new Array(num.bitLength()); + + for (var bit = 0; bit < w.length; bit++) { + var off = (bit / 26) | 0; + var wbit = bit % 26; + + w[bit] = (num.words[off] & (1 << wbit)) >>> wbit; + } + + return w; + } + + // Number of trailing zero bits + BN.prototype.zeroBits = function zeroBits () { + if (this.isZero()) return 0; + + var r = 0; + for (var i = 0; i < this.length; i++) { + var b = this._zeroBits(this.words[i]); + r += b; + if (b !== 26) break; + } + return r; + }; + + BN.prototype.byteLength = function byteLength () { + return Math.ceil(this.bitLength() / 8); + }; + + BN.prototype.toTwos = function toTwos (width) { + if (this.negative !== 0) { + return this.abs().inotn(width).iaddn(1); + } + return this.clone(); + }; + + BN.prototype.fromTwos = function fromTwos (width) { + if (this.testn(width - 1)) { + return this.notn(width).iaddn(1).ineg(); + } + return this.clone(); + }; + + BN.prototype.isNeg = function isNeg () { + return this.negative !== 0; + }; + + // Return negative clone of `this` + BN.prototype.neg = function neg () { + return this.clone().ineg(); + }; + + BN.prototype.ineg = function ineg () { + if (!this.isZero()) { + this.negative ^= 1; + } + + return this; + }; + + // Or `num` with `this` in-place + BN.prototype.iuor = function iuor (num) { + while (this.length < num.length) { + this.words[this.length++] = 0; + } + + for (var i = 0; i < num.length; i++) { + this.words[i] = this.words[i] | num.words[i]; + } + + return this.strip(); + }; + + BN.prototype.ior = function ior (num) { + assert((this.negative | num.negative) === 0); + return this.iuor(num); + }; + + // Or `num` with `this` + BN.prototype.or = function or (num) { + if (this.length > num.length) return this.clone().ior(num); + return num.clone().ior(this); + }; + + BN.prototype.uor = function uor (num) { + if (this.length > num.length) return this.clone().iuor(num); + return num.clone().iuor(this); + }; + + // And `num` with `this` in-place + BN.prototype.iuand = function iuand (num) { + // b = min-length(num, this) + var b; + if (this.length > num.length) { + b = num; + } else { + b = this; + } + + for (var i = 0; i < b.length; i++) { + this.words[i] = this.words[i] & num.words[i]; + } + + this.length = b.length; + + return this.strip(); + }; + + BN.prototype.iand = function iand (num) { + assert((this.negative | num.negative) === 0); + return this.iuand(num); + }; + + // And `num` with `this` + BN.prototype.and = function and (num) { + if (this.length > num.length) return this.clone().iand(num); + return num.clone().iand(this); + }; + + BN.prototype.uand = function uand (num) { + if (this.length > num.length) return this.clone().iuand(num); + return num.clone().iuand(this); + }; + + // Xor `num` with `this` in-place + BN.prototype.iuxor = function iuxor (num) { + // a.length > b.length + var a; + var b; + if (this.length > num.length) { + a = this; + b = num; + } else { + a = num; + b = this; + } + + for (var i = 0; i < b.length; i++) { + this.words[i] = a.words[i] ^ b.words[i]; + } + + if (this !== a) { + for (; i < a.length; i++) { + this.words[i] = a.words[i]; + } + } + + this.length = a.length; + + return this.strip(); + }; + + BN.prototype.ixor = function ixor (num) { + assert((this.negative | num.negative) === 0); + return this.iuxor(num); + }; + + // Xor `num` with `this` + BN.prototype.xor = function xor (num) { + if (this.length > num.length) return this.clone().ixor(num); + return num.clone().ixor(this); + }; + + BN.prototype.uxor = function uxor (num) { + if (this.length > num.length) return this.clone().iuxor(num); + return num.clone().iuxor(this); + }; + + // Not ``this`` with ``width`` bitwidth + BN.prototype.inotn = function inotn (width) { + assert(typeof width === 'number' && width >= 0); + + var bytesNeeded = Math.ceil(width / 26) | 0; + var bitsLeft = width % 26; + + // Extend the buffer with leading zeroes + this._expand(bytesNeeded); + + if (bitsLeft > 0) { + bytesNeeded--; + } + + // Handle complete words + for (var i = 0; i < bytesNeeded; i++) { + this.words[i] = ~this.words[i] & 0x3ffffff; + } + + // Handle the residue + if (bitsLeft > 0) { + this.words[i] = ~this.words[i] & (0x3ffffff >> (26 - bitsLeft)); + } + + // And remove leading zeroes + return this.strip(); + }; + + BN.prototype.notn = function notn (width) { + return this.clone().inotn(width); + }; + + // Set `bit` of `this` + BN.prototype.setn = function setn (bit, val) { + assert(typeof bit === 'number' && bit >= 0); + + var off = (bit / 26) | 0; + var wbit = bit % 26; + + this._expand(off + 1); + + if (val) { + this.words[off] = this.words[off] | (1 << wbit); + } else { + this.words[off] = this.words[off] & ~(1 << wbit); + } + + return this.strip(); + }; + + // Add `num` to `this` in-place + BN.prototype.iadd = function iadd (num) { + var r; + + // negative + positive + if (this.negative !== 0 && num.negative === 0) { + this.negative = 0; + r = this.isub(num); + this.negative ^= 1; + return this._normSign(); + + // positive + negative + } else if (this.negative === 0 && num.negative !== 0) { + num.negative = 0; + r = this.isub(num); + num.negative = 1; + return r._normSign(); + } + + // a.length > b.length + var a, b; + if (this.length > num.length) { + a = this; + b = num; + } else { + a = num; + b = this; + } + + var carry = 0; + for (var i = 0; i < b.length; i++) { + r = (a.words[i] | 0) + (b.words[i] | 0) + carry; + this.words[i] = r & 0x3ffffff; + carry = r >>> 26; + } + for (; carry !== 0 && i < a.length; i++) { + r = (a.words[i] | 0) + carry; + this.words[i] = r & 0x3ffffff; + carry = r >>> 26; + } + + this.length = a.length; + if (carry !== 0) { + this.words[this.length] = carry; + this.length++; + // Copy the rest of the words + } else if (a !== this) { + for (; i < a.length; i++) { + this.words[i] = a.words[i]; + } + } + + return this; + }; + + // Add `num` to `this` + BN.prototype.add = function add (num) { + var res; + if (num.negative !== 0 && this.negative === 0) { + num.negative = 0; + res = this.sub(num); + num.negative ^= 1; + return res; + } else if (num.negative === 0 && this.negative !== 0) { + this.negative = 0; + res = num.sub(this); + this.negative = 1; + return res; + } + + if (this.length > num.length) return this.clone().iadd(num); + + return num.clone().iadd(this); + }; + + // Subtract `num` from `this` in-place + BN.prototype.isub = function isub (num) { + // this - (-num) = this + num + if (num.negative !== 0) { + num.negative = 0; + var r = this.iadd(num); + num.negative = 1; + return r._normSign(); + + // -this - num = -(this + num) + } else if (this.negative !== 0) { + this.negative = 0; + this.iadd(num); + this.negative = 1; + return this._normSign(); + } + + // At this point both numbers are positive + var cmp = this.cmp(num); + + // Optimization - zeroify + if (cmp === 0) { + this.negative = 0; + this.length = 1; + this.words[0] = 0; + return this; + } + + // a > b + var a, b; + if (cmp > 0) { + a = this; + b = num; + } else { + a = num; + b = this; + } + + var carry = 0; + for (var i = 0; i < b.length; i++) { + r = (a.words[i] | 0) - (b.words[i] | 0) + carry; + carry = r >> 26; + this.words[i] = r & 0x3ffffff; + } + for (; carry !== 0 && i < a.length; i++) { + r = (a.words[i] | 0) + carry; + carry = r >> 26; + this.words[i] = r & 0x3ffffff; + } + + // Copy rest of the words + if (carry === 0 && i < a.length && a !== this) { + for (; i < a.length; i++) { + this.words[i] = a.words[i]; + } + } + + this.length = Math.max(this.length, i); + + if (a !== this) { + this.negative = 1; + } + + return this.strip(); + }; + + // Subtract `num` from `this` + BN.prototype.sub = function sub (num) { + return this.clone().isub(num); + }; + + function smallMulTo (self, num, out) { + out.negative = num.negative ^ self.negative; + var len = (self.length + num.length) | 0; + out.length = len; + len = (len - 1) | 0; + + // Peel one iteration (compiler can't do it, because of code complexity) + var a = self.words[0] | 0; + var b = num.words[0] | 0; + var r = a * b; + + var lo = r & 0x3ffffff; + var carry = (r / 0x4000000) | 0; + out.words[0] = lo; + + for (var k = 1; k < len; k++) { + // Sum all words with the same `i + j = k` and accumulate `ncarry`, + // note that ncarry could be >= 0x3ffffff + var ncarry = carry >>> 26; + var rword = carry & 0x3ffffff; + var maxJ = Math.min(k, num.length - 1); + for (var j = Math.max(0, k - self.length + 1); j <= maxJ; j++) { + var i = (k - j) | 0; + a = self.words[i] | 0; + b = num.words[j] | 0; + r = a * b + rword; + ncarry += (r / 0x4000000) | 0; + rword = r & 0x3ffffff; + } + out.words[k] = rword | 0; + carry = ncarry | 0; + } + if (carry !== 0) { + out.words[k] = carry | 0; + } else { + out.length--; + } + + return out.strip(); + } + + // TODO(indutny): it may be reasonable to omit it for users who don't need + // to work with 256-bit numbers, otherwise it gives 20% improvement for 256-bit + // multiplication (like elliptic secp256k1). + var comb10MulTo = function comb10MulTo (self, num, out) { + var a = self.words; + var b = num.words; + var o = out.words; + var c = 0; + var lo; + var mid; + var hi; + var a0 = a[0] | 0; + var al0 = a0 & 0x1fff; + var ah0 = a0 >>> 13; + var a1 = a[1] | 0; + var al1 = a1 & 0x1fff; + var ah1 = a1 >>> 13; + var a2 = a[2] | 0; + var al2 = a2 & 0x1fff; + var ah2 = a2 >>> 13; + var a3 = a[3] | 0; + var al3 = a3 & 0x1fff; + var ah3 = a3 >>> 13; + var a4 = a[4] | 0; + var al4 = a4 & 0x1fff; + var ah4 = a4 >>> 13; + var a5 = a[5] | 0; + var al5 = a5 & 0x1fff; + var ah5 = a5 >>> 13; + var a6 = a[6] | 0; + var al6 = a6 & 0x1fff; + var ah6 = a6 >>> 13; + var a7 = a[7] | 0; + var al7 = a7 & 0x1fff; + var ah7 = a7 >>> 13; + var a8 = a[8] | 0; + var al8 = a8 & 0x1fff; + var ah8 = a8 >>> 13; + var a9 = a[9] | 0; + var al9 = a9 & 0x1fff; + var ah9 = a9 >>> 13; + var b0 = b[0] | 0; + var bl0 = b0 & 0x1fff; + var bh0 = b0 >>> 13; + var b1 = b[1] | 0; + var bl1 = b1 & 0x1fff; + var bh1 = b1 >>> 13; + var b2 = b[2] | 0; + var bl2 = b2 & 0x1fff; + var bh2 = b2 >>> 13; + var b3 = b[3] | 0; + var bl3 = b3 & 0x1fff; + var bh3 = b3 >>> 13; + var b4 = b[4] | 0; + var bl4 = b4 & 0x1fff; + var bh4 = b4 >>> 13; + var b5 = b[5] | 0; + var bl5 = b5 & 0x1fff; + var bh5 = b5 >>> 13; + var b6 = b[6] | 0; + var bl6 = b6 & 0x1fff; + var bh6 = b6 >>> 13; + var b7 = b[7] | 0; + var bl7 = b7 & 0x1fff; + var bh7 = b7 >>> 13; + var b8 = b[8] | 0; + var bl8 = b8 & 0x1fff; + var bh8 = b8 >>> 13; + var b9 = b[9] | 0; + var bl9 = b9 & 0x1fff; + var bh9 = b9 >>> 13; + + out.negative = self.negative ^ num.negative; + out.length = 19; + /* k = 0 */ + lo = Math.imul(al0, bl0); + mid = Math.imul(al0, bh0); + mid = (mid + Math.imul(ah0, bl0)) | 0; + hi = Math.imul(ah0, bh0); + var w0 = (((c + lo) | 0) + ((mid & 0x1fff) << 13)) | 0; + c = (((hi + (mid >>> 13)) | 0) + (w0 >>> 26)) | 0; + w0 &= 0x3ffffff; + /* k = 1 */ + lo = Math.imul(al1, bl0); + mid = Math.imul(al1, bh0); + mid = (mid + Math.imul(ah1, bl0)) | 0; + hi = Math.imul(ah1, bh0); + lo = (lo + Math.imul(al0, bl1)) | 0; + mid = (mid + Math.imul(al0, bh1)) | 0; + mid = (mid + Math.imul(ah0, bl1)) | 0; + hi = (hi + Math.imul(ah0, bh1)) | 0; + var w1 = (((c + lo) | 0) + ((mid & 0x1fff) << 13)) | 0; + c = (((hi + (mid >>> 13)) | 0) + (w1 >>> 26)) | 0; + w1 &= 0x3ffffff; + /* k = 2 */ + lo = Math.imul(al2, bl0); + mid = Math.imul(al2, bh0); + mid = (mid + Math.imul(ah2, bl0)) | 0; + hi = Math.imul(ah2, bh0); + lo = (lo + Math.imul(al1, bl1)) | 0; + mid = (mid + Math.imul(al1, bh1)) | 0; + mid = (mid + Math.imul(ah1, bl1)) | 0; + hi = (hi + Math.imul(ah1, bh1)) | 0; + lo = (lo + Math.imul(al0, bl2)) | 0; + mid = (mid + Math.imul(al0, bh2)) | 0; + mid = (mid + Math.imul(ah0, bl2)) | 0; + hi = (hi + Math.imul(ah0, bh2)) | 0; + var w2 = (((c + lo) | 0) + ((mid & 0x1fff) << 13)) | 0; + c = (((hi + (mid >>> 13)) | 0) + (w2 >>> 26)) | 0; + w2 &= 0x3ffffff; + /* k = 3 */ + lo = Math.imul(al3, bl0); + mid = Math.imul(al3, bh0); + mid = (mid + Math.imul(ah3, bl0)) | 0; + hi = Math.imul(ah3, bh0); + lo = (lo + Math.imul(al2, bl1)) | 0; + mid = (mid + Math.imul(al2, bh1)) | 0; + mid = (mid + Math.imul(ah2, bl1)) | 0; + hi = (hi + Math.imul(ah2, bh1)) | 0; + lo = (lo + Math.imul(al1, bl2)) | 0; + mid = (mid + Math.imul(al1, bh2)) | 0; + mid = (mid + Math.imul(ah1, bl2)) | 0; + hi = (hi + Math.imul(ah1, bh2)) | 0; + lo = (lo + Math.imul(al0, bl3)) | 0; + mid = (mid + Math.imul(al0, bh3)) | 0; + mid = (mid + Math.imul(ah0, bl3)) | 0; + hi = (hi + Math.imul(ah0, bh3)) | 0; + var w3 = (((c + lo) | 0) + ((mid & 0x1fff) << 13)) | 0; + c = (((hi + (mid >>> 13)) | 0) + (w3 >>> 26)) | 0; + w3 &= 0x3ffffff; + /* k = 4 */ + lo = Math.imul(al4, bl0); + mid = Math.imul(al4, bh0); + mid = (mid + Math.imul(ah4, bl0)) | 0; + hi = Math.imul(ah4, bh0); + lo = (lo + Math.imul(al3, bl1)) | 0; + mid = (mid + Math.imul(al3, bh1)) | 0; + mid = (mid + Math.imul(ah3, bl1)) | 0; + hi = (hi + Math.imul(ah3, bh1)) | 0; + lo = (lo + Math.imul(al2, bl2)) | 0; + mid = (mid + Math.imul(al2, bh2)) | 0; + mid = (mid + Math.imul(ah2, bl2)) | 0; + hi = (hi + Math.imul(ah2, bh2)) | 0; + lo = (lo + Math.imul(al1, bl3)) | 0; + mid = (mid + Math.imul(al1, bh3)) | 0; + mid = (mid + Math.imul(ah1, bl3)) | 0; + hi = (hi + Math.imul(ah1, bh3)) | 0; + lo = (lo + Math.imul(al0, bl4)) | 0; + mid = (mid + Math.imul(al0, bh4)) | 0; + mid = (mid + Math.imul(ah0, bl4)) | 0; + hi = (hi + Math.imul(ah0, bh4)) | 0; + var w4 = (((c + lo) | 0) + ((mid & 0x1fff) << 13)) | 0; + c = (((hi + (mid >>> 13)) | 0) + (w4 >>> 26)) | 0; + w4 &= 0x3ffffff; + /* k = 5 */ + lo = Math.imul(al5, bl0); + mid = Math.imul(al5, bh0); + mid = (mid + Math.imul(ah5, bl0)) | 0; + hi = Math.imul(ah5, bh0); + lo = (lo + Math.imul(al4, bl1)) | 0; + mid = (mid + Math.imul(al4, bh1)) | 0; + mid = (mid + Math.imul(ah4, bl1)) | 0; + hi = (hi + Math.imul(ah4, bh1)) | 0; + lo = (lo + Math.imul(al3, bl2)) | 0; + mid = (mid + Math.imul(al3, bh2)) | 0; + mid = (mid + Math.imul(ah3, bl2)) | 0; + hi = (hi + Math.imul(ah3, bh2)) | 0; + lo = (lo + Math.imul(al2, bl3)) | 0; + mid = (mid + Math.imul(al2, bh3)) | 0; + mid = (mid + Math.imul(ah2, bl3)) | 0; + hi = (hi + Math.imul(ah2, bh3)) | 0; + lo = (lo + Math.imul(al1, bl4)) | 0; + mid = (mid + Math.imul(al1, bh4)) | 0; + mid = (mid + Math.imul(ah1, bl4)) | 0; + hi = (hi + Math.imul(ah1, bh4)) | 0; + lo = (lo + Math.imul(al0, bl5)) | 0; + mid = (mid + Math.imul(al0, bh5)) | 0; + mid = (mid + Math.imul(ah0, bl5)) | 0; + hi = (hi + Math.imul(ah0, bh5)) | 0; + var w5 = (((c + lo) | 0) + ((mid & 0x1fff) << 13)) | 0; + c = (((hi + (mid >>> 13)) | 0) + (w5 >>> 26)) | 0; + w5 &= 0x3ffffff; + /* k = 6 */ + lo = Math.imul(al6, bl0); + mid = Math.imul(al6, bh0); + mid = (mid + Math.imul(ah6, bl0)) | 0; + hi = Math.imul(ah6, bh0); + lo = (lo + Math.imul(al5, bl1)) | 0; + mid = (mid + Math.imul(al5, bh1)) | 0; + mid = (mid + Math.imul(ah5, bl1)) | 0; + hi = (hi + Math.imul(ah5, bh1)) | 0; + lo = (lo + Math.imul(al4, bl2)) | 0; + mid = (mid + Math.imul(al4, bh2)) | 0; + mid = (mid + Math.imul(ah4, bl2)) | 0; + hi = (hi + Math.imul(ah4, bh2)) | 0; + lo = (lo + Math.imul(al3, bl3)) | 0; + mid = (mid + Math.imul(al3, bh3)) | 0; + mid = (mid + Math.imul(ah3, bl3)) | 0; + hi = (hi + Math.imul(ah3, bh3)) | 0; + lo = (lo + Math.imul(al2, bl4)) | 0; + mid = (mid + Math.imul(al2, bh4)) | 0; + mid = (mid + Math.imul(ah2, bl4)) | 0; + hi = (hi + Math.imul(ah2, bh4)) | 0; + lo = (lo + Math.imul(al1, bl5)) | 0; + mid = (mid + Math.imul(al1, bh5)) | 0; + mid = (mid + Math.imul(ah1, bl5)) | 0; + hi = (hi + Math.imul(ah1, bh5)) | 0; + lo = (lo + Math.imul(al0, bl6)) | 0; + mid = (mid + Math.imul(al0, bh6)) | 0; + mid = (mid + Math.imul(ah0, bl6)) | 0; + hi = (hi + Math.imul(ah0, bh6)) | 0; + var w6 = (((c + lo) | 0) + ((mid & 0x1fff) << 13)) | 0; + c = (((hi + (mid >>> 13)) | 0) + (w6 >>> 26)) | 0; + w6 &= 0x3ffffff; + /* k = 7 */ + lo = Math.imul(al7, bl0); + mid = Math.imul(al7, bh0); + mid = (mid + Math.imul(ah7, bl0)) | 0; + hi = Math.imul(ah7, bh0); + lo = (lo + Math.imul(al6, bl1)) | 0; + mid = (mid + Math.imul(al6, bh1)) | 0; + mid = (mid + Math.imul(ah6, bl1)) | 0; + hi = (hi + Math.imul(ah6, bh1)) | 0; + lo = (lo + Math.imul(al5, bl2)) | 0; + mid = (mid + Math.imul(al5, bh2)) | 0; + mid = (mid + Math.imul(ah5, bl2)) | 0; + hi = (hi + Math.imul(ah5, bh2)) | 0; + lo = (lo + Math.imul(al4, bl3)) | 0; + mid = (mid + Math.imul(al4, bh3)) | 0; + mid = (mid + Math.imul(ah4, bl3)) | 0; + hi = (hi + Math.imul(ah4, bh3)) | 0; + lo = (lo + Math.imul(al3, bl4)) | 0; + mid = (mid + Math.imul(al3, bh4)) | 0; + mid = (mid + Math.imul(ah3, bl4)) | 0; + hi = (hi + Math.imul(ah3, bh4)) | 0; + lo = (lo + Math.imul(al2, bl5)) | 0; + mid = (mid + Math.imul(al2, bh5)) | 0; + mid = (mid + Math.imul(ah2, bl5)) | 0; + hi = (hi + Math.imul(ah2, bh5)) | 0; + lo = (lo + Math.imul(al1, bl6)) | 0; + mid = (mid + Math.imul(al1, bh6)) | 0; + mid = (mid + Math.imul(ah1, bl6)) | 0; + hi = (hi + Math.imul(ah1, bh6)) | 0; + lo = (lo + Math.imul(al0, bl7)) | 0; + mid = (mid + Math.imul(al0, bh7)) | 0; + mid = (mid + Math.imul(ah0, bl7)) | 0; + hi = (hi + Math.imul(ah0, bh7)) | 0; + var w7 = (((c + lo) | 0) + ((mid & 0x1fff) << 13)) | 0; + c = (((hi + (mid >>> 13)) | 0) + (w7 >>> 26)) | 0; + w7 &= 0x3ffffff; + /* k = 8 */ + lo = Math.imul(al8, bl0); + mid = Math.imul(al8, bh0); + mid = (mid + Math.imul(ah8, bl0)) | 0; + hi = Math.imul(ah8, bh0); + lo = (lo + Math.imul(al7, bl1)) | 0; + mid = (mid + Math.imul(al7, bh1)) | 0; + mid = (mid + Math.imul(ah7, bl1)) | 0; + hi = (hi + Math.imul(ah7, bh1)) | 0; + lo = (lo + Math.imul(al6, bl2)) | 0; + mid = (mid + Math.imul(al6, bh2)) | 0; + mid = (mid + Math.imul(ah6, bl2)) | 0; + hi = (hi + Math.imul(ah6, bh2)) | 0; + lo = (lo + Math.imul(al5, bl3)) | 0; + mid = (mid + Math.imul(al5, bh3)) | 0; + mid = (mid + Math.imul(ah5, bl3)) | 0; + hi = (hi + Math.imul(ah5, bh3)) | 0; + lo = (lo + Math.imul(al4, bl4)) | 0; + mid = (mid + Math.imul(al4, bh4)) | 0; + mid = (mid + Math.imul(ah4, bl4)) | 0; + hi = (hi + Math.imul(ah4, bh4)) | 0; + lo = (lo + Math.imul(al3, bl5)) | 0; + mid = (mid + Math.imul(al3, bh5)) | 0; + mid = (mid + Math.imul(ah3, bl5)) | 0; + hi = (hi + Math.imul(ah3, bh5)) | 0; + lo = (lo + Math.imul(al2, bl6)) | 0; + mid = (mid + Math.imul(al2, bh6)) | 0; + mid = (mid + Math.imul(ah2, bl6)) | 0; + hi = (hi + Math.imul(ah2, bh6)) | 0; + lo = (lo + Math.imul(al1, bl7)) | 0; + mid = (mid + Math.imul(al1, bh7)) | 0; + mid = (mid + Math.imul(ah1, bl7)) | 0; + hi = (hi + Math.imul(ah1, bh7)) | 0; + lo = (lo + Math.imul(al0, bl8)) | 0; + mid = (mid + Math.imul(al0, bh8)) | 0; + mid = (mid + Math.imul(ah0, bl8)) | 0; + hi = (hi + Math.imul(ah0, bh8)) | 0; + var w8 = (((c + lo) | 0) + ((mid & 0x1fff) << 13)) | 0; + c = (((hi + (mid >>> 13)) | 0) + (w8 >>> 26)) | 0; + w8 &= 0x3ffffff; + /* k = 9 */ + lo = Math.imul(al9, bl0); + mid = Math.imul(al9, bh0); + mid = (mid + Math.imul(ah9, bl0)) | 0; + hi = Math.imul(ah9, bh0); + lo = (lo + Math.imul(al8, bl1)) | 0; + mid = (mid + Math.imul(al8, bh1)) | 0; + mid = (mid + Math.imul(ah8, bl1)) | 0; + hi = (hi + Math.imul(ah8, bh1)) | 0; + lo = (lo + Math.imul(al7, bl2)) | 0; + mid = (mid + Math.imul(al7, bh2)) | 0; + mid = (mid + Math.imul(ah7, bl2)) | 0; + hi = (hi + Math.imul(ah7, bh2)) | 0; + lo = (lo + Math.imul(al6, bl3)) | 0; + mid = (mid + Math.imul(al6, bh3)) | 0; + mid = (mid + Math.imul(ah6, bl3)) | 0; + hi = (hi + Math.imul(ah6, bh3)) | 0; + lo = (lo + Math.imul(al5, bl4)) | 0; + mid = (mid + Math.imul(al5, bh4)) | 0; + mid = (mid + Math.imul(ah5, bl4)) | 0; + hi = (hi + Math.imul(ah5, bh4)) | 0; + lo = (lo + Math.imul(al4, bl5)) | 0; + mid = (mid + Math.imul(al4, bh5)) | 0; + mid = (mid + Math.imul(ah4, bl5)) | 0; + hi = (hi + Math.imul(ah4, bh5)) | 0; + lo = (lo + Math.imul(al3, bl6)) | 0; + mid = (mid + Math.imul(al3, bh6)) | 0; + mid = (mid + Math.imul(ah3, bl6)) | 0; + hi = (hi + Math.imul(ah3, bh6)) | 0; + lo = (lo + Math.imul(al2, bl7)) | 0; + mid = (mid + Math.imul(al2, bh7)) | 0; + mid = (mid + Math.imul(ah2, bl7)) | 0; + hi = (hi + Math.imul(ah2, bh7)) | 0; + lo = (lo + Math.imul(al1, bl8)) | 0; + mid = (mid + Math.imul(al1, bh8)) | 0; + mid = (mid + Math.imul(ah1, bl8)) | 0; + hi = (hi + Math.imul(ah1, bh8)) | 0; + lo = (lo + Math.imul(al0, bl9)) | 0; + mid = (mid + Math.imul(al0, bh9)) | 0; + mid = (mid + Math.imul(ah0, bl9)) | 0; + hi = (hi + Math.imul(ah0, bh9)) | 0; + var w9 = (((c + lo) | 0) + ((mid & 0x1fff) << 13)) | 0; + c = (((hi + (mid >>> 13)) | 0) + (w9 >>> 26)) | 0; + w9 &= 0x3ffffff; + /* k = 10 */ + lo = Math.imul(al9, bl1); + mid = Math.imul(al9, bh1); + mid = (mid + Math.imul(ah9, bl1)) | 0; + hi = Math.imul(ah9, bh1); + lo = (lo + Math.imul(al8, bl2)) | 0; + mid = (mid + Math.imul(al8, bh2)) | 0; + mid = (mid + Math.imul(ah8, bl2)) | 0; + hi = (hi + Math.imul(ah8, bh2)) | 0; + lo = (lo + Math.imul(al7, bl3)) | 0; + mid = (mid + Math.imul(al7, bh3)) | 0; + mid = (mid + Math.imul(ah7, bl3)) | 0; + hi = (hi + Math.imul(ah7, bh3)) | 0; + lo = (lo + Math.imul(al6, bl4)) | 0; + mid = (mid + Math.imul(al6, bh4)) | 0; + mid = (mid + Math.imul(ah6, bl4)) | 0; + hi = (hi + Math.imul(ah6, bh4)) | 0; + lo = (lo + Math.imul(al5, bl5)) | 0; + mid = (mid + Math.imul(al5, bh5)) | 0; + mid = (mid + Math.imul(ah5, bl5)) | 0; + hi = (hi + Math.imul(ah5, bh5)) | 0; + lo = (lo + Math.imul(al4, bl6)) | 0; + mid = (mid + Math.imul(al4, bh6)) | 0; + mid = (mid + Math.imul(ah4, bl6)) | 0; + hi = (hi + Math.imul(ah4, bh6)) | 0; + lo = (lo + Math.imul(al3, bl7)) | 0; + mid = (mid + Math.imul(al3, bh7)) | 0; + mid = (mid + Math.imul(ah3, bl7)) | 0; + hi = (hi + Math.imul(ah3, bh7)) | 0; + lo = (lo + Math.imul(al2, bl8)) | 0; + mid = (mid + Math.imul(al2, bh8)) | 0; + mid = (mid + Math.imul(ah2, bl8)) | 0; + hi = (hi + Math.imul(ah2, bh8)) | 0; + lo = (lo + Math.imul(al1, bl9)) | 0; + mid = (mid + Math.imul(al1, bh9)) | 0; + mid = (mid + Math.imul(ah1, bl9)) | 0; + hi = (hi + Math.imul(ah1, bh9)) | 0; + var w10 = (((c + lo) | 0) + ((mid & 0x1fff) << 13)) | 0; + c = (((hi + (mid >>> 13)) | 0) + (w10 >>> 26)) | 0; + w10 &= 0x3ffffff; + /* k = 11 */ + lo = Math.imul(al9, bl2); + mid = Math.imul(al9, bh2); + mid = (mid + Math.imul(ah9, bl2)) | 0; + hi = Math.imul(ah9, bh2); + lo = (lo + Math.imul(al8, bl3)) | 0; + mid = (mid + Math.imul(al8, bh3)) | 0; + mid = (mid + Math.imul(ah8, bl3)) | 0; + hi = (hi + Math.imul(ah8, bh3)) | 0; + lo = (lo + Math.imul(al7, bl4)) | 0; + mid = (mid + Math.imul(al7, bh4)) | 0; + mid = (mid + Math.imul(ah7, bl4)) | 0; + hi = (hi + Math.imul(ah7, bh4)) | 0; + lo = (lo + Math.imul(al6, bl5)) | 0; + mid = (mid + Math.imul(al6, bh5)) | 0; + mid = (mid + Math.imul(ah6, bl5)) | 0; + hi = (hi + Math.imul(ah6, bh5)) | 0; + lo = (lo + Math.imul(al5, bl6)) | 0; + mid = (mid + Math.imul(al5, bh6)) | 0; + mid = (mid + Math.imul(ah5, bl6)) | 0; + hi = (hi + Math.imul(ah5, bh6)) | 0; + lo = (lo + Math.imul(al4, bl7)) | 0; + mid = (mid + Math.imul(al4, bh7)) | 0; + mid = (mid + Math.imul(ah4, bl7)) | 0; + hi = (hi + Math.imul(ah4, bh7)) | 0; + lo = (lo + Math.imul(al3, bl8)) | 0; + mid = (mid + Math.imul(al3, bh8)) | 0; + mid = (mid + Math.imul(ah3, bl8)) | 0; + hi = (hi + Math.imul(ah3, bh8)) | 0; + lo = (lo + Math.imul(al2, bl9)) | 0; + mid = (mid + Math.imul(al2, bh9)) | 0; + mid = (mid + Math.imul(ah2, bl9)) | 0; + hi = (hi + Math.imul(ah2, bh9)) | 0; + var w11 = (((c + lo) | 0) + ((mid & 0x1fff) << 13)) | 0; + c = (((hi + (mid >>> 13)) | 0) + (w11 >>> 26)) | 0; + w11 &= 0x3ffffff; + /* k = 12 */ + lo = Math.imul(al9, bl3); + mid = Math.imul(al9, bh3); + mid = (mid + Math.imul(ah9, bl3)) | 0; + hi = Math.imul(ah9, bh3); + lo = (lo + Math.imul(al8, bl4)) | 0; + mid = (mid + Math.imul(al8, bh4)) | 0; + mid = (mid + Math.imul(ah8, bl4)) | 0; + hi = (hi + Math.imul(ah8, bh4)) | 0; + lo = (lo + Math.imul(al7, bl5)) | 0; + mid = (mid + Math.imul(al7, bh5)) | 0; + mid = (mid + Math.imul(ah7, bl5)) | 0; + hi = (hi + Math.imul(ah7, bh5)) | 0; + lo = (lo + Math.imul(al6, bl6)) | 0; + mid = (mid + Math.imul(al6, bh6)) | 0; + mid = (mid + Math.imul(ah6, bl6)) | 0; + hi = (hi + Math.imul(ah6, bh6)) | 0; + lo = (lo + Math.imul(al5, bl7)) | 0; + mid = (mid + Math.imul(al5, bh7)) | 0; + mid = (mid + Math.imul(ah5, bl7)) | 0; + hi = (hi + Math.imul(ah5, bh7)) | 0; + lo = (lo + Math.imul(al4, bl8)) | 0; + mid = (mid + Math.imul(al4, bh8)) | 0; + mid = (mid + Math.imul(ah4, bl8)) | 0; + hi = (hi + Math.imul(ah4, bh8)) | 0; + lo = (lo + Math.imul(al3, bl9)) | 0; + mid = (mid + Math.imul(al3, bh9)) | 0; + mid = (mid + Math.imul(ah3, bl9)) | 0; + hi = (hi + Math.imul(ah3, bh9)) | 0; + var w12 = (((c + lo) | 0) + ((mid & 0x1fff) << 13)) | 0; + c = (((hi + (mid >>> 13)) | 0) + (w12 >>> 26)) | 0; + w12 &= 0x3ffffff; + /* k = 13 */ + lo = Math.imul(al9, bl4); + mid = Math.imul(al9, bh4); + mid = (mid + Math.imul(ah9, bl4)) | 0; + hi = Math.imul(ah9, bh4); + lo = (lo + Math.imul(al8, bl5)) | 0; + mid = (mid + Math.imul(al8, bh5)) | 0; + mid = (mid + Math.imul(ah8, bl5)) | 0; + hi = (hi + Math.imul(ah8, bh5)) | 0; + lo = (lo + Math.imul(al7, bl6)) | 0; + mid = (mid + Math.imul(al7, bh6)) | 0; + mid = (mid + Math.imul(ah7, bl6)) | 0; + hi = (hi + Math.imul(ah7, bh6)) | 0; + lo = (lo + Math.imul(al6, bl7)) | 0; + mid = (mid + Math.imul(al6, bh7)) | 0; + mid = (mid + Math.imul(ah6, bl7)) | 0; + hi = (hi + Math.imul(ah6, bh7)) | 0; + lo = (lo + Math.imul(al5, bl8)) | 0; + mid = (mid + Math.imul(al5, bh8)) | 0; + mid = (mid + Math.imul(ah5, bl8)) | 0; + hi = (hi + Math.imul(ah5, bh8)) | 0; + lo = (lo + Math.imul(al4, bl9)) | 0; + mid = (mid + Math.imul(al4, bh9)) | 0; + mid = (mid + Math.imul(ah4, bl9)) | 0; + hi = (hi + Math.imul(ah4, bh9)) | 0; + var w13 = (((c + lo) | 0) + ((mid & 0x1fff) << 13)) | 0; + c = (((hi + (mid >>> 13)) | 0) + (w13 >>> 26)) | 0; + w13 &= 0x3ffffff; + /* k = 14 */ + lo = Math.imul(al9, bl5); + mid = Math.imul(al9, bh5); + mid = (mid + Math.imul(ah9, bl5)) | 0; + hi = Math.imul(ah9, bh5); + lo = (lo + Math.imul(al8, bl6)) | 0; + mid = (mid + Math.imul(al8, bh6)) | 0; + mid = (mid + Math.imul(ah8, bl6)) | 0; + hi = (hi + Math.imul(ah8, bh6)) | 0; + lo = (lo + Math.imul(al7, bl7)) | 0; + mid = (mid + Math.imul(al7, bh7)) | 0; + mid = (mid + Math.imul(ah7, bl7)) | 0; + hi = (hi + Math.imul(ah7, bh7)) | 0; + lo = (lo + Math.imul(al6, bl8)) | 0; + mid = (mid + Math.imul(al6, bh8)) | 0; + mid = (mid + Math.imul(ah6, bl8)) | 0; + hi = (hi + Math.imul(ah6, bh8)) | 0; + lo = (lo + Math.imul(al5, bl9)) | 0; + mid = (mid + Math.imul(al5, bh9)) | 0; + mid = (mid + Math.imul(ah5, bl9)) | 0; + hi = (hi + Math.imul(ah5, bh9)) | 0; + var w14 = (((c + lo) | 0) + ((mid & 0x1fff) << 13)) | 0; + c = (((hi + (mid >>> 13)) | 0) + (w14 >>> 26)) | 0; + w14 &= 0x3ffffff; + /* k = 15 */ + lo = Math.imul(al9, bl6); + mid = Math.imul(al9, bh6); + mid = (mid + Math.imul(ah9, bl6)) | 0; + hi = Math.imul(ah9, bh6); + lo = (lo + Math.imul(al8, bl7)) | 0; + mid = (mid + Math.imul(al8, bh7)) | 0; + mid = (mid + Math.imul(ah8, bl7)) | 0; + hi = (hi + Math.imul(ah8, bh7)) | 0; + lo = (lo + Math.imul(al7, bl8)) | 0; + mid = (mid + Math.imul(al7, bh8)) | 0; + mid = (mid + Math.imul(ah7, bl8)) | 0; + hi = (hi + Math.imul(ah7, bh8)) | 0; + lo = (lo + Math.imul(al6, bl9)) | 0; + mid = (mid + Math.imul(al6, bh9)) | 0; + mid = (mid + Math.imul(ah6, bl9)) | 0; + hi = (hi + Math.imul(ah6, bh9)) | 0; + var w15 = (((c + lo) | 0) + ((mid & 0x1fff) << 13)) | 0; + c = (((hi + (mid >>> 13)) | 0) + (w15 >>> 26)) | 0; + w15 &= 0x3ffffff; + /* k = 16 */ + lo = Math.imul(al9, bl7); + mid = Math.imul(al9, bh7); + mid = (mid + Math.imul(ah9, bl7)) | 0; + hi = Math.imul(ah9, bh7); + lo = (lo + Math.imul(al8, bl8)) | 0; + mid = (mid + Math.imul(al8, bh8)) | 0; + mid = (mid + Math.imul(ah8, bl8)) | 0; + hi = (hi + Math.imul(ah8, bh8)) | 0; + lo = (lo + Math.imul(al7, bl9)) | 0; + mid = (mid + Math.imul(al7, bh9)) | 0; + mid = (mid + Math.imul(ah7, bl9)) | 0; + hi = (hi + Math.imul(ah7, bh9)) | 0; + var w16 = (((c + lo) | 0) + ((mid & 0x1fff) << 13)) | 0; + c = (((hi + (mid >>> 13)) | 0) + (w16 >>> 26)) | 0; + w16 &= 0x3ffffff; + /* k = 17 */ + lo = Math.imul(al9, bl8); + mid = Math.imul(al9, bh8); + mid = (mid + Math.imul(ah9, bl8)) | 0; + hi = Math.imul(ah9, bh8); + lo = (lo + Math.imul(al8, bl9)) | 0; + mid = (mid + Math.imul(al8, bh9)) | 0; + mid = (mid + Math.imul(ah8, bl9)) | 0; + hi = (hi + Math.imul(ah8, bh9)) | 0; + var w17 = (((c + lo) | 0) + ((mid & 0x1fff) << 13)) | 0; + c = (((hi + (mid >>> 13)) | 0) + (w17 >>> 26)) | 0; + w17 &= 0x3ffffff; + /* k = 18 */ + lo = Math.imul(al9, bl9); + mid = Math.imul(al9, bh9); + mid = (mid + Math.imul(ah9, bl9)) | 0; + hi = Math.imul(ah9, bh9); + var w18 = (((c + lo) | 0) + ((mid & 0x1fff) << 13)) | 0; + c = (((hi + (mid >>> 13)) | 0) + (w18 >>> 26)) | 0; + w18 &= 0x3ffffff; + o[0] = w0; + o[1] = w1; + o[2] = w2; + o[3] = w3; + o[4] = w4; + o[5] = w5; + o[6] = w6; + o[7] = w7; + o[8] = w8; + o[9] = w9; + o[10] = w10; + o[11] = w11; + o[12] = w12; + o[13] = w13; + o[14] = w14; + o[15] = w15; + o[16] = w16; + o[17] = w17; + o[18] = w18; + if (c !== 0) { + o[19] = c; + out.length++; + } + return out; + }; + + // Polyfill comb + if (!Math.imul) { + comb10MulTo = smallMulTo; + } + + function bigMulTo (self, num, out) { + out.negative = num.negative ^ self.negative; + out.length = self.length + num.length; + + var carry = 0; + var hncarry = 0; + for (var k = 0; k < out.length - 1; k++) { + // Sum all words with the same `i + j = k` and accumulate `ncarry`, + // note that ncarry could be >= 0x3ffffff + var ncarry = hncarry; + hncarry = 0; + var rword = carry & 0x3ffffff; + var maxJ = Math.min(k, num.length - 1); + for (var j = Math.max(0, k - self.length + 1); j <= maxJ; j++) { + var i = k - j; + var a = self.words[i] | 0; + var b = num.words[j] | 0; + var r = a * b; + + var lo = r & 0x3ffffff; + ncarry = (ncarry + ((r / 0x4000000) | 0)) | 0; + lo = (lo + rword) | 0; + rword = lo & 0x3ffffff; + ncarry = (ncarry + (lo >>> 26)) | 0; + + hncarry += ncarry >>> 26; + ncarry &= 0x3ffffff; + } + out.words[k] = rword; + carry = ncarry; + ncarry = hncarry; + } + if (carry !== 0) { + out.words[k] = carry; + } else { + out.length--; + } + + return out.strip(); + } + + function jumboMulTo (self, num, out) { + var fftm = new FFTM(); + return fftm.mulp(self, num, out); + } + + BN.prototype.mulTo = function mulTo (num, out) { + var res; + var len = this.length + num.length; + if (this.length === 10 && num.length === 10) { + res = comb10MulTo(this, num, out); + } else if (len < 63) { + res = smallMulTo(this, num, out); + } else if (len < 1024) { + res = bigMulTo(this, num, out); + } else { + res = jumboMulTo(this, num, out); + } + + return res; + }; + + // Cooley-Tukey algorithm for FFT + // slightly revisited to rely on looping instead of recursion + + function FFTM (x, y) { + this.x = x; + this.y = y; + } + + FFTM.prototype.makeRBT = function makeRBT (N) { + var t = new Array(N); + var l = BN.prototype._countBits(N) - 1; + for (var i = 0; i < N; i++) { + t[i] = this.revBin(i, l, N); + } + + return t; + }; + + // Returns binary-reversed representation of `x` + FFTM.prototype.revBin = function revBin (x, l, N) { + if (x === 0 || x === N - 1) return x; + + var rb = 0; + for (var i = 0; i < l; i++) { + rb |= (x & 1) << (l - i - 1); + x >>= 1; + } + + return rb; + }; + + // Performs "tweedling" phase, therefore 'emulating' + // behaviour of the recursive algorithm + FFTM.prototype.permute = function permute (rbt, rws, iws, rtws, itws, N) { + for (var i = 0; i < N; i++) { + rtws[i] = rws[rbt[i]]; + itws[i] = iws[rbt[i]]; + } + }; + + FFTM.prototype.transform = function transform (rws, iws, rtws, itws, N, rbt) { + this.permute(rbt, rws, iws, rtws, itws, N); + + for (var s = 1; s < N; s <<= 1) { + var l = s << 1; + + var rtwdf = Math.cos(2 * Math.PI / l); + var itwdf = Math.sin(2 * Math.PI / l); + + for (var p = 0; p < N; p += l) { + var rtwdf_ = rtwdf; + var itwdf_ = itwdf; + + for (var j = 0; j < s; j++) { + var re = rtws[p + j]; + var ie = itws[p + j]; + + var ro = rtws[p + j + s]; + var io = itws[p + j + s]; + + var rx = rtwdf_ * ro - itwdf_ * io; + + io = rtwdf_ * io + itwdf_ * ro; + ro = rx; + + rtws[p + j] = re + ro; + itws[p + j] = ie + io; + + rtws[p + j + s] = re - ro; + itws[p + j + s] = ie - io; + + /* jshint maxdepth : false */ + if (j !== l) { + rx = rtwdf * rtwdf_ - itwdf * itwdf_; + + itwdf_ = rtwdf * itwdf_ + itwdf * rtwdf_; + rtwdf_ = rx; + } + } + } + } + }; + + FFTM.prototype.guessLen13b = function guessLen13b (n, m) { + var N = Math.max(m, n) | 1; + var odd = N & 1; + var i = 0; + for (N = N / 2 | 0; N; N = N >>> 1) { + i++; + } + + return 1 << i + 1 + odd; + }; + + FFTM.prototype.conjugate = function conjugate (rws, iws, N) { + if (N <= 1) return; + + for (var i = 0; i < N / 2; i++) { + var t = rws[i]; + + rws[i] = rws[N - i - 1]; + rws[N - i - 1] = t; + + t = iws[i]; + + iws[i] = -iws[N - i - 1]; + iws[N - i - 1] = -t; + } + }; + + FFTM.prototype.normalize13b = function normalize13b (ws, N) { + var carry = 0; + for (var i = 0; i < N / 2; i++) { + var w = Math.round(ws[2 * i + 1] / N) * 0x2000 + + Math.round(ws[2 * i] / N) + + carry; + + ws[i] = w & 0x3ffffff; + + if (w < 0x4000000) { + carry = 0; + } else { + carry = w / 0x4000000 | 0; + } + } + + return ws; + }; + + FFTM.prototype.convert13b = function convert13b (ws, len, rws, N) { + var carry = 0; + for (var i = 0; i < len; i++) { + carry = carry + (ws[i] | 0); + + rws[2 * i] = carry & 0x1fff; carry = carry >>> 13; + rws[2 * i + 1] = carry & 0x1fff; carry = carry >>> 13; + } + + // Pad with zeroes + for (i = 2 * len; i < N; ++i) { + rws[i] = 0; + } + + assert(carry === 0); + assert((carry & ~0x1fff) === 0); + }; + + FFTM.prototype.stub = function stub (N) { + var ph = new Array(N); + for (var i = 0; i < N; i++) { + ph[i] = 0; + } + + return ph; + }; + + FFTM.prototype.mulp = function mulp (x, y, out) { + var N = 2 * this.guessLen13b(x.length, y.length); + + var rbt = this.makeRBT(N); + + var _ = this.stub(N); + + var rws = new Array(N); + var rwst = new Array(N); + var iwst = new Array(N); + + var nrws = new Array(N); + var nrwst = new Array(N); + var niwst = new Array(N); + + var rmws = out.words; + rmws.length = N; + + this.convert13b(x.words, x.length, rws, N); + this.convert13b(y.words, y.length, nrws, N); + + this.transform(rws, _, rwst, iwst, N, rbt); + this.transform(nrws, _, nrwst, niwst, N, rbt); + + for (var i = 0; i < N; i++) { + var rx = rwst[i] * nrwst[i] - iwst[i] * niwst[i]; + iwst[i] = rwst[i] * niwst[i] + iwst[i] * nrwst[i]; + rwst[i] = rx; + } + + this.conjugate(rwst, iwst, N); + this.transform(rwst, iwst, rmws, _, N, rbt); + this.conjugate(rmws, _, N); + this.normalize13b(rmws, N); + + out.negative = x.negative ^ y.negative; + out.length = x.length + y.length; + return out.strip(); + }; + + // Multiply `this` by `num` + BN.prototype.mul = function mul (num) { + var out = new BN(null); + out.words = new Array(this.length + num.length); + return this.mulTo(num, out); + }; + + // Multiply employing FFT + BN.prototype.mulf = function mulf (num) { + var out = new BN(null); + out.words = new Array(this.length + num.length); + return jumboMulTo(this, num, out); + }; + + // In-place Multiplication + BN.prototype.imul = function imul (num) { + return this.clone().mulTo(num, this); + }; + + BN.prototype.imuln = function imuln (num) { + assert(typeof num === 'number'); + assert(num < 0x4000000); + + // Carry + var carry = 0; + for (var i = 0; i < this.length; i++) { + var w = (this.words[i] | 0) * num; + var lo = (w & 0x3ffffff) + (carry & 0x3ffffff); + carry >>= 26; + carry += (w / 0x4000000) | 0; + // NOTE: lo is 27bit maximum + carry += lo >>> 26; + this.words[i] = lo & 0x3ffffff; + } + + if (carry !== 0) { + this.words[i] = carry; + this.length++; + } + + return this; + }; + + BN.prototype.muln = function muln (num) { + return this.clone().imuln(num); + }; + + // `this` * `this` + BN.prototype.sqr = function sqr () { + return this.mul(this); + }; + + // `this` * `this` in-place + BN.prototype.isqr = function isqr () { + return this.imul(this.clone()); + }; + + // Math.pow(`this`, `num`) + BN.prototype.pow = function pow (num) { + var w = toBitArray(num); + if (w.length === 0) return new BN(1); + + // Skip leading zeroes + var res = this; + for (var i = 0; i < w.length; i++, res = res.sqr()) { + if (w[i] !== 0) break; + } + + if (++i < w.length) { + for (var q = res.sqr(); i < w.length; i++, q = q.sqr()) { + if (w[i] === 0) continue; + + res = res.mul(q); + } + } + + return res; + }; + + // Shift-left in-place + BN.prototype.iushln = function iushln (bits) { + assert(typeof bits === 'number' && bits >= 0); + var r = bits % 26; + var s = (bits - r) / 26; + var carryMask = (0x3ffffff >>> (26 - r)) << (26 - r); + var i; + + if (r !== 0) { + var carry = 0; + + for (i = 0; i < this.length; i++) { + var newCarry = this.words[i] & carryMask; + var c = ((this.words[i] | 0) - newCarry) << r; + this.words[i] = c | carry; + carry = newCarry >>> (26 - r); + } + + if (carry) { + this.words[i] = carry; + this.length++; + } + } + + if (s !== 0) { + for (i = this.length - 1; i >= 0; i--) { + this.words[i + s] = this.words[i]; + } + + for (i = 0; i < s; i++) { + this.words[i] = 0; + } + + this.length += s; + } + + return this.strip(); + }; + + BN.prototype.ishln = function ishln (bits) { + // TODO(indutny): implement me + assert(this.negative === 0); + return this.iushln(bits); + }; + + // Shift-right in-place + // NOTE: `hint` is a lowest bit before trailing zeroes + // NOTE: if `extended` is present - it will be filled with destroyed bits + BN.prototype.iushrn = function iushrn (bits, hint, extended) { + assert(typeof bits === 'number' && bits >= 0); + var h; + if (hint) { + h = (hint - (hint % 26)) / 26; + } else { + h = 0; + } + + var r = bits % 26; + var s = Math.min((bits - r) / 26, this.length); + var mask = 0x3ffffff ^ ((0x3ffffff >>> r) << r); + var maskedWords = extended; + + h -= s; + h = Math.max(0, h); + + // Extended mode, copy masked part + if (maskedWords) { + for (var i = 0; i < s; i++) { + maskedWords.words[i] = this.words[i]; + } + maskedWords.length = s; + } + + if (s === 0) { + // No-op, we should not move anything at all + } else if (this.length > s) { + this.length -= s; + for (i = 0; i < this.length; i++) { + this.words[i] = this.words[i + s]; + } + } else { + this.words[0] = 0; + this.length = 1; + } + + var carry = 0; + for (i = this.length - 1; i >= 0 && (carry !== 0 || i >= h); i--) { + var word = this.words[i] | 0; + this.words[i] = (carry << (26 - r)) | (word >>> r); + carry = word & mask; + } + + // Push carried bits as a mask + if (maskedWords && carry !== 0) { + maskedWords.words[maskedWords.length++] = carry; + } + + if (this.length === 0) { + this.words[0] = 0; + this.length = 1; + } + + return this.strip(); + }; + + BN.prototype.ishrn = function ishrn (bits, hint, extended) { + // TODO(indutny): implement me + assert(this.negative === 0); + return this.iushrn(bits, hint, extended); + }; + + // Shift-left + BN.prototype.shln = function shln (bits) { + return this.clone().ishln(bits); + }; + + BN.prototype.ushln = function ushln (bits) { + return this.clone().iushln(bits); + }; + + // Shift-right + BN.prototype.shrn = function shrn (bits) { + return this.clone().ishrn(bits); + }; + + BN.prototype.ushrn = function ushrn (bits) { + return this.clone().iushrn(bits); + }; + + // Test if n bit is set + BN.prototype.testn = function testn (bit) { + assert(typeof bit === 'number' && bit >= 0); + var r = bit % 26; + var s = (bit - r) / 26; + var q = 1 << r; + + // Fast case: bit is much higher than all existing words + if (this.length <= s) return false; + + // Check bit and return + var w = this.words[s]; + + return !!(w & q); + }; + + // Return only lowers bits of number (in-place) + BN.prototype.imaskn = function imaskn (bits) { + assert(typeof bits === 'number' && bits >= 0); + var r = bits % 26; + var s = (bits - r) / 26; + + assert(this.negative === 0, 'imaskn works only with positive numbers'); + + if (this.length <= s) { + return this; + } + + if (r !== 0) { + s++; + } + this.length = Math.min(s, this.length); + + if (r !== 0) { + var mask = 0x3ffffff ^ ((0x3ffffff >>> r) << r); + this.words[this.length - 1] &= mask; + } + + return this.strip(); + }; + + // Return only lowers bits of number + BN.prototype.maskn = function maskn (bits) { + return this.clone().imaskn(bits); + }; + + // Add plain number `num` to `this` + BN.prototype.iaddn = function iaddn (num) { + assert(typeof num === 'number'); + assert(num < 0x4000000); + if (num < 0) return this.isubn(-num); + + // Possible sign change + if (this.negative !== 0) { + if (this.length === 1 && (this.words[0] | 0) < num) { + this.words[0] = num - (this.words[0] | 0); + this.negative = 0; + return this; + } + + this.negative = 0; + this.isubn(num); + this.negative = 1; + return this; + } + + // Add without checks + return this._iaddn(num); + }; + + BN.prototype._iaddn = function _iaddn (num) { + this.words[0] += num; + + // Carry + for (var i = 0; i < this.length && this.words[i] >= 0x4000000; i++) { + this.words[i] -= 0x4000000; + if (i === this.length - 1) { + this.words[i + 1] = 1; + } else { + this.words[i + 1]++; + } + } + this.length = Math.max(this.length, i + 1); + + return this; + }; + + // Subtract plain number `num` from `this` + BN.prototype.isubn = function isubn (num) { + assert(typeof num === 'number'); + assert(num < 0x4000000); + if (num < 0) return this.iaddn(-num); + + if (this.negative !== 0) { + this.negative = 0; + this.iaddn(num); + this.negative = 1; + return this; + } + + this.words[0] -= num; + + if (this.length === 1 && this.words[0] < 0) { + this.words[0] = -this.words[0]; + this.negative = 1; + } else { + // Carry + for (var i = 0; i < this.length && this.words[i] < 0; i++) { + this.words[i] += 0x4000000; + this.words[i + 1] -= 1; + } + } + + return this.strip(); + }; + + BN.prototype.addn = function addn (num) { + return this.clone().iaddn(num); + }; + + BN.prototype.subn = function subn (num) { + return this.clone().isubn(num); + }; + + BN.prototype.iabs = function iabs () { + this.negative = 0; + + return this; + }; + + BN.prototype.abs = function abs () { + return this.clone().iabs(); + }; + + BN.prototype._ishlnsubmul = function _ishlnsubmul (num, mul, shift) { + var len = num.length + shift; + var i; + + this._expand(len); + + var w; + var carry = 0; + for (i = 0; i < num.length; i++) { + w = (this.words[i + shift] | 0) + carry; + var right = (num.words[i] | 0) * mul; + w -= right & 0x3ffffff; + carry = (w >> 26) - ((right / 0x4000000) | 0); + this.words[i + shift] = w & 0x3ffffff; + } + for (; i < this.length - shift; i++) { + w = (this.words[i + shift] | 0) + carry; + carry = w >> 26; + this.words[i + shift] = w & 0x3ffffff; + } + + if (carry === 0) return this.strip(); + + // Subtraction overflow + assert(carry === -1); + carry = 0; + for (i = 0; i < this.length; i++) { + w = -(this.words[i] | 0) + carry; + carry = w >> 26; + this.words[i] = w & 0x3ffffff; + } + this.negative = 1; + + return this.strip(); + }; + + BN.prototype._wordDiv = function _wordDiv (num, mode) { + var shift = this.length - num.length; + + var a = this.clone(); + var b = num; + + // Normalize + var bhi = b.words[b.length - 1] | 0; + var bhiBits = this._countBits(bhi); + shift = 26 - bhiBits; + if (shift !== 0) { + b = b.ushln(shift); + a.iushln(shift); + bhi = b.words[b.length - 1] | 0; + } + + // Initialize quotient + var m = a.length - b.length; + var q; + + if (mode !== 'mod') { + q = new BN(null); + q.length = m + 1; + q.words = new Array(q.length); + for (var i = 0; i < q.length; i++) { + q.words[i] = 0; + } + } + + var diff = a.clone()._ishlnsubmul(b, 1, m); + if (diff.negative === 0) { + a = diff; + if (q) { + q.words[m] = 1; + } + } + + for (var j = m - 1; j >= 0; j--) { + var qj = (a.words[b.length + j] | 0) * 0x4000000 + + (a.words[b.length + j - 1] | 0); + + // NOTE: (qj / bhi) is (0x3ffffff * 0x4000000 + 0x3ffffff) / 0x2000000 max + // (0x7ffffff) + qj = Math.min((qj / bhi) | 0, 0x3ffffff); + + a._ishlnsubmul(b, qj, j); + while (a.negative !== 0) { + qj--; + a.negative = 0; + a._ishlnsubmul(b, 1, j); + if (!a.isZero()) { + a.negative ^= 1; + } + } + if (q) { + q.words[j] = qj; + } + } + if (q) { + q.strip(); + } + a.strip(); + + // Denormalize + if (mode !== 'div' && shift !== 0) { + a.iushrn(shift); + } + + return { + div: q || null, + mod: a + }; + }; + + // NOTE: 1) `mode` can be set to `mod` to request mod only, + // to `div` to request div only, or be absent to + // request both div & mod + // 2) `positive` is true if unsigned mod is requested + BN.prototype.divmod = function divmod (num, mode, positive) { + assert(!num.isZero()); + + if (this.isZero()) { + return { + div: new BN(0), + mod: new BN(0) + }; + } + + var div, mod, res; + if (this.negative !== 0 && num.negative === 0) { + res = this.neg().divmod(num, mode); + + if (mode !== 'mod') { + div = res.div.neg(); + } + + if (mode !== 'div') { + mod = res.mod.neg(); + if (positive && mod.negative !== 0) { + mod.iadd(num); + } + } + + return { + div: div, + mod: mod + }; + } + + if (this.negative === 0 && num.negative !== 0) { + res = this.divmod(num.neg(), mode); + + if (mode !== 'mod') { + div = res.div.neg(); + } + + return { + div: div, + mod: res.mod + }; + } + + if ((this.negative & num.negative) !== 0) { + res = this.neg().divmod(num.neg(), mode); + + if (mode !== 'div') { + mod = res.mod.neg(); + if (positive && mod.negative !== 0) { + mod.isub(num); + } + } + + return { + div: res.div, + mod: mod + }; + } + + // Both numbers are positive at this point + + // Strip both numbers to approximate shift value + if (num.length > this.length || this.cmp(num) < 0) { + return { + div: new BN(0), + mod: this + }; + } + + // Very short reduction + if (num.length === 1) { + if (mode === 'div') { + return { + div: this.divn(num.words[0]), + mod: null + }; + } + + if (mode === 'mod') { + return { + div: null, + mod: new BN(this.modn(num.words[0])) + }; + } + + return { + div: this.divn(num.words[0]), + mod: new BN(this.modn(num.words[0])) + }; + } + + return this._wordDiv(num, mode); + }; + + // Find `this` / `num` + BN.prototype.div = function div (num) { + return this.divmod(num, 'div', false).div; + }; + + // Find `this` % `num` + BN.prototype.mod = function mod (num) { + return this.divmod(num, 'mod', false).mod; + }; + + BN.prototype.umod = function umod (num) { + return this.divmod(num, 'mod', true).mod; + }; + + // Find Round(`this` / `num`) + BN.prototype.divRound = function divRound (num) { + var dm = this.divmod(num); + + // Fast case - exact division + if (dm.mod.isZero()) return dm.div; + + var mod = dm.div.negative !== 0 ? dm.mod.isub(num) : dm.mod; + + var half = num.ushrn(1); + var r2 = num.andln(1); + var cmp = mod.cmp(half); + + // Round down + if (cmp < 0 || r2 === 1 && cmp === 0) return dm.div; + + // Round up + return dm.div.negative !== 0 ? dm.div.isubn(1) : dm.div.iaddn(1); + }; + + BN.prototype.modn = function modn (num) { + assert(num <= 0x3ffffff); + var p = (1 << 26) % num; + + var acc = 0; + for (var i = this.length - 1; i >= 0; i--) { + acc = (p * acc + (this.words[i] | 0)) % num; + } + + return acc; + }; + + // In-place division by number + BN.prototype.idivn = function idivn (num) { + assert(num <= 0x3ffffff); + + var carry = 0; + for (var i = this.length - 1; i >= 0; i--) { + var w = (this.words[i] | 0) + carry * 0x4000000; + this.words[i] = (w / num) | 0; + carry = w % num; + } + + return this.strip(); + }; + + BN.prototype.divn = function divn (num) { + return this.clone().idivn(num); + }; + + BN.prototype.egcd = function egcd (p) { + assert(p.negative === 0); + assert(!p.isZero()); + + var x = this; + var y = p.clone(); + + if (x.negative !== 0) { + x = x.umod(p); + } else { + x = x.clone(); + } + + // A * x + B * y = x + var A = new BN(1); + var B = new BN(0); + + // C * x + D * y = y + var C = new BN(0); + var D = new BN(1); + + var g = 0; + + while (x.isEven() && y.isEven()) { + x.iushrn(1); + y.iushrn(1); + ++g; + } + + var yp = y.clone(); + var xp = x.clone(); + + while (!x.isZero()) { + for (var i = 0, im = 1; (x.words[0] & im) === 0 && i < 26; ++i, im <<= 1); + if (i > 0) { + x.iushrn(i); + while (i-- > 0) { + if (A.isOdd() || B.isOdd()) { + A.iadd(yp); + B.isub(xp); + } + + A.iushrn(1); + B.iushrn(1); + } + } + + for (var j = 0, jm = 1; (y.words[0] & jm) === 0 && j < 26; ++j, jm <<= 1); + if (j > 0) { + y.iushrn(j); + while (j-- > 0) { + if (C.isOdd() || D.isOdd()) { + C.iadd(yp); + D.isub(xp); + } + + C.iushrn(1); + D.iushrn(1); + } + } + + if (x.cmp(y) >= 0) { + x.isub(y); + A.isub(C); + B.isub(D); + } else { + y.isub(x); + C.isub(A); + D.isub(B); + } + } + + return { + a: C, + b: D, + gcd: y.iushln(g) + }; + }; + + // This is reduced incarnation of the binary EEA + // above, designated to invert members of the + // _prime_ fields F(p) at a maximal speed + BN.prototype._invmp = function _invmp (p) { + assert(p.negative === 0); + assert(!p.isZero()); + + var a = this; + var b = p.clone(); + + if (a.negative !== 0) { + a = a.umod(p); + } else { + a = a.clone(); + } + + var x1 = new BN(1); + var x2 = new BN(0); + + var delta = b.clone(); + + while (a.cmpn(1) > 0 && b.cmpn(1) > 0) { + for (var i = 0, im = 1; (a.words[0] & im) === 0 && i < 26; ++i, im <<= 1); + if (i > 0) { + a.iushrn(i); + while (i-- > 0) { + if (x1.isOdd()) { + x1.iadd(delta); + } + + x1.iushrn(1); + } + } + + for (var j = 0, jm = 1; (b.words[0] & jm) === 0 && j < 26; ++j, jm <<= 1); + if (j > 0) { + b.iushrn(j); + while (j-- > 0) { + if (x2.isOdd()) { + x2.iadd(delta); + } + + x2.iushrn(1); + } + } + + if (a.cmp(b) >= 0) { + a.isub(b); + x1.isub(x2); + } else { + b.isub(a); + x2.isub(x1); + } + } + + var res; + if (a.cmpn(1) === 0) { + res = x1; + } else { + res = x2; + } + + if (res.cmpn(0) < 0) { + res.iadd(p); + } + + return res; + }; + + BN.prototype.gcd = function gcd (num) { + if (this.isZero()) return num.abs(); + if (num.isZero()) return this.abs(); + + var a = this.clone(); + var b = num.clone(); + a.negative = 0; + b.negative = 0; + + // Remove common factor of two + for (var shift = 0; a.isEven() && b.isEven(); shift++) { + a.iushrn(1); + b.iushrn(1); + } + + do { + while (a.isEven()) { + a.iushrn(1); + } + while (b.isEven()) { + b.iushrn(1); + } + + var r = a.cmp(b); + if (r < 0) { + // Swap `a` and `b` to make `a` always bigger than `b` + var t = a; + a = b; + b = t; + } else if (r === 0 || b.cmpn(1) === 0) { + break; + } + + a.isub(b); + } while (true); + + return b.iushln(shift); + }; + + // Invert number in the field F(num) + BN.prototype.invm = function invm (num) { + return this.egcd(num).a.umod(num); + }; + + BN.prototype.isEven = function isEven () { + return (this.words[0] & 1) === 0; + }; + + BN.prototype.isOdd = function isOdd () { + return (this.words[0] & 1) === 1; + }; + + // And first word and num + BN.prototype.andln = function andln (num) { + return this.words[0] & num; + }; + + // Increment at the bit position in-line + BN.prototype.bincn = function bincn (bit) { + assert(typeof bit === 'number'); + var r = bit % 26; + var s = (bit - r) / 26; + var q = 1 << r; + + // Fast case: bit is much higher than all existing words + if (this.length <= s) { + this._expand(s + 1); + this.words[s] |= q; + return this; + } + + // Add bit and propagate, if needed + var carry = q; + for (var i = s; carry !== 0 && i < this.length; i++) { + var w = this.words[i] | 0; + w += carry; + carry = w >>> 26; + w &= 0x3ffffff; + this.words[i] = w; + } + if (carry !== 0) { + this.words[i] = carry; + this.length++; + } + return this; + }; + + BN.prototype.isZero = function isZero () { + return this.length === 1 && this.words[0] === 0; + }; + + BN.prototype.cmpn = function cmpn (num) { + var negative = num < 0; + + if (this.negative !== 0 && !negative) return -1; + if (this.negative === 0 && negative) return 1; + + this.strip(); + + var res; + if (this.length > 1) { + res = 1; + } else { + if (negative) { + num = -num; + } + + assert(num <= 0x3ffffff, 'Number is too big'); + + var w = this.words[0] | 0; + res = w === num ? 0 : w < num ? -1 : 1; + } + if (this.negative !== 0) return -res | 0; + return res; + }; + + // Compare two numbers and return: + // 1 - if `this` > `num` + // 0 - if `this` == `num` + // -1 - if `this` < `num` + BN.prototype.cmp = function cmp (num) { + if (this.negative !== 0 && num.negative === 0) return -1; + if (this.negative === 0 && num.negative !== 0) return 1; + + var res = this.ucmp(num); + if (this.negative !== 0) return -res | 0; + return res; + }; + + // Unsigned comparison + BN.prototype.ucmp = function ucmp (num) { + // At this point both numbers have the same sign + if (this.length > num.length) return 1; + if (this.length < num.length) return -1; + + var res = 0; + for (var i = this.length - 1; i >= 0; i--) { + var a = this.words[i] | 0; + var b = num.words[i] | 0; + + if (a === b) continue; + if (a < b) { + res = -1; + } else if (a > b) { + res = 1; + } + break; + } + return res; + }; + + BN.prototype.gtn = function gtn (num) { + return this.cmpn(num) === 1; + }; + + BN.prototype.gt = function gt (num) { + return this.cmp(num) === 1; + }; + + BN.prototype.gten = function gten (num) { + return this.cmpn(num) >= 0; + }; + + BN.prototype.gte = function gte (num) { + return this.cmp(num) >= 0; + }; + + BN.prototype.ltn = function ltn (num) { + return this.cmpn(num) === -1; + }; + + BN.prototype.lt = function lt (num) { + return this.cmp(num) === -1; + }; + + BN.prototype.lten = function lten (num) { + return this.cmpn(num) <= 0; + }; + + BN.prototype.lte = function lte (num) { + return this.cmp(num) <= 0; + }; + + BN.prototype.eqn = function eqn (num) { + return this.cmpn(num) === 0; + }; + + BN.prototype.eq = function eq (num) { + return this.cmp(num) === 0; + }; + + // + // A reduce context, could be using montgomery or something better, depending + // on the `m` itself. + // + BN.red = function red (num) { + return new Red(num); + }; + + BN.prototype.toRed = function toRed (ctx) { + assert(!this.red, 'Already a number in reduction context'); + assert(this.negative === 0, 'red works only with positives'); + return ctx.convertTo(this)._forceRed(ctx); + }; + + BN.prototype.fromRed = function fromRed () { + assert(this.red, 'fromRed works only with numbers in reduction context'); + return this.red.convertFrom(this); + }; + + BN.prototype._forceRed = function _forceRed (ctx) { + this.red = ctx; + return this; + }; + + BN.prototype.forceRed = function forceRed (ctx) { + assert(!this.red, 'Already a number in reduction context'); + return this._forceRed(ctx); + }; + + BN.prototype.redAdd = function redAdd (num) { + assert(this.red, 'redAdd works only with red numbers'); + return this.red.add(this, num); + }; + + BN.prototype.redIAdd = function redIAdd (num) { + assert(this.red, 'redIAdd works only with red numbers'); + return this.red.iadd(this, num); + }; + + BN.prototype.redSub = function redSub (num) { + assert(this.red, 'redSub works only with red numbers'); + return this.red.sub(this, num); + }; + + BN.prototype.redISub = function redISub (num) { + assert(this.red, 'redISub works only with red numbers'); + return this.red.isub(this, num); + }; + + BN.prototype.redShl = function redShl (num) { + assert(this.red, 'redShl works only with red numbers'); + return this.red.shl(this, num); + }; + + BN.prototype.redMul = function redMul (num) { + assert(this.red, 'redMul works only with red numbers'); + this.red._verify2(this, num); + return this.red.mul(this, num); + }; + + BN.prototype.redIMul = function redIMul (num) { + assert(this.red, 'redMul works only with red numbers'); + this.red._verify2(this, num); + return this.red.imul(this, num); + }; + + BN.prototype.redSqr = function redSqr () { + assert(this.red, 'redSqr works only with red numbers'); + this.red._verify1(this); + return this.red.sqr(this); + }; + + BN.prototype.redISqr = function redISqr () { + assert(this.red, 'redISqr works only with red numbers'); + this.red._verify1(this); + return this.red.isqr(this); + }; + + // Square root over p + BN.prototype.redSqrt = function redSqrt () { + assert(this.red, 'redSqrt works only with red numbers'); + this.red._verify1(this); + return this.red.sqrt(this); + }; + + BN.prototype.redInvm = function redInvm () { + assert(this.red, 'redInvm works only with red numbers'); + this.red._verify1(this); + return this.red.invm(this); + }; + + // Return negative clone of `this` % `red modulo` + BN.prototype.redNeg = function redNeg () { + assert(this.red, 'redNeg works only with red numbers'); + this.red._verify1(this); + return this.red.neg(this); + }; + + BN.prototype.redPow = function redPow (num) { + assert(this.red && !num.red, 'redPow(normalNum)'); + this.red._verify1(this); + return this.red.pow(this, num); + }; + + // Prime numbers with efficient reduction + var primes = { + k256: null, + p224: null, + p192: null, + p25519: null + }; + + // Pseudo-Mersenne prime + function MPrime (name, p) { + // P = 2 ^ N - K + this.name = name; + this.p = new BN(p, 16); + this.n = this.p.bitLength(); + this.k = new BN(1).iushln(this.n).isub(this.p); + + this.tmp = this._tmp(); + } + + MPrime.prototype._tmp = function _tmp () { + var tmp = new BN(null); + tmp.words = new Array(Math.ceil(this.n / 13)); + return tmp; + }; + + MPrime.prototype.ireduce = function ireduce (num) { + // Assumes that `num` is less than `P^2` + // num = HI * (2 ^ N - K) + HI * K + LO = HI * K + LO (mod P) + var r = num; + var rlen; + + do { + this.split(r, this.tmp); + r = this.imulK(r); + r = r.iadd(this.tmp); + rlen = r.bitLength(); + } while (rlen > this.n); + + var cmp = rlen < this.n ? -1 : r.ucmp(this.p); + if (cmp === 0) { + r.words[0] = 0; + r.length = 1; + } else if (cmp > 0) { + r.isub(this.p); + } else { + if (r.strip !== undefined) { + // r is BN v4 instance + r.strip(); + } else { + // r is BN v5 instance + r._strip(); + } + } + + return r; + }; + + MPrime.prototype.split = function split (input, out) { + input.iushrn(this.n, 0, out); + }; + + MPrime.prototype.imulK = function imulK (num) { + return num.imul(this.k); + }; + + function K256 () { + MPrime.call( + this, + 'k256', + 'ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff fffffffe fffffc2f'); + } + inherits(K256, MPrime); + + K256.prototype.split = function split (input, output) { + // 256 = 9 * 26 + 22 + var mask = 0x3fffff; + + var outLen = Math.min(input.length, 9); + for (var i = 0; i < outLen; i++) { + output.words[i] = input.words[i]; + } + output.length = outLen; + + if (input.length <= 9) { + input.words[0] = 0; + input.length = 1; + return; + } + + // Shift by 9 limbs + var prev = input.words[9]; + output.words[output.length++] = prev & mask; + + for (i = 10; i < input.length; i++) { + var next = input.words[i] | 0; + input.words[i - 10] = ((next & mask) << 4) | (prev >>> 22); + prev = next; + } + prev >>>= 22; + input.words[i - 10] = prev; + if (prev === 0 && input.length > 10) { + input.length -= 10; + } else { + input.length -= 9; + } + }; + + K256.prototype.imulK = function imulK (num) { + // K = 0x1000003d1 = [ 0x40, 0x3d1 ] + num.words[num.length] = 0; + num.words[num.length + 1] = 0; + num.length += 2; + + // bounded at: 0x40 * 0x3ffffff + 0x3d0 = 0x100000390 + var lo = 0; + for (var i = 0; i < num.length; i++) { + var w = num.words[i] | 0; + lo += w * 0x3d1; + num.words[i] = lo & 0x3ffffff; + lo = w * 0x40 + ((lo / 0x4000000) | 0); + } + + // Fast length reduction + if (num.words[num.length - 1] === 0) { + num.length--; + if (num.words[num.length - 1] === 0) { + num.length--; + } + } + return num; + }; + + function P224 () { + MPrime.call( + this, + 'p224', + 'ffffffff ffffffff ffffffff ffffffff 00000000 00000000 00000001'); + } + inherits(P224, MPrime); + + function P192 () { + MPrime.call( + this, + 'p192', + 'ffffffff ffffffff ffffffff fffffffe ffffffff ffffffff'); + } + inherits(P192, MPrime); + + function P25519 () { + // 2 ^ 255 - 19 + MPrime.call( + this, + '25519', + '7fffffffffffffff ffffffffffffffff ffffffffffffffff ffffffffffffffed'); + } + inherits(P25519, MPrime); + + P25519.prototype.imulK = function imulK (num) { + // K = 0x13 + var carry = 0; + for (var i = 0; i < num.length; i++) { + var hi = (num.words[i] | 0) * 0x13 + carry; + var lo = hi & 0x3ffffff; + hi >>>= 26; + + num.words[i] = lo; + carry = hi; + } + if (carry !== 0) { + num.words[num.length++] = carry; + } + return num; + }; + + // Exported mostly for testing purposes, use plain name instead + BN._prime = function prime (name) { + // Cached version of prime + if (primes[name]) return primes[name]; + + var prime; + if (name === 'k256') { + prime = new K256(); + } else if (name === 'p224') { + prime = new P224(); + } else if (name === 'p192') { + prime = new P192(); + } else if (name === 'p25519') { + prime = new P25519(); + } else { + throw new Error('Unknown prime ' + name); + } + primes[name] = prime; + + return prime; + }; + + // + // Base reduction engine + // + function Red (m) { + if (typeof m === 'string') { + var prime = BN._prime(m); + this.m = prime.p; + this.prime = prime; + } else { + assert(m.gtn(1), 'modulus must be greater than 1'); + this.m = m; + this.prime = null; + } + } + + Red.prototype._verify1 = function _verify1 (a) { + assert(a.negative === 0, 'red works only with positives'); + assert(a.red, 'red works only with red numbers'); + }; + + Red.prototype._verify2 = function _verify2 (a, b) { + assert((a.negative | b.negative) === 0, 'red works only with positives'); + assert(a.red && a.red === b.red, + 'red works only with red numbers'); + }; + + Red.prototype.imod = function imod (a) { + if (this.prime) return this.prime.ireduce(a)._forceRed(this); + return a.umod(this.m)._forceRed(this); + }; + + Red.prototype.neg = function neg (a) { + if (a.isZero()) { + return a.clone(); + } + + return this.m.sub(a)._forceRed(this); + }; + + Red.prototype.add = function add (a, b) { + this._verify2(a, b); + + var res = a.add(b); + if (res.cmp(this.m) >= 0) { + res.isub(this.m); + } + return res._forceRed(this); + }; + + Red.prototype.iadd = function iadd (a, b) { + this._verify2(a, b); + + var res = a.iadd(b); + if (res.cmp(this.m) >= 0) { + res.isub(this.m); + } + return res; + }; + + Red.prototype.sub = function sub (a, b) { + this._verify2(a, b); + + var res = a.sub(b); + if (res.cmpn(0) < 0) { + res.iadd(this.m); + } + return res._forceRed(this); + }; + + Red.prototype.isub = function isub (a, b) { + this._verify2(a, b); + + var res = a.isub(b); + if (res.cmpn(0) < 0) { + res.iadd(this.m); + } + return res; + }; + + Red.prototype.shl = function shl (a, num) { + this._verify1(a); + return this.imod(a.ushln(num)); + }; + + Red.prototype.imul = function imul (a, b) { + this._verify2(a, b); + return this.imod(a.imul(b)); + }; + + Red.prototype.mul = function mul (a, b) { + this._verify2(a, b); + return this.imod(a.mul(b)); + }; + + Red.prototype.isqr = function isqr (a) { + return this.imul(a, a.clone()); + }; + + Red.prototype.sqr = function sqr (a) { + return this.mul(a, a); + }; + + Red.prototype.sqrt = function sqrt (a) { + if (a.isZero()) return a.clone(); + + var mod3 = this.m.andln(3); + assert(mod3 % 2 === 1); + + // Fast case + if (mod3 === 3) { + var pow = this.m.add(new BN(1)).iushrn(2); + return this.pow(a, pow); + } + + // Tonelli-Shanks algorithm (Totally unoptimized and slow) + // + // Find Q and S, that Q * 2 ^ S = (P - 1) + var q = this.m.subn(1); + var s = 0; + while (!q.isZero() && q.andln(1) === 0) { + s++; + q.iushrn(1); + } + assert(!q.isZero()); + + var one = new BN(1).toRed(this); + var nOne = one.redNeg(); + + // Find quadratic non-residue + // NOTE: Max is such because of generalized Riemann hypothesis. + var lpow = this.m.subn(1).iushrn(1); + var z = this.m.bitLength(); + z = new BN(2 * z * z).toRed(this); + + while (this.pow(z, lpow).cmp(nOne) !== 0) { + z.redIAdd(nOne); + } + + var c = this.pow(z, q); + var r = this.pow(a, q.addn(1).iushrn(1)); + var t = this.pow(a, q); + var m = s; + while (t.cmp(one) !== 0) { + var tmp = t; + for (var i = 0; tmp.cmp(one) !== 0; i++) { + tmp = tmp.redSqr(); + } + assert(i < m); + var b = this.pow(c, new BN(1).iushln(m - i - 1)); + + r = r.redMul(b); + c = b.redSqr(); + t = t.redMul(c); + m = i; + } + + return r; + }; + + Red.prototype.invm = function invm (a) { + var inv = a._invmp(this.m); + if (inv.negative !== 0) { + inv.negative = 0; + return this.imod(inv).redNeg(); + } else { + return this.imod(inv); + } + }; + + Red.prototype.pow = function pow (a, num) { + if (num.isZero()) return new BN(1).toRed(this); + if (num.cmpn(1) === 0) return a.clone(); + + var windowSize = 4; + var wnd = new Array(1 << windowSize); + wnd[0] = new BN(1).toRed(this); + wnd[1] = a; + for (var i = 2; i < wnd.length; i++) { + wnd[i] = this.mul(wnd[i - 1], a); + } + + var res = wnd[0]; + var current = 0; + var currentLen = 0; + var start = num.bitLength() % 26; + if (start === 0) { + start = 26; + } + + for (i = num.length - 1; i >= 0; i--) { + var word = num.words[i]; + for (var j = start - 1; j >= 0; j--) { + var bit = (word >> j) & 1; + if (res !== wnd[0]) { + res = this.sqr(res); + } + + if (bit === 0 && current === 0) { + currentLen = 0; + continue; + } + + current <<= 1; + current |= bit; + currentLen++; + if (currentLen !== windowSize && (i !== 0 || j !== 0)) continue; + + res = this.mul(res, wnd[current]); + currentLen = 0; + current = 0; + } + start = 26; + } + + return res; + }; + + Red.prototype.convertTo = function convertTo (num) { + var r = num.umod(this.m); + + return r === num ? r.clone() : r; + }; + + Red.prototype.convertFrom = function convertFrom (num) { + var res = num.clone(); + res.red = null; + return res; + }; + + // + // Montgomery method engine + // + + BN.mont = function mont (num) { + return new Mont(num); + }; + + function Mont (m) { + Red.call(this, m); + + this.shift = this.m.bitLength(); + if (this.shift % 26 !== 0) { + this.shift += 26 - (this.shift % 26); + } + + this.r = new BN(1).iushln(this.shift); + this.r2 = this.imod(this.r.sqr()); + this.rinv = this.r._invmp(this.m); + + this.minv = this.rinv.mul(this.r).isubn(1).div(this.m); + this.minv = this.minv.umod(this.r); + this.minv = this.r.sub(this.minv); + } + inherits(Mont, Red); + + Mont.prototype.convertTo = function convertTo (num) { + return this.imod(num.ushln(this.shift)); + }; + + Mont.prototype.convertFrom = function convertFrom (num) { + var r = this.imod(num.mul(this.rinv)); + r.red = null; + return r; + }; + + Mont.prototype.imul = function imul (a, b) { + if (a.isZero() || b.isZero()) { + a.words[0] = 0; + a.length = 1; + return a; + } + + var t = a.imul(b); + var c = t.maskn(this.shift).mul(this.minv).imaskn(this.shift).mul(this.m); + var u = t.isub(c).iushrn(this.shift); + var res = u; + + if (u.cmp(this.m) >= 0) { + res = u.isub(this.m); + } else if (u.cmpn(0) < 0) { + res = u.iadd(this.m); + } + + return res._forceRed(this); + }; + + Mont.prototype.mul = function mul (a, b) { + if (a.isZero() || b.isZero()) return new BN(0)._forceRed(this); + + var t = a.mul(b); + var c = t.maskn(this.shift).mul(this.minv).imaskn(this.shift).mul(this.m); + var u = t.isub(c).iushrn(this.shift); + var res = u; + if (u.cmp(this.m) >= 0) { + res = u.isub(this.m); + } else if (u.cmpn(0) < 0) { + res = u.iadd(this.m); + } + + return res._forceRed(this); + }; + + Mont.prototype.invm = function invm (a) { + // (AR)^-1 * R^2 = (A^-1 * R^-1) * R^2 = A^-1 * R + var res = this.imod(a._invmp(this.m).mul(this.r2)); + return res._forceRed(this); + }; +})(typeof module === 'undefined' || module, this); + +},{"buffer":20}],16:[function(require,module,exports){ +(function (global){(function (){ +'use strict'; + +var possibleNames = [ + 'BigInt64Array', + 'BigUint64Array', + 'Float32Array', + 'Float64Array', + 'Int16Array', + 'Int32Array', + 'Int8Array', + 'Uint16Array', + 'Uint32Array', + 'Uint8Array', + 'Uint8ClampedArray' +]; + +module.exports = function availableTypedArrays() { + var out = []; + for (var i = 0; i < possibleNames.length; i++) { + if (typeof global[possibleNames[i]] === 'function') { + out[out.length] = possibleNames[i]; + } + } + return out; +}; + +}).call(this)}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) +},{}],17:[function(require,module,exports){ +'use strict' + +exports.byteLength = byteLength +exports.toByteArray = toByteArray +exports.fromByteArray = fromByteArray + +var lookup = [] +var revLookup = [] +var Arr = typeof Uint8Array !== 'undefined' ? Uint8Array : Array + +var code = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/' +for (var i = 0, len = code.length; i < len; ++i) { + lookup[i] = code[i] + revLookup[code.charCodeAt(i)] = i +} + +// Support decoding URL-safe base64 strings, as Node.js does. +// See: https://en.wikipedia.org/wiki/Base64#URL_applications +revLookup['-'.charCodeAt(0)] = 62 +revLookup['_'.charCodeAt(0)] = 63 + +function getLens (b64) { + var len = b64.length + + if (len % 4 > 0) { + throw new Error('Invalid string. Length must be a multiple of 4') + } + + // Trim off extra bytes after placeholder bytes are found + // See: https://github.com/beatgammit/base64-js/issues/42 + var validLen = b64.indexOf('=') + if (validLen === -1) validLen = len + + var placeHoldersLen = validLen === len + ? 0 + : 4 - (validLen % 4) + + return [validLen, placeHoldersLen] +} + +// base64 is 4/3 + up to two characters of the original data +function byteLength (b64) { + var lens = getLens(b64) + var validLen = lens[0] + var placeHoldersLen = lens[1] + return ((validLen + placeHoldersLen) * 3 / 4) - placeHoldersLen +} + +function _byteLength (b64, validLen, placeHoldersLen) { + return ((validLen + placeHoldersLen) * 3 / 4) - placeHoldersLen +} + +function toByteArray (b64) { + var tmp + var lens = getLens(b64) + var validLen = lens[0] + var placeHoldersLen = lens[1] + + var arr = new Arr(_byteLength(b64, validLen, placeHoldersLen)) + + var curByte = 0 + + // if there are placeholders, only get up to the last complete 4 chars + var len = placeHoldersLen > 0 + ? validLen - 4 + : validLen + + var i + for (i = 0; i < len; i += 4) { + tmp = + (revLookup[b64.charCodeAt(i)] << 18) | + (revLookup[b64.charCodeAt(i + 1)] << 12) | + (revLookup[b64.charCodeAt(i + 2)] << 6) | + revLookup[b64.charCodeAt(i + 3)] + arr[curByte++] = (tmp >> 16) & 0xFF + arr[curByte++] = (tmp >> 8) & 0xFF + arr[curByte++] = tmp & 0xFF + } + + if (placeHoldersLen === 2) { + tmp = + (revLookup[b64.charCodeAt(i)] << 2) | + (revLookup[b64.charCodeAt(i + 1)] >> 4) + arr[curByte++] = tmp & 0xFF + } + + if (placeHoldersLen === 1) { + tmp = + (revLookup[b64.charCodeAt(i)] << 10) | + (revLookup[b64.charCodeAt(i + 1)] << 4) | + (revLookup[b64.charCodeAt(i + 2)] >> 2) + arr[curByte++] = (tmp >> 8) & 0xFF + arr[curByte++] = tmp & 0xFF + } + + return arr +} + +function tripletToBase64 (num) { + return lookup[num >> 18 & 0x3F] + + lookup[num >> 12 & 0x3F] + + lookup[num >> 6 & 0x3F] + + lookup[num & 0x3F] +} + +function encodeChunk (uint8, start, end) { + var tmp + var output = [] + for (var i = start; i < end; i += 3) { + tmp = + ((uint8[i] << 16) & 0xFF0000) + + ((uint8[i + 1] << 8) & 0xFF00) + + (uint8[i + 2] & 0xFF) + output.push(tripletToBase64(tmp)) + } + return output.join('') +} + +function fromByteArray (uint8) { + var tmp + var len = uint8.length + var extraBytes = len % 3 // if we have 1 byte left, pad 2 bytes + var parts = [] + var maxChunkLength = 16383 // must be multiple of 3 + + // go through the array every three bytes, we'll deal with trailing stuff later + for (var i = 0, len2 = len - extraBytes; i < len2; i += maxChunkLength) { + parts.push(encodeChunk(uint8, i, (i + maxChunkLength) > len2 ? len2 : (i + maxChunkLength))) + } + + // pad the end with zeros, but make sure to not forget the extra bytes + if (extraBytes === 1) { + tmp = uint8[len - 1] + parts.push( + lookup[tmp >> 2] + + lookup[(tmp << 4) & 0x3F] + + '==' + ) + } else if (extraBytes === 2) { + tmp = (uint8[len - 2] << 8) + uint8[len - 1] + parts.push( + lookup[tmp >> 10] + + lookup[(tmp >> 4) & 0x3F] + + lookup[(tmp << 2) & 0x3F] + + '=' + ) + } + + return parts.join('') +} + +},{}],18:[function(require,module,exports){ +(function (module, exports) { + 'use strict'; + + // Utils + function assert (val, msg) { + if (!val) throw new Error(msg || 'Assertion failed'); + } + + // Could use `inherits` module, but don't want to move from single file + // architecture yet. + function inherits (ctor, superCtor) { + ctor.super_ = superCtor; + var TempCtor = function () {}; + TempCtor.prototype = superCtor.prototype; + ctor.prototype = new TempCtor(); + ctor.prototype.constructor = ctor; + } + + // BN + + function BN (number, base, endian) { + if (BN.isBN(number)) { + return number; + } + + this.negative = 0; + this.words = null; + this.length = 0; + + // Reduction context + this.red = null; + + if (number !== null) { + if (base === 'le' || base === 'be') { + endian = base; + base = 10; + } + + this._init(number || 0, base || 10, endian || 'be'); + } + } + if (typeof module === 'object') { + module.exports = BN; + } else { + exports.BN = BN; + } + + BN.BN = BN; + BN.wordSize = 26; + + var Buffer; + try { + if (typeof window !== 'undefined' && typeof window.Buffer !== 'undefined') { + Buffer = window.Buffer; + } else { + Buffer = require('buffer').Buffer; + } + } catch (e) { + } + + BN.isBN = function isBN (num) { + if (num instanceof BN) { + return true; + } + + return num !== null && typeof num === 'object' && + num.constructor.wordSize === BN.wordSize && Array.isArray(num.words); + }; + + BN.max = function max (left, right) { + if (left.cmp(right) > 0) return left; + return right; + }; + + BN.min = function min (left, right) { + if (left.cmp(right) < 0) return left; + return right; + }; + + BN.prototype._init = function init (number, base, endian) { + if (typeof number === 'number') { + return this._initNumber(number, base, endian); + } + + if (typeof number === 'object') { + return this._initArray(number, base, endian); + } + + if (base === 'hex') { + base = 16; + } + assert(base === (base | 0) && base >= 2 && base <= 36); + + number = number.toString().replace(/\s+/g, ''); + var start = 0; + if (number[0] === '-') { + start++; + this.negative = 1; + } + + if (start < number.length) { + if (base === 16) { + this._parseHex(number, start, endian); + } else { + this._parseBase(number, base, start); + if (endian === 'le') { + this._initArray(this.toArray(), base, endian); + } + } + } + }; + + BN.prototype._initNumber = function _initNumber (number, base, endian) { + if (number < 0) { + this.negative = 1; + number = -number; + } + if (number < 0x4000000) { + this.words = [number & 0x3ffffff]; + this.length = 1; + } else if (number < 0x10000000000000) { + this.words = [ + number & 0x3ffffff, + (number / 0x4000000) & 0x3ffffff + ]; + this.length = 2; + } else { + assert(number < 0x20000000000000); // 2 ^ 53 (unsafe) + this.words = [ + number & 0x3ffffff, + (number / 0x4000000) & 0x3ffffff, + 1 + ]; + this.length = 3; + } + + if (endian !== 'le') return; + + // Reverse the bytes + this._initArray(this.toArray(), base, endian); + }; + + BN.prototype._initArray = function _initArray (number, base, endian) { + // Perhaps a Uint8Array + assert(typeof number.length === 'number'); + if (number.length <= 0) { + this.words = [0]; + this.length = 1; + return this; + } + + this.length = Math.ceil(number.length / 3); + this.words = new Array(this.length); + for (var i = 0; i < this.length; i++) { + this.words[i] = 0; + } + + var j, w; + var off = 0; + if (endian === 'be') { + for (i = number.length - 1, j = 0; i >= 0; i -= 3) { + w = number[i] | (number[i - 1] << 8) | (number[i - 2] << 16); + this.words[j] |= (w << off) & 0x3ffffff; + this.words[j + 1] = (w >>> (26 - off)) & 0x3ffffff; + off += 24; + if (off >= 26) { + off -= 26; + j++; + } + } + } else if (endian === 'le') { + for (i = 0, j = 0; i < number.length; i += 3) { + w = number[i] | (number[i + 1] << 8) | (number[i + 2] << 16); + this.words[j] |= (w << off) & 0x3ffffff; + this.words[j + 1] = (w >>> (26 - off)) & 0x3ffffff; + off += 24; + if (off >= 26) { + off -= 26; + j++; + } + } + } + return this._strip(); + }; + + function parseHex4Bits (string, index) { + var c = string.charCodeAt(index); + // '0' - '9' + if (c >= 48 && c <= 57) { + return c - 48; + // 'A' - 'F' + } else if (c >= 65 && c <= 70) { + return c - 55; + // 'a' - 'f' + } else if (c >= 97 && c <= 102) { + return c - 87; + } else { + assert(false, 'Invalid character in ' + string); + } + } + + function parseHexByte (string, lowerBound, index) { + var r = parseHex4Bits(string, index); + if (index - 1 >= lowerBound) { + r |= parseHex4Bits(string, index - 1) << 4; + } + return r; + } + + BN.prototype._parseHex = function _parseHex (number, start, endian) { + // Create possibly bigger array to ensure that it fits the number + this.length = Math.ceil((number.length - start) / 6); + this.words = new Array(this.length); + for (var i = 0; i < this.length; i++) { + this.words[i] = 0; + } + + // 24-bits chunks + var off = 0; + var j = 0; + + var w; + if (endian === 'be') { + for (i = number.length - 1; i >= start; i -= 2) { + w = parseHexByte(number, start, i) << off; + this.words[j] |= w & 0x3ffffff; + if (off >= 18) { + off -= 18; + j += 1; + this.words[j] |= w >>> 26; + } else { + off += 8; + } + } + } else { + var parseLength = number.length - start; + for (i = parseLength % 2 === 0 ? start + 1 : start; i < number.length; i += 2) { + w = parseHexByte(number, start, i) << off; + this.words[j] |= w & 0x3ffffff; + if (off >= 18) { + off -= 18; + j += 1; + this.words[j] |= w >>> 26; + } else { + off += 8; + } + } + } + + this._strip(); + }; + + function parseBase (str, start, end, mul) { + var r = 0; + var b = 0; + var len = Math.min(str.length, end); + for (var i = start; i < len; i++) { + var c = str.charCodeAt(i) - 48; + + r *= mul; + + // 'a' + if (c >= 49) { + b = c - 49 + 0xa; + + // 'A' + } else if (c >= 17) { + b = c - 17 + 0xa; + + // '0' - '9' + } else { + b = c; + } + assert(c >= 0 && b < mul, 'Invalid character'); + r += b; + } + return r; + } + + BN.prototype._parseBase = function _parseBase (number, base, start) { + // Initialize as zero + this.words = [0]; + this.length = 1; + + // Find length of limb in base + for (var limbLen = 0, limbPow = 1; limbPow <= 0x3ffffff; limbPow *= base) { + limbLen++; + } + limbLen--; + limbPow = (limbPow / base) | 0; + + var total = number.length - start; + var mod = total % limbLen; + var end = Math.min(total, total - mod) + start; + + var word = 0; + for (var i = start; i < end; i += limbLen) { + word = parseBase(number, i, i + limbLen, base); + + this.imuln(limbPow); + if (this.words[0] + word < 0x4000000) { + this.words[0] += word; + } else { + this._iaddn(word); + } + } + + if (mod !== 0) { + var pow = 1; + word = parseBase(number, i, number.length, base); + + for (i = 0; i < mod; i++) { + pow *= base; + } + + this.imuln(pow); + if (this.words[0] + word < 0x4000000) { + this.words[0] += word; + } else { + this._iaddn(word); + } + } + + this._strip(); + }; + + BN.prototype.copy = function copy (dest) { + dest.words = new Array(this.length); + for (var i = 0; i < this.length; i++) { + dest.words[i] = this.words[i]; + } + dest.length = this.length; + dest.negative = this.negative; + dest.red = this.red; + }; + + function move (dest, src) { + dest.words = src.words; + dest.length = src.length; + dest.negative = src.negative; + dest.red = src.red; + } + + BN.prototype._move = function _move (dest) { + move(dest, this); + }; + + BN.prototype.clone = function clone () { + var r = new BN(null); + this.copy(r); + return r; + }; + + BN.prototype._expand = function _expand (size) { + while (this.length < size) { + this.words[this.length++] = 0; + } + return this; + }; + + // Remove leading `0` from `this` + BN.prototype._strip = function strip () { + while (this.length > 1 && this.words[this.length - 1] === 0) { + this.length--; + } + return this._normSign(); + }; + + BN.prototype._normSign = function _normSign () { + // -0 = 0 + if (this.length === 1 && this.words[0] === 0) { + this.negative = 0; + } + return this; + }; + + // Check Symbol.for because not everywhere where Symbol defined + // See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Symbol#Browser_compatibility + if (typeof Symbol !== 'undefined' && typeof Symbol.for === 'function') { + try { + BN.prototype[Symbol.for('nodejs.util.inspect.custom')] = inspect; + } catch (e) { + BN.prototype.inspect = inspect; + } + } else { + BN.prototype.inspect = inspect; + } + + function inspect () { + return (this.red ? ''; + } + + /* + + var zeros = []; + var groupSizes = []; + var groupBases = []; + + var s = ''; + var i = -1; + while (++i < BN.wordSize) { + zeros[i] = s; + s += '0'; + } + groupSizes[0] = 0; + groupSizes[1] = 0; + groupBases[0] = 0; + groupBases[1] = 0; + var base = 2 - 1; + while (++base < 36 + 1) { + var groupSize = 0; + var groupBase = 1; + while (groupBase < (1 << BN.wordSize) / base) { + groupBase *= base; + groupSize += 1; + } + groupSizes[base] = groupSize; + groupBases[base] = groupBase; + } + + */ + + var zeros = [ + '', + '0', + '00', + '000', + '0000', + '00000', + '000000', + '0000000', + '00000000', + '000000000', + '0000000000', + '00000000000', + '000000000000', + '0000000000000', + '00000000000000', + '000000000000000', + '0000000000000000', + '00000000000000000', + '000000000000000000', + '0000000000000000000', + '00000000000000000000', + '000000000000000000000', + '0000000000000000000000', + '00000000000000000000000', + '000000000000000000000000', + '0000000000000000000000000' + ]; + + var groupSizes = [ + 0, 0, + 25, 16, 12, 11, 10, 9, 8, + 8, 7, 7, 7, 7, 6, 6, + 6, 6, 6, 6, 6, 5, 5, + 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5 + ]; + + var groupBases = [ + 0, 0, + 33554432, 43046721, 16777216, 48828125, 60466176, 40353607, 16777216, + 43046721, 10000000, 19487171, 35831808, 62748517, 7529536, 11390625, + 16777216, 24137569, 34012224, 47045881, 64000000, 4084101, 5153632, + 6436343, 7962624, 9765625, 11881376, 14348907, 17210368, 20511149, + 24300000, 28629151, 33554432, 39135393, 45435424, 52521875, 60466176 + ]; + + BN.prototype.toString = function toString (base, padding) { + base = base || 10; + padding = padding | 0 || 1; + + var out; + if (base === 16 || base === 'hex') { + out = ''; + var off = 0; + var carry = 0; + for (var i = 0; i < this.length; i++) { + var w = this.words[i]; + var word = (((w << off) | carry) & 0xffffff).toString(16); + carry = (w >>> (24 - off)) & 0xffffff; + if (carry !== 0 || i !== this.length - 1) { + out = zeros[6 - word.length] + word + out; + } else { + out = word + out; + } + off += 2; + if (off >= 26) { + off -= 26; + i--; + } + } + if (carry !== 0) { + out = carry.toString(16) + out; + } + while (out.length % padding !== 0) { + out = '0' + out; + } + if (this.negative !== 0) { + out = '-' + out; + } + return out; + } + + if (base === (base | 0) && base >= 2 && base <= 36) { + // var groupSize = Math.floor(BN.wordSize * Math.LN2 / Math.log(base)); + var groupSize = groupSizes[base]; + // var groupBase = Math.pow(base, groupSize); + var groupBase = groupBases[base]; + out = ''; + var c = this.clone(); + c.negative = 0; + while (!c.isZero()) { + var r = c.modrn(groupBase).toString(base); + c = c.idivn(groupBase); + + if (!c.isZero()) { + out = zeros[groupSize - r.length] + r + out; + } else { + out = r + out; + } + } + if (this.isZero()) { + out = '0' + out; + } + while (out.length % padding !== 0) { + out = '0' + out; + } + if (this.negative !== 0) { + out = '-' + out; + } + return out; + } + + assert(false, 'Base should be between 2 and 36'); + }; + + BN.prototype.toNumber = function toNumber () { + var ret = this.words[0]; + if (this.length === 2) { + ret += this.words[1] * 0x4000000; + } else if (this.length === 3 && this.words[2] === 0x01) { + // NOTE: at this stage it is known that the top bit is set + ret += 0x10000000000000 + (this.words[1] * 0x4000000); + } else if (this.length > 2) { + assert(false, 'Number can only safely store up to 53 bits'); + } + return (this.negative !== 0) ? -ret : ret; + }; + + BN.prototype.toJSON = function toJSON () { + return this.toString(16, 2); + }; + + if (Buffer) { + BN.prototype.toBuffer = function toBuffer (endian, length) { + return this.toArrayLike(Buffer, endian, length); + }; + } + + BN.prototype.toArray = function toArray (endian, length) { + return this.toArrayLike(Array, endian, length); + }; + + var allocate = function allocate (ArrayType, size) { + if (ArrayType.allocUnsafe) { + return ArrayType.allocUnsafe(size); + } + return new ArrayType(size); + }; + + BN.prototype.toArrayLike = function toArrayLike (ArrayType, endian, length) { + this._strip(); + + var byteLength = this.byteLength(); + var reqLength = length || Math.max(1, byteLength); + assert(byteLength <= reqLength, 'byte array longer than desired length'); + assert(reqLength > 0, 'Requested array length <= 0'); + + var res = allocate(ArrayType, reqLength); + var postfix = endian === 'le' ? 'LE' : 'BE'; + this['_toArrayLike' + postfix](res, byteLength); + return res; + }; + + BN.prototype._toArrayLikeLE = function _toArrayLikeLE (res, byteLength) { + var position = 0; + var carry = 0; + + for (var i = 0, shift = 0; i < this.length; i++) { + var word = (this.words[i] << shift) | carry; + + res[position++] = word & 0xff; + if (position < res.length) { + res[position++] = (word >> 8) & 0xff; + } + if (position < res.length) { + res[position++] = (word >> 16) & 0xff; + } + + if (shift === 6) { + if (position < res.length) { + res[position++] = (word >> 24) & 0xff; + } + carry = 0; + shift = 0; + } else { + carry = word >>> 24; + shift += 2; + } + } + + if (position < res.length) { + res[position++] = carry; + + while (position < res.length) { + res[position++] = 0; + } + } + }; + + BN.prototype._toArrayLikeBE = function _toArrayLikeBE (res, byteLength) { + var position = res.length - 1; + var carry = 0; + + for (var i = 0, shift = 0; i < this.length; i++) { + var word = (this.words[i] << shift) | carry; + + res[position--] = word & 0xff; + if (position >= 0) { + res[position--] = (word >> 8) & 0xff; + } + if (position >= 0) { + res[position--] = (word >> 16) & 0xff; + } + + if (shift === 6) { + if (position >= 0) { + res[position--] = (word >> 24) & 0xff; + } + carry = 0; + shift = 0; + } else { + carry = word >>> 24; + shift += 2; + } + } + + if (position >= 0) { + res[position--] = carry; + + while (position >= 0) { + res[position--] = 0; + } + } + }; + + if (Math.clz32) { + BN.prototype._countBits = function _countBits (w) { + return 32 - Math.clz32(w); + }; + } else { + BN.prototype._countBits = function _countBits (w) { + var t = w; + var r = 0; + if (t >= 0x1000) { + r += 13; + t >>>= 13; + } + if (t >= 0x40) { + r += 7; + t >>>= 7; + } + if (t >= 0x8) { + r += 4; + t >>>= 4; + } + if (t >= 0x02) { + r += 2; + t >>>= 2; + } + return r + t; + }; + } + + BN.prototype._zeroBits = function _zeroBits (w) { + // Short-cut + if (w === 0) return 26; + + var t = w; + var r = 0; + if ((t & 0x1fff) === 0) { + r += 13; + t >>>= 13; + } + if ((t & 0x7f) === 0) { + r += 7; + t >>>= 7; + } + if ((t & 0xf) === 0) { + r += 4; + t >>>= 4; + } + if ((t & 0x3) === 0) { + r += 2; + t >>>= 2; + } + if ((t & 0x1) === 0) { + r++; + } + return r; + }; + + // Return number of used bits in a BN + BN.prototype.bitLength = function bitLength () { + var w = this.words[this.length - 1]; + var hi = this._countBits(w); + return (this.length - 1) * 26 + hi; + }; + + function toBitArray (num) { + var w = new Array(num.bitLength()); + + for (var bit = 0; bit < w.length; bit++) { + var off = (bit / 26) | 0; + var wbit = bit % 26; + + w[bit] = (num.words[off] >>> wbit) & 0x01; + } + + return w; + } + + // Number of trailing zero bits + BN.prototype.zeroBits = function zeroBits () { + if (this.isZero()) return 0; + + var r = 0; + for (var i = 0; i < this.length; i++) { + var b = this._zeroBits(this.words[i]); + r += b; + if (b !== 26) break; + } + return r; + }; + + BN.prototype.byteLength = function byteLength () { + return Math.ceil(this.bitLength() / 8); + }; + + BN.prototype.toTwos = function toTwos (width) { + if (this.negative !== 0) { + return this.abs().inotn(width).iaddn(1); + } + return this.clone(); + }; + + BN.prototype.fromTwos = function fromTwos (width) { + if (this.testn(width - 1)) { + return this.notn(width).iaddn(1).ineg(); + } + return this.clone(); + }; + + BN.prototype.isNeg = function isNeg () { + return this.negative !== 0; + }; + + // Return negative clone of `this` + BN.prototype.neg = function neg () { + return this.clone().ineg(); + }; + + BN.prototype.ineg = function ineg () { + if (!this.isZero()) { + this.negative ^= 1; + } + + return this; + }; + + // Or `num` with `this` in-place + BN.prototype.iuor = function iuor (num) { + while (this.length < num.length) { + this.words[this.length++] = 0; + } + + for (var i = 0; i < num.length; i++) { + this.words[i] = this.words[i] | num.words[i]; + } + + return this._strip(); + }; + + BN.prototype.ior = function ior (num) { + assert((this.negative | num.negative) === 0); + return this.iuor(num); + }; + + // Or `num` with `this` + BN.prototype.or = function or (num) { + if (this.length > num.length) return this.clone().ior(num); + return num.clone().ior(this); + }; + + BN.prototype.uor = function uor (num) { + if (this.length > num.length) return this.clone().iuor(num); + return num.clone().iuor(this); + }; + + // And `num` with `this` in-place + BN.prototype.iuand = function iuand (num) { + // b = min-length(num, this) + var b; + if (this.length > num.length) { + b = num; + } else { + b = this; + } + + for (var i = 0; i < b.length; i++) { + this.words[i] = this.words[i] & num.words[i]; + } + + this.length = b.length; + + return this._strip(); + }; + + BN.prototype.iand = function iand (num) { + assert((this.negative | num.negative) === 0); + return this.iuand(num); + }; + + // And `num` with `this` + BN.prototype.and = function and (num) { + if (this.length > num.length) return this.clone().iand(num); + return num.clone().iand(this); + }; + + BN.prototype.uand = function uand (num) { + if (this.length > num.length) return this.clone().iuand(num); + return num.clone().iuand(this); + }; + + // Xor `num` with `this` in-place + BN.prototype.iuxor = function iuxor (num) { + // a.length > b.length + var a; + var b; + if (this.length > num.length) { + a = this; + b = num; + } else { + a = num; + b = this; + } + + for (var i = 0; i < b.length; i++) { + this.words[i] = a.words[i] ^ b.words[i]; + } + + if (this !== a) { + for (; i < a.length; i++) { + this.words[i] = a.words[i]; + } + } + + this.length = a.length; + + return this._strip(); + }; + + BN.prototype.ixor = function ixor (num) { + assert((this.negative | num.negative) === 0); + return this.iuxor(num); + }; + + // Xor `num` with `this` + BN.prototype.xor = function xor (num) { + if (this.length > num.length) return this.clone().ixor(num); + return num.clone().ixor(this); + }; + + BN.prototype.uxor = function uxor (num) { + if (this.length > num.length) return this.clone().iuxor(num); + return num.clone().iuxor(this); + }; + + // Not ``this`` with ``width`` bitwidth + BN.prototype.inotn = function inotn (width) { + assert(typeof width === 'number' && width >= 0); + + var bytesNeeded = Math.ceil(width / 26) | 0; + var bitsLeft = width % 26; + + // Extend the buffer with leading zeroes + this._expand(bytesNeeded); + + if (bitsLeft > 0) { + bytesNeeded--; + } + + // Handle complete words + for (var i = 0; i < bytesNeeded; i++) { + this.words[i] = ~this.words[i] & 0x3ffffff; + } + + // Handle the residue + if (bitsLeft > 0) { + this.words[i] = ~this.words[i] & (0x3ffffff >> (26 - bitsLeft)); + } + + // And remove leading zeroes + return this._strip(); + }; + + BN.prototype.notn = function notn (width) { + return this.clone().inotn(width); + }; + + // Set `bit` of `this` + BN.prototype.setn = function setn (bit, val) { + assert(typeof bit === 'number' && bit >= 0); + + var off = (bit / 26) | 0; + var wbit = bit % 26; + + this._expand(off + 1); + + if (val) { + this.words[off] = this.words[off] | (1 << wbit); + } else { + this.words[off] = this.words[off] & ~(1 << wbit); + } + + return this._strip(); + }; + + // Add `num` to `this` in-place + BN.prototype.iadd = function iadd (num) { + var r; + + // negative + positive + if (this.negative !== 0 && num.negative === 0) { + this.negative = 0; + r = this.isub(num); + this.negative ^= 1; + return this._normSign(); + + // positive + negative + } else if (this.negative === 0 && num.negative !== 0) { + num.negative = 0; + r = this.isub(num); + num.negative = 1; + return r._normSign(); + } + + // a.length > b.length + var a, b; + if (this.length > num.length) { + a = this; + b = num; + } else { + a = num; + b = this; + } + + var carry = 0; + for (var i = 0; i < b.length; i++) { + r = (a.words[i] | 0) + (b.words[i] | 0) + carry; + this.words[i] = r & 0x3ffffff; + carry = r >>> 26; + } + for (; carry !== 0 && i < a.length; i++) { + r = (a.words[i] | 0) + carry; + this.words[i] = r & 0x3ffffff; + carry = r >>> 26; + } + + this.length = a.length; + if (carry !== 0) { + this.words[this.length] = carry; + this.length++; + // Copy the rest of the words + } else if (a !== this) { + for (; i < a.length; i++) { + this.words[i] = a.words[i]; + } + } + + return this; + }; + + // Add `num` to `this` + BN.prototype.add = function add (num) { + var res; + if (num.negative !== 0 && this.negative === 0) { + num.negative = 0; + res = this.sub(num); + num.negative ^= 1; + return res; + } else if (num.negative === 0 && this.negative !== 0) { + this.negative = 0; + res = num.sub(this); + this.negative = 1; + return res; + } + + if (this.length > num.length) return this.clone().iadd(num); + + return num.clone().iadd(this); + }; + + // Subtract `num` from `this` in-place + BN.prototype.isub = function isub (num) { + // this - (-num) = this + num + if (num.negative !== 0) { + num.negative = 0; + var r = this.iadd(num); + num.negative = 1; + return r._normSign(); + + // -this - num = -(this + num) + } else if (this.negative !== 0) { + this.negative = 0; + this.iadd(num); + this.negative = 1; + return this._normSign(); + } + + // At this point both numbers are positive + var cmp = this.cmp(num); + + // Optimization - zeroify + if (cmp === 0) { + this.negative = 0; + this.length = 1; + this.words[0] = 0; + return this; + } + + // a > b + var a, b; + if (cmp > 0) { + a = this; + b = num; + } else { + a = num; + b = this; + } + + var carry = 0; + for (var i = 0; i < b.length; i++) { + r = (a.words[i] | 0) - (b.words[i] | 0) + carry; + carry = r >> 26; + this.words[i] = r & 0x3ffffff; + } + for (; carry !== 0 && i < a.length; i++) { + r = (a.words[i] | 0) + carry; + carry = r >> 26; + this.words[i] = r & 0x3ffffff; + } + + // Copy rest of the words + if (carry === 0 && i < a.length && a !== this) { + for (; i < a.length; i++) { + this.words[i] = a.words[i]; + } + } + + this.length = Math.max(this.length, i); + + if (a !== this) { + this.negative = 1; + } + + return this._strip(); + }; + + // Subtract `num` from `this` + BN.prototype.sub = function sub (num) { + return this.clone().isub(num); + }; + + function smallMulTo (self, num, out) { + out.negative = num.negative ^ self.negative; + var len = (self.length + num.length) | 0; + out.length = len; + len = (len - 1) | 0; + + // Peel one iteration (compiler can't do it, because of code complexity) + var a = self.words[0] | 0; + var b = num.words[0] | 0; + var r = a * b; + + var lo = r & 0x3ffffff; + var carry = (r / 0x4000000) | 0; + out.words[0] = lo; + + for (var k = 1; k < len; k++) { + // Sum all words with the same `i + j = k` and accumulate `ncarry`, + // note that ncarry could be >= 0x3ffffff + var ncarry = carry >>> 26; + var rword = carry & 0x3ffffff; + var maxJ = Math.min(k, num.length - 1); + for (var j = Math.max(0, k - self.length + 1); j <= maxJ; j++) { + var i = (k - j) | 0; + a = self.words[i] | 0; + b = num.words[j] | 0; + r = a * b + rword; + ncarry += (r / 0x4000000) | 0; + rword = r & 0x3ffffff; + } + out.words[k] = rword | 0; + carry = ncarry | 0; + } + if (carry !== 0) { + out.words[k] = carry | 0; + } else { + out.length--; + } + + return out._strip(); + } + + // TODO(indutny): it may be reasonable to omit it for users who don't need + // to work with 256-bit numbers, otherwise it gives 20% improvement for 256-bit + // multiplication (like elliptic secp256k1). + var comb10MulTo = function comb10MulTo (self, num, out) { + var a = self.words; + var b = num.words; + var o = out.words; + var c = 0; + var lo; + var mid; + var hi; + var a0 = a[0] | 0; + var al0 = a0 & 0x1fff; + var ah0 = a0 >>> 13; + var a1 = a[1] | 0; + var al1 = a1 & 0x1fff; + var ah1 = a1 >>> 13; + var a2 = a[2] | 0; + var al2 = a2 & 0x1fff; + var ah2 = a2 >>> 13; + var a3 = a[3] | 0; + var al3 = a3 & 0x1fff; + var ah3 = a3 >>> 13; + var a4 = a[4] | 0; + var al4 = a4 & 0x1fff; + var ah4 = a4 >>> 13; + var a5 = a[5] | 0; + var al5 = a5 & 0x1fff; + var ah5 = a5 >>> 13; + var a6 = a[6] | 0; + var al6 = a6 & 0x1fff; + var ah6 = a6 >>> 13; + var a7 = a[7] | 0; + var al7 = a7 & 0x1fff; + var ah7 = a7 >>> 13; + var a8 = a[8] | 0; + var al8 = a8 & 0x1fff; + var ah8 = a8 >>> 13; + var a9 = a[9] | 0; + var al9 = a9 & 0x1fff; + var ah9 = a9 >>> 13; + var b0 = b[0] | 0; + var bl0 = b0 & 0x1fff; + var bh0 = b0 >>> 13; + var b1 = b[1] | 0; + var bl1 = b1 & 0x1fff; + var bh1 = b1 >>> 13; + var b2 = b[2] | 0; + var bl2 = b2 & 0x1fff; + var bh2 = b2 >>> 13; + var b3 = b[3] | 0; + var bl3 = b3 & 0x1fff; + var bh3 = b3 >>> 13; + var b4 = b[4] | 0; + var bl4 = b4 & 0x1fff; + var bh4 = b4 >>> 13; + var b5 = b[5] | 0; + var bl5 = b5 & 0x1fff; + var bh5 = b5 >>> 13; + var b6 = b[6] | 0; + var bl6 = b6 & 0x1fff; + var bh6 = b6 >>> 13; + var b7 = b[7] | 0; + var bl7 = b7 & 0x1fff; + var bh7 = b7 >>> 13; + var b8 = b[8] | 0; + var bl8 = b8 & 0x1fff; + var bh8 = b8 >>> 13; + var b9 = b[9] | 0; + var bl9 = b9 & 0x1fff; + var bh9 = b9 >>> 13; + + out.negative = self.negative ^ num.negative; + out.length = 19; + /* k = 0 */ + lo = Math.imul(al0, bl0); + mid = Math.imul(al0, bh0); + mid = (mid + Math.imul(ah0, bl0)) | 0; + hi = Math.imul(ah0, bh0); + var w0 = (((c + lo) | 0) + ((mid & 0x1fff) << 13)) | 0; + c = (((hi + (mid >>> 13)) | 0) + (w0 >>> 26)) | 0; + w0 &= 0x3ffffff; + /* k = 1 */ + lo = Math.imul(al1, bl0); + mid = Math.imul(al1, bh0); + mid = (mid + Math.imul(ah1, bl0)) | 0; + hi = Math.imul(ah1, bh0); + lo = (lo + Math.imul(al0, bl1)) | 0; + mid = (mid + Math.imul(al0, bh1)) | 0; + mid = (mid + Math.imul(ah0, bl1)) | 0; + hi = (hi + Math.imul(ah0, bh1)) | 0; + var w1 = (((c + lo) | 0) + ((mid & 0x1fff) << 13)) | 0; + c = (((hi + (mid >>> 13)) | 0) + (w1 >>> 26)) | 0; + w1 &= 0x3ffffff; + /* k = 2 */ + lo = Math.imul(al2, bl0); + mid = Math.imul(al2, bh0); + mid = (mid + Math.imul(ah2, bl0)) | 0; + hi = Math.imul(ah2, bh0); + lo = (lo + Math.imul(al1, bl1)) | 0; + mid = (mid + Math.imul(al1, bh1)) | 0; + mid = (mid + Math.imul(ah1, bl1)) | 0; + hi = (hi + Math.imul(ah1, bh1)) | 0; + lo = (lo + Math.imul(al0, bl2)) | 0; + mid = (mid + Math.imul(al0, bh2)) | 0; + mid = (mid + Math.imul(ah0, bl2)) | 0; + hi = (hi + Math.imul(ah0, bh2)) | 0; + var w2 = (((c + lo) | 0) + ((mid & 0x1fff) << 13)) | 0; + c = (((hi + (mid >>> 13)) | 0) + (w2 >>> 26)) | 0; + w2 &= 0x3ffffff; + /* k = 3 */ + lo = Math.imul(al3, bl0); + mid = Math.imul(al3, bh0); + mid = (mid + Math.imul(ah3, bl0)) | 0; + hi = Math.imul(ah3, bh0); + lo = (lo + Math.imul(al2, bl1)) | 0; + mid = (mid + Math.imul(al2, bh1)) | 0; + mid = (mid + Math.imul(ah2, bl1)) | 0; + hi = (hi + Math.imul(ah2, bh1)) | 0; + lo = (lo + Math.imul(al1, bl2)) | 0; + mid = (mid + Math.imul(al1, bh2)) | 0; + mid = (mid + Math.imul(ah1, bl2)) | 0; + hi = (hi + Math.imul(ah1, bh2)) | 0; + lo = (lo + Math.imul(al0, bl3)) | 0; + mid = (mid + Math.imul(al0, bh3)) | 0; + mid = (mid + Math.imul(ah0, bl3)) | 0; + hi = (hi + Math.imul(ah0, bh3)) | 0; + var w3 = (((c + lo) | 0) + ((mid & 0x1fff) << 13)) | 0; + c = (((hi + (mid >>> 13)) | 0) + (w3 >>> 26)) | 0; + w3 &= 0x3ffffff; + /* k = 4 */ + lo = Math.imul(al4, bl0); + mid = Math.imul(al4, bh0); + mid = (mid + Math.imul(ah4, bl0)) | 0; + hi = Math.imul(ah4, bh0); + lo = (lo + Math.imul(al3, bl1)) | 0; + mid = (mid + Math.imul(al3, bh1)) | 0; + mid = (mid + Math.imul(ah3, bl1)) | 0; + hi = (hi + Math.imul(ah3, bh1)) | 0; + lo = (lo + Math.imul(al2, bl2)) | 0; + mid = (mid + Math.imul(al2, bh2)) | 0; + mid = (mid + Math.imul(ah2, bl2)) | 0; + hi = (hi + Math.imul(ah2, bh2)) | 0; + lo = (lo + Math.imul(al1, bl3)) | 0; + mid = (mid + Math.imul(al1, bh3)) | 0; + mid = (mid + Math.imul(ah1, bl3)) | 0; + hi = (hi + Math.imul(ah1, bh3)) | 0; + lo = (lo + Math.imul(al0, bl4)) | 0; + mid = (mid + Math.imul(al0, bh4)) | 0; + mid = (mid + Math.imul(ah0, bl4)) | 0; + hi = (hi + Math.imul(ah0, bh4)) | 0; + var w4 = (((c + lo) | 0) + ((mid & 0x1fff) << 13)) | 0; + c = (((hi + (mid >>> 13)) | 0) + (w4 >>> 26)) | 0; + w4 &= 0x3ffffff; + /* k = 5 */ + lo = Math.imul(al5, bl0); + mid = Math.imul(al5, bh0); + mid = (mid + Math.imul(ah5, bl0)) | 0; + hi = Math.imul(ah5, bh0); + lo = (lo + Math.imul(al4, bl1)) | 0; + mid = (mid + Math.imul(al4, bh1)) | 0; + mid = (mid + Math.imul(ah4, bl1)) | 0; + hi = (hi + Math.imul(ah4, bh1)) | 0; + lo = (lo + Math.imul(al3, bl2)) | 0; + mid = (mid + Math.imul(al3, bh2)) | 0; + mid = (mid + Math.imul(ah3, bl2)) | 0; + hi = (hi + Math.imul(ah3, bh2)) | 0; + lo = (lo + Math.imul(al2, bl3)) | 0; + mid = (mid + Math.imul(al2, bh3)) | 0; + mid = (mid + Math.imul(ah2, bl3)) | 0; + hi = (hi + Math.imul(ah2, bh3)) | 0; + lo = (lo + Math.imul(al1, bl4)) | 0; + mid = (mid + Math.imul(al1, bh4)) | 0; + mid = (mid + Math.imul(ah1, bl4)) | 0; + hi = (hi + Math.imul(ah1, bh4)) | 0; + lo = (lo + Math.imul(al0, bl5)) | 0; + mid = (mid + Math.imul(al0, bh5)) | 0; + mid = (mid + Math.imul(ah0, bl5)) | 0; + hi = (hi + Math.imul(ah0, bh5)) | 0; + var w5 = (((c + lo) | 0) + ((mid & 0x1fff) << 13)) | 0; + c = (((hi + (mid >>> 13)) | 0) + (w5 >>> 26)) | 0; + w5 &= 0x3ffffff; + /* k = 6 */ + lo = Math.imul(al6, bl0); + mid = Math.imul(al6, bh0); + mid = (mid + Math.imul(ah6, bl0)) | 0; + hi = Math.imul(ah6, bh0); + lo = (lo + Math.imul(al5, bl1)) | 0; + mid = (mid + Math.imul(al5, bh1)) | 0; + mid = (mid + Math.imul(ah5, bl1)) | 0; + hi = (hi + Math.imul(ah5, bh1)) | 0; + lo = (lo + Math.imul(al4, bl2)) | 0; + mid = (mid + Math.imul(al4, bh2)) | 0; + mid = (mid + Math.imul(ah4, bl2)) | 0; + hi = (hi + Math.imul(ah4, bh2)) | 0; + lo = (lo + Math.imul(al3, bl3)) | 0; + mid = (mid + Math.imul(al3, bh3)) | 0; + mid = (mid + Math.imul(ah3, bl3)) | 0; + hi = (hi + Math.imul(ah3, bh3)) | 0; + lo = (lo + Math.imul(al2, bl4)) | 0; + mid = (mid + Math.imul(al2, bh4)) | 0; + mid = (mid + Math.imul(ah2, bl4)) | 0; + hi = (hi + Math.imul(ah2, bh4)) | 0; + lo = (lo + Math.imul(al1, bl5)) | 0; + mid = (mid + Math.imul(al1, bh5)) | 0; + mid = (mid + Math.imul(ah1, bl5)) | 0; + hi = (hi + Math.imul(ah1, bh5)) | 0; + lo = (lo + Math.imul(al0, bl6)) | 0; + mid = (mid + Math.imul(al0, bh6)) | 0; + mid = (mid + Math.imul(ah0, bl6)) | 0; + hi = (hi + Math.imul(ah0, bh6)) | 0; + var w6 = (((c + lo) | 0) + ((mid & 0x1fff) << 13)) | 0; + c = (((hi + (mid >>> 13)) | 0) + (w6 >>> 26)) | 0; + w6 &= 0x3ffffff; + /* k = 7 */ + lo = Math.imul(al7, bl0); + mid = Math.imul(al7, bh0); + mid = (mid + Math.imul(ah7, bl0)) | 0; + hi = Math.imul(ah7, bh0); + lo = (lo + Math.imul(al6, bl1)) | 0; + mid = (mid + Math.imul(al6, bh1)) | 0; + mid = (mid + Math.imul(ah6, bl1)) | 0; + hi = (hi + Math.imul(ah6, bh1)) | 0; + lo = (lo + Math.imul(al5, bl2)) | 0; + mid = (mid + Math.imul(al5, bh2)) | 0; + mid = (mid + Math.imul(ah5, bl2)) | 0; + hi = (hi + Math.imul(ah5, bh2)) | 0; + lo = (lo + Math.imul(al4, bl3)) | 0; + mid = (mid + Math.imul(al4, bh3)) | 0; + mid = (mid + Math.imul(ah4, bl3)) | 0; + hi = (hi + Math.imul(ah4, bh3)) | 0; + lo = (lo + Math.imul(al3, bl4)) | 0; + mid = (mid + Math.imul(al3, bh4)) | 0; + mid = (mid + Math.imul(ah3, bl4)) | 0; + hi = (hi + Math.imul(ah3, bh4)) | 0; + lo = (lo + Math.imul(al2, bl5)) | 0; + mid = (mid + Math.imul(al2, bh5)) | 0; + mid = (mid + Math.imul(ah2, bl5)) | 0; + hi = (hi + Math.imul(ah2, bh5)) | 0; + lo = (lo + Math.imul(al1, bl6)) | 0; + mid = (mid + Math.imul(al1, bh6)) | 0; + mid = (mid + Math.imul(ah1, bl6)) | 0; + hi = (hi + Math.imul(ah1, bh6)) | 0; + lo = (lo + Math.imul(al0, bl7)) | 0; + mid = (mid + Math.imul(al0, bh7)) | 0; + mid = (mid + Math.imul(ah0, bl7)) | 0; + hi = (hi + Math.imul(ah0, bh7)) | 0; + var w7 = (((c + lo) | 0) + ((mid & 0x1fff) << 13)) | 0; + c = (((hi + (mid >>> 13)) | 0) + (w7 >>> 26)) | 0; + w7 &= 0x3ffffff; + /* k = 8 */ + lo = Math.imul(al8, bl0); + mid = Math.imul(al8, bh0); + mid = (mid + Math.imul(ah8, bl0)) | 0; + hi = Math.imul(ah8, bh0); + lo = (lo + Math.imul(al7, bl1)) | 0; + mid = (mid + Math.imul(al7, bh1)) | 0; + mid = (mid + Math.imul(ah7, bl1)) | 0; + hi = (hi + Math.imul(ah7, bh1)) | 0; + lo = (lo + Math.imul(al6, bl2)) | 0; + mid = (mid + Math.imul(al6, bh2)) | 0; + mid = (mid + Math.imul(ah6, bl2)) | 0; + hi = (hi + Math.imul(ah6, bh2)) | 0; + lo = (lo + Math.imul(al5, bl3)) | 0; + mid = (mid + Math.imul(al5, bh3)) | 0; + mid = (mid + Math.imul(ah5, bl3)) | 0; + hi = (hi + Math.imul(ah5, bh3)) | 0; + lo = (lo + Math.imul(al4, bl4)) | 0; + mid = (mid + Math.imul(al4, bh4)) | 0; + mid = (mid + Math.imul(ah4, bl4)) | 0; + hi = (hi + Math.imul(ah4, bh4)) | 0; + lo = (lo + Math.imul(al3, bl5)) | 0; + mid = (mid + Math.imul(al3, bh5)) | 0; + mid = (mid + Math.imul(ah3, bl5)) | 0; + hi = (hi + Math.imul(ah3, bh5)) | 0; + lo = (lo + Math.imul(al2, bl6)) | 0; + mid = (mid + Math.imul(al2, bh6)) | 0; + mid = (mid + Math.imul(ah2, bl6)) | 0; + hi = (hi + Math.imul(ah2, bh6)) | 0; + lo = (lo + Math.imul(al1, bl7)) | 0; + mid = (mid + Math.imul(al1, bh7)) | 0; + mid = (mid + Math.imul(ah1, bl7)) | 0; + hi = (hi + Math.imul(ah1, bh7)) | 0; + lo = (lo + Math.imul(al0, bl8)) | 0; + mid = (mid + Math.imul(al0, bh8)) | 0; + mid = (mid + Math.imul(ah0, bl8)) | 0; + hi = (hi + Math.imul(ah0, bh8)) | 0; + var w8 = (((c + lo) | 0) + ((mid & 0x1fff) << 13)) | 0; + c = (((hi + (mid >>> 13)) | 0) + (w8 >>> 26)) | 0; + w8 &= 0x3ffffff; + /* k = 9 */ + lo = Math.imul(al9, bl0); + mid = Math.imul(al9, bh0); + mid = (mid + Math.imul(ah9, bl0)) | 0; + hi = Math.imul(ah9, bh0); + lo = (lo + Math.imul(al8, bl1)) | 0; + mid = (mid + Math.imul(al8, bh1)) | 0; + mid = (mid + Math.imul(ah8, bl1)) | 0; + hi = (hi + Math.imul(ah8, bh1)) | 0; + lo = (lo + Math.imul(al7, bl2)) | 0; + mid = (mid + Math.imul(al7, bh2)) | 0; + mid = (mid + Math.imul(ah7, bl2)) | 0; + hi = (hi + Math.imul(ah7, bh2)) | 0; + lo = (lo + Math.imul(al6, bl3)) | 0; + mid = (mid + Math.imul(al6, bh3)) | 0; + mid = (mid + Math.imul(ah6, bl3)) | 0; + hi = (hi + Math.imul(ah6, bh3)) | 0; + lo = (lo + Math.imul(al5, bl4)) | 0; + mid = (mid + Math.imul(al5, bh4)) | 0; + mid = (mid + Math.imul(ah5, bl4)) | 0; + hi = (hi + Math.imul(ah5, bh4)) | 0; + lo = (lo + Math.imul(al4, bl5)) | 0; + mid = (mid + Math.imul(al4, bh5)) | 0; + mid = (mid + Math.imul(ah4, bl5)) | 0; + hi = (hi + Math.imul(ah4, bh5)) | 0; + lo = (lo + Math.imul(al3, bl6)) | 0; + mid = (mid + Math.imul(al3, bh6)) | 0; + mid = (mid + Math.imul(ah3, bl6)) | 0; + hi = (hi + Math.imul(ah3, bh6)) | 0; + lo = (lo + Math.imul(al2, bl7)) | 0; + mid = (mid + Math.imul(al2, bh7)) | 0; + mid = (mid + Math.imul(ah2, bl7)) | 0; + hi = (hi + Math.imul(ah2, bh7)) | 0; + lo = (lo + Math.imul(al1, bl8)) | 0; + mid = (mid + Math.imul(al1, bh8)) | 0; + mid = (mid + Math.imul(ah1, bl8)) | 0; + hi = (hi + Math.imul(ah1, bh8)) | 0; + lo = (lo + Math.imul(al0, bl9)) | 0; + mid = (mid + Math.imul(al0, bh9)) | 0; + mid = (mid + Math.imul(ah0, bl9)) | 0; + hi = (hi + Math.imul(ah0, bh9)) | 0; + var w9 = (((c + lo) | 0) + ((mid & 0x1fff) << 13)) | 0; + c = (((hi + (mid >>> 13)) | 0) + (w9 >>> 26)) | 0; + w9 &= 0x3ffffff; + /* k = 10 */ + lo = Math.imul(al9, bl1); + mid = Math.imul(al9, bh1); + mid = (mid + Math.imul(ah9, bl1)) | 0; + hi = Math.imul(ah9, bh1); + lo = (lo + Math.imul(al8, bl2)) | 0; + mid = (mid + Math.imul(al8, bh2)) | 0; + mid = (mid + Math.imul(ah8, bl2)) | 0; + hi = (hi + Math.imul(ah8, bh2)) | 0; + lo = (lo + Math.imul(al7, bl3)) | 0; + mid = (mid + Math.imul(al7, bh3)) | 0; + mid = (mid + Math.imul(ah7, bl3)) | 0; + hi = (hi + Math.imul(ah7, bh3)) | 0; + lo = (lo + Math.imul(al6, bl4)) | 0; + mid = (mid + Math.imul(al6, bh4)) | 0; + mid = (mid + Math.imul(ah6, bl4)) | 0; + hi = (hi + Math.imul(ah6, bh4)) | 0; + lo = (lo + Math.imul(al5, bl5)) | 0; + mid = (mid + Math.imul(al5, bh5)) | 0; + mid = (mid + Math.imul(ah5, bl5)) | 0; + hi = (hi + Math.imul(ah5, bh5)) | 0; + lo = (lo + Math.imul(al4, bl6)) | 0; + mid = (mid + Math.imul(al4, bh6)) | 0; + mid = (mid + Math.imul(ah4, bl6)) | 0; + hi = (hi + Math.imul(ah4, bh6)) | 0; + lo = (lo + Math.imul(al3, bl7)) | 0; + mid = (mid + Math.imul(al3, bh7)) | 0; + mid = (mid + Math.imul(ah3, bl7)) | 0; + hi = (hi + Math.imul(ah3, bh7)) | 0; + lo = (lo + Math.imul(al2, bl8)) | 0; + mid = (mid + Math.imul(al2, bh8)) | 0; + mid = (mid + Math.imul(ah2, bl8)) | 0; + hi = (hi + Math.imul(ah2, bh8)) | 0; + lo = (lo + Math.imul(al1, bl9)) | 0; + mid = (mid + Math.imul(al1, bh9)) | 0; + mid = (mid + Math.imul(ah1, bl9)) | 0; + hi = (hi + Math.imul(ah1, bh9)) | 0; + var w10 = (((c + lo) | 0) + ((mid & 0x1fff) << 13)) | 0; + c = (((hi + (mid >>> 13)) | 0) + (w10 >>> 26)) | 0; + w10 &= 0x3ffffff; + /* k = 11 */ + lo = Math.imul(al9, bl2); + mid = Math.imul(al9, bh2); + mid = (mid + Math.imul(ah9, bl2)) | 0; + hi = Math.imul(ah9, bh2); + lo = (lo + Math.imul(al8, bl3)) | 0; + mid = (mid + Math.imul(al8, bh3)) | 0; + mid = (mid + Math.imul(ah8, bl3)) | 0; + hi = (hi + Math.imul(ah8, bh3)) | 0; + lo = (lo + Math.imul(al7, bl4)) | 0; + mid = (mid + Math.imul(al7, bh4)) | 0; + mid = (mid + Math.imul(ah7, bl4)) | 0; + hi = (hi + Math.imul(ah7, bh4)) | 0; + lo = (lo + Math.imul(al6, bl5)) | 0; + mid = (mid + Math.imul(al6, bh5)) | 0; + mid = (mid + Math.imul(ah6, bl5)) | 0; + hi = (hi + Math.imul(ah6, bh5)) | 0; + lo = (lo + Math.imul(al5, bl6)) | 0; + mid = (mid + Math.imul(al5, bh6)) | 0; + mid = (mid + Math.imul(ah5, bl6)) | 0; + hi = (hi + Math.imul(ah5, bh6)) | 0; + lo = (lo + Math.imul(al4, bl7)) | 0; + mid = (mid + Math.imul(al4, bh7)) | 0; + mid = (mid + Math.imul(ah4, bl7)) | 0; + hi = (hi + Math.imul(ah4, bh7)) | 0; + lo = (lo + Math.imul(al3, bl8)) | 0; + mid = (mid + Math.imul(al3, bh8)) | 0; + mid = (mid + Math.imul(ah3, bl8)) | 0; + hi = (hi + Math.imul(ah3, bh8)) | 0; + lo = (lo + Math.imul(al2, bl9)) | 0; + mid = (mid + Math.imul(al2, bh9)) | 0; + mid = (mid + Math.imul(ah2, bl9)) | 0; + hi = (hi + Math.imul(ah2, bh9)) | 0; + var w11 = (((c + lo) | 0) + ((mid & 0x1fff) << 13)) | 0; + c = (((hi + (mid >>> 13)) | 0) + (w11 >>> 26)) | 0; + w11 &= 0x3ffffff; + /* k = 12 */ + lo = Math.imul(al9, bl3); + mid = Math.imul(al9, bh3); + mid = (mid + Math.imul(ah9, bl3)) | 0; + hi = Math.imul(ah9, bh3); + lo = (lo + Math.imul(al8, bl4)) | 0; + mid = (mid + Math.imul(al8, bh4)) | 0; + mid = (mid + Math.imul(ah8, bl4)) | 0; + hi = (hi + Math.imul(ah8, bh4)) | 0; + lo = (lo + Math.imul(al7, bl5)) | 0; + mid = (mid + Math.imul(al7, bh5)) | 0; + mid = (mid + Math.imul(ah7, bl5)) | 0; + hi = (hi + Math.imul(ah7, bh5)) | 0; + lo = (lo + Math.imul(al6, bl6)) | 0; + mid = (mid + Math.imul(al6, bh6)) | 0; + mid = (mid + Math.imul(ah6, bl6)) | 0; + hi = (hi + Math.imul(ah6, bh6)) | 0; + lo = (lo + Math.imul(al5, bl7)) | 0; + mid = (mid + Math.imul(al5, bh7)) | 0; + mid = (mid + Math.imul(ah5, bl7)) | 0; + hi = (hi + Math.imul(ah5, bh7)) | 0; + lo = (lo + Math.imul(al4, bl8)) | 0; + mid = (mid + Math.imul(al4, bh8)) | 0; + mid = (mid + Math.imul(ah4, bl8)) | 0; + hi = (hi + Math.imul(ah4, bh8)) | 0; + lo = (lo + Math.imul(al3, bl9)) | 0; + mid = (mid + Math.imul(al3, bh9)) | 0; + mid = (mid + Math.imul(ah3, bl9)) | 0; + hi = (hi + Math.imul(ah3, bh9)) | 0; + var w12 = (((c + lo) | 0) + ((mid & 0x1fff) << 13)) | 0; + c = (((hi + (mid >>> 13)) | 0) + (w12 >>> 26)) | 0; + w12 &= 0x3ffffff; + /* k = 13 */ + lo = Math.imul(al9, bl4); + mid = Math.imul(al9, bh4); + mid = (mid + Math.imul(ah9, bl4)) | 0; + hi = Math.imul(ah9, bh4); + lo = (lo + Math.imul(al8, bl5)) | 0; + mid = (mid + Math.imul(al8, bh5)) | 0; + mid = (mid + Math.imul(ah8, bl5)) | 0; + hi = (hi + Math.imul(ah8, bh5)) | 0; + lo = (lo + Math.imul(al7, bl6)) | 0; + mid = (mid + Math.imul(al7, bh6)) | 0; + mid = (mid + Math.imul(ah7, bl6)) | 0; + hi = (hi + Math.imul(ah7, bh6)) | 0; + lo = (lo + Math.imul(al6, bl7)) | 0; + mid = (mid + Math.imul(al6, bh7)) | 0; + mid = (mid + Math.imul(ah6, bl7)) | 0; + hi = (hi + Math.imul(ah6, bh7)) | 0; + lo = (lo + Math.imul(al5, bl8)) | 0; + mid = (mid + Math.imul(al5, bh8)) | 0; + mid = (mid + Math.imul(ah5, bl8)) | 0; + hi = (hi + Math.imul(ah5, bh8)) | 0; + lo = (lo + Math.imul(al4, bl9)) | 0; + mid = (mid + Math.imul(al4, bh9)) | 0; + mid = (mid + Math.imul(ah4, bl9)) | 0; + hi = (hi + Math.imul(ah4, bh9)) | 0; + var w13 = (((c + lo) | 0) + ((mid & 0x1fff) << 13)) | 0; + c = (((hi + (mid >>> 13)) | 0) + (w13 >>> 26)) | 0; + w13 &= 0x3ffffff; + /* k = 14 */ + lo = Math.imul(al9, bl5); + mid = Math.imul(al9, bh5); + mid = (mid + Math.imul(ah9, bl5)) | 0; + hi = Math.imul(ah9, bh5); + lo = (lo + Math.imul(al8, bl6)) | 0; + mid = (mid + Math.imul(al8, bh6)) | 0; + mid = (mid + Math.imul(ah8, bl6)) | 0; + hi = (hi + Math.imul(ah8, bh6)) | 0; + lo = (lo + Math.imul(al7, bl7)) | 0; + mid = (mid + Math.imul(al7, bh7)) | 0; + mid = (mid + Math.imul(ah7, bl7)) | 0; + hi = (hi + Math.imul(ah7, bh7)) | 0; + lo = (lo + Math.imul(al6, bl8)) | 0; + mid = (mid + Math.imul(al6, bh8)) | 0; + mid = (mid + Math.imul(ah6, bl8)) | 0; + hi = (hi + Math.imul(ah6, bh8)) | 0; + lo = (lo + Math.imul(al5, bl9)) | 0; + mid = (mid + Math.imul(al5, bh9)) | 0; + mid = (mid + Math.imul(ah5, bl9)) | 0; + hi = (hi + Math.imul(ah5, bh9)) | 0; + var w14 = (((c + lo) | 0) + ((mid & 0x1fff) << 13)) | 0; + c = (((hi + (mid >>> 13)) | 0) + (w14 >>> 26)) | 0; + w14 &= 0x3ffffff; + /* k = 15 */ + lo = Math.imul(al9, bl6); + mid = Math.imul(al9, bh6); + mid = (mid + Math.imul(ah9, bl6)) | 0; + hi = Math.imul(ah9, bh6); + lo = (lo + Math.imul(al8, bl7)) | 0; + mid = (mid + Math.imul(al8, bh7)) | 0; + mid = (mid + Math.imul(ah8, bl7)) | 0; + hi = (hi + Math.imul(ah8, bh7)) | 0; + lo = (lo + Math.imul(al7, bl8)) | 0; + mid = (mid + Math.imul(al7, bh8)) | 0; + mid = (mid + Math.imul(ah7, bl8)) | 0; + hi = (hi + Math.imul(ah7, bh8)) | 0; + lo = (lo + Math.imul(al6, bl9)) | 0; + mid = (mid + Math.imul(al6, bh9)) | 0; + mid = (mid + Math.imul(ah6, bl9)) | 0; + hi = (hi + Math.imul(ah6, bh9)) | 0; + var w15 = (((c + lo) | 0) + ((mid & 0x1fff) << 13)) | 0; + c = (((hi + (mid >>> 13)) | 0) + (w15 >>> 26)) | 0; + w15 &= 0x3ffffff; + /* k = 16 */ + lo = Math.imul(al9, bl7); + mid = Math.imul(al9, bh7); + mid = (mid + Math.imul(ah9, bl7)) | 0; + hi = Math.imul(ah9, bh7); + lo = (lo + Math.imul(al8, bl8)) | 0; + mid = (mid + Math.imul(al8, bh8)) | 0; + mid = (mid + Math.imul(ah8, bl8)) | 0; + hi = (hi + Math.imul(ah8, bh8)) | 0; + lo = (lo + Math.imul(al7, bl9)) | 0; + mid = (mid + Math.imul(al7, bh9)) | 0; + mid = (mid + Math.imul(ah7, bl9)) | 0; + hi = (hi + Math.imul(ah7, bh9)) | 0; + var w16 = (((c + lo) | 0) + ((mid & 0x1fff) << 13)) | 0; + c = (((hi + (mid >>> 13)) | 0) + (w16 >>> 26)) | 0; + w16 &= 0x3ffffff; + /* k = 17 */ + lo = Math.imul(al9, bl8); + mid = Math.imul(al9, bh8); + mid = (mid + Math.imul(ah9, bl8)) | 0; + hi = Math.imul(ah9, bh8); + lo = (lo + Math.imul(al8, bl9)) | 0; + mid = (mid + Math.imul(al8, bh9)) | 0; + mid = (mid + Math.imul(ah8, bl9)) | 0; + hi = (hi + Math.imul(ah8, bh9)) | 0; + var w17 = (((c + lo) | 0) + ((mid & 0x1fff) << 13)) | 0; + c = (((hi + (mid >>> 13)) | 0) + (w17 >>> 26)) | 0; + w17 &= 0x3ffffff; + /* k = 18 */ + lo = Math.imul(al9, bl9); + mid = Math.imul(al9, bh9); + mid = (mid + Math.imul(ah9, bl9)) | 0; + hi = Math.imul(ah9, bh9); + var w18 = (((c + lo) | 0) + ((mid & 0x1fff) << 13)) | 0; + c = (((hi + (mid >>> 13)) | 0) + (w18 >>> 26)) | 0; + w18 &= 0x3ffffff; + o[0] = w0; + o[1] = w1; + o[2] = w2; + o[3] = w3; + o[4] = w4; + o[5] = w5; + o[6] = w6; + o[7] = w7; + o[8] = w8; + o[9] = w9; + o[10] = w10; + o[11] = w11; + o[12] = w12; + o[13] = w13; + o[14] = w14; + o[15] = w15; + o[16] = w16; + o[17] = w17; + o[18] = w18; + if (c !== 0) { + o[19] = c; + out.length++; + } + return out; + }; + + // Polyfill comb + if (!Math.imul) { + comb10MulTo = smallMulTo; + } + + function bigMulTo (self, num, out) { + out.negative = num.negative ^ self.negative; + out.length = self.length + num.length; + + var carry = 0; + var hncarry = 0; + for (var k = 0; k < out.length - 1; k++) { + // Sum all words with the same `i + j = k` and accumulate `ncarry`, + // note that ncarry could be >= 0x3ffffff + var ncarry = hncarry; + hncarry = 0; + var rword = carry & 0x3ffffff; + var maxJ = Math.min(k, num.length - 1); + for (var j = Math.max(0, k - self.length + 1); j <= maxJ; j++) { + var i = k - j; + var a = self.words[i] | 0; + var b = num.words[j] | 0; + var r = a * b; + + var lo = r & 0x3ffffff; + ncarry = (ncarry + ((r / 0x4000000) | 0)) | 0; + lo = (lo + rword) | 0; + rword = lo & 0x3ffffff; + ncarry = (ncarry + (lo >>> 26)) | 0; + + hncarry += ncarry >>> 26; + ncarry &= 0x3ffffff; + } + out.words[k] = rword; + carry = ncarry; + ncarry = hncarry; + } + if (carry !== 0) { + out.words[k] = carry; + } else { + out.length--; + } + + return out._strip(); + } + + function jumboMulTo (self, num, out) { + // Temporary disable, see https://github.com/indutny/bn.js/issues/211 + // var fftm = new FFTM(); + // return fftm.mulp(self, num, out); + return bigMulTo(self, num, out); + } + + BN.prototype.mulTo = function mulTo (num, out) { + var res; + var len = this.length + num.length; + if (this.length === 10 && num.length === 10) { + res = comb10MulTo(this, num, out); + } else if (len < 63) { + res = smallMulTo(this, num, out); + } else if (len < 1024) { + res = bigMulTo(this, num, out); + } else { + res = jumboMulTo(this, num, out); + } + + return res; + }; + + // Cooley-Tukey algorithm for FFT + // slightly revisited to rely on looping instead of recursion + + function FFTM (x, y) { + this.x = x; + this.y = y; + } + + FFTM.prototype.makeRBT = function makeRBT (N) { + var t = new Array(N); + var l = BN.prototype._countBits(N) - 1; + for (var i = 0; i < N; i++) { + t[i] = this.revBin(i, l, N); + } + + return t; + }; + + // Returns binary-reversed representation of `x` + FFTM.prototype.revBin = function revBin (x, l, N) { + if (x === 0 || x === N - 1) return x; + + var rb = 0; + for (var i = 0; i < l; i++) { + rb |= (x & 1) << (l - i - 1); + x >>= 1; + } + + return rb; + }; + + // Performs "tweedling" phase, therefore 'emulating' + // behaviour of the recursive algorithm + FFTM.prototype.permute = function permute (rbt, rws, iws, rtws, itws, N) { + for (var i = 0; i < N; i++) { + rtws[i] = rws[rbt[i]]; + itws[i] = iws[rbt[i]]; + } + }; + + FFTM.prototype.transform = function transform (rws, iws, rtws, itws, N, rbt) { + this.permute(rbt, rws, iws, rtws, itws, N); + + for (var s = 1; s < N; s <<= 1) { + var l = s << 1; + + var rtwdf = Math.cos(2 * Math.PI / l); + var itwdf = Math.sin(2 * Math.PI / l); + + for (var p = 0; p < N; p += l) { + var rtwdf_ = rtwdf; + var itwdf_ = itwdf; + + for (var j = 0; j < s; j++) { + var re = rtws[p + j]; + var ie = itws[p + j]; + + var ro = rtws[p + j + s]; + var io = itws[p + j + s]; + + var rx = rtwdf_ * ro - itwdf_ * io; + + io = rtwdf_ * io + itwdf_ * ro; + ro = rx; + + rtws[p + j] = re + ro; + itws[p + j] = ie + io; + + rtws[p + j + s] = re - ro; + itws[p + j + s] = ie - io; + + /* jshint maxdepth : false */ + if (j !== l) { + rx = rtwdf * rtwdf_ - itwdf * itwdf_; + + itwdf_ = rtwdf * itwdf_ + itwdf * rtwdf_; + rtwdf_ = rx; + } + } + } + } + }; + + FFTM.prototype.guessLen13b = function guessLen13b (n, m) { + var N = Math.max(m, n) | 1; + var odd = N & 1; + var i = 0; + for (N = N / 2 | 0; N; N = N >>> 1) { + i++; + } + + return 1 << i + 1 + odd; + }; + + FFTM.prototype.conjugate = function conjugate (rws, iws, N) { + if (N <= 1) return; + + for (var i = 0; i < N / 2; i++) { + var t = rws[i]; + + rws[i] = rws[N - i - 1]; + rws[N - i - 1] = t; + + t = iws[i]; + + iws[i] = -iws[N - i - 1]; + iws[N - i - 1] = -t; + } + }; + + FFTM.prototype.normalize13b = function normalize13b (ws, N) { + var carry = 0; + for (var i = 0; i < N / 2; i++) { + var w = Math.round(ws[2 * i + 1] / N) * 0x2000 + + Math.round(ws[2 * i] / N) + + carry; + + ws[i] = w & 0x3ffffff; + + if (w < 0x4000000) { + carry = 0; + } else { + carry = w / 0x4000000 | 0; + } + } + + return ws; + }; + + FFTM.prototype.convert13b = function convert13b (ws, len, rws, N) { + var carry = 0; + for (var i = 0; i < len; i++) { + carry = carry + (ws[i] | 0); + + rws[2 * i] = carry & 0x1fff; carry = carry >>> 13; + rws[2 * i + 1] = carry & 0x1fff; carry = carry >>> 13; + } + + // Pad with zeroes + for (i = 2 * len; i < N; ++i) { + rws[i] = 0; + } + + assert(carry === 0); + assert((carry & ~0x1fff) === 0); + }; + + FFTM.prototype.stub = function stub (N) { + var ph = new Array(N); + for (var i = 0; i < N; i++) { + ph[i] = 0; + } + + return ph; + }; + + FFTM.prototype.mulp = function mulp (x, y, out) { + var N = 2 * this.guessLen13b(x.length, y.length); + + var rbt = this.makeRBT(N); + + var _ = this.stub(N); + + var rws = new Array(N); + var rwst = new Array(N); + var iwst = new Array(N); + + var nrws = new Array(N); + var nrwst = new Array(N); + var niwst = new Array(N); + + var rmws = out.words; + rmws.length = N; + + this.convert13b(x.words, x.length, rws, N); + this.convert13b(y.words, y.length, nrws, N); + + this.transform(rws, _, rwst, iwst, N, rbt); + this.transform(nrws, _, nrwst, niwst, N, rbt); + + for (var i = 0; i < N; i++) { + var rx = rwst[i] * nrwst[i] - iwst[i] * niwst[i]; + iwst[i] = rwst[i] * niwst[i] + iwst[i] * nrwst[i]; + rwst[i] = rx; + } + + this.conjugate(rwst, iwst, N); + this.transform(rwst, iwst, rmws, _, N, rbt); + this.conjugate(rmws, _, N); + this.normalize13b(rmws, N); + + out.negative = x.negative ^ y.negative; + out.length = x.length + y.length; + return out._strip(); + }; + + // Multiply `this` by `num` + BN.prototype.mul = function mul (num) { + var out = new BN(null); + out.words = new Array(this.length + num.length); + return this.mulTo(num, out); + }; + + // Multiply employing FFT + BN.prototype.mulf = function mulf (num) { + var out = new BN(null); + out.words = new Array(this.length + num.length); + return jumboMulTo(this, num, out); + }; + + // In-place Multiplication + BN.prototype.imul = function imul (num) { + return this.clone().mulTo(num, this); + }; + + BN.prototype.imuln = function imuln (num) { + var isNegNum = num < 0; + if (isNegNum) num = -num; + + assert(typeof num === 'number'); + assert(num < 0x4000000); + + // Carry + var carry = 0; + for (var i = 0; i < this.length; i++) { + var w = (this.words[i] | 0) * num; + var lo = (w & 0x3ffffff) + (carry & 0x3ffffff); + carry >>= 26; + carry += (w / 0x4000000) | 0; + // NOTE: lo is 27bit maximum + carry += lo >>> 26; + this.words[i] = lo & 0x3ffffff; + } + + if (carry !== 0) { + this.words[i] = carry; + this.length++; + } + + return isNegNum ? this.ineg() : this; + }; + + BN.prototype.muln = function muln (num) { + return this.clone().imuln(num); + }; + + // `this` * `this` + BN.prototype.sqr = function sqr () { + return this.mul(this); + }; + + // `this` * `this` in-place + BN.prototype.isqr = function isqr () { + return this.imul(this.clone()); + }; + + // Math.pow(`this`, `num`) + BN.prototype.pow = function pow (num) { + var w = toBitArray(num); + if (w.length === 0) return new BN(1); + + // Skip leading zeroes + var res = this; + for (var i = 0; i < w.length; i++, res = res.sqr()) { + if (w[i] !== 0) break; + } + + if (++i < w.length) { + for (var q = res.sqr(); i < w.length; i++, q = q.sqr()) { + if (w[i] === 0) continue; + + res = res.mul(q); + } + } + + return res; + }; + + // Shift-left in-place + BN.prototype.iushln = function iushln (bits) { + assert(typeof bits === 'number' && bits >= 0); + var r = bits % 26; + var s = (bits - r) / 26; + var carryMask = (0x3ffffff >>> (26 - r)) << (26 - r); + var i; + + if (r !== 0) { + var carry = 0; + + for (i = 0; i < this.length; i++) { + var newCarry = this.words[i] & carryMask; + var c = ((this.words[i] | 0) - newCarry) << r; + this.words[i] = c | carry; + carry = newCarry >>> (26 - r); + } + + if (carry) { + this.words[i] = carry; + this.length++; + } + } + + if (s !== 0) { + for (i = this.length - 1; i >= 0; i--) { + this.words[i + s] = this.words[i]; + } + + for (i = 0; i < s; i++) { + this.words[i] = 0; + } + + this.length += s; + } + + return this._strip(); + }; + + BN.prototype.ishln = function ishln (bits) { + // TODO(indutny): implement me + assert(this.negative === 0); + return this.iushln(bits); + }; + + // Shift-right in-place + // NOTE: `hint` is a lowest bit before trailing zeroes + // NOTE: if `extended` is present - it will be filled with destroyed bits + BN.prototype.iushrn = function iushrn (bits, hint, extended) { + assert(typeof bits === 'number' && bits >= 0); + var h; + if (hint) { + h = (hint - (hint % 26)) / 26; + } else { + h = 0; + } + + var r = bits % 26; + var s = Math.min((bits - r) / 26, this.length); + var mask = 0x3ffffff ^ ((0x3ffffff >>> r) << r); + var maskedWords = extended; + + h -= s; + h = Math.max(0, h); + + // Extended mode, copy masked part + if (maskedWords) { + for (var i = 0; i < s; i++) { + maskedWords.words[i] = this.words[i]; + } + maskedWords.length = s; + } + + if (s === 0) { + // No-op, we should not move anything at all + } else if (this.length > s) { + this.length -= s; + for (i = 0; i < this.length; i++) { + this.words[i] = this.words[i + s]; + } + } else { + this.words[0] = 0; + this.length = 1; + } + + var carry = 0; + for (i = this.length - 1; i >= 0 && (carry !== 0 || i >= h); i--) { + var word = this.words[i] | 0; + this.words[i] = (carry << (26 - r)) | (word >>> r); + carry = word & mask; + } + + // Push carried bits as a mask + if (maskedWords && carry !== 0) { + maskedWords.words[maskedWords.length++] = carry; + } + + if (this.length === 0) { + this.words[0] = 0; + this.length = 1; + } + + return this._strip(); + }; + + BN.prototype.ishrn = function ishrn (bits, hint, extended) { + // TODO(indutny): implement me + assert(this.negative === 0); + return this.iushrn(bits, hint, extended); + }; + + // Shift-left + BN.prototype.shln = function shln (bits) { + return this.clone().ishln(bits); + }; + + BN.prototype.ushln = function ushln (bits) { + return this.clone().iushln(bits); + }; + + // Shift-right + BN.prototype.shrn = function shrn (bits) { + return this.clone().ishrn(bits); + }; + + BN.prototype.ushrn = function ushrn (bits) { + return this.clone().iushrn(bits); + }; + + // Test if n bit is set + BN.prototype.testn = function testn (bit) { + assert(typeof bit === 'number' && bit >= 0); + var r = bit % 26; + var s = (bit - r) / 26; + var q = 1 << r; + + // Fast case: bit is much higher than all existing words + if (this.length <= s) return false; + + // Check bit and return + var w = this.words[s]; + + return !!(w & q); + }; + + // Return only lowers bits of number (in-place) + BN.prototype.imaskn = function imaskn (bits) { + assert(typeof bits === 'number' && bits >= 0); + var r = bits % 26; + var s = (bits - r) / 26; + + assert(this.negative === 0, 'imaskn works only with positive numbers'); + + if (this.length <= s) { + return this; + } + + if (r !== 0) { + s++; + } + this.length = Math.min(s, this.length); + + if (r !== 0) { + var mask = 0x3ffffff ^ ((0x3ffffff >>> r) << r); + this.words[this.length - 1] &= mask; + } + + return this._strip(); + }; + + // Return only lowers bits of number + BN.prototype.maskn = function maskn (bits) { + return this.clone().imaskn(bits); + }; + + // Add plain number `num` to `this` + BN.prototype.iaddn = function iaddn (num) { + assert(typeof num === 'number'); + assert(num < 0x4000000); + if (num < 0) return this.isubn(-num); + + // Possible sign change + if (this.negative !== 0) { + if (this.length === 1 && (this.words[0] | 0) <= num) { + this.words[0] = num - (this.words[0] | 0); + this.negative = 0; + return this; + } + + this.negative = 0; + this.isubn(num); + this.negative = 1; + return this; + } + + // Add without checks + return this._iaddn(num); + }; + + BN.prototype._iaddn = function _iaddn (num) { + this.words[0] += num; + + // Carry + for (var i = 0; i < this.length && this.words[i] >= 0x4000000; i++) { + this.words[i] -= 0x4000000; + if (i === this.length - 1) { + this.words[i + 1] = 1; + } else { + this.words[i + 1]++; + } + } + this.length = Math.max(this.length, i + 1); + + return this; + }; + + // Subtract plain number `num` from `this` + BN.prototype.isubn = function isubn (num) { + assert(typeof num === 'number'); + assert(num < 0x4000000); + if (num < 0) return this.iaddn(-num); + + if (this.negative !== 0) { + this.negative = 0; + this.iaddn(num); + this.negative = 1; + return this; + } + + this.words[0] -= num; + + if (this.length === 1 && this.words[0] < 0) { + this.words[0] = -this.words[0]; + this.negative = 1; + } else { + // Carry + for (var i = 0; i < this.length && this.words[i] < 0; i++) { + this.words[i] += 0x4000000; + this.words[i + 1] -= 1; + } + } + + return this._strip(); + }; + + BN.prototype.addn = function addn (num) { + return this.clone().iaddn(num); + }; + + BN.prototype.subn = function subn (num) { + return this.clone().isubn(num); + }; + + BN.prototype.iabs = function iabs () { + this.negative = 0; + + return this; + }; + + BN.prototype.abs = function abs () { + return this.clone().iabs(); + }; + + BN.prototype._ishlnsubmul = function _ishlnsubmul (num, mul, shift) { + var len = num.length + shift; + var i; + + this._expand(len); + + var w; + var carry = 0; + for (i = 0; i < num.length; i++) { + w = (this.words[i + shift] | 0) + carry; + var right = (num.words[i] | 0) * mul; + w -= right & 0x3ffffff; + carry = (w >> 26) - ((right / 0x4000000) | 0); + this.words[i + shift] = w & 0x3ffffff; + } + for (; i < this.length - shift; i++) { + w = (this.words[i + shift] | 0) + carry; + carry = w >> 26; + this.words[i + shift] = w & 0x3ffffff; + } + + if (carry === 0) return this._strip(); + + // Subtraction overflow + assert(carry === -1); + carry = 0; + for (i = 0; i < this.length; i++) { + w = -(this.words[i] | 0) + carry; + carry = w >> 26; + this.words[i] = w & 0x3ffffff; + } + this.negative = 1; + + return this._strip(); + }; + + BN.prototype._wordDiv = function _wordDiv (num, mode) { + var shift = this.length - num.length; + + var a = this.clone(); + var b = num; + + // Normalize + var bhi = b.words[b.length - 1] | 0; + var bhiBits = this._countBits(bhi); + shift = 26 - bhiBits; + if (shift !== 0) { + b = b.ushln(shift); + a.iushln(shift); + bhi = b.words[b.length - 1] | 0; + } + + // Initialize quotient + var m = a.length - b.length; + var q; + + if (mode !== 'mod') { + q = new BN(null); + q.length = m + 1; + q.words = new Array(q.length); + for (var i = 0; i < q.length; i++) { + q.words[i] = 0; + } + } + + var diff = a.clone()._ishlnsubmul(b, 1, m); + if (diff.negative === 0) { + a = diff; + if (q) { + q.words[m] = 1; + } + } + + for (var j = m - 1; j >= 0; j--) { + var qj = (a.words[b.length + j] | 0) * 0x4000000 + + (a.words[b.length + j - 1] | 0); + + // NOTE: (qj / bhi) is (0x3ffffff * 0x4000000 + 0x3ffffff) / 0x2000000 max + // (0x7ffffff) + qj = Math.min((qj / bhi) | 0, 0x3ffffff); + + a._ishlnsubmul(b, qj, j); + while (a.negative !== 0) { + qj--; + a.negative = 0; + a._ishlnsubmul(b, 1, j); + if (!a.isZero()) { + a.negative ^= 1; + } + } + if (q) { + q.words[j] = qj; + } + } + if (q) { + q._strip(); + } + a._strip(); + + // Denormalize + if (mode !== 'div' && shift !== 0) { + a.iushrn(shift); + } + + return { + div: q || null, + mod: a + }; + }; + + // NOTE: 1) `mode` can be set to `mod` to request mod only, + // to `div` to request div only, or be absent to + // request both div & mod + // 2) `positive` is true if unsigned mod is requested + BN.prototype.divmod = function divmod (num, mode, positive) { + assert(!num.isZero()); + + if (this.isZero()) { + return { + div: new BN(0), + mod: new BN(0) + }; + } + + var div, mod, res; + if (this.negative !== 0 && num.negative === 0) { + res = this.neg().divmod(num, mode); + + if (mode !== 'mod') { + div = res.div.neg(); + } + + if (mode !== 'div') { + mod = res.mod.neg(); + if (positive && mod.negative !== 0) { + mod.iadd(num); + } + } + + return { + div: div, + mod: mod + }; + } + + if (this.negative === 0 && num.negative !== 0) { + res = this.divmod(num.neg(), mode); + + if (mode !== 'mod') { + div = res.div.neg(); + } + + return { + div: div, + mod: res.mod + }; + } + + if ((this.negative & num.negative) !== 0) { + res = this.neg().divmod(num.neg(), mode); + + if (mode !== 'div') { + mod = res.mod.neg(); + if (positive && mod.negative !== 0) { + mod.isub(num); + } + } + + return { + div: res.div, + mod: mod + }; + } + + // Both numbers are positive at this point + + // Strip both numbers to approximate shift value + if (num.length > this.length || this.cmp(num) < 0) { + return { + div: new BN(0), + mod: this + }; + } + + // Very short reduction + if (num.length === 1) { + if (mode === 'div') { + return { + div: this.divn(num.words[0]), + mod: null + }; + } + + if (mode === 'mod') { + return { + div: null, + mod: new BN(this.modrn(num.words[0])) + }; + } + + return { + div: this.divn(num.words[0]), + mod: new BN(this.modrn(num.words[0])) + }; + } + + return this._wordDiv(num, mode); + }; + + // Find `this` / `num` + BN.prototype.div = function div (num) { + return this.divmod(num, 'div', false).div; + }; + + // Find `this` % `num` + BN.prototype.mod = function mod (num) { + return this.divmod(num, 'mod', false).mod; + }; + + BN.prototype.umod = function umod (num) { + return this.divmod(num, 'mod', true).mod; + }; + + // Find Round(`this` / `num`) + BN.prototype.divRound = function divRound (num) { + var dm = this.divmod(num); + + // Fast case - exact division + if (dm.mod.isZero()) return dm.div; + + var mod = dm.div.negative !== 0 ? dm.mod.isub(num) : dm.mod; + + var half = num.ushrn(1); + var r2 = num.andln(1); + var cmp = mod.cmp(half); + + // Round down + if (cmp < 0 || (r2 === 1 && cmp === 0)) return dm.div; + + // Round up + return dm.div.negative !== 0 ? dm.div.isubn(1) : dm.div.iaddn(1); + }; + + BN.prototype.modrn = function modrn (num) { + var isNegNum = num < 0; + if (isNegNum) num = -num; + + assert(num <= 0x3ffffff); + var p = (1 << 26) % num; + + var acc = 0; + for (var i = this.length - 1; i >= 0; i--) { + acc = (p * acc + (this.words[i] | 0)) % num; + } + + return isNegNum ? -acc : acc; + }; + + // WARNING: DEPRECATED + BN.prototype.modn = function modn (num) { + return this.modrn(num); + }; + + // In-place division by number + BN.prototype.idivn = function idivn (num) { + var isNegNum = num < 0; + if (isNegNum) num = -num; + + assert(num <= 0x3ffffff); + + var carry = 0; + for (var i = this.length - 1; i >= 0; i--) { + var w = (this.words[i] | 0) + carry * 0x4000000; + this.words[i] = (w / num) | 0; + carry = w % num; + } + + this._strip(); + return isNegNum ? this.ineg() : this; + }; + + BN.prototype.divn = function divn (num) { + return this.clone().idivn(num); + }; + + BN.prototype.egcd = function egcd (p) { + assert(p.negative === 0); + assert(!p.isZero()); + + var x = this; + var y = p.clone(); + + if (x.negative !== 0) { + x = x.umod(p); + } else { + x = x.clone(); + } + + // A * x + B * y = x + var A = new BN(1); + var B = new BN(0); + + // C * x + D * y = y + var C = new BN(0); + var D = new BN(1); + + var g = 0; + + while (x.isEven() && y.isEven()) { + x.iushrn(1); + y.iushrn(1); + ++g; + } + + var yp = y.clone(); + var xp = x.clone(); + + while (!x.isZero()) { + for (var i = 0, im = 1; (x.words[0] & im) === 0 && i < 26; ++i, im <<= 1); + if (i > 0) { + x.iushrn(i); + while (i-- > 0) { + if (A.isOdd() || B.isOdd()) { + A.iadd(yp); + B.isub(xp); + } + + A.iushrn(1); + B.iushrn(1); + } + } + + for (var j = 0, jm = 1; (y.words[0] & jm) === 0 && j < 26; ++j, jm <<= 1); + if (j > 0) { + y.iushrn(j); + while (j-- > 0) { + if (C.isOdd() || D.isOdd()) { + C.iadd(yp); + D.isub(xp); + } + + C.iushrn(1); + D.iushrn(1); + } + } + + if (x.cmp(y) >= 0) { + x.isub(y); + A.isub(C); + B.isub(D); + } else { + y.isub(x); + C.isub(A); + D.isub(B); + } + } + + return { + a: C, + b: D, + gcd: y.iushln(g) + }; + }; + + // This is reduced incarnation of the binary EEA + // above, designated to invert members of the + // _prime_ fields F(p) at a maximal speed + BN.prototype._invmp = function _invmp (p) { + assert(p.negative === 0); + assert(!p.isZero()); + + var a = this; + var b = p.clone(); + + if (a.negative !== 0) { + a = a.umod(p); + } else { + a = a.clone(); + } + + var x1 = new BN(1); + var x2 = new BN(0); + + var delta = b.clone(); + + while (a.cmpn(1) > 0 && b.cmpn(1) > 0) { + for (var i = 0, im = 1; (a.words[0] & im) === 0 && i < 26; ++i, im <<= 1); + if (i > 0) { + a.iushrn(i); + while (i-- > 0) { + if (x1.isOdd()) { + x1.iadd(delta); + } + + x1.iushrn(1); + } + } + + for (var j = 0, jm = 1; (b.words[0] & jm) === 0 && j < 26; ++j, jm <<= 1); + if (j > 0) { + b.iushrn(j); + while (j-- > 0) { + if (x2.isOdd()) { + x2.iadd(delta); + } + + x2.iushrn(1); + } + } + + if (a.cmp(b) >= 0) { + a.isub(b); + x1.isub(x2); + } else { + b.isub(a); + x2.isub(x1); + } + } + + var res; + if (a.cmpn(1) === 0) { + res = x1; + } else { + res = x2; + } + + if (res.cmpn(0) < 0) { + res.iadd(p); + } + + return res; + }; + + BN.prototype.gcd = function gcd (num) { + if (this.isZero()) return num.abs(); + if (num.isZero()) return this.abs(); + + var a = this.clone(); + var b = num.clone(); + a.negative = 0; + b.negative = 0; + + // Remove common factor of two + for (var shift = 0; a.isEven() && b.isEven(); shift++) { + a.iushrn(1); + b.iushrn(1); + } + + do { + while (a.isEven()) { + a.iushrn(1); + } + while (b.isEven()) { + b.iushrn(1); + } + + var r = a.cmp(b); + if (r < 0) { + // Swap `a` and `b` to make `a` always bigger than `b` + var t = a; + a = b; + b = t; + } else if (r === 0 || b.cmpn(1) === 0) { + break; + } + + a.isub(b); + } while (true); + + return b.iushln(shift); + }; + + // Invert number in the field F(num) + BN.prototype.invm = function invm (num) { + return this.egcd(num).a.umod(num); + }; + + BN.prototype.isEven = function isEven () { + return (this.words[0] & 1) === 0; + }; + + BN.prototype.isOdd = function isOdd () { + return (this.words[0] & 1) === 1; + }; + + // And first word and num + BN.prototype.andln = function andln (num) { + return this.words[0] & num; + }; + + // Increment at the bit position in-line + BN.prototype.bincn = function bincn (bit) { + assert(typeof bit === 'number'); + var r = bit % 26; + var s = (bit - r) / 26; + var q = 1 << r; + + // Fast case: bit is much higher than all existing words + if (this.length <= s) { + this._expand(s + 1); + this.words[s] |= q; + return this; + } + + // Add bit and propagate, if needed + var carry = q; + for (var i = s; carry !== 0 && i < this.length; i++) { + var w = this.words[i] | 0; + w += carry; + carry = w >>> 26; + w &= 0x3ffffff; + this.words[i] = w; + } + if (carry !== 0) { + this.words[i] = carry; + this.length++; + } + return this; + }; + + BN.prototype.isZero = function isZero () { + return this.length === 1 && this.words[0] === 0; + }; + + BN.prototype.cmpn = function cmpn (num) { + var negative = num < 0; + + if (this.negative !== 0 && !negative) return -1; + if (this.negative === 0 && negative) return 1; + + this._strip(); + + var res; + if (this.length > 1) { + res = 1; + } else { + if (negative) { + num = -num; + } + + assert(num <= 0x3ffffff, 'Number is too big'); + + var w = this.words[0] | 0; + res = w === num ? 0 : w < num ? -1 : 1; + } + if (this.negative !== 0) return -res | 0; + return res; + }; + + // Compare two numbers and return: + // 1 - if `this` > `num` + // 0 - if `this` == `num` + // -1 - if `this` < `num` + BN.prototype.cmp = function cmp (num) { + if (this.negative !== 0 && num.negative === 0) return -1; + if (this.negative === 0 && num.negative !== 0) return 1; + + var res = this.ucmp(num); + if (this.negative !== 0) return -res | 0; + return res; + }; + + // Unsigned comparison + BN.prototype.ucmp = function ucmp (num) { + // At this point both numbers have the same sign + if (this.length > num.length) return 1; + if (this.length < num.length) return -1; + + var res = 0; + for (var i = this.length - 1; i >= 0; i--) { + var a = this.words[i] | 0; + var b = num.words[i] | 0; + + if (a === b) continue; + if (a < b) { + res = -1; + } else if (a > b) { + res = 1; + } + break; + } + return res; + }; + + BN.prototype.gtn = function gtn (num) { + return this.cmpn(num) === 1; + }; + + BN.prototype.gt = function gt (num) { + return this.cmp(num) === 1; + }; + + BN.prototype.gten = function gten (num) { + return this.cmpn(num) >= 0; + }; + + BN.prototype.gte = function gte (num) { + return this.cmp(num) >= 0; + }; + + BN.prototype.ltn = function ltn (num) { + return this.cmpn(num) === -1; + }; + + BN.prototype.lt = function lt (num) { + return this.cmp(num) === -1; + }; + + BN.prototype.lten = function lten (num) { + return this.cmpn(num) <= 0; + }; + + BN.prototype.lte = function lte (num) { + return this.cmp(num) <= 0; + }; + + BN.prototype.eqn = function eqn (num) { + return this.cmpn(num) === 0; + }; + + BN.prototype.eq = function eq (num) { + return this.cmp(num) === 0; + }; + + // + // A reduce context, could be using montgomery or something better, depending + // on the `m` itself. + // + BN.red = function red (num) { + return new Red(num); + }; + + BN.prototype.toRed = function toRed (ctx) { + assert(!this.red, 'Already a number in reduction context'); + assert(this.negative === 0, 'red works only with positives'); + return ctx.convertTo(this)._forceRed(ctx); + }; + + BN.prototype.fromRed = function fromRed () { + assert(this.red, 'fromRed works only with numbers in reduction context'); + return this.red.convertFrom(this); + }; + + BN.prototype._forceRed = function _forceRed (ctx) { + this.red = ctx; + return this; + }; + + BN.prototype.forceRed = function forceRed (ctx) { + assert(!this.red, 'Already a number in reduction context'); + return this._forceRed(ctx); + }; + + BN.prototype.redAdd = function redAdd (num) { + assert(this.red, 'redAdd works only with red numbers'); + return this.red.add(this, num); + }; + + BN.prototype.redIAdd = function redIAdd (num) { + assert(this.red, 'redIAdd works only with red numbers'); + return this.red.iadd(this, num); + }; + + BN.prototype.redSub = function redSub (num) { + assert(this.red, 'redSub works only with red numbers'); + return this.red.sub(this, num); + }; + + BN.prototype.redISub = function redISub (num) { + assert(this.red, 'redISub works only with red numbers'); + return this.red.isub(this, num); + }; + + BN.prototype.redShl = function redShl (num) { + assert(this.red, 'redShl works only with red numbers'); + return this.red.shl(this, num); + }; + + BN.prototype.redMul = function redMul (num) { + assert(this.red, 'redMul works only with red numbers'); + this.red._verify2(this, num); + return this.red.mul(this, num); + }; + + BN.prototype.redIMul = function redIMul (num) { + assert(this.red, 'redMul works only with red numbers'); + this.red._verify2(this, num); + return this.red.imul(this, num); + }; + + BN.prototype.redSqr = function redSqr () { + assert(this.red, 'redSqr works only with red numbers'); + this.red._verify1(this); + return this.red.sqr(this); + }; + + BN.prototype.redISqr = function redISqr () { + assert(this.red, 'redISqr works only with red numbers'); + this.red._verify1(this); + return this.red.isqr(this); + }; + + // Square root over p + BN.prototype.redSqrt = function redSqrt () { + assert(this.red, 'redSqrt works only with red numbers'); + this.red._verify1(this); + return this.red.sqrt(this); + }; + + BN.prototype.redInvm = function redInvm () { + assert(this.red, 'redInvm works only with red numbers'); + this.red._verify1(this); + return this.red.invm(this); + }; + + // Return negative clone of `this` % `red modulo` + BN.prototype.redNeg = function redNeg () { + assert(this.red, 'redNeg works only with red numbers'); + this.red._verify1(this); + return this.red.neg(this); + }; + + BN.prototype.redPow = function redPow (num) { + assert(this.red && !num.red, 'redPow(normalNum)'); + this.red._verify1(this); + return this.red.pow(this, num); + }; + + // Prime numbers with efficient reduction + var primes = { + k256: null, + p224: null, + p192: null, + p25519: null + }; + + // Pseudo-Mersenne prime + function MPrime (name, p) { + // P = 2 ^ N - K + this.name = name; + this.p = new BN(p, 16); + this.n = this.p.bitLength(); + this.k = new BN(1).iushln(this.n).isub(this.p); + + this.tmp = this._tmp(); + } + + MPrime.prototype._tmp = function _tmp () { + var tmp = new BN(null); + tmp.words = new Array(Math.ceil(this.n / 13)); + return tmp; + }; + + MPrime.prototype.ireduce = function ireduce (num) { + // Assumes that `num` is less than `P^2` + // num = HI * (2 ^ N - K) + HI * K + LO = HI * K + LO (mod P) + var r = num; + var rlen; + + do { + this.split(r, this.tmp); + r = this.imulK(r); + r = r.iadd(this.tmp); + rlen = r.bitLength(); + } while (rlen > this.n); + + var cmp = rlen < this.n ? -1 : r.ucmp(this.p); + if (cmp === 0) { + r.words[0] = 0; + r.length = 1; + } else if (cmp > 0) { + r.isub(this.p); + } else { + if (r.strip !== undefined) { + // r is a BN v4 instance + r.strip(); + } else { + // r is a BN v5 instance + r._strip(); + } + } + + return r; + }; + + MPrime.prototype.split = function split (input, out) { + input.iushrn(this.n, 0, out); + }; + + MPrime.prototype.imulK = function imulK (num) { + return num.imul(this.k); + }; + + function K256 () { + MPrime.call( + this, + 'k256', + 'ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff fffffffe fffffc2f'); + } + inherits(K256, MPrime); + + K256.prototype.split = function split (input, output) { + // 256 = 9 * 26 + 22 + var mask = 0x3fffff; + + var outLen = Math.min(input.length, 9); + for (var i = 0; i < outLen; i++) { + output.words[i] = input.words[i]; + } + output.length = outLen; + + if (input.length <= 9) { + input.words[0] = 0; + input.length = 1; + return; + } + + // Shift by 9 limbs + var prev = input.words[9]; + output.words[output.length++] = prev & mask; + + for (i = 10; i < input.length; i++) { + var next = input.words[i] | 0; + input.words[i - 10] = ((next & mask) << 4) | (prev >>> 22); + prev = next; + } + prev >>>= 22; + input.words[i - 10] = prev; + if (prev === 0 && input.length > 10) { + input.length -= 10; + } else { + input.length -= 9; + } + }; + + K256.prototype.imulK = function imulK (num) { + // K = 0x1000003d1 = [ 0x40, 0x3d1 ] + num.words[num.length] = 0; + num.words[num.length + 1] = 0; + num.length += 2; + + // bounded at: 0x40 * 0x3ffffff + 0x3d0 = 0x100000390 + var lo = 0; + for (var i = 0; i < num.length; i++) { + var w = num.words[i] | 0; + lo += w * 0x3d1; + num.words[i] = lo & 0x3ffffff; + lo = w * 0x40 + ((lo / 0x4000000) | 0); + } + + // Fast length reduction + if (num.words[num.length - 1] === 0) { + num.length--; + if (num.words[num.length - 1] === 0) { + num.length--; + } + } + return num; + }; + + function P224 () { + MPrime.call( + this, + 'p224', + 'ffffffff ffffffff ffffffff ffffffff 00000000 00000000 00000001'); + } + inherits(P224, MPrime); + + function P192 () { + MPrime.call( + this, + 'p192', + 'ffffffff ffffffff ffffffff fffffffe ffffffff ffffffff'); + } + inherits(P192, MPrime); + + function P25519 () { + // 2 ^ 255 - 19 + MPrime.call( + this, + '25519', + '7fffffffffffffff ffffffffffffffff ffffffffffffffff ffffffffffffffed'); + } + inherits(P25519, MPrime); + + P25519.prototype.imulK = function imulK (num) { + // K = 0x13 + var carry = 0; + for (var i = 0; i < num.length; i++) { + var hi = (num.words[i] | 0) * 0x13 + carry; + var lo = hi & 0x3ffffff; + hi >>>= 26; + + num.words[i] = lo; + carry = hi; + } + if (carry !== 0) { + num.words[num.length++] = carry; + } + return num; + }; + + // Exported mostly for testing purposes, use plain name instead + BN._prime = function prime (name) { + // Cached version of prime + if (primes[name]) return primes[name]; + + var prime; + if (name === 'k256') { + prime = new K256(); + } else if (name === 'p224') { + prime = new P224(); + } else if (name === 'p192') { + prime = new P192(); + } else if (name === 'p25519') { + prime = new P25519(); + } else { + throw new Error('Unknown prime ' + name); + } + primes[name] = prime; + + return prime; + }; + + // + // Base reduction engine + // + function Red (m) { + if (typeof m === 'string') { + var prime = BN._prime(m); + this.m = prime.p; + this.prime = prime; + } else { + assert(m.gtn(1), 'modulus must be greater than 1'); + this.m = m; + this.prime = null; + } + } + + Red.prototype._verify1 = function _verify1 (a) { + assert(a.negative === 0, 'red works only with positives'); + assert(a.red, 'red works only with red numbers'); + }; + + Red.prototype._verify2 = function _verify2 (a, b) { + assert((a.negative | b.negative) === 0, 'red works only with positives'); + assert(a.red && a.red === b.red, + 'red works only with red numbers'); + }; + + Red.prototype.imod = function imod (a) { + if (this.prime) return this.prime.ireduce(a)._forceRed(this); + + move(a, a.umod(this.m)._forceRed(this)); + return a; + }; + + Red.prototype.neg = function neg (a) { + if (a.isZero()) { + return a.clone(); + } + + return this.m.sub(a)._forceRed(this); + }; + + Red.prototype.add = function add (a, b) { + this._verify2(a, b); + + var res = a.add(b); + if (res.cmp(this.m) >= 0) { + res.isub(this.m); + } + return res._forceRed(this); + }; + + Red.prototype.iadd = function iadd (a, b) { + this._verify2(a, b); + + var res = a.iadd(b); + if (res.cmp(this.m) >= 0) { + res.isub(this.m); + } + return res; + }; + + Red.prototype.sub = function sub (a, b) { + this._verify2(a, b); + + var res = a.sub(b); + if (res.cmpn(0) < 0) { + res.iadd(this.m); + } + return res._forceRed(this); + }; + + Red.prototype.isub = function isub (a, b) { + this._verify2(a, b); + + var res = a.isub(b); + if (res.cmpn(0) < 0) { + res.iadd(this.m); + } + return res; + }; + + Red.prototype.shl = function shl (a, num) { + this._verify1(a); + return this.imod(a.ushln(num)); + }; + + Red.prototype.imul = function imul (a, b) { + this._verify2(a, b); + return this.imod(a.imul(b)); + }; + + Red.prototype.mul = function mul (a, b) { + this._verify2(a, b); + return this.imod(a.mul(b)); + }; + + Red.prototype.isqr = function isqr (a) { + return this.imul(a, a.clone()); + }; + + Red.prototype.sqr = function sqr (a) { + return this.mul(a, a); + }; + + Red.prototype.sqrt = function sqrt (a) { + if (a.isZero()) return a.clone(); + + var mod3 = this.m.andln(3); + assert(mod3 % 2 === 1); + + // Fast case + if (mod3 === 3) { + var pow = this.m.add(new BN(1)).iushrn(2); + return this.pow(a, pow); + } + + // Tonelli-Shanks algorithm (Totally unoptimized and slow) + // + // Find Q and S, that Q * 2 ^ S = (P - 1) + var q = this.m.subn(1); + var s = 0; + while (!q.isZero() && q.andln(1) === 0) { + s++; + q.iushrn(1); + } + assert(!q.isZero()); + + var one = new BN(1).toRed(this); + var nOne = one.redNeg(); + + // Find quadratic non-residue + // NOTE: Max is such because of generalized Riemann hypothesis. + var lpow = this.m.subn(1).iushrn(1); + var z = this.m.bitLength(); + z = new BN(2 * z * z).toRed(this); + + while (this.pow(z, lpow).cmp(nOne) !== 0) { + z.redIAdd(nOne); + } + + var c = this.pow(z, q); + var r = this.pow(a, q.addn(1).iushrn(1)); + var t = this.pow(a, q); + var m = s; + while (t.cmp(one) !== 0) { + var tmp = t; + for (var i = 0; tmp.cmp(one) !== 0; i++) { + tmp = tmp.redSqr(); + } + assert(i < m); + var b = this.pow(c, new BN(1).iushln(m - i - 1)); + + r = r.redMul(b); + c = b.redSqr(); + t = t.redMul(c); + m = i; + } + + return r; + }; + + Red.prototype.invm = function invm (a) { + var inv = a._invmp(this.m); + if (inv.negative !== 0) { + inv.negative = 0; + return this.imod(inv).redNeg(); + } else { + return this.imod(inv); + } + }; + + Red.prototype.pow = function pow (a, num) { + if (num.isZero()) return new BN(1).toRed(this); + if (num.cmpn(1) === 0) return a.clone(); + + var windowSize = 4; + var wnd = new Array(1 << windowSize); + wnd[0] = new BN(1).toRed(this); + wnd[1] = a; + for (var i = 2; i < wnd.length; i++) { + wnd[i] = this.mul(wnd[i - 1], a); + } + + var res = wnd[0]; + var current = 0; + var currentLen = 0; + var start = num.bitLength() % 26; + if (start === 0) { + start = 26; + } + + for (i = num.length - 1; i >= 0; i--) { + var word = num.words[i]; + for (var j = start - 1; j >= 0; j--) { + var bit = (word >> j) & 1; + if (res !== wnd[0]) { + res = this.sqr(res); + } + + if (bit === 0 && current === 0) { + currentLen = 0; + continue; + } + + current <<= 1; + current |= bit; + currentLen++; + if (currentLen !== windowSize && (i !== 0 || j !== 0)) continue; + + res = this.mul(res, wnd[current]); + currentLen = 0; + current = 0; + } + start = 26; + } + + return res; + }; + + Red.prototype.convertTo = function convertTo (num) { + var r = num.umod(this.m); + + return r === num ? r.clone() : r; + }; + + Red.prototype.convertFrom = function convertFrom (num) { + var res = num.clone(); + res.red = null; + return res; + }; + + // + // Montgomery method engine + // + + BN.mont = function mont (num) { + return new Mont(num); + }; + + function Mont (m) { + Red.call(this, m); + + this.shift = this.m.bitLength(); + if (this.shift % 26 !== 0) { + this.shift += 26 - (this.shift % 26); + } + + this.r = new BN(1).iushln(this.shift); + this.r2 = this.imod(this.r.sqr()); + this.rinv = this.r._invmp(this.m); + + this.minv = this.rinv.mul(this.r).isubn(1).div(this.m); + this.minv = this.minv.umod(this.r); + this.minv = this.r.sub(this.minv); + } + inherits(Mont, Red); + + Mont.prototype.convertTo = function convertTo (num) { + return this.imod(num.ushln(this.shift)); + }; + + Mont.prototype.convertFrom = function convertFrom (num) { + var r = this.imod(num.mul(this.rinv)); + r.red = null; + return r; + }; + + Mont.prototype.imul = function imul (a, b) { + if (a.isZero() || b.isZero()) { + a.words[0] = 0; + a.length = 1; + return a; + } + + var t = a.imul(b); + var c = t.maskn(this.shift).mul(this.minv).imaskn(this.shift).mul(this.m); + var u = t.isub(c).iushrn(this.shift); + var res = u; + + if (u.cmp(this.m) >= 0) { + res = u.isub(this.m); + } else if (u.cmpn(0) < 0) { + res = u.iadd(this.m); + } + + return res._forceRed(this); + }; + + Mont.prototype.mul = function mul (a, b) { + if (a.isZero() || b.isZero()) return new BN(0)._forceRed(this); + + var t = a.mul(b); + var c = t.maskn(this.shift).mul(this.minv).imaskn(this.shift).mul(this.m); + var u = t.isub(c).iushrn(this.shift); + var res = u; + if (u.cmp(this.m) >= 0) { + res = u.isub(this.m); + } else if (u.cmpn(0) < 0) { + res = u.iadd(this.m); + } + + return res._forceRed(this); + }; + + Mont.prototype.invm = function invm (a) { + // (AR)^-1 * R^2 = (A^-1 * R^-1) * R^2 = A^-1 * R + var res = this.imod(a._invmp(this.m).mul(this.r2)); + return res._forceRed(this); + }; +})(typeof module === 'undefined' || module, this); + +},{"buffer":20}],19:[function(require,module,exports){ +var r; + +module.exports = function rand(len) { + if (!r) + r = new Rand(null); + + return r.generate(len); +}; + +function Rand(rand) { + this.rand = rand; +} +module.exports.Rand = Rand; + +Rand.prototype.generate = function generate(len) { + return this._rand(len); +}; + +// Emulate crypto API using randy +Rand.prototype._rand = function _rand(n) { + if (this.rand.getBytes) + return this.rand.getBytes(n); + + var res = new Uint8Array(n); + for (var i = 0; i < res.length; i++) + res[i] = this.rand.getByte(); + return res; +}; + +if (typeof self === 'object') { + if (self.crypto && self.crypto.getRandomValues) { + // Modern browsers + Rand.prototype._rand = function _rand(n) { + var arr = new Uint8Array(n); + self.crypto.getRandomValues(arr); + return arr; + }; + } else if (self.msCrypto && self.msCrypto.getRandomValues) { + // IE + Rand.prototype._rand = function _rand(n) { + var arr = new Uint8Array(n); + self.msCrypto.getRandomValues(arr); + return arr; + }; + + // Safari's WebWorkers do not have `crypto` + } else if (typeof window === 'object') { + // Old junk + Rand.prototype._rand = function() { + throw new Error('Not implemented yet'); + }; + } +} else { + // Node.js or Web worker with no crypto support + try { + var crypto = require('crypto'); + if (typeof crypto.randomBytes !== 'function') + throw new Error('Not supported'); + + Rand.prototype._rand = function _rand(n) { + return crypto.randomBytes(n); + }; + } catch (e) { + } +} + +},{"crypto":20}],20:[function(require,module,exports){ + +},{}],21:[function(require,module,exports){ +// based on the aes implimentation in triple sec +// https://github.com/keybase/triplesec +// which is in turn based on the one from crypto-js +// https://code.google.com/p/crypto-js/ + +var Buffer = require('safe-buffer').Buffer + +function asUInt32Array (buf) { + if (!Buffer.isBuffer(buf)) buf = Buffer.from(buf) + + var len = (buf.length / 4) | 0 + var out = new Array(len) + + for (var i = 0; i < len; i++) { + out[i] = buf.readUInt32BE(i * 4) + } + + return out +} + +function scrubVec (v) { + for (var i = 0; i < v.length; v++) { + v[i] = 0 + } +} + +function cryptBlock (M, keySchedule, SUB_MIX, SBOX, nRounds) { + var SUB_MIX0 = SUB_MIX[0] + var SUB_MIX1 = SUB_MIX[1] + var SUB_MIX2 = SUB_MIX[2] + var SUB_MIX3 = SUB_MIX[3] + + var s0 = M[0] ^ keySchedule[0] + var s1 = M[1] ^ keySchedule[1] + var s2 = M[2] ^ keySchedule[2] + var s3 = M[3] ^ keySchedule[3] + var t0, t1, t2, t3 + var ksRow = 4 + + for (var round = 1; round < nRounds; round++) { + t0 = SUB_MIX0[s0 >>> 24] ^ SUB_MIX1[(s1 >>> 16) & 0xff] ^ SUB_MIX2[(s2 >>> 8) & 0xff] ^ SUB_MIX3[s3 & 0xff] ^ keySchedule[ksRow++] + t1 = SUB_MIX0[s1 >>> 24] ^ SUB_MIX1[(s2 >>> 16) & 0xff] ^ SUB_MIX2[(s3 >>> 8) & 0xff] ^ SUB_MIX3[s0 & 0xff] ^ keySchedule[ksRow++] + t2 = SUB_MIX0[s2 >>> 24] ^ SUB_MIX1[(s3 >>> 16) & 0xff] ^ SUB_MIX2[(s0 >>> 8) & 0xff] ^ SUB_MIX3[s1 & 0xff] ^ keySchedule[ksRow++] + t3 = SUB_MIX0[s3 >>> 24] ^ SUB_MIX1[(s0 >>> 16) & 0xff] ^ SUB_MIX2[(s1 >>> 8) & 0xff] ^ SUB_MIX3[s2 & 0xff] ^ keySchedule[ksRow++] + s0 = t0 + s1 = t1 + s2 = t2 + s3 = t3 + } + + t0 = ((SBOX[s0 >>> 24] << 24) | (SBOX[(s1 >>> 16) & 0xff] << 16) | (SBOX[(s2 >>> 8) & 0xff] << 8) | SBOX[s3 & 0xff]) ^ keySchedule[ksRow++] + t1 = ((SBOX[s1 >>> 24] << 24) | (SBOX[(s2 >>> 16) & 0xff] << 16) | (SBOX[(s3 >>> 8) & 0xff] << 8) | SBOX[s0 & 0xff]) ^ keySchedule[ksRow++] + t2 = ((SBOX[s2 >>> 24] << 24) | (SBOX[(s3 >>> 16) & 0xff] << 16) | (SBOX[(s0 >>> 8) & 0xff] << 8) | SBOX[s1 & 0xff]) ^ keySchedule[ksRow++] + t3 = ((SBOX[s3 >>> 24] << 24) | (SBOX[(s0 >>> 16) & 0xff] << 16) | (SBOX[(s1 >>> 8) & 0xff] << 8) | SBOX[s2 & 0xff]) ^ keySchedule[ksRow++] + t0 = t0 >>> 0 + t1 = t1 >>> 0 + t2 = t2 >>> 0 + t3 = t3 >>> 0 + + return [t0, t1, t2, t3] +} + +// AES constants +var RCON = [0x00, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36] +var G = (function () { + // Compute double table + var d = new Array(256) + for (var j = 0; j < 256; j++) { + if (j < 128) { + d[j] = j << 1 + } else { + d[j] = (j << 1) ^ 0x11b + } + } + + var SBOX = [] + var INV_SBOX = [] + var SUB_MIX = [[], [], [], []] + var INV_SUB_MIX = [[], [], [], []] + + // Walk GF(2^8) + var x = 0 + var xi = 0 + for (var i = 0; i < 256; ++i) { + // Compute sbox + var sx = xi ^ (xi << 1) ^ (xi << 2) ^ (xi << 3) ^ (xi << 4) + sx = (sx >>> 8) ^ (sx & 0xff) ^ 0x63 + SBOX[x] = sx + INV_SBOX[sx] = x + + // Compute multiplication + var x2 = d[x] + var x4 = d[x2] + var x8 = d[x4] + + // Compute sub bytes, mix columns tables + var t = (d[sx] * 0x101) ^ (sx * 0x1010100) + SUB_MIX[0][x] = (t << 24) | (t >>> 8) + SUB_MIX[1][x] = (t << 16) | (t >>> 16) + SUB_MIX[2][x] = (t << 8) | (t >>> 24) + SUB_MIX[3][x] = t + + // Compute inv sub bytes, inv mix columns tables + t = (x8 * 0x1010101) ^ (x4 * 0x10001) ^ (x2 * 0x101) ^ (x * 0x1010100) + INV_SUB_MIX[0][sx] = (t << 24) | (t >>> 8) + INV_SUB_MIX[1][sx] = (t << 16) | (t >>> 16) + INV_SUB_MIX[2][sx] = (t << 8) | (t >>> 24) + INV_SUB_MIX[3][sx] = t + + if (x === 0) { + x = xi = 1 + } else { + x = x2 ^ d[d[d[x8 ^ x2]]] + xi ^= d[d[xi]] + } + } + + return { + SBOX: SBOX, + INV_SBOX: INV_SBOX, + SUB_MIX: SUB_MIX, + INV_SUB_MIX: INV_SUB_MIX + } +})() + +function AES (key) { + this._key = asUInt32Array(key) + this._reset() +} + +AES.blockSize = 4 * 4 +AES.keySize = 256 / 8 +AES.prototype.blockSize = AES.blockSize +AES.prototype.keySize = AES.keySize +AES.prototype._reset = function () { + var keyWords = this._key + var keySize = keyWords.length + var nRounds = keySize + 6 + var ksRows = (nRounds + 1) * 4 + + var keySchedule = [] + for (var k = 0; k < keySize; k++) { + keySchedule[k] = keyWords[k] + } + + for (k = keySize; k < ksRows; k++) { + var t = keySchedule[k - 1] + + if (k % keySize === 0) { + t = (t << 8) | (t >>> 24) + t = + (G.SBOX[t >>> 24] << 24) | + (G.SBOX[(t >>> 16) & 0xff] << 16) | + (G.SBOX[(t >>> 8) & 0xff] << 8) | + (G.SBOX[t & 0xff]) + + t ^= RCON[(k / keySize) | 0] << 24 + } else if (keySize > 6 && k % keySize === 4) { + t = + (G.SBOX[t >>> 24] << 24) | + (G.SBOX[(t >>> 16) & 0xff] << 16) | + (G.SBOX[(t >>> 8) & 0xff] << 8) | + (G.SBOX[t & 0xff]) + } + + keySchedule[k] = keySchedule[k - keySize] ^ t + } + + var invKeySchedule = [] + for (var ik = 0; ik < ksRows; ik++) { + var ksR = ksRows - ik + var tt = keySchedule[ksR - (ik % 4 ? 0 : 4)] + + if (ik < 4 || ksR <= 4) { + invKeySchedule[ik] = tt + } else { + invKeySchedule[ik] = + G.INV_SUB_MIX[0][G.SBOX[tt >>> 24]] ^ + G.INV_SUB_MIX[1][G.SBOX[(tt >>> 16) & 0xff]] ^ + G.INV_SUB_MIX[2][G.SBOX[(tt >>> 8) & 0xff]] ^ + G.INV_SUB_MIX[3][G.SBOX[tt & 0xff]] + } + } + + this._nRounds = nRounds + this._keySchedule = keySchedule + this._invKeySchedule = invKeySchedule +} + +AES.prototype.encryptBlockRaw = function (M) { + M = asUInt32Array(M) + return cryptBlock(M, this._keySchedule, G.SUB_MIX, G.SBOX, this._nRounds) +} + +AES.prototype.encryptBlock = function (M) { + var out = this.encryptBlockRaw(M) + var buf = Buffer.allocUnsafe(16) + buf.writeUInt32BE(out[0], 0) + buf.writeUInt32BE(out[1], 4) + buf.writeUInt32BE(out[2], 8) + buf.writeUInt32BE(out[3], 12) + return buf +} + +AES.prototype.decryptBlock = function (M) { + M = asUInt32Array(M) + + // swap + var m1 = M[1] + M[1] = M[3] + M[3] = m1 + + var out = cryptBlock(M, this._invKeySchedule, G.INV_SUB_MIX, G.INV_SBOX, this._nRounds) + var buf = Buffer.allocUnsafe(16) + buf.writeUInt32BE(out[0], 0) + buf.writeUInt32BE(out[3], 4) + buf.writeUInt32BE(out[2], 8) + buf.writeUInt32BE(out[1], 12) + return buf +} + +AES.prototype.scrub = function () { + scrubVec(this._keySchedule) + scrubVec(this._invKeySchedule) + scrubVec(this._key) +} + +module.exports.AES = AES + +},{"safe-buffer":179}],22:[function(require,module,exports){ +var aes = require('./aes') +var Buffer = require('safe-buffer').Buffer +var Transform = require('cipher-base') +var inherits = require('inherits') +var GHASH = require('./ghash') +var xor = require('buffer-xor') +var incr32 = require('./incr32') + +function xorTest (a, b) { + var out = 0 + if (a.length !== b.length) out++ + + var len = Math.min(a.length, b.length) + for (var i = 0; i < len; ++i) { + out += (a[i] ^ b[i]) + } + + return out +} + +function calcIv (self, iv, ck) { + if (iv.length === 12) { + self._finID = Buffer.concat([iv, Buffer.from([0, 0, 0, 1])]) + return Buffer.concat([iv, Buffer.from([0, 0, 0, 2])]) + } + var ghash = new GHASH(ck) + var len = iv.length + var toPad = len % 16 + ghash.update(iv) + if (toPad) { + toPad = 16 - toPad + ghash.update(Buffer.alloc(toPad, 0)) + } + ghash.update(Buffer.alloc(8, 0)) + var ivBits = len * 8 + var tail = Buffer.alloc(8) + tail.writeUIntBE(ivBits, 0, 8) + ghash.update(tail) + self._finID = ghash.state + var out = Buffer.from(self._finID) + incr32(out) + return out +} +function StreamCipher (mode, key, iv, decrypt) { + Transform.call(this) + + var h = Buffer.alloc(4, 0) + + this._cipher = new aes.AES(key) + var ck = this._cipher.encryptBlock(h) + this._ghash = new GHASH(ck) + iv = calcIv(this, iv, ck) + + this._prev = Buffer.from(iv) + this._cache = Buffer.allocUnsafe(0) + this._secCache = Buffer.allocUnsafe(0) + this._decrypt = decrypt + this._alen = 0 + this._len = 0 + this._mode = mode + + this._authTag = null + this._called = false +} + +inherits(StreamCipher, Transform) + +StreamCipher.prototype._update = function (chunk) { + if (!this._called && this._alen) { + var rump = 16 - (this._alen % 16) + if (rump < 16) { + rump = Buffer.alloc(rump, 0) + this._ghash.update(rump) + } + } + + this._called = true + var out = this._mode.encrypt(this, chunk) + if (this._decrypt) { + this._ghash.update(chunk) + } else { + this._ghash.update(out) + } + this._len += chunk.length + return out +} + +StreamCipher.prototype._final = function () { + if (this._decrypt && !this._authTag) throw new Error('Unsupported state or unable to authenticate data') + + var tag = xor(this._ghash.final(this._alen * 8, this._len * 8), this._cipher.encryptBlock(this._finID)) + if (this._decrypt && xorTest(tag, this._authTag)) throw new Error('Unsupported state or unable to authenticate data') + + this._authTag = tag + this._cipher.scrub() +} + +StreamCipher.prototype.getAuthTag = function getAuthTag () { + if (this._decrypt || !Buffer.isBuffer(this._authTag)) throw new Error('Attempting to get auth tag in unsupported state') + + return this._authTag +} + +StreamCipher.prototype.setAuthTag = function setAuthTag (tag) { + if (!this._decrypt) throw new Error('Attempting to set auth tag in unsupported state') + + this._authTag = tag +} + +StreamCipher.prototype.setAAD = function setAAD (buf) { + if (this._called) throw new Error('Attempting to set AAD in unsupported state') + + this._ghash.update(buf) + this._alen += buf.length +} + +module.exports = StreamCipher + +},{"./aes":21,"./ghash":26,"./incr32":27,"buffer-xor":63,"cipher-base":67,"inherits":143,"safe-buffer":179}],23:[function(require,module,exports){ +var ciphers = require('./encrypter') +var deciphers = require('./decrypter') +var modes = require('./modes/list.json') + +function getCiphers () { + return Object.keys(modes) +} + +exports.createCipher = exports.Cipher = ciphers.createCipher +exports.createCipheriv = exports.Cipheriv = ciphers.createCipheriv +exports.createDecipher = exports.Decipher = deciphers.createDecipher +exports.createDecipheriv = exports.Decipheriv = deciphers.createDecipheriv +exports.listCiphers = exports.getCiphers = getCiphers + +},{"./decrypter":24,"./encrypter":25,"./modes/list.json":35}],24:[function(require,module,exports){ +var AuthCipher = require('./authCipher') +var Buffer = require('safe-buffer').Buffer +var MODES = require('./modes') +var StreamCipher = require('./streamCipher') +var Transform = require('cipher-base') +var aes = require('./aes') +var ebtk = require('evp_bytestokey') +var inherits = require('inherits') + +function Decipher (mode, key, iv) { + Transform.call(this) + + this._cache = new Splitter() + this._last = void 0 + this._cipher = new aes.AES(key) + this._prev = Buffer.from(iv) + this._mode = mode + this._autopadding = true +} + +inherits(Decipher, Transform) + +Decipher.prototype._update = function (data) { + this._cache.add(data) + var chunk + var thing + var out = [] + while ((chunk = this._cache.get(this._autopadding))) { + thing = this._mode.decrypt(this, chunk) + out.push(thing) + } + return Buffer.concat(out) +} + +Decipher.prototype._final = function () { + var chunk = this._cache.flush() + if (this._autopadding) { + return unpad(this._mode.decrypt(this, chunk)) + } else if (chunk) { + throw new Error('data not multiple of block length') + } +} + +Decipher.prototype.setAutoPadding = function (setTo) { + this._autopadding = !!setTo + return this +} + +function Splitter () { + this.cache = Buffer.allocUnsafe(0) +} + +Splitter.prototype.add = function (data) { + this.cache = Buffer.concat([this.cache, data]) +} + +Splitter.prototype.get = function (autoPadding) { + var out + if (autoPadding) { + if (this.cache.length > 16) { + out = this.cache.slice(0, 16) + this.cache = this.cache.slice(16) + return out + } + } else { + if (this.cache.length >= 16) { + out = this.cache.slice(0, 16) + this.cache = this.cache.slice(16) + return out + } + } + + return null +} + +Splitter.prototype.flush = function () { + if (this.cache.length) return this.cache +} + +function unpad (last) { + var padded = last[15] + if (padded < 1 || padded > 16) { + throw new Error('unable to decrypt data') + } + var i = -1 + while (++i < padded) { + if (last[(i + (16 - padded))] !== padded) { + throw new Error('unable to decrypt data') + } + } + if (padded === 16) return + + return last.slice(0, 16 - padded) +} + +function createDecipheriv (suite, password, iv) { + var config = MODES[suite.toLowerCase()] + if (!config) throw new TypeError('invalid suite type') + + if (typeof iv === 'string') iv = Buffer.from(iv) + if (config.mode !== 'GCM' && iv.length !== config.iv) throw new TypeError('invalid iv length ' + iv.length) + + if (typeof password === 'string') password = Buffer.from(password) + if (password.length !== config.key / 8) throw new TypeError('invalid key length ' + password.length) + + if (config.type === 'stream') { + return new StreamCipher(config.module, password, iv, true) + } else if (config.type === 'auth') { + return new AuthCipher(config.module, password, iv, true) + } + + return new Decipher(config.module, password, iv) +} + +function createDecipher (suite, password) { + var config = MODES[suite.toLowerCase()] + if (!config) throw new TypeError('invalid suite type') + + var keys = ebtk(password, false, config.key, config.iv) + return createDecipheriv(suite, keys.key, keys.iv) +} + +exports.createDecipher = createDecipher +exports.createDecipheriv = createDecipheriv + +},{"./aes":21,"./authCipher":22,"./modes":34,"./streamCipher":37,"cipher-base":67,"evp_bytestokey":105,"inherits":143,"safe-buffer":179}],25:[function(require,module,exports){ +var MODES = require('./modes') +var AuthCipher = require('./authCipher') +var Buffer = require('safe-buffer').Buffer +var StreamCipher = require('./streamCipher') +var Transform = require('cipher-base') +var aes = require('./aes') +var ebtk = require('evp_bytestokey') +var inherits = require('inherits') + +function Cipher (mode, key, iv) { + Transform.call(this) + + this._cache = new Splitter() + this._cipher = new aes.AES(key) + this._prev = Buffer.from(iv) + this._mode = mode + this._autopadding = true +} + +inherits(Cipher, Transform) + +Cipher.prototype._update = function (data) { + this._cache.add(data) + var chunk + var thing + var out = [] + + while ((chunk = this._cache.get())) { + thing = this._mode.encrypt(this, chunk) + out.push(thing) + } + + return Buffer.concat(out) +} + +var PADDING = Buffer.alloc(16, 0x10) + +Cipher.prototype._final = function () { + var chunk = this._cache.flush() + if (this._autopadding) { + chunk = this._mode.encrypt(this, chunk) + this._cipher.scrub() + return chunk + } + + if (!chunk.equals(PADDING)) { + this._cipher.scrub() + throw new Error('data not multiple of block length') + } +} + +Cipher.prototype.setAutoPadding = function (setTo) { + this._autopadding = !!setTo + return this +} + +function Splitter () { + this.cache = Buffer.allocUnsafe(0) +} + +Splitter.prototype.add = function (data) { + this.cache = Buffer.concat([this.cache, data]) +} + +Splitter.prototype.get = function () { + if (this.cache.length > 15) { + var out = this.cache.slice(0, 16) + this.cache = this.cache.slice(16) + return out + } + return null +} + +Splitter.prototype.flush = function () { + var len = 16 - this.cache.length + var padBuff = Buffer.allocUnsafe(len) + + var i = -1 + while (++i < len) { + padBuff.writeUInt8(len, i) + } + + return Buffer.concat([this.cache, padBuff]) +} + +function createCipheriv (suite, password, iv) { + var config = MODES[suite.toLowerCase()] + if (!config) throw new TypeError('invalid suite type') + + if (typeof password === 'string') password = Buffer.from(password) + if (password.length !== config.key / 8) throw new TypeError('invalid key length ' + password.length) + + if (typeof iv === 'string') iv = Buffer.from(iv) + if (config.mode !== 'GCM' && iv.length !== config.iv) throw new TypeError('invalid iv length ' + iv.length) + + if (config.type === 'stream') { + return new StreamCipher(config.module, password, iv) + } else if (config.type === 'auth') { + return new AuthCipher(config.module, password, iv) + } + + return new Cipher(config.module, password, iv) +} + +function createCipher (suite, password) { + var config = MODES[suite.toLowerCase()] + if (!config) throw new TypeError('invalid suite type') + + var keys = ebtk(password, false, config.key, config.iv) + return createCipheriv(suite, keys.key, keys.iv) +} + +exports.createCipheriv = createCipheriv +exports.createCipher = createCipher + +},{"./aes":21,"./authCipher":22,"./modes":34,"./streamCipher":37,"cipher-base":67,"evp_bytestokey":105,"inherits":143,"safe-buffer":179}],26:[function(require,module,exports){ +var Buffer = require('safe-buffer').Buffer +var ZEROES = Buffer.alloc(16, 0) + +function toArray (buf) { + return [ + buf.readUInt32BE(0), + buf.readUInt32BE(4), + buf.readUInt32BE(8), + buf.readUInt32BE(12) + ] +} + +function fromArray (out) { + var buf = Buffer.allocUnsafe(16) + buf.writeUInt32BE(out[0] >>> 0, 0) + buf.writeUInt32BE(out[1] >>> 0, 4) + buf.writeUInt32BE(out[2] >>> 0, 8) + buf.writeUInt32BE(out[3] >>> 0, 12) + return buf +} + +function GHASH (key) { + this.h = key + this.state = Buffer.alloc(16, 0) + this.cache = Buffer.allocUnsafe(0) +} + +// from http://bitwiseshiftleft.github.io/sjcl/doc/symbols/src/core_gcm.js.html +// by Juho Vähä-Herttua +GHASH.prototype.ghash = function (block) { + var i = -1 + while (++i < block.length) { + this.state[i] ^= block[i] + } + this._multiply() +} + +GHASH.prototype._multiply = function () { + var Vi = toArray(this.h) + var Zi = [0, 0, 0, 0] + var j, xi, lsbVi + var i = -1 + while (++i < 128) { + xi = (this.state[~~(i / 8)] & (1 << (7 - (i % 8)))) !== 0 + if (xi) { + // Z_i+1 = Z_i ^ V_i + Zi[0] ^= Vi[0] + Zi[1] ^= Vi[1] + Zi[2] ^= Vi[2] + Zi[3] ^= Vi[3] + } + + // Store the value of LSB(V_i) + lsbVi = (Vi[3] & 1) !== 0 + + // V_i+1 = V_i >> 1 + for (j = 3; j > 0; j--) { + Vi[j] = (Vi[j] >>> 1) | ((Vi[j - 1] & 1) << 31) + } + Vi[0] = Vi[0] >>> 1 + + // If LSB(V_i) is 1, V_i+1 = (V_i >> 1) ^ R + if (lsbVi) { + Vi[0] = Vi[0] ^ (0xe1 << 24) + } + } + this.state = fromArray(Zi) +} + +GHASH.prototype.update = function (buf) { + this.cache = Buffer.concat([this.cache, buf]) + var chunk + while (this.cache.length >= 16) { + chunk = this.cache.slice(0, 16) + this.cache = this.cache.slice(16) + this.ghash(chunk) + } +} + +GHASH.prototype.final = function (abl, bl) { + if (this.cache.length) { + this.ghash(Buffer.concat([this.cache, ZEROES], 16)) + } + + this.ghash(fromArray([0, abl, 0, bl])) + return this.state +} + +module.exports = GHASH + +},{"safe-buffer":179}],27:[function(require,module,exports){ +function incr32 (iv) { + var len = iv.length + var item + while (len--) { + item = iv.readUInt8(len) + if (item === 255) { + iv.writeUInt8(0, len) + } else { + item++ + iv.writeUInt8(item, len) + break + } + } +} +module.exports = incr32 + +},{}],28:[function(require,module,exports){ +var xor = require('buffer-xor') + +exports.encrypt = function (self, block) { + var data = xor(block, self._prev) + + self._prev = self._cipher.encryptBlock(data) + return self._prev +} + +exports.decrypt = function (self, block) { + var pad = self._prev + + self._prev = block + var out = self._cipher.decryptBlock(block) + + return xor(out, pad) +} + +},{"buffer-xor":63}],29:[function(require,module,exports){ +var Buffer = require('safe-buffer').Buffer +var xor = require('buffer-xor') + +function encryptStart (self, data, decrypt) { + var len = data.length + var out = xor(data, self._cache) + self._cache = self._cache.slice(len) + self._prev = Buffer.concat([self._prev, decrypt ? data : out]) + return out +} + +exports.encrypt = function (self, data, decrypt) { + var out = Buffer.allocUnsafe(0) + var len + + while (data.length) { + if (self._cache.length === 0) { + self._cache = self._cipher.encryptBlock(self._prev) + self._prev = Buffer.allocUnsafe(0) + } + + if (self._cache.length <= data.length) { + len = self._cache.length + out = Buffer.concat([out, encryptStart(self, data.slice(0, len), decrypt)]) + data = data.slice(len) + } else { + out = Buffer.concat([out, encryptStart(self, data, decrypt)]) + break + } + } + + return out +} + +},{"buffer-xor":63,"safe-buffer":179}],30:[function(require,module,exports){ +var Buffer = require('safe-buffer').Buffer + +function encryptByte (self, byteParam, decrypt) { + var pad + var i = -1 + var len = 8 + var out = 0 + var bit, value + while (++i < len) { + pad = self._cipher.encryptBlock(self._prev) + bit = (byteParam & (1 << (7 - i))) ? 0x80 : 0 + value = pad[0] ^ bit + out += ((value & 0x80) >> (i % 8)) + self._prev = shiftIn(self._prev, decrypt ? bit : value) + } + return out +} + +function shiftIn (buffer, value) { + var len = buffer.length + var i = -1 + var out = Buffer.allocUnsafe(buffer.length) + buffer = Buffer.concat([buffer, Buffer.from([value])]) + + while (++i < len) { + out[i] = buffer[i] << 1 | buffer[i + 1] >> (7) + } + + return out +} + +exports.encrypt = function (self, chunk, decrypt) { + var len = chunk.length + var out = Buffer.allocUnsafe(len) + var i = -1 + + while (++i < len) { + out[i] = encryptByte(self, chunk[i], decrypt) + } + + return out +} + +},{"safe-buffer":179}],31:[function(require,module,exports){ +var Buffer = require('safe-buffer').Buffer + +function encryptByte (self, byteParam, decrypt) { + var pad = self._cipher.encryptBlock(self._prev) + var out = pad[0] ^ byteParam + + self._prev = Buffer.concat([ + self._prev.slice(1), + Buffer.from([decrypt ? byteParam : out]) + ]) + + return out +} + +exports.encrypt = function (self, chunk, decrypt) { + var len = chunk.length + var out = Buffer.allocUnsafe(len) + var i = -1 + + while (++i < len) { + out[i] = encryptByte(self, chunk[i], decrypt) + } + + return out +} + +},{"safe-buffer":179}],32:[function(require,module,exports){ +var xor = require('buffer-xor') +var Buffer = require('safe-buffer').Buffer +var incr32 = require('../incr32') + +function getBlock (self) { + var out = self._cipher.encryptBlockRaw(self._prev) + incr32(self._prev) + return out +} + +var blockSize = 16 +exports.encrypt = function (self, chunk) { + var chunkNum = Math.ceil(chunk.length / blockSize) + var start = self._cache.length + self._cache = Buffer.concat([ + self._cache, + Buffer.allocUnsafe(chunkNum * blockSize) + ]) + for (var i = 0; i < chunkNum; i++) { + var out = getBlock(self) + var offset = start + i * blockSize + self._cache.writeUInt32BE(out[0], offset + 0) + self._cache.writeUInt32BE(out[1], offset + 4) + self._cache.writeUInt32BE(out[2], offset + 8) + self._cache.writeUInt32BE(out[3], offset + 12) + } + var pad = self._cache.slice(0, chunk.length) + self._cache = self._cache.slice(chunk.length) + return xor(chunk, pad) +} + +},{"../incr32":27,"buffer-xor":63,"safe-buffer":179}],33:[function(require,module,exports){ +exports.encrypt = function (self, block) { + return self._cipher.encryptBlock(block) +} + +exports.decrypt = function (self, block) { + return self._cipher.decryptBlock(block) +} + +},{}],34:[function(require,module,exports){ +var modeModules = { + ECB: require('./ecb'), + CBC: require('./cbc'), + CFB: require('./cfb'), + CFB8: require('./cfb8'), + CFB1: require('./cfb1'), + OFB: require('./ofb'), + CTR: require('./ctr'), + GCM: require('./ctr') +} + +var modes = require('./list.json') + +for (var key in modes) { + modes[key].module = modeModules[modes[key].mode] +} + +module.exports = modes + +},{"./cbc":28,"./cfb":29,"./cfb1":30,"./cfb8":31,"./ctr":32,"./ecb":33,"./list.json":35,"./ofb":36}],35:[function(require,module,exports){ +module.exports={ + "aes-128-ecb": { + "cipher": "AES", + "key": 128, + "iv": 0, + "mode": "ECB", + "type": "block" + }, + "aes-192-ecb": { + "cipher": "AES", + "key": 192, + "iv": 0, + "mode": "ECB", + "type": "block" + }, + "aes-256-ecb": { + "cipher": "AES", + "key": 256, + "iv": 0, + "mode": "ECB", + "type": "block" + }, + "aes-128-cbc": { + "cipher": "AES", + "key": 128, + "iv": 16, + "mode": "CBC", + "type": "block" + }, + "aes-192-cbc": { + "cipher": "AES", + "key": 192, + "iv": 16, + "mode": "CBC", + "type": "block" + }, + "aes-256-cbc": { + "cipher": "AES", + "key": 256, + "iv": 16, + "mode": "CBC", + "type": "block" + }, + "aes128": { + "cipher": "AES", + "key": 128, + "iv": 16, + "mode": "CBC", + "type": "block" + }, + "aes192": { + "cipher": "AES", + "key": 192, + "iv": 16, + "mode": "CBC", + "type": "block" + }, + "aes256": { + "cipher": "AES", + "key": 256, + "iv": 16, + "mode": "CBC", + "type": "block" + }, + "aes-128-cfb": { + "cipher": "AES", + "key": 128, + "iv": 16, + "mode": "CFB", + "type": "stream" + }, + "aes-192-cfb": { + "cipher": "AES", + "key": 192, + "iv": 16, + "mode": "CFB", + "type": "stream" + }, + "aes-256-cfb": { + "cipher": "AES", + "key": 256, + "iv": 16, + "mode": "CFB", + "type": "stream" + }, + "aes-128-cfb8": { + "cipher": "AES", + "key": 128, + "iv": 16, + "mode": "CFB8", + "type": "stream" + }, + "aes-192-cfb8": { + "cipher": "AES", + "key": 192, + "iv": 16, + "mode": "CFB8", + "type": "stream" + }, + "aes-256-cfb8": { + "cipher": "AES", + "key": 256, + "iv": 16, + "mode": "CFB8", + "type": "stream" + }, + "aes-128-cfb1": { + "cipher": "AES", + "key": 128, + "iv": 16, + "mode": "CFB1", + "type": "stream" + }, + "aes-192-cfb1": { + "cipher": "AES", + "key": 192, + "iv": 16, + "mode": "CFB1", + "type": "stream" + }, + "aes-256-cfb1": { + "cipher": "AES", + "key": 256, + "iv": 16, + "mode": "CFB1", + "type": "stream" + }, + "aes-128-ofb": { + "cipher": "AES", + "key": 128, + "iv": 16, + "mode": "OFB", + "type": "stream" + }, + "aes-192-ofb": { + "cipher": "AES", + "key": 192, + "iv": 16, + "mode": "OFB", + "type": "stream" + }, + "aes-256-ofb": { + "cipher": "AES", + "key": 256, + "iv": 16, + "mode": "OFB", + "type": "stream" + }, + "aes-128-ctr": { + "cipher": "AES", + "key": 128, + "iv": 16, + "mode": "CTR", + "type": "stream" + }, + "aes-192-ctr": { + "cipher": "AES", + "key": 192, + "iv": 16, + "mode": "CTR", + "type": "stream" + }, + "aes-256-ctr": { + "cipher": "AES", + "key": 256, + "iv": 16, + "mode": "CTR", + "type": "stream" + }, + "aes-128-gcm": { + "cipher": "AES", + "key": 128, + "iv": 12, + "mode": "GCM", + "type": "auth" + }, + "aes-192-gcm": { + "cipher": "AES", + "key": 192, + "iv": 12, + "mode": "GCM", + "type": "auth" + }, + "aes-256-gcm": { + "cipher": "AES", + "key": 256, + "iv": 12, + "mode": "GCM", + "type": "auth" + } +} + +},{}],36:[function(require,module,exports){ +(function (Buffer){(function (){ +var xor = require('buffer-xor') + +function getBlock (self) { + self._prev = self._cipher.encryptBlock(self._prev) + return self._prev +} + +exports.encrypt = function (self, chunk) { + while (self._cache.length < chunk.length) { + self._cache = Buffer.concat([self._cache, getBlock(self)]) + } + + var pad = self._cache.slice(0, chunk.length) + self._cache = self._cache.slice(chunk.length) + return xor(chunk, pad) +} + +}).call(this)}).call(this,require("buffer").Buffer) +},{"buffer":64,"buffer-xor":63}],37:[function(require,module,exports){ +var aes = require('./aes') +var Buffer = require('safe-buffer').Buffer +var Transform = require('cipher-base') +var inherits = require('inherits') + +function StreamCipher (mode, key, iv, decrypt) { + Transform.call(this) + + this._cipher = new aes.AES(key) + this._prev = Buffer.from(iv) + this._cache = Buffer.allocUnsafe(0) + this._secCache = Buffer.allocUnsafe(0) + this._decrypt = decrypt + this._mode = mode +} + +inherits(StreamCipher, Transform) + +StreamCipher.prototype._update = function (chunk) { + return this._mode.encrypt(this, chunk, this._decrypt) +} + +StreamCipher.prototype._final = function () { + this._cipher.scrub() +} + +module.exports = StreamCipher + +},{"./aes":21,"cipher-base":67,"inherits":143,"safe-buffer":179}],38:[function(require,module,exports){ +var DES = require('browserify-des') +var aes = require('browserify-aes/browser') +var aesModes = require('browserify-aes/modes') +var desModes = require('browserify-des/modes') +var ebtk = require('evp_bytestokey') + +function createCipher (suite, password) { + suite = suite.toLowerCase() + + var keyLen, ivLen + if (aesModes[suite]) { + keyLen = aesModes[suite].key + ivLen = aesModes[suite].iv + } else if (desModes[suite]) { + keyLen = desModes[suite].key * 8 + ivLen = desModes[suite].iv + } else { + throw new TypeError('invalid suite type') + } + + var keys = ebtk(password, false, keyLen, ivLen) + return createCipheriv(suite, keys.key, keys.iv) +} + +function createDecipher (suite, password) { + suite = suite.toLowerCase() + + var keyLen, ivLen + if (aesModes[suite]) { + keyLen = aesModes[suite].key + ivLen = aesModes[suite].iv + } else if (desModes[suite]) { + keyLen = desModes[suite].key * 8 + ivLen = desModes[suite].iv + } else { + throw new TypeError('invalid suite type') + } + + var keys = ebtk(password, false, keyLen, ivLen) + return createDecipheriv(suite, keys.key, keys.iv) +} + +function createCipheriv (suite, key, iv) { + suite = suite.toLowerCase() + if (aesModes[suite]) return aes.createCipheriv(suite, key, iv) + if (desModes[suite]) return new DES({ key: key, iv: iv, mode: suite }) + + throw new TypeError('invalid suite type') +} + +function createDecipheriv (suite, key, iv) { + suite = suite.toLowerCase() + if (aesModes[suite]) return aes.createDecipheriv(suite, key, iv) + if (desModes[suite]) return new DES({ key: key, iv: iv, mode: suite, decrypt: true }) + + throw new TypeError('invalid suite type') +} + +function getCiphers () { + return Object.keys(desModes).concat(aes.getCiphers()) +} + +exports.createCipher = exports.Cipher = createCipher +exports.createCipheriv = exports.Cipheriv = createCipheriv +exports.createDecipher = exports.Decipher = createDecipher +exports.createDecipheriv = exports.Decipheriv = createDecipheriv +exports.listCiphers = exports.getCiphers = getCiphers + +},{"browserify-aes/browser":23,"browserify-aes/modes":34,"browserify-des":39,"browserify-des/modes":40,"evp_bytestokey":105}],39:[function(require,module,exports){ +var CipherBase = require('cipher-base') +var des = require('des.js') +var inherits = require('inherits') +var Buffer = require('safe-buffer').Buffer + +var modes = { + 'des-ede3-cbc': des.CBC.instantiate(des.EDE), + 'des-ede3': des.EDE, + 'des-ede-cbc': des.CBC.instantiate(des.EDE), + 'des-ede': des.EDE, + 'des-cbc': des.CBC.instantiate(des.DES), + 'des-ecb': des.DES +} +modes.des = modes['des-cbc'] +modes.des3 = modes['des-ede3-cbc'] +module.exports = DES +inherits(DES, CipherBase) +function DES (opts) { + CipherBase.call(this) + var modeName = opts.mode.toLowerCase() + var mode = modes[modeName] + var type + if (opts.decrypt) { + type = 'decrypt' + } else { + type = 'encrypt' + } + var key = opts.key + if (!Buffer.isBuffer(key)) { + key = Buffer.from(key) + } + if (modeName === 'des-ede' || modeName === 'des-ede-cbc') { + key = Buffer.concat([key, key.slice(0, 8)]) + } + var iv = opts.iv + if (!Buffer.isBuffer(iv)) { + iv = Buffer.from(iv) + } + this._des = mode.create({ + key: key, + iv: iv, + type: type + }) +} +DES.prototype._update = function (data) { + return Buffer.from(this._des.update(data)) +} +DES.prototype._final = function () { + return Buffer.from(this._des.final()) +} + +},{"cipher-base":67,"des.js":75,"inherits":143,"safe-buffer":179}],40:[function(require,module,exports){ +exports['des-ecb'] = { + key: 8, + iv: 0 +} +exports['des-cbc'] = exports.des = { + key: 8, + iv: 8 +} +exports['des-ede3-cbc'] = exports.des3 = { + key: 24, + iv: 8 +} +exports['des-ede3'] = { + key: 24, + iv: 0 +} +exports['des-ede-cbc'] = { + key: 16, + iv: 8 +} +exports['des-ede'] = { + key: 16, + iv: 0 +} + +},{}],41:[function(require,module,exports){ +(function (Buffer){(function (){ +var BN = require('bn.js') +var randomBytes = require('randombytes') + +function blind (priv) { + var r = getr(priv) + var blinder = r.toRed(BN.mont(priv.modulus)).redPow(new BN(priv.publicExponent)).fromRed() + return { blinder: blinder, unblinder: r.invm(priv.modulus) } +} + +function getr (priv) { + var len = priv.modulus.byteLength() + var r + do { + r = new BN(randomBytes(len)) + } while (r.cmp(priv.modulus) >= 0 || !r.umod(priv.prime1) || !r.umod(priv.prime2)) + return r +} + +function crt (msg, priv) { + var blinds = blind(priv) + var len = priv.modulus.byteLength() + var blinded = new BN(msg).mul(blinds.blinder).umod(priv.modulus) + var c1 = blinded.toRed(BN.mont(priv.prime1)) + var c2 = blinded.toRed(BN.mont(priv.prime2)) + var qinv = priv.coefficient + var p = priv.prime1 + var q = priv.prime2 + var m1 = c1.redPow(priv.exponent1).fromRed() + var m2 = c2.redPow(priv.exponent2).fromRed() + var h = m1.isub(m2).imul(qinv).umod(p).imul(q) + return m2.iadd(h).imul(blinds.unblinder).umod(priv.modulus).toArrayLike(Buffer, 'be', len) +} +crt.getr = getr + +module.exports = crt + +}).call(this)}).call(this,require("buffer").Buffer) +},{"bn.js":18,"buffer":64,"randombytes":176}],42:[function(require,module,exports){ +module.exports = require('./browser/algorithms.json') + +},{"./browser/algorithms.json":43}],43:[function(require,module,exports){ +module.exports={ + "sha224WithRSAEncryption": { + "sign": "rsa", + "hash": "sha224", + "id": "302d300d06096086480165030402040500041c" + }, + "RSA-SHA224": { + "sign": "ecdsa/rsa", + "hash": "sha224", + "id": "302d300d06096086480165030402040500041c" + }, + "sha256WithRSAEncryption": { + "sign": "rsa", + "hash": "sha256", + "id": "3031300d060960864801650304020105000420" + }, + "RSA-SHA256": { + "sign": "ecdsa/rsa", + "hash": "sha256", + "id": "3031300d060960864801650304020105000420" + }, + "sha384WithRSAEncryption": { + "sign": "rsa", + "hash": "sha384", + "id": "3041300d060960864801650304020205000430" + }, + "RSA-SHA384": { + "sign": "ecdsa/rsa", + "hash": "sha384", + "id": "3041300d060960864801650304020205000430" + }, + "sha512WithRSAEncryption": { + "sign": "rsa", + "hash": "sha512", + "id": "3051300d060960864801650304020305000440" + }, + "RSA-SHA512": { + "sign": "ecdsa/rsa", + "hash": "sha512", + "id": "3051300d060960864801650304020305000440" + }, + "RSA-SHA1": { + "sign": "rsa", + "hash": "sha1", + "id": "3021300906052b0e03021a05000414" + }, + "ecdsa-with-SHA1": { + "sign": "ecdsa", + "hash": "sha1", + "id": "" + }, + "sha256": { + "sign": "ecdsa", + "hash": "sha256", + "id": "" + }, + "sha224": { + "sign": "ecdsa", + "hash": "sha224", + "id": "" + }, + "sha384": { + "sign": "ecdsa", + "hash": "sha384", + "id": "" + }, + "sha512": { + "sign": "ecdsa", + "hash": "sha512", + "id": "" + }, + "DSA-SHA": { + "sign": "dsa", + "hash": "sha1", + "id": "" + }, + "DSA-SHA1": { + "sign": "dsa", + "hash": "sha1", + "id": "" + }, + "DSA": { + "sign": "dsa", + "hash": "sha1", + "id": "" + }, + "DSA-WITH-SHA224": { + "sign": "dsa", + "hash": "sha224", + "id": "" + }, + "DSA-SHA224": { + "sign": "dsa", + "hash": "sha224", + "id": "" + }, + "DSA-WITH-SHA256": { + "sign": "dsa", + "hash": "sha256", + "id": "" + }, + "DSA-SHA256": { + "sign": "dsa", + "hash": "sha256", + "id": "" + }, + "DSA-WITH-SHA384": { + "sign": "dsa", + "hash": "sha384", + "id": "" + }, + "DSA-SHA384": { + "sign": "dsa", + "hash": "sha384", + "id": "" + }, + "DSA-WITH-SHA512": { + "sign": "dsa", + "hash": "sha512", + "id": "" + }, + "DSA-SHA512": { + "sign": "dsa", + "hash": "sha512", + "id": "" + }, + "DSA-RIPEMD160": { + "sign": "dsa", + "hash": "rmd160", + "id": "" + }, + "ripemd160WithRSA": { + "sign": "rsa", + "hash": "rmd160", + "id": "3021300906052b2403020105000414" + }, + "RSA-RIPEMD160": { + "sign": "rsa", + "hash": "rmd160", + "id": "3021300906052b2403020105000414" + }, + "md5WithRSAEncryption": { + "sign": "rsa", + "hash": "md5", + "id": "3020300c06082a864886f70d020505000410" + }, + "RSA-MD5": { + "sign": "rsa", + "hash": "md5", + "id": "3020300c06082a864886f70d020505000410" + } +} + +},{}],44:[function(require,module,exports){ +module.exports={ + "1.3.132.0.10": "secp256k1", + "1.3.132.0.33": "p224", + "1.2.840.10045.3.1.1": "p192", + "1.2.840.10045.3.1.7": "p256", + "1.3.132.0.34": "p384", + "1.3.132.0.35": "p521" +} + +},{}],45:[function(require,module,exports){ +var Buffer = require('safe-buffer').Buffer +var createHash = require('create-hash') +var stream = require('readable-stream') +var inherits = require('inherits') +var sign = require('./sign') +var verify = require('./verify') + +var algorithms = require('./algorithms.json') +Object.keys(algorithms).forEach(function (key) { + algorithms[key].id = Buffer.from(algorithms[key].id, 'hex') + algorithms[key.toLowerCase()] = algorithms[key] +}) + +function Sign (algorithm) { + stream.Writable.call(this) + + var data = algorithms[algorithm] + if (!data) throw new Error('Unknown message digest') + + this._hashType = data.hash + this._hash = createHash(data.hash) + this._tag = data.id + this._signType = data.sign +} +inherits(Sign, stream.Writable) + +Sign.prototype._write = function _write (data, _, done) { + this._hash.update(data) + done() +} + +Sign.prototype.update = function update (data, enc) { + if (typeof data === 'string') data = Buffer.from(data, enc) + + this._hash.update(data) + return this +} + +Sign.prototype.sign = function signMethod (key, enc) { + this.end() + var hash = this._hash.digest() + var sig = sign(hash, key, this._hashType, this._signType, this._tag) + + return enc ? sig.toString(enc) : sig +} + +function Verify (algorithm) { + stream.Writable.call(this) + + var data = algorithms[algorithm] + if (!data) throw new Error('Unknown message digest') + + this._hash = createHash(data.hash) + this._tag = data.id + this._signType = data.sign +} +inherits(Verify, stream.Writable) + +Verify.prototype._write = function _write (data, _, done) { + this._hash.update(data) + done() +} + +Verify.prototype.update = function update (data, enc) { + if (typeof data === 'string') data = Buffer.from(data, enc) + + this._hash.update(data) + return this +} + +Verify.prototype.verify = function verifyMethod (key, sig, enc) { + if (typeof sig === 'string') sig = Buffer.from(sig, enc) + + this.end() + var hash = this._hash.digest() + return verify(sig, hash, key, this._signType, this._tag) +} + +function createSign (algorithm) { + return new Sign(algorithm) +} + +function createVerify (algorithm) { + return new Verify(algorithm) +} + +module.exports = { + Sign: createSign, + Verify: createVerify, + createSign: createSign, + createVerify: createVerify +} + +},{"./algorithms.json":43,"./sign":46,"./verify":47,"create-hash":70,"inherits":143,"readable-stream":62,"safe-buffer":179}],46:[function(require,module,exports){ +// much of this based on https://github.com/indutny/self-signed/blob/gh-pages/lib/rsa.js +var Buffer = require('safe-buffer').Buffer +var createHmac = require('create-hmac') +var crt = require('browserify-rsa') +var EC = require('elliptic').ec +var BN = require('bn.js') +var parseKeys = require('parse-asn1') +var curves = require('./curves.json') + +function sign (hash, key, hashType, signType, tag) { + var priv = parseKeys(key) + if (priv.curve) { + // rsa keys can be interpreted as ecdsa ones in openssl + if (signType !== 'ecdsa' && signType !== 'ecdsa/rsa') throw new Error('wrong private key type') + return ecSign(hash, priv) + } else if (priv.type === 'dsa') { + if (signType !== 'dsa') throw new Error('wrong private key type') + return dsaSign(hash, priv, hashType) + } else { + if (signType !== 'rsa' && signType !== 'ecdsa/rsa') throw new Error('wrong private key type') + } + hash = Buffer.concat([tag, hash]) + var len = priv.modulus.byteLength() + var pad = [0, 1] + while (hash.length + pad.length + 1 < len) pad.push(0xff) + pad.push(0x00) + var i = -1 + while (++i < hash.length) pad.push(hash[i]) + + var out = crt(pad, priv) + return out +} + +function ecSign (hash, priv) { + var curveId = curves[priv.curve.join('.')] + if (!curveId) throw new Error('unknown curve ' + priv.curve.join('.')) + + var curve = new EC(curveId) + var key = curve.keyFromPrivate(priv.privateKey) + var out = key.sign(hash) + + return Buffer.from(out.toDER()) +} + +function dsaSign (hash, priv, algo) { + var x = priv.params.priv_key + var p = priv.params.p + var q = priv.params.q + var g = priv.params.g + var r = new BN(0) + var k + var H = bits2int(hash, q).mod(q) + var s = false + var kv = getKey(x, q, hash, algo) + while (s === false) { + k = makeKey(q, kv, algo) + r = makeR(g, k, p, q) + s = k.invm(q).imul(H.add(x.mul(r))).mod(q) + if (s.cmpn(0) === 0) { + s = false + r = new BN(0) + } + } + return toDER(r, s) +} + +function toDER (r, s) { + r = r.toArray() + s = s.toArray() + + // Pad values + if (r[0] & 0x80) r = [0].concat(r) + if (s[0] & 0x80) s = [0].concat(s) + + var total = r.length + s.length + 4 + var res = [0x30, total, 0x02, r.length] + res = res.concat(r, [0x02, s.length], s) + return Buffer.from(res) +} + +function getKey (x, q, hash, algo) { + x = Buffer.from(x.toArray()) + if (x.length < q.byteLength()) { + var zeros = Buffer.alloc(q.byteLength() - x.length) + x = Buffer.concat([zeros, x]) + } + var hlen = hash.length + var hbits = bits2octets(hash, q) + var v = Buffer.alloc(hlen) + v.fill(1) + var k = Buffer.alloc(hlen) + k = createHmac(algo, k).update(v).update(Buffer.from([0])).update(x).update(hbits).digest() + v = createHmac(algo, k).update(v).digest() + k = createHmac(algo, k).update(v).update(Buffer.from([1])).update(x).update(hbits).digest() + v = createHmac(algo, k).update(v).digest() + return { k: k, v: v } +} + +function bits2int (obits, q) { + var bits = new BN(obits) + var shift = (obits.length << 3) - q.bitLength() + if (shift > 0) bits.ishrn(shift) + return bits +} + +function bits2octets (bits, q) { + bits = bits2int(bits, q) + bits = bits.mod(q) + var out = Buffer.from(bits.toArray()) + if (out.length < q.byteLength()) { + var zeros = Buffer.alloc(q.byteLength() - out.length) + out = Buffer.concat([zeros, out]) + } + return out +} + +function makeKey (q, kv, algo) { + var t + var k + + do { + t = Buffer.alloc(0) + + while (t.length * 8 < q.bitLength()) { + kv.v = createHmac(algo, kv.k).update(kv.v).digest() + t = Buffer.concat([t, kv.v]) + } + + k = bits2int(t, q) + kv.k = createHmac(algo, kv.k).update(kv.v).update(Buffer.from([0])).digest() + kv.v = createHmac(algo, kv.k).update(kv.v).digest() + } while (k.cmp(q) !== -1) + + return k +} + +function makeR (g, k, p, q) { + return g.toRed(BN.mont(p)).redPow(k).fromRed().mod(q) +} + +module.exports = sign +module.exports.getKey = getKey +module.exports.makeKey = makeKey + +},{"./curves.json":44,"bn.js":18,"browserify-rsa":41,"create-hmac":72,"elliptic":86,"parse-asn1":157,"safe-buffer":179}],47:[function(require,module,exports){ +// much of this based on https://github.com/indutny/self-signed/blob/gh-pages/lib/rsa.js +var Buffer = require('safe-buffer').Buffer +var BN = require('bn.js') +var EC = require('elliptic').ec +var parseKeys = require('parse-asn1') +var curves = require('./curves.json') + +function verify (sig, hash, key, signType, tag) { + var pub = parseKeys(key) + if (pub.type === 'ec') { + // rsa keys can be interpreted as ecdsa ones in openssl + if (signType !== 'ecdsa' && signType !== 'ecdsa/rsa') throw new Error('wrong public key type') + return ecVerify(sig, hash, pub) + } else if (pub.type === 'dsa') { + if (signType !== 'dsa') throw new Error('wrong public key type') + return dsaVerify(sig, hash, pub) + } else { + if (signType !== 'rsa' && signType !== 'ecdsa/rsa') throw new Error('wrong public key type') + } + hash = Buffer.concat([tag, hash]) + var len = pub.modulus.byteLength() + var pad = [1] + var padNum = 0 + while (hash.length + pad.length + 2 < len) { + pad.push(0xff) + padNum++ + } + pad.push(0x00) + var i = -1 + while (++i < hash.length) { + pad.push(hash[i]) + } + pad = Buffer.from(pad) + var red = BN.mont(pub.modulus) + sig = new BN(sig).toRed(red) + + sig = sig.redPow(new BN(pub.publicExponent)) + sig = Buffer.from(sig.fromRed().toArray()) + var out = padNum < 8 ? 1 : 0 + len = Math.min(sig.length, pad.length) + if (sig.length !== pad.length) out = 1 + + i = -1 + while (++i < len) out |= sig[i] ^ pad[i] + return out === 0 +} + +function ecVerify (sig, hash, pub) { + var curveId = curves[pub.data.algorithm.curve.join('.')] + if (!curveId) throw new Error('unknown curve ' + pub.data.algorithm.curve.join('.')) + + var curve = new EC(curveId) + var pubkey = pub.data.subjectPrivateKey.data + + return curve.verify(hash, sig, pubkey) +} + +function dsaVerify (sig, hash, pub) { + var p = pub.data.p + var q = pub.data.q + var g = pub.data.g + var y = pub.data.pub_key + var unpacked = parseKeys.signature.decode(sig, 'der') + var s = unpacked.s + var r = unpacked.r + checkValue(s, q) + checkValue(r, q) + var montp = BN.mont(p) + var w = s.invm(q) + var v = g.toRed(montp) + .redPow(new BN(hash).mul(w).mod(q)) + .fromRed() + .mul(y.toRed(montp).redPow(r.mul(w).mod(q)).fromRed()) + .mod(p) + .mod(q) + return v.cmp(r) === 0 +} + +function checkValue (b, q) { + if (b.cmpn(0) <= 0) throw new Error('invalid sig') + if (b.cmp(q) >= q) throw new Error('invalid sig') +} + +module.exports = verify + +},{"./curves.json":44,"bn.js":18,"elliptic":86,"parse-asn1":157,"safe-buffer":179}],48:[function(require,module,exports){ +'use strict'; + +function _inheritsLoose(subClass, superClass) { subClass.prototype = Object.create(superClass.prototype); subClass.prototype.constructor = subClass; subClass.__proto__ = superClass; } + +var codes = {}; + +function createErrorType(code, message, Base) { + if (!Base) { + Base = Error; + } + + function getMessage(arg1, arg2, arg3) { + if (typeof message === 'string') { + return message; + } else { + return message(arg1, arg2, arg3); + } + } + + var NodeError = + /*#__PURE__*/ + function (_Base) { + _inheritsLoose(NodeError, _Base); + + function NodeError(arg1, arg2, arg3) { + return _Base.call(this, getMessage(arg1, arg2, arg3)) || this; + } + + return NodeError; + }(Base); + + NodeError.prototype.name = Base.name; + NodeError.prototype.code = code; + codes[code] = NodeError; +} // https://github.com/nodejs/node/blob/v10.8.0/lib/internal/errors.js + + +function oneOf(expected, thing) { + if (Array.isArray(expected)) { + var len = expected.length; + expected = expected.map(function (i) { + return String(i); + }); + + if (len > 2) { + return "one of ".concat(thing, " ").concat(expected.slice(0, len - 1).join(', '), ", or ") + expected[len - 1]; + } else if (len === 2) { + return "one of ".concat(thing, " ").concat(expected[0], " or ").concat(expected[1]); + } else { + return "of ".concat(thing, " ").concat(expected[0]); + } + } else { + return "of ".concat(thing, " ").concat(String(expected)); + } +} // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/startsWith + + +function startsWith(str, search, pos) { + return str.substr(!pos || pos < 0 ? 0 : +pos, search.length) === search; +} // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/endsWith + + +function endsWith(str, search, this_len) { + if (this_len === undefined || this_len > str.length) { + this_len = str.length; + } + + return str.substring(this_len - search.length, this_len) === search; +} // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/includes + + +function includes(str, search, start) { + if (typeof start !== 'number') { + start = 0; + } + + if (start + search.length > str.length) { + return false; + } else { + return str.indexOf(search, start) !== -1; + } +} + +createErrorType('ERR_INVALID_OPT_VALUE', function (name, value) { + return 'The value "' + value + '" is invalid for option "' + name + '"'; +}, TypeError); +createErrorType('ERR_INVALID_ARG_TYPE', function (name, expected, actual) { + // determiner: 'must be' or 'must not be' + var determiner; + + if (typeof expected === 'string' && startsWith(expected, 'not ')) { + determiner = 'must not be'; + expected = expected.replace(/^not /, ''); + } else { + determiner = 'must be'; + } + + var msg; + + if (endsWith(name, ' argument')) { + // For cases like 'first argument' + msg = "The ".concat(name, " ").concat(determiner, " ").concat(oneOf(expected, 'type')); + } else { + var type = includes(name, '.') ? 'property' : 'argument'; + msg = "The \"".concat(name, "\" ").concat(type, " ").concat(determiner, " ").concat(oneOf(expected, 'type')); + } + + msg += ". Received type ".concat(typeof actual); + return msg; +}, TypeError); +createErrorType('ERR_STREAM_PUSH_AFTER_EOF', 'stream.push() after EOF'); +createErrorType('ERR_METHOD_NOT_IMPLEMENTED', function (name) { + return 'The ' + name + ' method is not implemented'; +}); +createErrorType('ERR_STREAM_PREMATURE_CLOSE', 'Premature close'); +createErrorType('ERR_STREAM_DESTROYED', function (name) { + return 'Cannot call ' + name + ' after a stream was destroyed'; +}); +createErrorType('ERR_MULTIPLE_CALLBACK', 'Callback called multiple times'); +createErrorType('ERR_STREAM_CANNOT_PIPE', 'Cannot pipe, not readable'); +createErrorType('ERR_STREAM_WRITE_AFTER_END', 'write after end'); +createErrorType('ERR_STREAM_NULL_VALUES', 'May not write null values to stream', TypeError); +createErrorType('ERR_UNKNOWN_ENCODING', function (arg) { + return 'Unknown encoding: ' + arg; +}, TypeError); +createErrorType('ERR_STREAM_UNSHIFT_AFTER_END_EVENT', 'stream.unshift() after end event'); +module.exports.codes = codes; + +},{}],49:[function(require,module,exports){ +(function (process){(function (){ +// Copyright Joyent, Inc. and other Node contributors. +// +// 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. +// a duplex stream is just a stream that is both readable and writable. +// Since JS doesn't have multiple prototypal inheritance, this class +// prototypally inherits from Readable, and then parasitically from +// Writable. +'use strict'; +/**/ + +var objectKeys = Object.keys || function (obj) { + var keys = []; + + for (var key in obj) { + keys.push(key); + } + + return keys; +}; +/**/ + + +module.exports = Duplex; + +var Readable = require('./_stream_readable'); + +var Writable = require('./_stream_writable'); + +require('inherits')(Duplex, Readable); + +{ + // Allow the keys array to be GC'ed. + var keys = objectKeys(Writable.prototype); + + for (var v = 0; v < keys.length; v++) { + var method = keys[v]; + if (!Duplex.prototype[method]) Duplex.prototype[method] = Writable.prototype[method]; + } +} + +function Duplex(options) { + if (!(this instanceof Duplex)) return new Duplex(options); + Readable.call(this, options); + Writable.call(this, options); + this.allowHalfOpen = true; + + if (options) { + if (options.readable === false) this.readable = false; + if (options.writable === false) this.writable = false; + + if (options.allowHalfOpen === false) { + this.allowHalfOpen = false; + this.once('end', onend); + } + } +} + +Object.defineProperty(Duplex.prototype, 'writableHighWaterMark', { + // making it explicit this property is not enumerable + // because otherwise some prototype manipulation in + // userland will fail + enumerable: false, + get: function get() { + return this._writableState.highWaterMark; + } +}); +Object.defineProperty(Duplex.prototype, 'writableBuffer', { + // making it explicit this property is not enumerable + // because otherwise some prototype manipulation in + // userland will fail + enumerable: false, + get: function get() { + return this._writableState && this._writableState.getBuffer(); + } +}); +Object.defineProperty(Duplex.prototype, 'writableLength', { + // making it explicit this property is not enumerable + // because otherwise some prototype manipulation in + // userland will fail + enumerable: false, + get: function get() { + return this._writableState.length; + } +}); // the no-half-open enforcer + +function onend() { + // If the writable side ended, then we're ok. + if (this._writableState.ended) return; // no more data can be written. + // But allow more writes to happen in this tick. + + process.nextTick(onEndNT, this); +} + +function onEndNT(self) { + self.end(); +} + +Object.defineProperty(Duplex.prototype, 'destroyed', { + // making it explicit this property is not enumerable + // because otherwise some prototype manipulation in + // userland will fail + enumerable: false, + get: function get() { + if (this._readableState === undefined || this._writableState === undefined) { + return false; + } + + return this._readableState.destroyed && this._writableState.destroyed; + }, + set: function set(value) { + // we ignore the value if the stream + // has not been initialized yet + if (this._readableState === undefined || this._writableState === undefined) { + return; + } // backward compatibility, the user is explicitly + // managing destroyed + + + this._readableState.destroyed = value; + this._writableState.destroyed = value; + } +}); +}).call(this)}).call(this,require('_process')) +},{"./_stream_readable":51,"./_stream_writable":53,"_process":164,"inherits":143}],50:[function(require,module,exports){ +// Copyright Joyent, Inc. and other Node contributors. +// +// 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. +// a passthrough stream. +// basically just the most minimal sort of Transform stream. +// Every written chunk gets output as-is. +'use strict'; + +module.exports = PassThrough; + +var Transform = require('./_stream_transform'); + +require('inherits')(PassThrough, Transform); + +function PassThrough(options) { + if (!(this instanceof PassThrough)) return new PassThrough(options); + Transform.call(this, options); +} + +PassThrough.prototype._transform = function (chunk, encoding, cb) { + cb(null, chunk); +}; +},{"./_stream_transform":52,"inherits":143}],51:[function(require,module,exports){ +(function (process,global){(function (){ +// Copyright Joyent, Inc. and other Node contributors. +// +// 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. +'use strict'; + +module.exports = Readable; +/**/ + +var Duplex; +/**/ + +Readable.ReadableState = ReadableState; +/**/ + +var EE = require('events').EventEmitter; + +var EElistenerCount = function EElistenerCount(emitter, type) { + return emitter.listeners(type).length; +}; +/**/ + +/**/ + + +var Stream = require('./internal/streams/stream'); +/**/ + + +var Buffer = require('buffer').Buffer; + +var OurUint8Array = global.Uint8Array || function () {}; + +function _uint8ArrayToBuffer(chunk) { + return Buffer.from(chunk); +} + +function _isUint8Array(obj) { + return Buffer.isBuffer(obj) || obj instanceof OurUint8Array; +} +/**/ + + +var debugUtil = require('util'); + +var debug; + +if (debugUtil && debugUtil.debuglog) { + debug = debugUtil.debuglog('stream'); +} else { + debug = function debug() {}; +} +/**/ + + +var BufferList = require('./internal/streams/buffer_list'); + +var destroyImpl = require('./internal/streams/destroy'); + +var _require = require('./internal/streams/state'), + getHighWaterMark = _require.getHighWaterMark; + +var _require$codes = require('../errors').codes, + ERR_INVALID_ARG_TYPE = _require$codes.ERR_INVALID_ARG_TYPE, + ERR_STREAM_PUSH_AFTER_EOF = _require$codes.ERR_STREAM_PUSH_AFTER_EOF, + ERR_METHOD_NOT_IMPLEMENTED = _require$codes.ERR_METHOD_NOT_IMPLEMENTED, + ERR_STREAM_UNSHIFT_AFTER_END_EVENT = _require$codes.ERR_STREAM_UNSHIFT_AFTER_END_EVENT; // Lazy loaded to improve the startup performance. + + +var StringDecoder; +var createReadableStreamAsyncIterator; +var from; + +require('inherits')(Readable, Stream); + +var errorOrDestroy = destroyImpl.errorOrDestroy; +var kProxyEvents = ['error', 'close', 'destroy', 'pause', 'resume']; + +function prependListener(emitter, event, fn) { + // Sadly this is not cacheable as some libraries bundle their own + // event emitter implementation with them. + if (typeof emitter.prependListener === 'function') return emitter.prependListener(event, fn); // This is a hack to make sure that our error handler is attached before any + // userland ones. NEVER DO THIS. This is here only because this code needs + // to continue to work with older versions of Node.js that do not include + // the prependListener() method. The goal is to eventually remove this hack. + + if (!emitter._events || !emitter._events[event]) emitter.on(event, fn);else if (Array.isArray(emitter._events[event])) emitter._events[event].unshift(fn);else emitter._events[event] = [fn, emitter._events[event]]; +} + +function ReadableState(options, stream, isDuplex) { + Duplex = Duplex || require('./_stream_duplex'); + options = options || {}; // Duplex streams are both readable and writable, but share + // the same options object. + // However, some cases require setting options to different + // values for the readable and the writable sides of the duplex stream. + // These options can be provided separately as readableXXX and writableXXX. + + if (typeof isDuplex !== 'boolean') isDuplex = stream instanceof Duplex; // object stream flag. Used to make read(n) ignore n and to + // make all the buffer merging and length checks go away + + this.objectMode = !!options.objectMode; + if (isDuplex) this.objectMode = this.objectMode || !!options.readableObjectMode; // the point at which it stops calling _read() to fill the buffer + // Note: 0 is a valid value, means "don't call _read preemptively ever" + + this.highWaterMark = getHighWaterMark(this, options, 'readableHighWaterMark', isDuplex); // A linked list is used to store data chunks instead of an array because the + // linked list can remove elements from the beginning faster than + // array.shift() + + this.buffer = new BufferList(); + this.length = 0; + this.pipes = null; + this.pipesCount = 0; + this.flowing = null; + this.ended = false; + this.endEmitted = false; + this.reading = false; // a flag to be able to tell if the event 'readable'/'data' is emitted + // immediately, or on a later tick. We set this to true at first, because + // any actions that shouldn't happen until "later" should generally also + // not happen before the first read call. + + this.sync = true; // whenever we return null, then we set a flag to say + // that we're awaiting a 'readable' event emission. + + this.needReadable = false; + this.emittedReadable = false; + this.readableListening = false; + this.resumeScheduled = false; + this.paused = true; // Should close be emitted on destroy. Defaults to true. + + this.emitClose = options.emitClose !== false; // Should .destroy() be called after 'end' (and potentially 'finish') + + this.autoDestroy = !!options.autoDestroy; // has it been destroyed + + this.destroyed = false; // Crypto is kind of old and crusty. Historically, its default string + // encoding is 'binary' so we have to make this configurable. + // Everything else in the universe uses 'utf8', though. + + this.defaultEncoding = options.defaultEncoding || 'utf8'; // the number of writers that are awaiting a drain event in .pipe()s + + this.awaitDrain = 0; // if true, a maybeReadMore has been scheduled + + this.readingMore = false; + this.decoder = null; + this.encoding = null; + + if (options.encoding) { + if (!StringDecoder) StringDecoder = require('string_decoder/').StringDecoder; + this.decoder = new StringDecoder(options.encoding); + this.encoding = options.encoding; + } +} + +function Readable(options) { + Duplex = Duplex || require('./_stream_duplex'); + if (!(this instanceof Readable)) return new Readable(options); // Checking for a Stream.Duplex instance is faster here instead of inside + // the ReadableState constructor, at least with V8 6.5 + + var isDuplex = this instanceof Duplex; + this._readableState = new ReadableState(options, this, isDuplex); // legacy + + this.readable = true; + + if (options) { + if (typeof options.read === 'function') this._read = options.read; + if (typeof options.destroy === 'function') this._destroy = options.destroy; + } + + Stream.call(this); +} + +Object.defineProperty(Readable.prototype, 'destroyed', { + // making it explicit this property is not enumerable + // because otherwise some prototype manipulation in + // userland will fail + enumerable: false, + get: function get() { + if (this._readableState === undefined) { + return false; + } + + return this._readableState.destroyed; + }, + set: function set(value) { + // we ignore the value if the stream + // has not been initialized yet + if (!this._readableState) { + return; + } // backward compatibility, the user is explicitly + // managing destroyed + + + this._readableState.destroyed = value; + } +}); +Readable.prototype.destroy = destroyImpl.destroy; +Readable.prototype._undestroy = destroyImpl.undestroy; + +Readable.prototype._destroy = function (err, cb) { + cb(err); +}; // Manually shove something into the read() buffer. +// This returns true if the highWaterMark has not been hit yet, +// similar to how Writable.write() returns true if you should +// write() some more. + + +Readable.prototype.push = function (chunk, encoding) { + var state = this._readableState; + var skipChunkCheck; + + if (!state.objectMode) { + if (typeof chunk === 'string') { + encoding = encoding || state.defaultEncoding; + + if (encoding !== state.encoding) { + chunk = Buffer.from(chunk, encoding); + encoding = ''; + } + + skipChunkCheck = true; + } + } else { + skipChunkCheck = true; + } + + return readableAddChunk(this, chunk, encoding, false, skipChunkCheck); +}; // Unshift should *always* be something directly out of read() + + +Readable.prototype.unshift = function (chunk) { + return readableAddChunk(this, chunk, null, true, false); +}; + +function readableAddChunk(stream, chunk, encoding, addToFront, skipChunkCheck) { + debug('readableAddChunk', chunk); + var state = stream._readableState; + + if (chunk === null) { + state.reading = false; + onEofChunk(stream, state); + } else { + var er; + if (!skipChunkCheck) er = chunkInvalid(state, chunk); + + if (er) { + errorOrDestroy(stream, er); + } else if (state.objectMode || chunk && chunk.length > 0) { + if (typeof chunk !== 'string' && !state.objectMode && Object.getPrototypeOf(chunk) !== Buffer.prototype) { + chunk = _uint8ArrayToBuffer(chunk); + } + + if (addToFront) { + if (state.endEmitted) errorOrDestroy(stream, new ERR_STREAM_UNSHIFT_AFTER_END_EVENT());else addChunk(stream, state, chunk, true); + } else if (state.ended) { + errorOrDestroy(stream, new ERR_STREAM_PUSH_AFTER_EOF()); + } else if (state.destroyed) { + return false; + } else { + state.reading = false; + + if (state.decoder && !encoding) { + chunk = state.decoder.write(chunk); + if (state.objectMode || chunk.length !== 0) addChunk(stream, state, chunk, false);else maybeReadMore(stream, state); + } else { + addChunk(stream, state, chunk, false); + } + } + } else if (!addToFront) { + state.reading = false; + maybeReadMore(stream, state); + } + } // We can push more data if we are below the highWaterMark. + // Also, if we have no data yet, we can stand some more bytes. + // This is to work around cases where hwm=0, such as the repl. + + + return !state.ended && (state.length < state.highWaterMark || state.length === 0); +} + +function addChunk(stream, state, chunk, addToFront) { + if (state.flowing && state.length === 0 && !state.sync) { + state.awaitDrain = 0; + stream.emit('data', chunk); + } else { + // update the buffer info. + state.length += state.objectMode ? 1 : chunk.length; + if (addToFront) state.buffer.unshift(chunk);else state.buffer.push(chunk); + if (state.needReadable) emitReadable(stream); + } + + maybeReadMore(stream, state); +} + +function chunkInvalid(state, chunk) { + var er; + + if (!_isUint8Array(chunk) && typeof chunk !== 'string' && chunk !== undefined && !state.objectMode) { + er = new ERR_INVALID_ARG_TYPE('chunk', ['string', 'Buffer', 'Uint8Array'], chunk); + } + + return er; +} + +Readable.prototype.isPaused = function () { + return this._readableState.flowing === false; +}; // backwards compatibility. + + +Readable.prototype.setEncoding = function (enc) { + if (!StringDecoder) StringDecoder = require('string_decoder/').StringDecoder; + var decoder = new StringDecoder(enc); + this._readableState.decoder = decoder; // If setEncoding(null), decoder.encoding equals utf8 + + this._readableState.encoding = this._readableState.decoder.encoding; // Iterate over current buffer to convert already stored Buffers: + + var p = this._readableState.buffer.head; + var content = ''; + + while (p !== null) { + content += decoder.write(p.data); + p = p.next; + } + + this._readableState.buffer.clear(); + + if (content !== '') this._readableState.buffer.push(content); + this._readableState.length = content.length; + return this; +}; // Don't raise the hwm > 1GB + + +var MAX_HWM = 0x40000000; + +function computeNewHighWaterMark(n) { + if (n >= MAX_HWM) { + // TODO(ronag): Throw ERR_VALUE_OUT_OF_RANGE. + n = MAX_HWM; + } else { + // Get the next highest power of 2 to prevent increasing hwm excessively in + // tiny amounts + n--; + n |= n >>> 1; + n |= n >>> 2; + n |= n >>> 4; + n |= n >>> 8; + n |= n >>> 16; + n++; + } + + return n; +} // This function is designed to be inlinable, so please take care when making +// changes to the function body. + + +function howMuchToRead(n, state) { + if (n <= 0 || state.length === 0 && state.ended) return 0; + if (state.objectMode) return 1; + + if (n !== n) { + // Only flow one buffer at a time + if (state.flowing && state.length) return state.buffer.head.data.length;else return state.length; + } // If we're asking for more than the current hwm, then raise the hwm. + + + if (n > state.highWaterMark) state.highWaterMark = computeNewHighWaterMark(n); + if (n <= state.length) return n; // Don't have enough + + if (!state.ended) { + state.needReadable = true; + return 0; + } + + return state.length; +} // you can override either this method, or the async _read(n) below. + + +Readable.prototype.read = function (n) { + debug('read', n); + n = parseInt(n, 10); + var state = this._readableState; + var nOrig = n; + if (n !== 0) state.emittedReadable = false; // if we're doing read(0) to trigger a readable event, but we + // already have a bunch of data in the buffer, then just trigger + // the 'readable' event and move on. + + if (n === 0 && state.needReadable && ((state.highWaterMark !== 0 ? state.length >= state.highWaterMark : state.length > 0) || state.ended)) { + debug('read: emitReadable', state.length, state.ended); + if (state.length === 0 && state.ended) endReadable(this);else emitReadable(this); + return null; + } + + n = howMuchToRead(n, state); // if we've ended, and we're now clear, then finish it up. + + if (n === 0 && state.ended) { + if (state.length === 0) endReadable(this); + return null; + } // All the actual chunk generation logic needs to be + // *below* the call to _read. The reason is that in certain + // synthetic stream cases, such as passthrough streams, _read + // may be a completely synchronous operation which may change + // the state of the read buffer, providing enough data when + // before there was *not* enough. + // + // So, the steps are: + // 1. Figure out what the state of things will be after we do + // a read from the buffer. + // + // 2. If that resulting state will trigger a _read, then call _read. + // Note that this may be asynchronous, or synchronous. Yes, it is + // deeply ugly to write APIs this way, but that still doesn't mean + // that the Readable class should behave improperly, as streams are + // designed to be sync/async agnostic. + // Take note if the _read call is sync or async (ie, if the read call + // has returned yet), so that we know whether or not it's safe to emit + // 'readable' etc. + // + // 3. Actually pull the requested chunks out of the buffer and return. + // if we need a readable event, then we need to do some reading. + + + var doRead = state.needReadable; + debug('need readable', doRead); // if we currently have less than the highWaterMark, then also read some + + if (state.length === 0 || state.length - n < state.highWaterMark) { + doRead = true; + debug('length less than watermark', doRead); + } // however, if we've ended, then there's no point, and if we're already + // reading, then it's unnecessary. + + + if (state.ended || state.reading) { + doRead = false; + debug('reading or ended', doRead); + } else if (doRead) { + debug('do read'); + state.reading = true; + state.sync = true; // if the length is currently zero, then we *need* a readable event. + + if (state.length === 0) state.needReadable = true; // call internal read method + + this._read(state.highWaterMark); + + state.sync = false; // If _read pushed data synchronously, then `reading` will be false, + // and we need to re-evaluate how much data we can return to the user. + + if (!state.reading) n = howMuchToRead(nOrig, state); + } + + var ret; + if (n > 0) ret = fromList(n, state);else ret = null; + + if (ret === null) { + state.needReadable = state.length <= state.highWaterMark; + n = 0; + } else { + state.length -= n; + state.awaitDrain = 0; + } + + if (state.length === 0) { + // If we have nothing in the buffer, then we want to know + // as soon as we *do* get something into the buffer. + if (!state.ended) state.needReadable = true; // If we tried to read() past the EOF, then emit end on the next tick. + + if (nOrig !== n && state.ended) endReadable(this); + } + + if (ret !== null) this.emit('data', ret); + return ret; +}; + +function onEofChunk(stream, state) { + debug('onEofChunk'); + if (state.ended) return; + + if (state.decoder) { + var chunk = state.decoder.end(); + + if (chunk && chunk.length) { + state.buffer.push(chunk); + state.length += state.objectMode ? 1 : chunk.length; + } + } + + state.ended = true; + + if (state.sync) { + // if we are sync, wait until next tick to emit the data. + // Otherwise we risk emitting data in the flow() + // the readable code triggers during a read() call + emitReadable(stream); + } else { + // emit 'readable' now to make sure it gets picked up. + state.needReadable = false; + + if (!state.emittedReadable) { + state.emittedReadable = true; + emitReadable_(stream); + } + } +} // Don't emit readable right away in sync mode, because this can trigger +// another read() call => stack overflow. This way, it might trigger +// a nextTick recursion warning, but that's not so bad. + + +function emitReadable(stream) { + var state = stream._readableState; + debug('emitReadable', state.needReadable, state.emittedReadable); + state.needReadable = false; + + if (!state.emittedReadable) { + debug('emitReadable', state.flowing); + state.emittedReadable = true; + process.nextTick(emitReadable_, stream); + } +} + +function emitReadable_(stream) { + var state = stream._readableState; + debug('emitReadable_', state.destroyed, state.length, state.ended); + + if (!state.destroyed && (state.length || state.ended)) { + stream.emit('readable'); + state.emittedReadable = false; + } // The stream needs another readable event if + // 1. It is not flowing, as the flow mechanism will take + // care of it. + // 2. It is not ended. + // 3. It is below the highWaterMark, so we can schedule + // another readable later. + + + state.needReadable = !state.flowing && !state.ended && state.length <= state.highWaterMark; + flow(stream); +} // at this point, the user has presumably seen the 'readable' event, +// and called read() to consume some data. that may have triggered +// in turn another _read(n) call, in which case reading = true if +// it's in progress. +// However, if we're not ended, or reading, and the length < hwm, +// then go ahead and try to read some more preemptively. + + +function maybeReadMore(stream, state) { + if (!state.readingMore) { + state.readingMore = true; + process.nextTick(maybeReadMore_, stream, state); + } +} + +function maybeReadMore_(stream, state) { + // Attempt to read more data if we should. + // + // The conditions for reading more data are (one of): + // - Not enough data buffered (state.length < state.highWaterMark). The loop + // is responsible for filling the buffer with enough data if such data + // is available. If highWaterMark is 0 and we are not in the flowing mode + // we should _not_ attempt to buffer any extra data. We'll get more data + // when the stream consumer calls read() instead. + // - No data in the buffer, and the stream is in flowing mode. In this mode + // the loop below is responsible for ensuring read() is called. Failing to + // call read here would abort the flow and there's no other mechanism for + // continuing the flow if the stream consumer has just subscribed to the + // 'data' event. + // + // In addition to the above conditions to keep reading data, the following + // conditions prevent the data from being read: + // - The stream has ended (state.ended). + // - There is already a pending 'read' operation (state.reading). This is a + // case where the the stream has called the implementation defined _read() + // method, but they are processing the call asynchronously and have _not_ + // called push() with new data. In this case we skip performing more + // read()s. The execution ends in this method again after the _read() ends + // up calling push() with more data. + while (!state.reading && !state.ended && (state.length < state.highWaterMark || state.flowing && state.length === 0)) { + var len = state.length; + debug('maybeReadMore read 0'); + stream.read(0); + if (len === state.length) // didn't get any data, stop spinning. + break; + } + + state.readingMore = false; +} // abstract method. to be overridden in specific implementation classes. +// call cb(er, data) where data is <= n in length. +// for virtual (non-string, non-buffer) streams, "length" is somewhat +// arbitrary, and perhaps not very meaningful. + + +Readable.prototype._read = function (n) { + errorOrDestroy(this, new ERR_METHOD_NOT_IMPLEMENTED('_read()')); +}; + +Readable.prototype.pipe = function (dest, pipeOpts) { + var src = this; + var state = this._readableState; + + switch (state.pipesCount) { + case 0: + state.pipes = dest; + break; + + case 1: + state.pipes = [state.pipes, dest]; + break; + + default: + state.pipes.push(dest); + break; + } + + state.pipesCount += 1; + debug('pipe count=%d opts=%j', state.pipesCount, pipeOpts); + var doEnd = (!pipeOpts || pipeOpts.end !== false) && dest !== process.stdout && dest !== process.stderr; + var endFn = doEnd ? onend : unpipe; + if (state.endEmitted) process.nextTick(endFn);else src.once('end', endFn); + dest.on('unpipe', onunpipe); + + function onunpipe(readable, unpipeInfo) { + debug('onunpipe'); + + if (readable === src) { + if (unpipeInfo && unpipeInfo.hasUnpiped === false) { + unpipeInfo.hasUnpiped = true; + cleanup(); + } + } + } + + function onend() { + debug('onend'); + dest.end(); + } // when the dest drains, it reduces the awaitDrain counter + // on the source. This would be more elegant with a .once() + // handler in flow(), but adding and removing repeatedly is + // too slow. + + + var ondrain = pipeOnDrain(src); + dest.on('drain', ondrain); + var cleanedUp = false; + + function cleanup() { + debug('cleanup'); // cleanup event handlers once the pipe is broken + + dest.removeListener('close', onclose); + dest.removeListener('finish', onfinish); + dest.removeListener('drain', ondrain); + dest.removeListener('error', onerror); + dest.removeListener('unpipe', onunpipe); + src.removeListener('end', onend); + src.removeListener('end', unpipe); + src.removeListener('data', ondata); + cleanedUp = true; // if the reader is waiting for a drain event from this + // specific writer, then it would cause it to never start + // flowing again. + // So, if this is awaiting a drain, then we just call it now. + // If we don't know, then assume that we are waiting for one. + + if (state.awaitDrain && (!dest._writableState || dest._writableState.needDrain)) ondrain(); + } + + src.on('data', ondata); + + function ondata(chunk) { + debug('ondata'); + var ret = dest.write(chunk); + debug('dest.write', ret); + + if (ret === false) { + // If the user unpiped during `dest.write()`, it is possible + // to get stuck in a permanently paused state if that write + // also returned false. + // => Check whether `dest` is still a piping destination. + if ((state.pipesCount === 1 && state.pipes === dest || state.pipesCount > 1 && indexOf(state.pipes, dest) !== -1) && !cleanedUp) { + debug('false write response, pause', state.awaitDrain); + state.awaitDrain++; + } + + src.pause(); + } + } // if the dest has an error, then stop piping into it. + // however, don't suppress the throwing behavior for this. + + + function onerror(er) { + debug('onerror', er); + unpipe(); + dest.removeListener('error', onerror); + if (EElistenerCount(dest, 'error') === 0) errorOrDestroy(dest, er); + } // Make sure our error handler is attached before userland ones. + + + prependListener(dest, 'error', onerror); // Both close and finish should trigger unpipe, but only once. + + function onclose() { + dest.removeListener('finish', onfinish); + unpipe(); + } + + dest.once('close', onclose); + + function onfinish() { + debug('onfinish'); + dest.removeListener('close', onclose); + unpipe(); + } + + dest.once('finish', onfinish); + + function unpipe() { + debug('unpipe'); + src.unpipe(dest); + } // tell the dest that it's being piped to + + + dest.emit('pipe', src); // start the flow if it hasn't been started already. + + if (!state.flowing) { + debug('pipe resume'); + src.resume(); + } + + return dest; +}; + +function pipeOnDrain(src) { + return function pipeOnDrainFunctionResult() { + var state = src._readableState; + debug('pipeOnDrain', state.awaitDrain); + if (state.awaitDrain) state.awaitDrain--; + + if (state.awaitDrain === 0 && EElistenerCount(src, 'data')) { + state.flowing = true; + flow(src); + } + }; +} + +Readable.prototype.unpipe = function (dest) { + var state = this._readableState; + var unpipeInfo = { + hasUnpiped: false + }; // if we're not piping anywhere, then do nothing. + + if (state.pipesCount === 0) return this; // just one destination. most common case. + + if (state.pipesCount === 1) { + // passed in one, but it's not the right one. + if (dest && dest !== state.pipes) return this; + if (!dest) dest = state.pipes; // got a match. + + state.pipes = null; + state.pipesCount = 0; + state.flowing = false; + if (dest) dest.emit('unpipe', this, unpipeInfo); + return this; + } // slow case. multiple pipe destinations. + + + if (!dest) { + // remove all. + var dests = state.pipes; + var len = state.pipesCount; + state.pipes = null; + state.pipesCount = 0; + state.flowing = false; + + for (var i = 0; i < len; i++) { + dests[i].emit('unpipe', this, { + hasUnpiped: false + }); + } + + return this; + } // try to find the right one. + + + var index = indexOf(state.pipes, dest); + if (index === -1) return this; + state.pipes.splice(index, 1); + state.pipesCount -= 1; + if (state.pipesCount === 1) state.pipes = state.pipes[0]; + dest.emit('unpipe', this, unpipeInfo); + return this; +}; // set up data events if they are asked for +// Ensure readable listeners eventually get something + + +Readable.prototype.on = function (ev, fn) { + var res = Stream.prototype.on.call(this, ev, fn); + var state = this._readableState; + + if (ev === 'data') { + // update readableListening so that resume() may be a no-op + // a few lines down. This is needed to support once('readable'). + state.readableListening = this.listenerCount('readable') > 0; // Try start flowing on next tick if stream isn't explicitly paused + + if (state.flowing !== false) this.resume(); + } else if (ev === 'readable') { + if (!state.endEmitted && !state.readableListening) { + state.readableListening = state.needReadable = true; + state.flowing = false; + state.emittedReadable = false; + debug('on readable', state.length, state.reading); + + if (state.length) { + emitReadable(this); + } else if (!state.reading) { + process.nextTick(nReadingNextTick, this); + } + } + } + + return res; +}; + +Readable.prototype.addListener = Readable.prototype.on; + +Readable.prototype.removeListener = function (ev, fn) { + var res = Stream.prototype.removeListener.call(this, ev, fn); + + if (ev === 'readable') { + // We need to check if there is someone still listening to + // readable and reset the state. However this needs to happen + // after readable has been emitted but before I/O (nextTick) to + // support once('readable', fn) cycles. This means that calling + // resume within the same tick will have no + // effect. + process.nextTick(updateReadableListening, this); + } + + return res; +}; + +Readable.prototype.removeAllListeners = function (ev) { + var res = Stream.prototype.removeAllListeners.apply(this, arguments); + + if (ev === 'readable' || ev === undefined) { + // We need to check if there is someone still listening to + // readable and reset the state. However this needs to happen + // after readable has been emitted but before I/O (nextTick) to + // support once('readable', fn) cycles. This means that calling + // resume within the same tick will have no + // effect. + process.nextTick(updateReadableListening, this); + } + + return res; +}; + +function updateReadableListening(self) { + var state = self._readableState; + state.readableListening = self.listenerCount('readable') > 0; + + if (state.resumeScheduled && !state.paused) { + // flowing needs to be set to true now, otherwise + // the upcoming resume will not flow. + state.flowing = true; // crude way to check if we should resume + } else if (self.listenerCount('data') > 0) { + self.resume(); + } +} + +function nReadingNextTick(self) { + debug('readable nexttick read 0'); + self.read(0); +} // pause() and resume() are remnants of the legacy readable stream API +// If the user uses them, then switch into old mode. + + +Readable.prototype.resume = function () { + var state = this._readableState; + + if (!state.flowing) { + debug('resume'); // we flow only if there is no one listening + // for readable, but we still have to call + // resume() + + state.flowing = !state.readableListening; + resume(this, state); + } + + state.paused = false; + return this; +}; + +function resume(stream, state) { + if (!state.resumeScheduled) { + state.resumeScheduled = true; + process.nextTick(resume_, stream, state); + } +} + +function resume_(stream, state) { + debug('resume', state.reading); + + if (!state.reading) { + stream.read(0); + } + + state.resumeScheduled = false; + stream.emit('resume'); + flow(stream); + if (state.flowing && !state.reading) stream.read(0); +} + +Readable.prototype.pause = function () { + debug('call pause flowing=%j', this._readableState.flowing); + + if (this._readableState.flowing !== false) { + debug('pause'); + this._readableState.flowing = false; + this.emit('pause'); + } + + this._readableState.paused = true; + return this; +}; + +function flow(stream) { + var state = stream._readableState; + debug('flow', state.flowing); + + while (state.flowing && stream.read() !== null) { + ; + } +} // wrap an old-style stream as the async data source. +// This is *not* part of the readable stream interface. +// It is an ugly unfortunate mess of history. + + +Readable.prototype.wrap = function (stream) { + var _this = this; + + var state = this._readableState; + var paused = false; + stream.on('end', function () { + debug('wrapped end'); + + if (state.decoder && !state.ended) { + var chunk = state.decoder.end(); + if (chunk && chunk.length) _this.push(chunk); + } + + _this.push(null); + }); + stream.on('data', function (chunk) { + debug('wrapped data'); + if (state.decoder) chunk = state.decoder.write(chunk); // don't skip over falsy values in objectMode + + if (state.objectMode && (chunk === null || chunk === undefined)) return;else if (!state.objectMode && (!chunk || !chunk.length)) return; + + var ret = _this.push(chunk); + + if (!ret) { + paused = true; + stream.pause(); + } + }); // proxy all the other methods. + // important when wrapping filters and duplexes. + + for (var i in stream) { + if (this[i] === undefined && typeof stream[i] === 'function') { + this[i] = function methodWrap(method) { + return function methodWrapReturnFunction() { + return stream[method].apply(stream, arguments); + }; + }(i); + } + } // proxy certain important events. + + + for (var n = 0; n < kProxyEvents.length; n++) { + stream.on(kProxyEvents[n], this.emit.bind(this, kProxyEvents[n])); + } // when we try to consume some more bytes, simply unpause the + // underlying stream. + + + this._read = function (n) { + debug('wrapped _read', n); + + if (paused) { + paused = false; + stream.resume(); + } + }; + + return this; +}; + +if (typeof Symbol === 'function') { + Readable.prototype[Symbol.asyncIterator] = function () { + if (createReadableStreamAsyncIterator === undefined) { + createReadableStreamAsyncIterator = require('./internal/streams/async_iterator'); + } + + return createReadableStreamAsyncIterator(this); + }; +} + +Object.defineProperty(Readable.prototype, 'readableHighWaterMark', { + // making it explicit this property is not enumerable + // because otherwise some prototype manipulation in + // userland will fail + enumerable: false, + get: function get() { + return this._readableState.highWaterMark; + } +}); +Object.defineProperty(Readable.prototype, 'readableBuffer', { + // making it explicit this property is not enumerable + // because otherwise some prototype manipulation in + // userland will fail + enumerable: false, + get: function get() { + return this._readableState && this._readableState.buffer; + } +}); +Object.defineProperty(Readable.prototype, 'readableFlowing', { + // making it explicit this property is not enumerable + // because otherwise some prototype manipulation in + // userland will fail + enumerable: false, + get: function get() { + return this._readableState.flowing; + }, + set: function set(state) { + if (this._readableState) { + this._readableState.flowing = state; + } + } +}); // exposed for testing purposes only. + +Readable._fromList = fromList; +Object.defineProperty(Readable.prototype, 'readableLength', { + // making it explicit this property is not enumerable + // because otherwise some prototype manipulation in + // userland will fail + enumerable: false, + get: function get() { + return this._readableState.length; + } +}); // Pluck off n bytes from an array of buffers. +// Length is the combined lengths of all the buffers in the list. +// This function is designed to be inlinable, so please take care when making +// changes to the function body. + +function fromList(n, state) { + // nothing buffered + if (state.length === 0) return null; + var ret; + if (state.objectMode) ret = state.buffer.shift();else if (!n || n >= state.length) { + // read it all, truncate the list + if (state.decoder) ret = state.buffer.join('');else if (state.buffer.length === 1) ret = state.buffer.first();else ret = state.buffer.concat(state.length); + state.buffer.clear(); + } else { + // read part of list + ret = state.buffer.consume(n, state.decoder); + } + return ret; +} + +function endReadable(stream) { + var state = stream._readableState; + debug('endReadable', state.endEmitted); + + if (!state.endEmitted) { + state.ended = true; + process.nextTick(endReadableNT, state, stream); + } +} + +function endReadableNT(state, stream) { + debug('endReadableNT', state.endEmitted, state.length); // Check that we didn't get one last unshift. + + if (!state.endEmitted && state.length === 0) { + state.endEmitted = true; + stream.readable = false; + stream.emit('end'); + + if (state.autoDestroy) { + // In case of duplex streams we need a way to detect + // if the writable side is ready for autoDestroy as well + var wState = stream._writableState; + + if (!wState || wState.autoDestroy && wState.finished) { + stream.destroy(); + } + } + } +} + +if (typeof Symbol === 'function') { + Readable.from = function (iterable, opts) { + if (from === undefined) { + from = require('./internal/streams/from'); + } + + return from(Readable, iterable, opts); + }; +} + +function indexOf(xs, x) { + for (var i = 0, l = xs.length; i < l; i++) { + if (xs[i] === x) return i; + } + + return -1; +} +}).call(this)}).call(this,require('_process'),typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) +},{"../errors":48,"./_stream_duplex":49,"./internal/streams/async_iterator":54,"./internal/streams/buffer_list":55,"./internal/streams/destroy":56,"./internal/streams/from":58,"./internal/streams/state":60,"./internal/streams/stream":61,"_process":164,"buffer":64,"events":104,"inherits":143,"string_decoder/":204,"util":20}],52:[function(require,module,exports){ +// Copyright Joyent, Inc. and other Node contributors. +// +// 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. +// a transform stream is a readable/writable stream where you do +// something with the data. Sometimes it's called a "filter", +// but that's not a great name for it, since that implies a thing where +// some bits pass through, and others are simply ignored. (That would +// be a valid example of a transform, of course.) +// +// While the output is causally related to the input, it's not a +// necessarily symmetric or synchronous transformation. For example, +// a zlib stream might take multiple plain-text writes(), and then +// emit a single compressed chunk some time in the future. +// +// Here's how this works: +// +// The Transform stream has all the aspects of the readable and writable +// stream classes. When you write(chunk), that calls _write(chunk,cb) +// internally, and returns false if there's a lot of pending writes +// buffered up. When you call read(), that calls _read(n) until +// there's enough pending readable data buffered up. +// +// In a transform stream, the written data is placed in a buffer. When +// _read(n) is called, it transforms the queued up data, calling the +// buffered _write cb's as it consumes chunks. If consuming a single +// written chunk would result in multiple output chunks, then the first +// outputted bit calls the readcb, and subsequent chunks just go into +// the read buffer, and will cause it to emit 'readable' if necessary. +// +// This way, back-pressure is actually determined by the reading side, +// since _read has to be called to start processing a new chunk. However, +// a pathological inflate type of transform can cause excessive buffering +// here. For example, imagine a stream where every byte of input is +// interpreted as an integer from 0-255, and then results in that many +// bytes of output. Writing the 4 bytes {ff,ff,ff,ff} would result in +// 1kb of data being output. In this case, you could write a very small +// amount of input, and end up with a very large amount of output. In +// such a pathological inflating mechanism, there'd be no way to tell +// the system to stop doing the transform. A single 4MB write could +// cause the system to run out of memory. +// +// However, even in such a pathological case, only a single written chunk +// would be consumed, and then the rest would wait (un-transformed) until +// the results of the previous transformed chunk were consumed. +'use strict'; + +module.exports = Transform; + +var _require$codes = require('../errors').codes, + ERR_METHOD_NOT_IMPLEMENTED = _require$codes.ERR_METHOD_NOT_IMPLEMENTED, + ERR_MULTIPLE_CALLBACK = _require$codes.ERR_MULTIPLE_CALLBACK, + ERR_TRANSFORM_ALREADY_TRANSFORMING = _require$codes.ERR_TRANSFORM_ALREADY_TRANSFORMING, + ERR_TRANSFORM_WITH_LENGTH_0 = _require$codes.ERR_TRANSFORM_WITH_LENGTH_0; + +var Duplex = require('./_stream_duplex'); + +require('inherits')(Transform, Duplex); + +function afterTransform(er, data) { + var ts = this._transformState; + ts.transforming = false; + var cb = ts.writecb; + + if (cb === null) { + return this.emit('error', new ERR_MULTIPLE_CALLBACK()); + } + + ts.writechunk = null; + ts.writecb = null; + if (data != null) // single equals check for both `null` and `undefined` + this.push(data); + cb(er); + var rs = this._readableState; + rs.reading = false; + + if (rs.needReadable || rs.length < rs.highWaterMark) { + this._read(rs.highWaterMark); + } +} + +function Transform(options) { + if (!(this instanceof Transform)) return new Transform(options); + Duplex.call(this, options); + this._transformState = { + afterTransform: afterTransform.bind(this), + needTransform: false, + transforming: false, + writecb: null, + writechunk: null, + writeencoding: null + }; // start out asking for a readable event once data is transformed. + + this._readableState.needReadable = true; // we have implemented the _read method, and done the other things + // that Readable wants before the first _read call, so unset the + // sync guard flag. + + this._readableState.sync = false; + + if (options) { + if (typeof options.transform === 'function') this._transform = options.transform; + if (typeof options.flush === 'function') this._flush = options.flush; + } // When the writable side finishes, then flush out anything remaining. + + + this.on('prefinish', prefinish); +} + +function prefinish() { + var _this = this; + + if (typeof this._flush === 'function' && !this._readableState.destroyed) { + this._flush(function (er, data) { + done(_this, er, data); + }); + } else { + done(this, null, null); + } +} + +Transform.prototype.push = function (chunk, encoding) { + this._transformState.needTransform = false; + return Duplex.prototype.push.call(this, chunk, encoding); +}; // This is the part where you do stuff! +// override this function in implementation classes. +// 'chunk' is an input chunk. +// +// Call `push(newChunk)` to pass along transformed output +// to the readable side. You may call 'push' zero or more times. +// +// Call `cb(err)` when you are done with this chunk. If you pass +// an error, then that'll put the hurt on the whole operation. If you +// never call cb(), then you'll never get another chunk. + + +Transform.prototype._transform = function (chunk, encoding, cb) { + cb(new ERR_METHOD_NOT_IMPLEMENTED('_transform()')); +}; + +Transform.prototype._write = function (chunk, encoding, cb) { + var ts = this._transformState; + ts.writecb = cb; + ts.writechunk = chunk; + ts.writeencoding = encoding; + + if (!ts.transforming) { + var rs = this._readableState; + if (ts.needTransform || rs.needReadable || rs.length < rs.highWaterMark) this._read(rs.highWaterMark); + } +}; // Doesn't matter what the args are here. +// _transform does all the work. +// That we got here means that the readable side wants more data. + + +Transform.prototype._read = function (n) { + var ts = this._transformState; + + if (ts.writechunk !== null && !ts.transforming) { + ts.transforming = true; + + this._transform(ts.writechunk, ts.writeencoding, ts.afterTransform); + } else { + // mark that we need a transform, so that any data that comes in + // will get processed, now that we've asked for it. + ts.needTransform = true; + } +}; + +Transform.prototype._destroy = function (err, cb) { + Duplex.prototype._destroy.call(this, err, function (err2) { + cb(err2); + }); +}; + +function done(stream, er, data) { + if (er) return stream.emit('error', er); + if (data != null) // single equals check for both `null` and `undefined` + stream.push(data); // TODO(BridgeAR): Write a test for these two error cases + // if there's nothing in the write buffer, then that means + // that nothing more will ever be provided + + if (stream._writableState.length) throw new ERR_TRANSFORM_WITH_LENGTH_0(); + if (stream._transformState.transforming) throw new ERR_TRANSFORM_ALREADY_TRANSFORMING(); + return stream.push(null); +} +},{"../errors":48,"./_stream_duplex":49,"inherits":143}],53:[function(require,module,exports){ +(function (process,global){(function (){ +// Copyright Joyent, Inc. and other Node contributors. +// +// 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. +// A bit simpler than readable streams. +// Implement an async ._write(chunk, encoding, cb), and it'll handle all +// the drain event emission and buffering. +'use strict'; + +module.exports = Writable; +/* */ + +function WriteReq(chunk, encoding, cb) { + this.chunk = chunk; + this.encoding = encoding; + this.callback = cb; + this.next = null; +} // It seems a linked list but it is not +// there will be only 2 of these for each stream + + +function CorkedRequest(state) { + var _this = this; + + this.next = null; + this.entry = null; + + this.finish = function () { + onCorkedFinish(_this, state); + }; +} +/* */ + +/**/ + + +var Duplex; +/**/ + +Writable.WritableState = WritableState; +/**/ + +var internalUtil = { + deprecate: require('util-deprecate') +}; +/**/ + +/**/ + +var Stream = require('./internal/streams/stream'); +/**/ + + +var Buffer = require('buffer').Buffer; + +var OurUint8Array = global.Uint8Array || function () {}; + +function _uint8ArrayToBuffer(chunk) { + return Buffer.from(chunk); +} + +function _isUint8Array(obj) { + return Buffer.isBuffer(obj) || obj instanceof OurUint8Array; +} + +var destroyImpl = require('./internal/streams/destroy'); + +var _require = require('./internal/streams/state'), + getHighWaterMark = _require.getHighWaterMark; + +var _require$codes = require('../errors').codes, + ERR_INVALID_ARG_TYPE = _require$codes.ERR_INVALID_ARG_TYPE, + ERR_METHOD_NOT_IMPLEMENTED = _require$codes.ERR_METHOD_NOT_IMPLEMENTED, + ERR_MULTIPLE_CALLBACK = _require$codes.ERR_MULTIPLE_CALLBACK, + ERR_STREAM_CANNOT_PIPE = _require$codes.ERR_STREAM_CANNOT_PIPE, + ERR_STREAM_DESTROYED = _require$codes.ERR_STREAM_DESTROYED, + ERR_STREAM_NULL_VALUES = _require$codes.ERR_STREAM_NULL_VALUES, + ERR_STREAM_WRITE_AFTER_END = _require$codes.ERR_STREAM_WRITE_AFTER_END, + ERR_UNKNOWN_ENCODING = _require$codes.ERR_UNKNOWN_ENCODING; + +var errorOrDestroy = destroyImpl.errorOrDestroy; + +require('inherits')(Writable, Stream); + +function nop() {} + +function WritableState(options, stream, isDuplex) { + Duplex = Duplex || require('./_stream_duplex'); + options = options || {}; // Duplex streams are both readable and writable, but share + // the same options object. + // However, some cases require setting options to different + // values for the readable and the writable sides of the duplex stream, + // e.g. options.readableObjectMode vs. options.writableObjectMode, etc. + + if (typeof isDuplex !== 'boolean') isDuplex = stream instanceof Duplex; // object stream flag to indicate whether or not this stream + // contains buffers or objects. + + this.objectMode = !!options.objectMode; + if (isDuplex) this.objectMode = this.objectMode || !!options.writableObjectMode; // the point at which write() starts returning false + // Note: 0 is a valid value, means that we always return false if + // the entire buffer is not flushed immediately on write() + + this.highWaterMark = getHighWaterMark(this, options, 'writableHighWaterMark', isDuplex); // if _final has been called + + this.finalCalled = false; // drain event flag. + + this.needDrain = false; // at the start of calling end() + + this.ending = false; // when end() has been called, and returned + + this.ended = false; // when 'finish' is emitted + + this.finished = false; // has it been destroyed + + this.destroyed = false; // should we decode strings into buffers before passing to _write? + // this is here so that some node-core streams can optimize string + // handling at a lower level. + + var noDecode = options.decodeStrings === false; + this.decodeStrings = !noDecode; // Crypto is kind of old and crusty. Historically, its default string + // encoding is 'binary' so we have to make this configurable. + // Everything else in the universe uses 'utf8', though. + + this.defaultEncoding = options.defaultEncoding || 'utf8'; // not an actual buffer we keep track of, but a measurement + // of how much we're waiting to get pushed to some underlying + // socket or file. + + this.length = 0; // a flag to see when we're in the middle of a write. + + this.writing = false; // when true all writes will be buffered until .uncork() call + + this.corked = 0; // a flag to be able to tell if the onwrite cb is called immediately, + // or on a later tick. We set this to true at first, because any + // actions that shouldn't happen until "later" should generally also + // not happen before the first write call. + + this.sync = true; // a flag to know if we're processing previously buffered items, which + // may call the _write() callback in the same tick, so that we don't + // end up in an overlapped onwrite situation. + + this.bufferProcessing = false; // the callback that's passed to _write(chunk,cb) + + this.onwrite = function (er) { + onwrite(stream, er); + }; // the callback that the user supplies to write(chunk,encoding,cb) + + + this.writecb = null; // the amount that is being written when _write is called. + + this.writelen = 0; + this.bufferedRequest = null; + this.lastBufferedRequest = null; // number of pending user-supplied write callbacks + // this must be 0 before 'finish' can be emitted + + this.pendingcb = 0; // emit prefinish if the only thing we're waiting for is _write cbs + // This is relevant for synchronous Transform streams + + this.prefinished = false; // True if the error was already emitted and should not be thrown again + + this.errorEmitted = false; // Should close be emitted on destroy. Defaults to true. + + this.emitClose = options.emitClose !== false; // Should .destroy() be called after 'finish' (and potentially 'end') + + this.autoDestroy = !!options.autoDestroy; // count buffered requests + + this.bufferedRequestCount = 0; // allocate the first CorkedRequest, there is always + // one allocated and free to use, and we maintain at most two + + this.corkedRequestsFree = new CorkedRequest(this); +} + +WritableState.prototype.getBuffer = function getBuffer() { + var current = this.bufferedRequest; + var out = []; + + while (current) { + out.push(current); + current = current.next; + } + + return out; +}; + +(function () { + try { + Object.defineProperty(WritableState.prototype, 'buffer', { + get: internalUtil.deprecate(function writableStateBufferGetter() { + return this.getBuffer(); + }, '_writableState.buffer is deprecated. Use _writableState.getBuffer ' + 'instead.', 'DEP0003') + }); + } catch (_) {} +})(); // Test _writableState for inheritance to account for Duplex streams, +// whose prototype chain only points to Readable. + + +var realHasInstance; + +if (typeof Symbol === 'function' && Symbol.hasInstance && typeof Function.prototype[Symbol.hasInstance] === 'function') { + realHasInstance = Function.prototype[Symbol.hasInstance]; + Object.defineProperty(Writable, Symbol.hasInstance, { + value: function value(object) { + if (realHasInstance.call(this, object)) return true; + if (this !== Writable) return false; + return object && object._writableState instanceof WritableState; + } + }); +} else { + realHasInstance = function realHasInstance(object) { + return object instanceof this; + }; +} + +function Writable(options) { + Duplex = Duplex || require('./_stream_duplex'); // Writable ctor is applied to Duplexes, too. + // `realHasInstance` is necessary because using plain `instanceof` + // would return false, as no `_writableState` property is attached. + // Trying to use the custom `instanceof` for Writable here will also break the + // Node.js LazyTransform implementation, which has a non-trivial getter for + // `_writableState` that would lead to infinite recursion. + // Checking for a Stream.Duplex instance is faster here instead of inside + // the WritableState constructor, at least with V8 6.5 + + var isDuplex = this instanceof Duplex; + if (!isDuplex && !realHasInstance.call(Writable, this)) return new Writable(options); + this._writableState = new WritableState(options, this, isDuplex); // legacy. + + this.writable = true; + + if (options) { + if (typeof options.write === 'function') this._write = options.write; + if (typeof options.writev === 'function') this._writev = options.writev; + if (typeof options.destroy === 'function') this._destroy = options.destroy; + if (typeof options.final === 'function') this._final = options.final; + } + + Stream.call(this); +} // Otherwise people can pipe Writable streams, which is just wrong. + + +Writable.prototype.pipe = function () { + errorOrDestroy(this, new ERR_STREAM_CANNOT_PIPE()); +}; + +function writeAfterEnd(stream, cb) { + var er = new ERR_STREAM_WRITE_AFTER_END(); // TODO: defer error events consistently everywhere, not just the cb + + errorOrDestroy(stream, er); + process.nextTick(cb, er); +} // Checks that a user-supplied chunk is valid, especially for the particular +// mode the stream is in. Currently this means that `null` is never accepted +// and undefined/non-string values are only allowed in object mode. + + +function validChunk(stream, state, chunk, cb) { + var er; + + if (chunk === null) { + er = new ERR_STREAM_NULL_VALUES(); + } else if (typeof chunk !== 'string' && !state.objectMode) { + er = new ERR_INVALID_ARG_TYPE('chunk', ['string', 'Buffer'], chunk); + } + + if (er) { + errorOrDestroy(stream, er); + process.nextTick(cb, er); + return false; + } + + return true; +} + +Writable.prototype.write = function (chunk, encoding, cb) { + var state = this._writableState; + var ret = false; + + var isBuf = !state.objectMode && _isUint8Array(chunk); + + if (isBuf && !Buffer.isBuffer(chunk)) { + chunk = _uint8ArrayToBuffer(chunk); + } + + if (typeof encoding === 'function') { + cb = encoding; + encoding = null; + } + + if (isBuf) encoding = 'buffer';else if (!encoding) encoding = state.defaultEncoding; + if (typeof cb !== 'function') cb = nop; + if (state.ending) writeAfterEnd(this, cb);else if (isBuf || validChunk(this, state, chunk, cb)) { + state.pendingcb++; + ret = writeOrBuffer(this, state, isBuf, chunk, encoding, cb); + } + return ret; +}; + +Writable.prototype.cork = function () { + this._writableState.corked++; +}; + +Writable.prototype.uncork = function () { + var state = this._writableState; + + if (state.corked) { + state.corked--; + if (!state.writing && !state.corked && !state.bufferProcessing && state.bufferedRequest) clearBuffer(this, state); + } +}; + +Writable.prototype.setDefaultEncoding = function setDefaultEncoding(encoding) { + // node::ParseEncoding() requires lower case. + if (typeof encoding === 'string') encoding = encoding.toLowerCase(); + if (!(['hex', 'utf8', 'utf-8', 'ascii', 'binary', 'base64', 'ucs2', 'ucs-2', 'utf16le', 'utf-16le', 'raw'].indexOf((encoding + '').toLowerCase()) > -1)) throw new ERR_UNKNOWN_ENCODING(encoding); + this._writableState.defaultEncoding = encoding; + return this; +}; + +Object.defineProperty(Writable.prototype, 'writableBuffer', { + // making it explicit this property is not enumerable + // because otherwise some prototype manipulation in + // userland will fail + enumerable: false, + get: function get() { + return this._writableState && this._writableState.getBuffer(); + } +}); + +function decodeChunk(state, chunk, encoding) { + if (!state.objectMode && state.decodeStrings !== false && typeof chunk === 'string') { + chunk = Buffer.from(chunk, encoding); + } + + return chunk; +} + +Object.defineProperty(Writable.prototype, 'writableHighWaterMark', { + // making it explicit this property is not enumerable + // because otherwise some prototype manipulation in + // userland will fail + enumerable: false, + get: function get() { + return this._writableState.highWaterMark; + } +}); // if we're already writing something, then just put this +// in the queue, and wait our turn. Otherwise, call _write +// If we return false, then we need a drain event, so set that flag. + +function writeOrBuffer(stream, state, isBuf, chunk, encoding, cb) { + if (!isBuf) { + var newChunk = decodeChunk(state, chunk, encoding); + + if (chunk !== newChunk) { + isBuf = true; + encoding = 'buffer'; + chunk = newChunk; + } + } + + var len = state.objectMode ? 1 : chunk.length; + state.length += len; + var ret = state.length < state.highWaterMark; // we must ensure that previous needDrain will not be reset to false. + + if (!ret) state.needDrain = true; + + if (state.writing || state.corked) { + var last = state.lastBufferedRequest; + state.lastBufferedRequest = { + chunk: chunk, + encoding: encoding, + isBuf: isBuf, + callback: cb, + next: null + }; + + if (last) { + last.next = state.lastBufferedRequest; + } else { + state.bufferedRequest = state.lastBufferedRequest; + } + + state.bufferedRequestCount += 1; + } else { + doWrite(stream, state, false, len, chunk, encoding, cb); + } + + return ret; +} + +function doWrite(stream, state, writev, len, chunk, encoding, cb) { + state.writelen = len; + state.writecb = cb; + state.writing = true; + state.sync = true; + if (state.destroyed) state.onwrite(new ERR_STREAM_DESTROYED('write'));else if (writev) stream._writev(chunk, state.onwrite);else stream._write(chunk, encoding, state.onwrite); + state.sync = false; +} + +function onwriteError(stream, state, sync, er, cb) { + --state.pendingcb; + + if (sync) { + // defer the callback if we are being called synchronously + // to avoid piling up things on the stack + process.nextTick(cb, er); // this can emit finish, and it will always happen + // after error + + process.nextTick(finishMaybe, stream, state); + stream._writableState.errorEmitted = true; + errorOrDestroy(stream, er); + } else { + // the caller expect this to happen before if + // it is async + cb(er); + stream._writableState.errorEmitted = true; + errorOrDestroy(stream, er); // this can emit finish, but finish must + // always follow error + + finishMaybe(stream, state); + } +} + +function onwriteStateUpdate(state) { + state.writing = false; + state.writecb = null; + state.length -= state.writelen; + state.writelen = 0; +} + +function onwrite(stream, er) { + var state = stream._writableState; + var sync = state.sync; + var cb = state.writecb; + if (typeof cb !== 'function') throw new ERR_MULTIPLE_CALLBACK(); + onwriteStateUpdate(state); + if (er) onwriteError(stream, state, sync, er, cb);else { + // Check if we're actually ready to finish, but don't emit yet + var finished = needFinish(state) || stream.destroyed; + + if (!finished && !state.corked && !state.bufferProcessing && state.bufferedRequest) { + clearBuffer(stream, state); + } + + if (sync) { + process.nextTick(afterWrite, stream, state, finished, cb); + } else { + afterWrite(stream, state, finished, cb); + } + } +} + +function afterWrite(stream, state, finished, cb) { + if (!finished) onwriteDrain(stream, state); + state.pendingcb--; + cb(); + finishMaybe(stream, state); +} // Must force callback to be called on nextTick, so that we don't +// emit 'drain' before the write() consumer gets the 'false' return +// value, and has a chance to attach a 'drain' listener. + + +function onwriteDrain(stream, state) { + if (state.length === 0 && state.needDrain) { + state.needDrain = false; + stream.emit('drain'); + } +} // if there's something in the buffer waiting, then process it + + +function clearBuffer(stream, state) { + state.bufferProcessing = true; + var entry = state.bufferedRequest; + + if (stream._writev && entry && entry.next) { + // Fast case, write everything using _writev() + var l = state.bufferedRequestCount; + var buffer = new Array(l); + var holder = state.corkedRequestsFree; + holder.entry = entry; + var count = 0; + var allBuffers = true; + + while (entry) { + buffer[count] = entry; + if (!entry.isBuf) allBuffers = false; + entry = entry.next; + count += 1; + } + + buffer.allBuffers = allBuffers; + doWrite(stream, state, true, state.length, buffer, '', holder.finish); // doWrite is almost always async, defer these to save a bit of time + // as the hot path ends with doWrite + + state.pendingcb++; + state.lastBufferedRequest = null; + + if (holder.next) { + state.corkedRequestsFree = holder.next; + holder.next = null; + } else { + state.corkedRequestsFree = new CorkedRequest(state); + } + + state.bufferedRequestCount = 0; + } else { + // Slow case, write chunks one-by-one + while (entry) { + var chunk = entry.chunk; + var encoding = entry.encoding; + var cb = entry.callback; + var len = state.objectMode ? 1 : chunk.length; + doWrite(stream, state, false, len, chunk, encoding, cb); + entry = entry.next; + state.bufferedRequestCount--; // if we didn't call the onwrite immediately, then + // it means that we need to wait until it does. + // also, that means that the chunk and cb are currently + // being processed, so move the buffer counter past them. + + if (state.writing) { + break; + } + } + + if (entry === null) state.lastBufferedRequest = null; + } + + state.bufferedRequest = entry; + state.bufferProcessing = false; +} + +Writable.prototype._write = function (chunk, encoding, cb) { + cb(new ERR_METHOD_NOT_IMPLEMENTED('_write()')); +}; + +Writable.prototype._writev = null; + +Writable.prototype.end = function (chunk, encoding, cb) { + var state = this._writableState; + + if (typeof chunk === 'function') { + cb = chunk; + chunk = null; + encoding = null; + } else if (typeof encoding === 'function') { + cb = encoding; + encoding = null; + } + + if (chunk !== null && chunk !== undefined) this.write(chunk, encoding); // .end() fully uncorks + + if (state.corked) { + state.corked = 1; + this.uncork(); + } // ignore unnecessary end() calls. + + + if (!state.ending) endWritable(this, state, cb); + return this; +}; + +Object.defineProperty(Writable.prototype, 'writableLength', { + // making it explicit this property is not enumerable + // because otherwise some prototype manipulation in + // userland will fail + enumerable: false, + get: function get() { + return this._writableState.length; + } +}); + +function needFinish(state) { + return state.ending && state.length === 0 && state.bufferedRequest === null && !state.finished && !state.writing; +} + +function callFinal(stream, state) { + stream._final(function (err) { + state.pendingcb--; + + if (err) { + errorOrDestroy(stream, err); + } + + state.prefinished = true; + stream.emit('prefinish'); + finishMaybe(stream, state); + }); +} + +function prefinish(stream, state) { + if (!state.prefinished && !state.finalCalled) { + if (typeof stream._final === 'function' && !state.destroyed) { + state.pendingcb++; + state.finalCalled = true; + process.nextTick(callFinal, stream, state); + } else { + state.prefinished = true; + stream.emit('prefinish'); + } + } +} + +function finishMaybe(stream, state) { + var need = needFinish(state); + + if (need) { + prefinish(stream, state); + + if (state.pendingcb === 0) { + state.finished = true; + stream.emit('finish'); + + if (state.autoDestroy) { + // In case of duplex streams we need a way to detect + // if the readable side is ready for autoDestroy as well + var rState = stream._readableState; + + if (!rState || rState.autoDestroy && rState.endEmitted) { + stream.destroy(); + } + } + } + } + + return need; +} + +function endWritable(stream, state, cb) { + state.ending = true; + finishMaybe(stream, state); + + if (cb) { + if (state.finished) process.nextTick(cb);else stream.once('finish', cb); + } + + state.ended = true; + stream.writable = false; +} + +function onCorkedFinish(corkReq, state, err) { + var entry = corkReq.entry; + corkReq.entry = null; + + while (entry) { + var cb = entry.callback; + state.pendingcb--; + cb(err); + entry = entry.next; + } // reuse the free corkReq. + + + state.corkedRequestsFree.next = corkReq; +} + +Object.defineProperty(Writable.prototype, 'destroyed', { + // making it explicit this property is not enumerable + // because otherwise some prototype manipulation in + // userland will fail + enumerable: false, + get: function get() { + if (this._writableState === undefined) { + return false; + } + + return this._writableState.destroyed; + }, + set: function set(value) { + // we ignore the value if the stream + // has not been initialized yet + if (!this._writableState) { + return; + } // backward compatibility, the user is explicitly + // managing destroyed + + + this._writableState.destroyed = value; + } +}); +Writable.prototype.destroy = destroyImpl.destroy; +Writable.prototype._undestroy = destroyImpl.undestroy; + +Writable.prototype._destroy = function (err, cb) { + cb(err); +}; +}).call(this)}).call(this,require('_process'),typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) +},{"../errors":48,"./_stream_duplex":49,"./internal/streams/destroy":56,"./internal/streams/state":60,"./internal/streams/stream":61,"_process":164,"buffer":64,"inherits":143,"util-deprecate":207}],54:[function(require,module,exports){ +(function (process){(function (){ +'use strict'; + +var _Object$setPrototypeO; + +function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; } + +var finished = require('./end-of-stream'); + +var kLastResolve = Symbol('lastResolve'); +var kLastReject = Symbol('lastReject'); +var kError = Symbol('error'); +var kEnded = Symbol('ended'); +var kLastPromise = Symbol('lastPromise'); +var kHandlePromise = Symbol('handlePromise'); +var kStream = Symbol('stream'); + +function createIterResult(value, done) { + return { + value: value, + done: done + }; +} + +function readAndResolve(iter) { + var resolve = iter[kLastResolve]; + + if (resolve !== null) { + var data = iter[kStream].read(); // we defer if data is null + // we can be expecting either 'end' or + // 'error' + + if (data !== null) { + iter[kLastPromise] = null; + iter[kLastResolve] = null; + iter[kLastReject] = null; + resolve(createIterResult(data, false)); + } + } +} + +function onReadable(iter) { + // we wait for the next tick, because it might + // emit an error with process.nextTick + process.nextTick(readAndResolve, iter); +} + +function wrapForNext(lastPromise, iter) { + return function (resolve, reject) { + lastPromise.then(function () { + if (iter[kEnded]) { + resolve(createIterResult(undefined, true)); + return; + } + + iter[kHandlePromise](resolve, reject); + }, reject); + }; +} + +var AsyncIteratorPrototype = Object.getPrototypeOf(function () {}); +var ReadableStreamAsyncIteratorPrototype = Object.setPrototypeOf((_Object$setPrototypeO = { + get stream() { + return this[kStream]; + }, + + next: function next() { + var _this = this; + + // if we have detected an error in the meanwhile + // reject straight away + var error = this[kError]; + + if (error !== null) { + return Promise.reject(error); + } + + if (this[kEnded]) { + return Promise.resolve(createIterResult(undefined, true)); + } + + if (this[kStream].destroyed) { + // We need to defer via nextTick because if .destroy(err) is + // called, the error will be emitted via nextTick, and + // we cannot guarantee that there is no error lingering around + // waiting to be emitted. + return new Promise(function (resolve, reject) { + process.nextTick(function () { + if (_this[kError]) { + reject(_this[kError]); + } else { + resolve(createIterResult(undefined, true)); + } + }); + }); + } // if we have multiple next() calls + // we will wait for the previous Promise to finish + // this logic is optimized to support for await loops, + // where next() is only called once at a time + + + var lastPromise = this[kLastPromise]; + var promise; + + if (lastPromise) { + promise = new Promise(wrapForNext(lastPromise, this)); + } else { + // fast path needed to support multiple this.push() + // without triggering the next() queue + var data = this[kStream].read(); + + if (data !== null) { + return Promise.resolve(createIterResult(data, false)); + } + + promise = new Promise(this[kHandlePromise]); + } + + this[kLastPromise] = promise; + return promise; + } +}, _defineProperty(_Object$setPrototypeO, Symbol.asyncIterator, function () { + return this; +}), _defineProperty(_Object$setPrototypeO, "return", function _return() { + var _this2 = this; + + // destroy(err, cb) is a private API + // we can guarantee we have that here, because we control the + // Readable class this is attached to + return new Promise(function (resolve, reject) { + _this2[kStream].destroy(null, function (err) { + if (err) { + reject(err); + return; + } + + resolve(createIterResult(undefined, true)); + }); + }); +}), _Object$setPrototypeO), AsyncIteratorPrototype); + +var createReadableStreamAsyncIterator = function createReadableStreamAsyncIterator(stream) { + var _Object$create; + + var iterator = Object.create(ReadableStreamAsyncIteratorPrototype, (_Object$create = {}, _defineProperty(_Object$create, kStream, { + value: stream, + writable: true + }), _defineProperty(_Object$create, kLastResolve, { + value: null, + writable: true + }), _defineProperty(_Object$create, kLastReject, { + value: null, + writable: true + }), _defineProperty(_Object$create, kError, { + value: null, + writable: true + }), _defineProperty(_Object$create, kEnded, { + value: stream._readableState.endEmitted, + writable: true + }), _defineProperty(_Object$create, kHandlePromise, { + value: function value(resolve, reject) { + var data = iterator[kStream].read(); + + if (data) { + iterator[kLastPromise] = null; + iterator[kLastResolve] = null; + iterator[kLastReject] = null; + resolve(createIterResult(data, false)); + } else { + iterator[kLastResolve] = resolve; + iterator[kLastReject] = reject; + } + }, + writable: true + }), _Object$create)); + iterator[kLastPromise] = null; + finished(stream, function (err) { + if (err && err.code !== 'ERR_STREAM_PREMATURE_CLOSE') { + var reject = iterator[kLastReject]; // reject if we are waiting for data in the Promise + // returned by next() and store the error + + if (reject !== null) { + iterator[kLastPromise] = null; + iterator[kLastResolve] = null; + iterator[kLastReject] = null; + reject(err); + } + + iterator[kError] = err; + return; + } + + var resolve = iterator[kLastResolve]; + + if (resolve !== null) { + iterator[kLastPromise] = null; + iterator[kLastResolve] = null; + iterator[kLastReject] = null; + resolve(createIterResult(undefined, true)); + } + + iterator[kEnded] = true; + }); + stream.on('readable', onReadable.bind(null, iterator)); + return iterator; +}; + +module.exports = createReadableStreamAsyncIterator; +}).call(this)}).call(this,require('_process')) +},{"./end-of-stream":57,"_process":164}],55:[function(require,module,exports){ +'use strict'; + +function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); keys.push.apply(keys, symbols); } return keys; } + +function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys(Object(source), true).forEach(function (key) { _defineProperty(target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } } return target; } + +function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; } + +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } + +function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } + +function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; } + +var _require = require('buffer'), + Buffer = _require.Buffer; + +var _require2 = require('util'), + inspect = _require2.inspect; + +var custom = inspect && inspect.custom || 'inspect'; + +function copyBuffer(src, target, offset) { + Buffer.prototype.copy.call(src, target, offset); +} + +module.exports = +/*#__PURE__*/ +function () { + function BufferList() { + _classCallCheck(this, BufferList); + + this.head = null; + this.tail = null; + this.length = 0; + } + + _createClass(BufferList, [{ + key: "push", + value: function push(v) { + var entry = { + data: v, + next: null + }; + if (this.length > 0) this.tail.next = entry;else this.head = entry; + this.tail = entry; + ++this.length; + } + }, { + key: "unshift", + value: function unshift(v) { + var entry = { + data: v, + next: this.head + }; + if (this.length === 0) this.tail = entry; + this.head = entry; + ++this.length; + } + }, { + key: "shift", + value: function shift() { + if (this.length === 0) return; + var ret = this.head.data; + if (this.length === 1) this.head = this.tail = null;else this.head = this.head.next; + --this.length; + return ret; + } + }, { + key: "clear", + value: function clear() { + this.head = this.tail = null; + this.length = 0; + } + }, { + key: "join", + value: function join(s) { + if (this.length === 0) return ''; + var p = this.head; + var ret = '' + p.data; + + while (p = p.next) { + ret += s + p.data; + } + + return ret; + } + }, { + key: "concat", + value: function concat(n) { + if (this.length === 0) return Buffer.alloc(0); + var ret = Buffer.allocUnsafe(n >>> 0); + var p = this.head; + var i = 0; + + while (p) { + copyBuffer(p.data, ret, i); + i += p.data.length; + p = p.next; + } + + return ret; + } // Consumes a specified amount of bytes or characters from the buffered data. + + }, { + key: "consume", + value: function consume(n, hasStrings) { + var ret; + + if (n < this.head.data.length) { + // `slice` is the same for buffers and strings. + ret = this.head.data.slice(0, n); + this.head.data = this.head.data.slice(n); + } else if (n === this.head.data.length) { + // First chunk is a perfect match. + ret = this.shift(); + } else { + // Result spans more than one buffer. + ret = hasStrings ? this._getString(n) : this._getBuffer(n); + } + + return ret; + } + }, { + key: "first", + value: function first() { + return this.head.data; + } // Consumes a specified amount of characters from the buffered data. + + }, { + key: "_getString", + value: function _getString(n) { + var p = this.head; + var c = 1; + var ret = p.data; + n -= ret.length; + + while (p = p.next) { + var str = p.data; + var nb = n > str.length ? str.length : n; + if (nb === str.length) ret += str;else ret += str.slice(0, n); + n -= nb; + + if (n === 0) { + if (nb === str.length) { + ++c; + if (p.next) this.head = p.next;else this.head = this.tail = null; + } else { + this.head = p; + p.data = str.slice(nb); + } + + break; + } + + ++c; + } + + this.length -= c; + return ret; + } // Consumes a specified amount of bytes from the buffered data. + + }, { + key: "_getBuffer", + value: function _getBuffer(n) { + var ret = Buffer.allocUnsafe(n); + var p = this.head; + var c = 1; + p.data.copy(ret); + n -= p.data.length; + + while (p = p.next) { + var buf = p.data; + var nb = n > buf.length ? buf.length : n; + buf.copy(ret, ret.length - n, 0, nb); + n -= nb; + + if (n === 0) { + if (nb === buf.length) { + ++c; + if (p.next) this.head = p.next;else this.head = this.tail = null; + } else { + this.head = p; + p.data = buf.slice(nb); + } + + break; + } + + ++c; + } + + this.length -= c; + return ret; + } // Make sure the linked list only shows the minimal necessary information. + + }, { + key: custom, + value: function value(_, options) { + return inspect(this, _objectSpread({}, options, { + // Only inspect one level. + depth: 0, + // It should not recurse. + customInspect: false + })); + } + }]); + + return BufferList; +}(); +},{"buffer":64,"util":20}],56:[function(require,module,exports){ +(function (process){(function (){ +'use strict'; // undocumented cb() API, needed for core, not for public API + +function destroy(err, cb) { + var _this = this; + + var readableDestroyed = this._readableState && this._readableState.destroyed; + var writableDestroyed = this._writableState && this._writableState.destroyed; + + if (readableDestroyed || writableDestroyed) { + if (cb) { + cb(err); + } else if (err) { + if (!this._writableState) { + process.nextTick(emitErrorNT, this, err); + } else if (!this._writableState.errorEmitted) { + this._writableState.errorEmitted = true; + process.nextTick(emitErrorNT, this, err); + } + } + + return this; + } // we set destroyed to true before firing error callbacks in order + // to make it re-entrance safe in case destroy() is called within callbacks + + + if (this._readableState) { + this._readableState.destroyed = true; + } // if this is a duplex stream mark the writable part as destroyed as well + + + if (this._writableState) { + this._writableState.destroyed = true; + } + + this._destroy(err || null, function (err) { + if (!cb && err) { + if (!_this._writableState) { + process.nextTick(emitErrorAndCloseNT, _this, err); + } else if (!_this._writableState.errorEmitted) { + _this._writableState.errorEmitted = true; + process.nextTick(emitErrorAndCloseNT, _this, err); + } else { + process.nextTick(emitCloseNT, _this); + } + } else if (cb) { + process.nextTick(emitCloseNT, _this); + cb(err); + } else { + process.nextTick(emitCloseNT, _this); + } + }); + + return this; +} + +function emitErrorAndCloseNT(self, err) { + emitErrorNT(self, err); + emitCloseNT(self); +} + +function emitCloseNT(self) { + if (self._writableState && !self._writableState.emitClose) return; + if (self._readableState && !self._readableState.emitClose) return; + self.emit('close'); +} + +function undestroy() { + if (this._readableState) { + this._readableState.destroyed = false; + this._readableState.reading = false; + this._readableState.ended = false; + this._readableState.endEmitted = false; + } + + if (this._writableState) { + this._writableState.destroyed = false; + this._writableState.ended = false; + this._writableState.ending = false; + this._writableState.finalCalled = false; + this._writableState.prefinished = false; + this._writableState.finished = false; + this._writableState.errorEmitted = false; + } +} + +function emitErrorNT(self, err) { + self.emit('error', err); +} + +function errorOrDestroy(stream, err) { + // We have tests that rely on errors being emitted + // in the same tick, so changing this is semver major. + // For now when you opt-in to autoDestroy we allow + // the error to be emitted nextTick. In a future + // semver major update we should change the default to this. + var rState = stream._readableState; + var wState = stream._writableState; + if (rState && rState.autoDestroy || wState && wState.autoDestroy) stream.destroy(err);else stream.emit('error', err); +} + +module.exports = { + destroy: destroy, + undestroy: undestroy, + errorOrDestroy: errorOrDestroy +}; +}).call(this)}).call(this,require('_process')) +},{"_process":164}],57:[function(require,module,exports){ +// Ported from https://github.com/mafintosh/end-of-stream with +// permission from the author, Mathias Buus (@mafintosh). +'use strict'; + +var ERR_STREAM_PREMATURE_CLOSE = require('../../../errors').codes.ERR_STREAM_PREMATURE_CLOSE; + +function once(callback) { + var called = false; + return function () { + if (called) return; + called = true; + + for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) { + args[_key] = arguments[_key]; + } + + callback.apply(this, args); + }; +} + +function noop() {} + +function isRequest(stream) { + return stream.setHeader && typeof stream.abort === 'function'; +} + +function eos(stream, opts, callback) { + if (typeof opts === 'function') return eos(stream, null, opts); + if (!opts) opts = {}; + callback = once(callback || noop); + var readable = opts.readable || opts.readable !== false && stream.readable; + var writable = opts.writable || opts.writable !== false && stream.writable; + + var onlegacyfinish = function onlegacyfinish() { + if (!stream.writable) onfinish(); + }; + + var writableEnded = stream._writableState && stream._writableState.finished; + + var onfinish = function onfinish() { + writable = false; + writableEnded = true; + if (!readable) callback.call(stream); + }; + + var readableEnded = stream._readableState && stream._readableState.endEmitted; + + var onend = function onend() { + readable = false; + readableEnded = true; + if (!writable) callback.call(stream); + }; + + var onerror = function onerror(err) { + callback.call(stream, err); + }; + + var onclose = function onclose() { + var err; + + if (readable && !readableEnded) { + if (!stream._readableState || !stream._readableState.ended) err = new ERR_STREAM_PREMATURE_CLOSE(); + return callback.call(stream, err); + } + + if (writable && !writableEnded) { + if (!stream._writableState || !stream._writableState.ended) err = new ERR_STREAM_PREMATURE_CLOSE(); + return callback.call(stream, err); + } + }; + + var onrequest = function onrequest() { + stream.req.on('finish', onfinish); + }; + + if (isRequest(stream)) { + stream.on('complete', onfinish); + stream.on('abort', onclose); + if (stream.req) onrequest();else stream.on('request', onrequest); + } else if (writable && !stream._writableState) { + // legacy streams + stream.on('end', onlegacyfinish); + stream.on('close', onlegacyfinish); + } + + stream.on('end', onend); + stream.on('finish', onfinish); + if (opts.error !== false) stream.on('error', onerror); + stream.on('close', onclose); + return function () { + stream.removeListener('complete', onfinish); + stream.removeListener('abort', onclose); + stream.removeListener('request', onrequest); + if (stream.req) stream.req.removeListener('finish', onfinish); + stream.removeListener('end', onlegacyfinish); + stream.removeListener('close', onlegacyfinish); + stream.removeListener('finish', onfinish); + stream.removeListener('end', onend); + stream.removeListener('error', onerror); + stream.removeListener('close', onclose); + }; +} + +module.exports = eos; +},{"../../../errors":48}],58:[function(require,module,exports){ +module.exports = function () { + throw new Error('Readable.from is not available in the browser') +}; + +},{}],59:[function(require,module,exports){ +// Ported from https://github.com/mafintosh/pump with +// permission from the author, Mathias Buus (@mafintosh). +'use strict'; + +var eos; + +function once(callback) { + var called = false; + return function () { + if (called) return; + called = true; + callback.apply(void 0, arguments); + }; +} + +var _require$codes = require('../../../errors').codes, + ERR_MISSING_ARGS = _require$codes.ERR_MISSING_ARGS, + ERR_STREAM_DESTROYED = _require$codes.ERR_STREAM_DESTROYED; + +function noop(err) { + // Rethrow the error if it exists to avoid swallowing it + if (err) throw err; +} + +function isRequest(stream) { + return stream.setHeader && typeof stream.abort === 'function'; +} + +function destroyer(stream, reading, writing, callback) { + callback = once(callback); + var closed = false; + stream.on('close', function () { + closed = true; + }); + if (eos === undefined) eos = require('./end-of-stream'); + eos(stream, { + readable: reading, + writable: writing + }, function (err) { + if (err) return callback(err); + closed = true; + callback(); + }); + var destroyed = false; + return function (err) { + if (closed) return; + if (destroyed) return; + destroyed = true; // request.destroy just do .end - .abort is what we want + + if (isRequest(stream)) return stream.abort(); + if (typeof stream.destroy === 'function') return stream.destroy(); + callback(err || new ERR_STREAM_DESTROYED('pipe')); + }; +} + +function call(fn) { + fn(); +} + +function pipe(from, to) { + return from.pipe(to); +} + +function popCallback(streams) { + if (!streams.length) return noop; + if (typeof streams[streams.length - 1] !== 'function') return noop; + return streams.pop(); +} + +function pipeline() { + for (var _len = arguments.length, streams = new Array(_len), _key = 0; _key < _len; _key++) { + streams[_key] = arguments[_key]; + } + + var callback = popCallback(streams); + if (Array.isArray(streams[0])) streams = streams[0]; + + if (streams.length < 2) { + throw new ERR_MISSING_ARGS('streams'); + } + + var error; + var destroys = streams.map(function (stream, i) { + var reading = i < streams.length - 1; + var writing = i > 0; + return destroyer(stream, reading, writing, function (err) { + if (!error) error = err; + if (err) destroys.forEach(call); + if (reading) return; + destroys.forEach(call); + callback(error); + }); + }); + return streams.reduce(pipe); +} + +module.exports = pipeline; +},{"../../../errors":48,"./end-of-stream":57}],60:[function(require,module,exports){ +'use strict'; + +var ERR_INVALID_OPT_VALUE = require('../../../errors').codes.ERR_INVALID_OPT_VALUE; + +function highWaterMarkFrom(options, isDuplex, duplexKey) { + return options.highWaterMark != null ? options.highWaterMark : isDuplex ? options[duplexKey] : null; +} + +function getHighWaterMark(state, options, duplexKey, isDuplex) { + var hwm = highWaterMarkFrom(options, isDuplex, duplexKey); + + if (hwm != null) { + if (!(isFinite(hwm) && Math.floor(hwm) === hwm) || hwm < 0) { + var name = isDuplex ? duplexKey : 'highWaterMark'; + throw new ERR_INVALID_OPT_VALUE(name, hwm); + } + + return Math.floor(hwm); + } // Default value + + + return state.objectMode ? 16 : 16 * 1024; +} + +module.exports = { + getHighWaterMark: getHighWaterMark +}; +},{"../../../errors":48}],61:[function(require,module,exports){ +module.exports = require('events').EventEmitter; + +},{"events":104}],62:[function(require,module,exports){ +exports = module.exports = require('./lib/_stream_readable.js'); +exports.Stream = exports; +exports.Readable = exports; +exports.Writable = require('./lib/_stream_writable.js'); +exports.Duplex = require('./lib/_stream_duplex.js'); +exports.Transform = require('./lib/_stream_transform.js'); +exports.PassThrough = require('./lib/_stream_passthrough.js'); +exports.finished = require('./lib/internal/streams/end-of-stream.js'); +exports.pipeline = require('./lib/internal/streams/pipeline.js'); + +},{"./lib/_stream_duplex.js":49,"./lib/_stream_passthrough.js":50,"./lib/_stream_readable.js":51,"./lib/_stream_transform.js":52,"./lib/_stream_writable.js":53,"./lib/internal/streams/end-of-stream.js":57,"./lib/internal/streams/pipeline.js":59}],63:[function(require,module,exports){ +(function (Buffer){(function (){ +module.exports = function xor (a, b) { + var length = Math.min(a.length, b.length) + var buffer = new Buffer(length) + + for (var i = 0; i < length; ++i) { + buffer[i] = a[i] ^ b[i] + } + + return buffer +} + +}).call(this)}).call(this,require("buffer").Buffer) +},{"buffer":64}],64:[function(require,module,exports){ +(function (Buffer){(function (){ +/*! + * The buffer module from node.js, for the browser. + * + * @author Feross Aboukhadijeh + * @license MIT + */ +/* eslint-disable no-proto */ + +'use strict' + +var base64 = require('base64-js') +var ieee754 = require('ieee754') + +exports.Buffer = Buffer +exports.SlowBuffer = SlowBuffer +exports.INSPECT_MAX_BYTES = 50 + +var K_MAX_LENGTH = 0x7fffffff +exports.kMaxLength = K_MAX_LENGTH + +/** + * If `Buffer.TYPED_ARRAY_SUPPORT`: + * === true Use Uint8Array implementation (fastest) + * === false Print warning and recommend using `buffer` v4.x which has an Object + * implementation (most compatible, even IE6) + * + * Browsers that support typed arrays are IE 10+, Firefox 4+, Chrome 7+, Safari 5.1+, + * Opera 11.6+, iOS 4.2+. + * + * We report that the browser does not support typed arrays if the are not subclassable + * using __proto__. Firefox 4-29 lacks support for adding new properties to `Uint8Array` + * (See: https://bugzilla.mozilla.org/show_bug.cgi?id=695438). IE 10 lacks support + * for __proto__ and has a buggy typed array implementation. + */ +Buffer.TYPED_ARRAY_SUPPORT = typedArraySupport() + +if (!Buffer.TYPED_ARRAY_SUPPORT && typeof console !== 'undefined' && + typeof console.error === 'function') { + console.error( + 'This browser lacks typed array (Uint8Array) support which is required by ' + + '`buffer` v5.x. Use `buffer` v4.x if you require old browser support.' + ) +} + +function typedArraySupport () { + // Can typed array instances can be augmented? + try { + var arr = new Uint8Array(1) + arr.__proto__ = { __proto__: Uint8Array.prototype, foo: function () { return 42 } } + return arr.foo() === 42 + } catch (e) { + return false + } +} + +Object.defineProperty(Buffer.prototype, 'parent', { + enumerable: true, + get: function () { + if (!Buffer.isBuffer(this)) return undefined + return this.buffer + } +}) + +Object.defineProperty(Buffer.prototype, 'offset', { + enumerable: true, + get: function () { + if (!Buffer.isBuffer(this)) return undefined + return this.byteOffset + } +}) + +function createBuffer (length) { + if (length > K_MAX_LENGTH) { + throw new RangeError('The value "' + length + '" is invalid for option "size"') + } + // Return an augmented `Uint8Array` instance + var buf = new Uint8Array(length) + buf.__proto__ = Buffer.prototype + return buf +} + +/** + * The Buffer constructor returns instances of `Uint8Array` that have their + * prototype changed to `Buffer.prototype`. Furthermore, `Buffer` is a subclass of + * `Uint8Array`, so the returned instances will have all the node `Buffer` methods + * and the `Uint8Array` methods. Square bracket notation works as expected -- it + * returns a single octet. + * + * The `Uint8Array` prototype remains unmodified. + */ + +function Buffer (arg, encodingOrOffset, length) { + // Common case. + if (typeof arg === 'number') { + if (typeof encodingOrOffset === 'string') { + throw new TypeError( + 'The "string" argument must be of type string. Received type number' + ) + } + return allocUnsafe(arg) + } + return from(arg, encodingOrOffset, length) +} + +// Fix subarray() in ES2016. See: https://github.com/feross/buffer/pull/97 +if (typeof Symbol !== 'undefined' && Symbol.species != null && + Buffer[Symbol.species] === Buffer) { + Object.defineProperty(Buffer, Symbol.species, { + value: null, + configurable: true, + enumerable: false, + writable: false + }) +} + +Buffer.poolSize = 8192 // not used by this implementation + +function from (value, encodingOrOffset, length) { + if (typeof value === 'string') { + return fromString(value, encodingOrOffset) + } + + if (ArrayBuffer.isView(value)) { + return fromArrayLike(value) + } + + if (value == null) { + throw TypeError( + 'The first argument must be one of type string, Buffer, ArrayBuffer, Array, ' + + 'or Array-like Object. Received type ' + (typeof value) + ) + } + + if (isInstance(value, ArrayBuffer) || + (value && isInstance(value.buffer, ArrayBuffer))) { + return fromArrayBuffer(value, encodingOrOffset, length) + } + + if (typeof value === 'number') { + throw new TypeError( + 'The "value" argument must not be of type number. Received type number' + ) + } + + var valueOf = value.valueOf && value.valueOf() + if (valueOf != null && valueOf !== value) { + return Buffer.from(valueOf, encodingOrOffset, length) + } + + var b = fromObject(value) + if (b) return b + + if (typeof Symbol !== 'undefined' && Symbol.toPrimitive != null && + typeof value[Symbol.toPrimitive] === 'function') { + return Buffer.from( + value[Symbol.toPrimitive]('string'), encodingOrOffset, length + ) + } + + throw new TypeError( + 'The first argument must be one of type string, Buffer, ArrayBuffer, Array, ' + + 'or Array-like Object. Received type ' + (typeof value) + ) +} + +/** + * Functionally equivalent to Buffer(arg, encoding) but throws a TypeError + * if value is a number. + * Buffer.from(str[, encoding]) + * Buffer.from(array) + * Buffer.from(buffer) + * Buffer.from(arrayBuffer[, byteOffset[, length]]) + **/ +Buffer.from = function (value, encodingOrOffset, length) { + return from(value, encodingOrOffset, length) +} + +// Note: Change prototype *after* Buffer.from is defined to workaround Chrome bug: +// https://github.com/feross/buffer/pull/148 +Buffer.prototype.__proto__ = Uint8Array.prototype +Buffer.__proto__ = Uint8Array + +function assertSize (size) { + if (typeof size !== 'number') { + throw new TypeError('"size" argument must be of type number') + } else if (size < 0) { + throw new RangeError('The value "' + size + '" is invalid for option "size"') + } +} + +function alloc (size, fill, encoding) { + assertSize(size) + if (size <= 0) { + return createBuffer(size) + } + if (fill !== undefined) { + // Only pay attention to encoding if it's a string. This + // prevents accidentally sending in a number that would + // be interpretted as a start offset. + return typeof encoding === 'string' + ? createBuffer(size).fill(fill, encoding) + : createBuffer(size).fill(fill) + } + return createBuffer(size) +} + +/** + * Creates a new filled Buffer instance. + * alloc(size[, fill[, encoding]]) + **/ +Buffer.alloc = function (size, fill, encoding) { + return alloc(size, fill, encoding) +} + +function allocUnsafe (size) { + assertSize(size) + return createBuffer(size < 0 ? 0 : checked(size) | 0) +} + +/** + * Equivalent to Buffer(num), by default creates a non-zero-filled Buffer instance. + * */ +Buffer.allocUnsafe = function (size) { + return allocUnsafe(size) +} +/** + * Equivalent to SlowBuffer(num), by default creates a non-zero-filled Buffer instance. + */ +Buffer.allocUnsafeSlow = function (size) { + return allocUnsafe(size) +} + +function fromString (string, encoding) { + if (typeof encoding !== 'string' || encoding === '') { + encoding = 'utf8' + } + + if (!Buffer.isEncoding(encoding)) { + throw new TypeError('Unknown encoding: ' + encoding) + } + + var length = byteLength(string, encoding) | 0 + var buf = createBuffer(length) + + var actual = buf.write(string, encoding) + + if (actual !== length) { + // Writing a hex string, for example, that contains invalid characters will + // cause everything after the first invalid character to be ignored. (e.g. + // 'abxxcd' will be treated as 'ab') + buf = buf.slice(0, actual) + } + + return buf +} + +function fromArrayLike (array) { + var length = array.length < 0 ? 0 : checked(array.length) | 0 + var buf = createBuffer(length) + for (var i = 0; i < length; i += 1) { + buf[i] = array[i] & 255 + } + return buf +} + +function fromArrayBuffer (array, byteOffset, length) { + if (byteOffset < 0 || array.byteLength < byteOffset) { + throw new RangeError('"offset" is outside of buffer bounds') + } + + if (array.byteLength < byteOffset + (length || 0)) { + throw new RangeError('"length" is outside of buffer bounds') + } + + var buf + if (byteOffset === undefined && length === undefined) { + buf = new Uint8Array(array) + } else if (length === undefined) { + buf = new Uint8Array(array, byteOffset) + } else { + buf = new Uint8Array(array, byteOffset, length) + } + + // Return an augmented `Uint8Array` instance + buf.__proto__ = Buffer.prototype + return buf +} + +function fromObject (obj) { + if (Buffer.isBuffer(obj)) { + var len = checked(obj.length) | 0 + var buf = createBuffer(len) + + if (buf.length === 0) { + return buf + } + + obj.copy(buf, 0, 0, len) + return buf + } + + if (obj.length !== undefined) { + if (typeof obj.length !== 'number' || numberIsNaN(obj.length)) { + return createBuffer(0) + } + return fromArrayLike(obj) + } + + if (obj.type === 'Buffer' && Array.isArray(obj.data)) { + return fromArrayLike(obj.data) + } +} + +function checked (length) { + // Note: cannot use `length < K_MAX_LENGTH` here because that fails when + // length is NaN (which is otherwise coerced to zero.) + if (length >= K_MAX_LENGTH) { + throw new RangeError('Attempt to allocate Buffer larger than maximum ' + + 'size: 0x' + K_MAX_LENGTH.toString(16) + ' bytes') + } + return length | 0 +} + +function SlowBuffer (length) { + if (+length != length) { // eslint-disable-line eqeqeq + length = 0 + } + return Buffer.alloc(+length) +} + +Buffer.isBuffer = function isBuffer (b) { + return b != null && b._isBuffer === true && + b !== Buffer.prototype // so Buffer.isBuffer(Buffer.prototype) will be false +} + +Buffer.compare = function compare (a, b) { + if (isInstance(a, Uint8Array)) a = Buffer.from(a, a.offset, a.byteLength) + if (isInstance(b, Uint8Array)) b = Buffer.from(b, b.offset, b.byteLength) + if (!Buffer.isBuffer(a) || !Buffer.isBuffer(b)) { + throw new TypeError( + 'The "buf1", "buf2" arguments must be one of type Buffer or Uint8Array' + ) + } + + if (a === b) return 0 + + var x = a.length + var y = b.length + + for (var i = 0, len = Math.min(x, y); i < len; ++i) { + if (a[i] !== b[i]) { + x = a[i] + y = b[i] + break + } + } + + if (x < y) return -1 + if (y < x) return 1 + return 0 +} + +Buffer.isEncoding = function isEncoding (encoding) { + switch (String(encoding).toLowerCase()) { + case 'hex': + case 'utf8': + case 'utf-8': + case 'ascii': + case 'latin1': + case 'binary': + case 'base64': + case 'ucs2': + case 'ucs-2': + case 'utf16le': + case 'utf-16le': + return true + default: + return false + } +} + +Buffer.concat = function concat (list, length) { + if (!Array.isArray(list)) { + throw new TypeError('"list" argument must be an Array of Buffers') + } + + if (list.length === 0) { + return Buffer.alloc(0) + } + + var i + if (length === undefined) { + length = 0 + for (i = 0; i < list.length; ++i) { + length += list[i].length + } + } + + var buffer = Buffer.allocUnsafe(length) + var pos = 0 + for (i = 0; i < list.length; ++i) { + var buf = list[i] + if (isInstance(buf, Uint8Array)) { + buf = Buffer.from(buf) + } + if (!Buffer.isBuffer(buf)) { + throw new TypeError('"list" argument must be an Array of Buffers') + } + buf.copy(buffer, pos) + pos += buf.length + } + return buffer +} + +function byteLength (string, encoding) { + if (Buffer.isBuffer(string)) { + return string.length + } + if (ArrayBuffer.isView(string) || isInstance(string, ArrayBuffer)) { + return string.byteLength + } + if (typeof string !== 'string') { + throw new TypeError( + 'The "string" argument must be one of type string, Buffer, or ArrayBuffer. ' + + 'Received type ' + typeof string + ) + } + + var len = string.length + var mustMatch = (arguments.length > 2 && arguments[2] === true) + if (!mustMatch && len === 0) return 0 + + // Use a for loop to avoid recursion + var loweredCase = false + for (;;) { + switch (encoding) { + case 'ascii': + case 'latin1': + case 'binary': + return len + case 'utf8': + case 'utf-8': + return utf8ToBytes(string).length + case 'ucs2': + case 'ucs-2': + case 'utf16le': + case 'utf-16le': + return len * 2 + case 'hex': + return len >>> 1 + case 'base64': + return base64ToBytes(string).length + default: + if (loweredCase) { + return mustMatch ? -1 : utf8ToBytes(string).length // assume utf8 + } + encoding = ('' + encoding).toLowerCase() + loweredCase = true + } + } +} +Buffer.byteLength = byteLength + +function slowToString (encoding, start, end) { + var loweredCase = false + + // No need to verify that "this.length <= MAX_UINT32" since it's a read-only + // property of a typed array. + + // This behaves neither like String nor Uint8Array in that we set start/end + // to their upper/lower bounds if the value passed is out of range. + // undefined is handled specially as per ECMA-262 6th Edition, + // Section 13.3.3.7 Runtime Semantics: KeyedBindingInitialization. + if (start === undefined || start < 0) { + start = 0 + } + // Return early if start > this.length. Done here to prevent potential uint32 + // coercion fail below. + if (start > this.length) { + return '' + } + + if (end === undefined || end > this.length) { + end = this.length + } + + if (end <= 0) { + return '' + } + + // Force coersion to uint32. This will also coerce falsey/NaN values to 0. + end >>>= 0 + start >>>= 0 + + if (end <= start) { + return '' + } + + if (!encoding) encoding = 'utf8' + + while (true) { + switch (encoding) { + case 'hex': + return hexSlice(this, start, end) + + case 'utf8': + case 'utf-8': + return utf8Slice(this, start, end) + + case 'ascii': + return asciiSlice(this, start, end) + + case 'latin1': + case 'binary': + return latin1Slice(this, start, end) + + case 'base64': + return base64Slice(this, start, end) + + case 'ucs2': + case 'ucs-2': + case 'utf16le': + case 'utf-16le': + return utf16leSlice(this, start, end) + + default: + if (loweredCase) throw new TypeError('Unknown encoding: ' + encoding) + encoding = (encoding + '').toLowerCase() + loweredCase = true + } + } +} + +// This property is used by `Buffer.isBuffer` (and the `is-buffer` npm package) +// to detect a Buffer instance. It's not possible to use `instanceof Buffer` +// reliably in a browserify context because there could be multiple different +// copies of the 'buffer' package in use. This method works even for Buffer +// instances that were created from another copy of the `buffer` package. +// See: https://github.com/feross/buffer/issues/154 +Buffer.prototype._isBuffer = true + +function swap (b, n, m) { + var i = b[n] + b[n] = b[m] + b[m] = i +} + +Buffer.prototype.swap16 = function swap16 () { + var len = this.length + if (len % 2 !== 0) { + throw new RangeError('Buffer size must be a multiple of 16-bits') + } + for (var i = 0; i < len; i += 2) { + swap(this, i, i + 1) + } + return this +} + +Buffer.prototype.swap32 = function swap32 () { + var len = this.length + if (len % 4 !== 0) { + throw new RangeError('Buffer size must be a multiple of 32-bits') + } + for (var i = 0; i < len; i += 4) { + swap(this, i, i + 3) + swap(this, i + 1, i + 2) + } + return this +} + +Buffer.prototype.swap64 = function swap64 () { + var len = this.length + if (len % 8 !== 0) { + throw new RangeError('Buffer size must be a multiple of 64-bits') + } + for (var i = 0; i < len; i += 8) { + swap(this, i, i + 7) + swap(this, i + 1, i + 6) + swap(this, i + 2, i + 5) + swap(this, i + 3, i + 4) + } + return this +} + +Buffer.prototype.toString = function toString () { + var length = this.length + if (length === 0) return '' + if (arguments.length === 0) return utf8Slice(this, 0, length) + return slowToString.apply(this, arguments) +} + +Buffer.prototype.toLocaleString = Buffer.prototype.toString + +Buffer.prototype.equals = function equals (b) { + if (!Buffer.isBuffer(b)) throw new TypeError('Argument must be a Buffer') + if (this === b) return true + return Buffer.compare(this, b) === 0 +} + +Buffer.prototype.inspect = function inspect () { + var str = '' + var max = exports.INSPECT_MAX_BYTES + str = this.toString('hex', 0, max).replace(/(.{2})/g, '$1 ').trim() + if (this.length > max) str += ' ... ' + return '' +} + +Buffer.prototype.compare = function compare (target, start, end, thisStart, thisEnd) { + if (isInstance(target, Uint8Array)) { + target = Buffer.from(target, target.offset, target.byteLength) + } + if (!Buffer.isBuffer(target)) { + throw new TypeError( + 'The "target" argument must be one of type Buffer or Uint8Array. ' + + 'Received type ' + (typeof target) + ) + } + + if (start === undefined) { + start = 0 + } + if (end === undefined) { + end = target ? target.length : 0 + } + if (thisStart === undefined) { + thisStart = 0 + } + if (thisEnd === undefined) { + thisEnd = this.length + } + + if (start < 0 || end > target.length || thisStart < 0 || thisEnd > this.length) { + throw new RangeError('out of range index') + } + + if (thisStart >= thisEnd && start >= end) { + return 0 + } + if (thisStart >= thisEnd) { + return -1 + } + if (start >= end) { + return 1 + } + + start >>>= 0 + end >>>= 0 + thisStart >>>= 0 + thisEnd >>>= 0 + + if (this === target) return 0 + + var x = thisEnd - thisStart + var y = end - start + var len = Math.min(x, y) + + var thisCopy = this.slice(thisStart, thisEnd) + var targetCopy = target.slice(start, end) + + for (var i = 0; i < len; ++i) { + if (thisCopy[i] !== targetCopy[i]) { + x = thisCopy[i] + y = targetCopy[i] + break + } + } + + if (x < y) return -1 + if (y < x) return 1 + return 0 +} + +// Finds either the first index of `val` in `buffer` at offset >= `byteOffset`, +// OR the last index of `val` in `buffer` at offset <= `byteOffset`. +// +// Arguments: +// - buffer - a Buffer to search +// - val - a string, Buffer, or number +// - byteOffset - an index into `buffer`; will be clamped to an int32 +// - encoding - an optional encoding, relevant is val is a string +// - dir - true for indexOf, false for lastIndexOf +function bidirectionalIndexOf (buffer, val, byteOffset, encoding, dir) { + // Empty buffer means no match + if (buffer.length === 0) return -1 + + // Normalize byteOffset + if (typeof byteOffset === 'string') { + encoding = byteOffset + byteOffset = 0 + } else if (byteOffset > 0x7fffffff) { + byteOffset = 0x7fffffff + } else if (byteOffset < -0x80000000) { + byteOffset = -0x80000000 + } + byteOffset = +byteOffset // Coerce to Number. + if (numberIsNaN(byteOffset)) { + // byteOffset: it it's undefined, null, NaN, "foo", etc, search whole buffer + byteOffset = dir ? 0 : (buffer.length - 1) + } + + // Normalize byteOffset: negative offsets start from the end of the buffer + if (byteOffset < 0) byteOffset = buffer.length + byteOffset + if (byteOffset >= buffer.length) { + if (dir) return -1 + else byteOffset = buffer.length - 1 + } else if (byteOffset < 0) { + if (dir) byteOffset = 0 + else return -1 + } + + // Normalize val + if (typeof val === 'string') { + val = Buffer.from(val, encoding) + } + + // Finally, search either indexOf (if dir is true) or lastIndexOf + if (Buffer.isBuffer(val)) { + // Special case: looking for empty string/buffer always fails + if (val.length === 0) { + return -1 + } + return arrayIndexOf(buffer, val, byteOffset, encoding, dir) + } else if (typeof val === 'number') { + val = val & 0xFF // Search for a byte value [0-255] + if (typeof Uint8Array.prototype.indexOf === 'function') { + if (dir) { + return Uint8Array.prototype.indexOf.call(buffer, val, byteOffset) + } else { + return Uint8Array.prototype.lastIndexOf.call(buffer, val, byteOffset) + } + } + return arrayIndexOf(buffer, [ val ], byteOffset, encoding, dir) + } + + throw new TypeError('val must be string, number or Buffer') +} + +function arrayIndexOf (arr, val, byteOffset, encoding, dir) { + var indexSize = 1 + var arrLength = arr.length + var valLength = val.length + + if (encoding !== undefined) { + encoding = String(encoding).toLowerCase() + if (encoding === 'ucs2' || encoding === 'ucs-2' || + encoding === 'utf16le' || encoding === 'utf-16le') { + if (arr.length < 2 || val.length < 2) { + return -1 + } + indexSize = 2 + arrLength /= 2 + valLength /= 2 + byteOffset /= 2 + } + } + + function read (buf, i) { + if (indexSize === 1) { + return buf[i] + } else { + return buf.readUInt16BE(i * indexSize) + } + } + + var i + if (dir) { + var foundIndex = -1 + for (i = byteOffset; i < arrLength; i++) { + if (read(arr, i) === read(val, foundIndex === -1 ? 0 : i - foundIndex)) { + if (foundIndex === -1) foundIndex = i + if (i - foundIndex + 1 === valLength) return foundIndex * indexSize + } else { + if (foundIndex !== -1) i -= i - foundIndex + foundIndex = -1 + } + } + } else { + if (byteOffset + valLength > arrLength) byteOffset = arrLength - valLength + for (i = byteOffset; i >= 0; i--) { + var found = true + for (var j = 0; j < valLength; j++) { + if (read(arr, i + j) !== read(val, j)) { + found = false + break + } + } + if (found) return i + } + } + + return -1 +} + +Buffer.prototype.includes = function includes (val, byteOffset, encoding) { + return this.indexOf(val, byteOffset, encoding) !== -1 +} + +Buffer.prototype.indexOf = function indexOf (val, byteOffset, encoding) { + return bidirectionalIndexOf(this, val, byteOffset, encoding, true) +} + +Buffer.prototype.lastIndexOf = function lastIndexOf (val, byteOffset, encoding) { + return bidirectionalIndexOf(this, val, byteOffset, encoding, false) +} + +function hexWrite (buf, string, offset, length) { + offset = Number(offset) || 0 + var remaining = buf.length - offset + if (!length) { + length = remaining + } else { + length = Number(length) + if (length > remaining) { + length = remaining + } + } + + var strLen = string.length + + if (length > strLen / 2) { + length = strLen / 2 + } + for (var i = 0; i < length; ++i) { + var parsed = parseInt(string.substr(i * 2, 2), 16) + if (numberIsNaN(parsed)) return i + buf[offset + i] = parsed + } + return i +} + +function utf8Write (buf, string, offset, length) { + return blitBuffer(utf8ToBytes(string, buf.length - offset), buf, offset, length) +} + +function asciiWrite (buf, string, offset, length) { + return blitBuffer(asciiToBytes(string), buf, offset, length) +} + +function latin1Write (buf, string, offset, length) { + return asciiWrite(buf, string, offset, length) +} + +function base64Write (buf, string, offset, length) { + return blitBuffer(base64ToBytes(string), buf, offset, length) +} + +function ucs2Write (buf, string, offset, length) { + return blitBuffer(utf16leToBytes(string, buf.length - offset), buf, offset, length) +} + +Buffer.prototype.write = function write (string, offset, length, encoding) { + // Buffer#write(string) + if (offset === undefined) { + encoding = 'utf8' + length = this.length + offset = 0 + // Buffer#write(string, encoding) + } else if (length === undefined && typeof offset === 'string') { + encoding = offset + length = this.length + offset = 0 + // Buffer#write(string, offset[, length][, encoding]) + } else if (isFinite(offset)) { + offset = offset >>> 0 + if (isFinite(length)) { + length = length >>> 0 + if (encoding === undefined) encoding = 'utf8' + } else { + encoding = length + length = undefined + } + } else { + throw new Error( + 'Buffer.write(string, encoding, offset[, length]) is no longer supported' + ) + } + + var remaining = this.length - offset + if (length === undefined || length > remaining) length = remaining + + if ((string.length > 0 && (length < 0 || offset < 0)) || offset > this.length) { + throw new RangeError('Attempt to write outside buffer bounds') + } + + if (!encoding) encoding = 'utf8' + + var loweredCase = false + for (;;) { + switch (encoding) { + case 'hex': + return hexWrite(this, string, offset, length) + + case 'utf8': + case 'utf-8': + return utf8Write(this, string, offset, length) + + case 'ascii': + return asciiWrite(this, string, offset, length) + + case 'latin1': + case 'binary': + return latin1Write(this, string, offset, length) + + case 'base64': + // Warning: maxLength not taken into account in base64Write + return base64Write(this, string, offset, length) + + case 'ucs2': + case 'ucs-2': + case 'utf16le': + case 'utf-16le': + return ucs2Write(this, string, offset, length) + + default: + if (loweredCase) throw new TypeError('Unknown encoding: ' + encoding) + encoding = ('' + encoding).toLowerCase() + loweredCase = true + } + } +} + +Buffer.prototype.toJSON = function toJSON () { + return { + type: 'Buffer', + data: Array.prototype.slice.call(this._arr || this, 0) + } +} + +function base64Slice (buf, start, end) { + if (start === 0 && end === buf.length) { + return base64.fromByteArray(buf) + } else { + return base64.fromByteArray(buf.slice(start, end)) + } +} + +function utf8Slice (buf, start, end) { + end = Math.min(buf.length, end) + var res = [] + + var i = start + while (i < end) { + var firstByte = buf[i] + var codePoint = null + var bytesPerSequence = (firstByte > 0xEF) ? 4 + : (firstByte > 0xDF) ? 3 + : (firstByte > 0xBF) ? 2 + : 1 + + if (i + bytesPerSequence <= end) { + var secondByte, thirdByte, fourthByte, tempCodePoint + + switch (bytesPerSequence) { + case 1: + if (firstByte < 0x80) { + codePoint = firstByte + } + break + case 2: + secondByte = buf[i + 1] + if ((secondByte & 0xC0) === 0x80) { + tempCodePoint = (firstByte & 0x1F) << 0x6 | (secondByte & 0x3F) + if (tempCodePoint > 0x7F) { + codePoint = tempCodePoint + } + } + break + case 3: + secondByte = buf[i + 1] + thirdByte = buf[i + 2] + if ((secondByte & 0xC0) === 0x80 && (thirdByte & 0xC0) === 0x80) { + tempCodePoint = (firstByte & 0xF) << 0xC | (secondByte & 0x3F) << 0x6 | (thirdByte & 0x3F) + if (tempCodePoint > 0x7FF && (tempCodePoint < 0xD800 || tempCodePoint > 0xDFFF)) { + codePoint = tempCodePoint + } + } + break + case 4: + secondByte = buf[i + 1] + thirdByte = buf[i + 2] + fourthByte = buf[i + 3] + if ((secondByte & 0xC0) === 0x80 && (thirdByte & 0xC0) === 0x80 && (fourthByte & 0xC0) === 0x80) { + tempCodePoint = (firstByte & 0xF) << 0x12 | (secondByte & 0x3F) << 0xC | (thirdByte & 0x3F) << 0x6 | (fourthByte & 0x3F) + if (tempCodePoint > 0xFFFF && tempCodePoint < 0x110000) { + codePoint = tempCodePoint + } + } + } + } + + if (codePoint === null) { + // we did not generate a valid codePoint so insert a + // replacement char (U+FFFD) and advance only 1 byte + codePoint = 0xFFFD + bytesPerSequence = 1 + } else if (codePoint > 0xFFFF) { + // encode to utf16 (surrogate pair dance) + codePoint -= 0x10000 + res.push(codePoint >>> 10 & 0x3FF | 0xD800) + codePoint = 0xDC00 | codePoint & 0x3FF + } + + res.push(codePoint) + i += bytesPerSequence + } + + return decodeCodePointsArray(res) +} + +// Based on http://stackoverflow.com/a/22747272/680742, the browser with +// the lowest limit is Chrome, with 0x10000 args. +// We go 1 magnitude less, for safety +var MAX_ARGUMENTS_LENGTH = 0x1000 + +function decodeCodePointsArray (codePoints) { + var len = codePoints.length + if (len <= MAX_ARGUMENTS_LENGTH) { + return String.fromCharCode.apply(String, codePoints) // avoid extra slice() + } + + // Decode in chunks to avoid "call stack size exceeded". + var res = '' + var i = 0 + while (i < len) { + res += String.fromCharCode.apply( + String, + codePoints.slice(i, i += MAX_ARGUMENTS_LENGTH) + ) + } + return res +} + +function asciiSlice (buf, start, end) { + var ret = '' + end = Math.min(buf.length, end) + + for (var i = start; i < end; ++i) { + ret += String.fromCharCode(buf[i] & 0x7F) + } + return ret +} + +function latin1Slice (buf, start, end) { + var ret = '' + end = Math.min(buf.length, end) + + for (var i = start; i < end; ++i) { + ret += String.fromCharCode(buf[i]) + } + return ret +} + +function hexSlice (buf, start, end) { + var len = buf.length + + if (!start || start < 0) start = 0 + if (!end || end < 0 || end > len) end = len + + var out = '' + for (var i = start; i < end; ++i) { + out += toHex(buf[i]) + } + return out +} + +function utf16leSlice (buf, start, end) { + var bytes = buf.slice(start, end) + var res = '' + for (var i = 0; i < bytes.length; i += 2) { + res += String.fromCharCode(bytes[i] + (bytes[i + 1] * 256)) + } + return res +} + +Buffer.prototype.slice = function slice (start, end) { + var len = this.length + start = ~~start + end = end === undefined ? len : ~~end + + if (start < 0) { + start += len + if (start < 0) start = 0 + } else if (start > len) { + start = len + } + + if (end < 0) { + end += len + if (end < 0) end = 0 + } else if (end > len) { + end = len + } + + if (end < start) end = start + + var newBuf = this.subarray(start, end) + // Return an augmented `Uint8Array` instance + newBuf.__proto__ = Buffer.prototype + return newBuf +} + +/* + * Need to make sure that buffer isn't trying to write out of bounds. + */ +function checkOffset (offset, ext, length) { + if ((offset % 1) !== 0 || offset < 0) throw new RangeError('offset is not uint') + if (offset + ext > length) throw new RangeError('Trying to access beyond buffer length') +} + +Buffer.prototype.readUIntLE = function readUIntLE (offset, byteLength, noAssert) { + offset = offset >>> 0 + byteLength = byteLength >>> 0 + if (!noAssert) checkOffset(offset, byteLength, this.length) + + var val = this[offset] + var mul = 1 + var i = 0 + while (++i < byteLength && (mul *= 0x100)) { + val += this[offset + i] * mul + } + + return val +} + +Buffer.prototype.readUIntBE = function readUIntBE (offset, byteLength, noAssert) { + offset = offset >>> 0 + byteLength = byteLength >>> 0 + if (!noAssert) { + checkOffset(offset, byteLength, this.length) + } + + var val = this[offset + --byteLength] + var mul = 1 + while (byteLength > 0 && (mul *= 0x100)) { + val += this[offset + --byteLength] * mul + } + + return val +} + +Buffer.prototype.readUInt8 = function readUInt8 (offset, noAssert) { + offset = offset >>> 0 + if (!noAssert) checkOffset(offset, 1, this.length) + return this[offset] +} + +Buffer.prototype.readUInt16LE = function readUInt16LE (offset, noAssert) { + offset = offset >>> 0 + if (!noAssert) checkOffset(offset, 2, this.length) + return this[offset] | (this[offset + 1] << 8) +} + +Buffer.prototype.readUInt16BE = function readUInt16BE (offset, noAssert) { + offset = offset >>> 0 + if (!noAssert) checkOffset(offset, 2, this.length) + return (this[offset] << 8) | this[offset + 1] +} + +Buffer.prototype.readUInt32LE = function readUInt32LE (offset, noAssert) { + offset = offset >>> 0 + if (!noAssert) checkOffset(offset, 4, this.length) + + return ((this[offset]) | + (this[offset + 1] << 8) | + (this[offset + 2] << 16)) + + (this[offset + 3] * 0x1000000) +} + +Buffer.prototype.readUInt32BE = function readUInt32BE (offset, noAssert) { + offset = offset >>> 0 + if (!noAssert) checkOffset(offset, 4, this.length) + + return (this[offset] * 0x1000000) + + ((this[offset + 1] << 16) | + (this[offset + 2] << 8) | + this[offset + 3]) +} + +Buffer.prototype.readIntLE = function readIntLE (offset, byteLength, noAssert) { + offset = offset >>> 0 + byteLength = byteLength >>> 0 + if (!noAssert) checkOffset(offset, byteLength, this.length) + + var val = this[offset] + var mul = 1 + var i = 0 + while (++i < byteLength && (mul *= 0x100)) { + val += this[offset + i] * mul + } + mul *= 0x80 + + if (val >= mul) val -= Math.pow(2, 8 * byteLength) + + return val +} + +Buffer.prototype.readIntBE = function readIntBE (offset, byteLength, noAssert) { + offset = offset >>> 0 + byteLength = byteLength >>> 0 + if (!noAssert) checkOffset(offset, byteLength, this.length) + + var i = byteLength + var mul = 1 + var val = this[offset + --i] + while (i > 0 && (mul *= 0x100)) { + val += this[offset + --i] * mul + } + mul *= 0x80 + + if (val >= mul) val -= Math.pow(2, 8 * byteLength) + + return val +} + +Buffer.prototype.readInt8 = function readInt8 (offset, noAssert) { + offset = offset >>> 0 + if (!noAssert) checkOffset(offset, 1, this.length) + if (!(this[offset] & 0x80)) return (this[offset]) + return ((0xff - this[offset] + 1) * -1) +} + +Buffer.prototype.readInt16LE = function readInt16LE (offset, noAssert) { + offset = offset >>> 0 + if (!noAssert) checkOffset(offset, 2, this.length) + var val = this[offset] | (this[offset + 1] << 8) + return (val & 0x8000) ? val | 0xFFFF0000 : val +} + +Buffer.prototype.readInt16BE = function readInt16BE (offset, noAssert) { + offset = offset >>> 0 + if (!noAssert) checkOffset(offset, 2, this.length) + var val = this[offset + 1] | (this[offset] << 8) + return (val & 0x8000) ? val | 0xFFFF0000 : val +} + +Buffer.prototype.readInt32LE = function readInt32LE (offset, noAssert) { + offset = offset >>> 0 + if (!noAssert) checkOffset(offset, 4, this.length) + + return (this[offset]) | + (this[offset + 1] << 8) | + (this[offset + 2] << 16) | + (this[offset + 3] << 24) +} + +Buffer.prototype.readInt32BE = function readInt32BE (offset, noAssert) { + offset = offset >>> 0 + if (!noAssert) checkOffset(offset, 4, this.length) + + return (this[offset] << 24) | + (this[offset + 1] << 16) | + (this[offset + 2] << 8) | + (this[offset + 3]) +} + +Buffer.prototype.readFloatLE = function readFloatLE (offset, noAssert) { + offset = offset >>> 0 + if (!noAssert) checkOffset(offset, 4, this.length) + return ieee754.read(this, offset, true, 23, 4) +} + +Buffer.prototype.readFloatBE = function readFloatBE (offset, noAssert) { + offset = offset >>> 0 + if (!noAssert) checkOffset(offset, 4, this.length) + return ieee754.read(this, offset, false, 23, 4) +} + +Buffer.prototype.readDoubleLE = function readDoubleLE (offset, noAssert) { + offset = offset >>> 0 + if (!noAssert) checkOffset(offset, 8, this.length) + return ieee754.read(this, offset, true, 52, 8) +} + +Buffer.prototype.readDoubleBE = function readDoubleBE (offset, noAssert) { + offset = offset >>> 0 + if (!noAssert) checkOffset(offset, 8, this.length) + return ieee754.read(this, offset, false, 52, 8) +} + +function checkInt (buf, value, offset, ext, max, min) { + if (!Buffer.isBuffer(buf)) throw new TypeError('"buffer" argument must be a Buffer instance') + if (value > max || value < min) throw new RangeError('"value" argument is out of bounds') + if (offset + ext > buf.length) throw new RangeError('Index out of range') +} + +Buffer.prototype.writeUIntLE = function writeUIntLE (value, offset, byteLength, noAssert) { + value = +value + offset = offset >>> 0 + byteLength = byteLength >>> 0 + if (!noAssert) { + var maxBytes = Math.pow(2, 8 * byteLength) - 1 + checkInt(this, value, offset, byteLength, maxBytes, 0) + } + + var mul = 1 + var i = 0 + this[offset] = value & 0xFF + while (++i < byteLength && (mul *= 0x100)) { + this[offset + i] = (value / mul) & 0xFF + } + + return offset + byteLength +} + +Buffer.prototype.writeUIntBE = function writeUIntBE (value, offset, byteLength, noAssert) { + value = +value + offset = offset >>> 0 + byteLength = byteLength >>> 0 + if (!noAssert) { + var maxBytes = Math.pow(2, 8 * byteLength) - 1 + checkInt(this, value, offset, byteLength, maxBytes, 0) + } + + var i = byteLength - 1 + var mul = 1 + this[offset + i] = value & 0xFF + while (--i >= 0 && (mul *= 0x100)) { + this[offset + i] = (value / mul) & 0xFF + } + + return offset + byteLength +} + +Buffer.prototype.writeUInt8 = function writeUInt8 (value, offset, noAssert) { + value = +value + offset = offset >>> 0 + if (!noAssert) checkInt(this, value, offset, 1, 0xff, 0) + this[offset] = (value & 0xff) + return offset + 1 +} + +Buffer.prototype.writeUInt16LE = function writeUInt16LE (value, offset, noAssert) { + value = +value + offset = offset >>> 0 + if (!noAssert) checkInt(this, value, offset, 2, 0xffff, 0) + this[offset] = (value & 0xff) + this[offset + 1] = (value >>> 8) + return offset + 2 +} + +Buffer.prototype.writeUInt16BE = function writeUInt16BE (value, offset, noAssert) { + value = +value + offset = offset >>> 0 + if (!noAssert) checkInt(this, value, offset, 2, 0xffff, 0) + this[offset] = (value >>> 8) + this[offset + 1] = (value & 0xff) + return offset + 2 +} + +Buffer.prototype.writeUInt32LE = function writeUInt32LE (value, offset, noAssert) { + value = +value + offset = offset >>> 0 + if (!noAssert) checkInt(this, value, offset, 4, 0xffffffff, 0) + this[offset + 3] = (value >>> 24) + this[offset + 2] = (value >>> 16) + this[offset + 1] = (value >>> 8) + this[offset] = (value & 0xff) + return offset + 4 +} + +Buffer.prototype.writeUInt32BE = function writeUInt32BE (value, offset, noAssert) { + value = +value + offset = offset >>> 0 + if (!noAssert) checkInt(this, value, offset, 4, 0xffffffff, 0) + this[offset] = (value >>> 24) + this[offset + 1] = (value >>> 16) + this[offset + 2] = (value >>> 8) + this[offset + 3] = (value & 0xff) + return offset + 4 +} + +Buffer.prototype.writeIntLE = function writeIntLE (value, offset, byteLength, noAssert) { + value = +value + offset = offset >>> 0 + if (!noAssert) { + var limit = Math.pow(2, (8 * byteLength) - 1) + + checkInt(this, value, offset, byteLength, limit - 1, -limit) + } + + var i = 0 + var mul = 1 + var sub = 0 + this[offset] = value & 0xFF + while (++i < byteLength && (mul *= 0x100)) { + if (value < 0 && sub === 0 && this[offset + i - 1] !== 0) { + sub = 1 + } + this[offset + i] = ((value / mul) >> 0) - sub & 0xFF + } + + return offset + byteLength +} + +Buffer.prototype.writeIntBE = function writeIntBE (value, offset, byteLength, noAssert) { + value = +value + offset = offset >>> 0 + if (!noAssert) { + var limit = Math.pow(2, (8 * byteLength) - 1) + + checkInt(this, value, offset, byteLength, limit - 1, -limit) + } + + var i = byteLength - 1 + var mul = 1 + var sub = 0 + this[offset + i] = value & 0xFF + while (--i >= 0 && (mul *= 0x100)) { + if (value < 0 && sub === 0 && this[offset + i + 1] !== 0) { + sub = 1 + } + this[offset + i] = ((value / mul) >> 0) - sub & 0xFF + } + + return offset + byteLength +} + +Buffer.prototype.writeInt8 = function writeInt8 (value, offset, noAssert) { + value = +value + offset = offset >>> 0 + if (!noAssert) checkInt(this, value, offset, 1, 0x7f, -0x80) + if (value < 0) value = 0xff + value + 1 + this[offset] = (value & 0xff) + return offset + 1 +} + +Buffer.prototype.writeInt16LE = function writeInt16LE (value, offset, noAssert) { + value = +value + offset = offset >>> 0 + if (!noAssert) checkInt(this, value, offset, 2, 0x7fff, -0x8000) + this[offset] = (value & 0xff) + this[offset + 1] = (value >>> 8) + return offset + 2 +} + +Buffer.prototype.writeInt16BE = function writeInt16BE (value, offset, noAssert) { + value = +value + offset = offset >>> 0 + if (!noAssert) checkInt(this, value, offset, 2, 0x7fff, -0x8000) + this[offset] = (value >>> 8) + this[offset + 1] = (value & 0xff) + return offset + 2 +} + +Buffer.prototype.writeInt32LE = function writeInt32LE (value, offset, noAssert) { + value = +value + offset = offset >>> 0 + if (!noAssert) checkInt(this, value, offset, 4, 0x7fffffff, -0x80000000) + this[offset] = (value & 0xff) + this[offset + 1] = (value >>> 8) + this[offset + 2] = (value >>> 16) + this[offset + 3] = (value >>> 24) + return offset + 4 +} + +Buffer.prototype.writeInt32BE = function writeInt32BE (value, offset, noAssert) { + value = +value + offset = offset >>> 0 + if (!noAssert) checkInt(this, value, offset, 4, 0x7fffffff, -0x80000000) + if (value < 0) value = 0xffffffff + value + 1 + this[offset] = (value >>> 24) + this[offset + 1] = (value >>> 16) + this[offset + 2] = (value >>> 8) + this[offset + 3] = (value & 0xff) + return offset + 4 +} + +function checkIEEE754 (buf, value, offset, ext, max, min) { + if (offset + ext > buf.length) throw new RangeError('Index out of range') + if (offset < 0) throw new RangeError('Index out of range') +} + +function writeFloat (buf, value, offset, littleEndian, noAssert) { + value = +value + offset = offset >>> 0 + if (!noAssert) { + checkIEEE754(buf, value, offset, 4, 3.4028234663852886e+38, -3.4028234663852886e+38) + } + ieee754.write(buf, value, offset, littleEndian, 23, 4) + return offset + 4 +} + +Buffer.prototype.writeFloatLE = function writeFloatLE (value, offset, noAssert) { + return writeFloat(this, value, offset, true, noAssert) +} + +Buffer.prototype.writeFloatBE = function writeFloatBE (value, offset, noAssert) { + return writeFloat(this, value, offset, false, noAssert) +} + +function writeDouble (buf, value, offset, littleEndian, noAssert) { + value = +value + offset = offset >>> 0 + if (!noAssert) { + checkIEEE754(buf, value, offset, 8, 1.7976931348623157E+308, -1.7976931348623157E+308) + } + ieee754.write(buf, value, offset, littleEndian, 52, 8) + return offset + 8 +} + +Buffer.prototype.writeDoubleLE = function writeDoubleLE (value, offset, noAssert) { + return writeDouble(this, value, offset, true, noAssert) +} + +Buffer.prototype.writeDoubleBE = function writeDoubleBE (value, offset, noAssert) { + return writeDouble(this, value, offset, false, noAssert) +} + +// copy(targetBuffer, targetStart=0, sourceStart=0, sourceEnd=buffer.length) +Buffer.prototype.copy = function copy (target, targetStart, start, end) { + if (!Buffer.isBuffer(target)) throw new TypeError('argument should be a Buffer') + if (!start) start = 0 + if (!end && end !== 0) end = this.length + if (targetStart >= target.length) targetStart = target.length + if (!targetStart) targetStart = 0 + if (end > 0 && end < start) end = start + + // Copy 0 bytes; we're done + if (end === start) return 0 + if (target.length === 0 || this.length === 0) return 0 + + // Fatal error conditions + if (targetStart < 0) { + throw new RangeError('targetStart out of bounds') + } + if (start < 0 || start >= this.length) throw new RangeError('Index out of range') + if (end < 0) throw new RangeError('sourceEnd out of bounds') + + // Are we oob? + if (end > this.length) end = this.length + if (target.length - targetStart < end - start) { + end = target.length - targetStart + start + } + + var len = end - start + + if (this === target && typeof Uint8Array.prototype.copyWithin === 'function') { + // Use built-in when available, missing from IE11 + this.copyWithin(targetStart, start, end) + } else if (this === target && start < targetStart && targetStart < end) { + // descending copy from end + for (var i = len - 1; i >= 0; --i) { + target[i + targetStart] = this[i + start] + } + } else { + Uint8Array.prototype.set.call( + target, + this.subarray(start, end), + targetStart + ) + } + + return len +} + +// Usage: +// buffer.fill(number[, offset[, end]]) +// buffer.fill(buffer[, offset[, end]]) +// buffer.fill(string[, offset[, end]][, encoding]) +Buffer.prototype.fill = function fill (val, start, end, encoding) { + // Handle string cases: + if (typeof val === 'string') { + if (typeof start === 'string') { + encoding = start + start = 0 + end = this.length + } else if (typeof end === 'string') { + encoding = end + end = this.length + } + if (encoding !== undefined && typeof encoding !== 'string') { + throw new TypeError('encoding must be a string') + } + if (typeof encoding === 'string' && !Buffer.isEncoding(encoding)) { + throw new TypeError('Unknown encoding: ' + encoding) + } + if (val.length === 1) { + var code = val.charCodeAt(0) + if ((encoding === 'utf8' && code < 128) || + encoding === 'latin1') { + // Fast path: If `val` fits into a single byte, use that numeric value. + val = code + } + } + } else if (typeof val === 'number') { + val = val & 255 + } + + // Invalid ranges are not set to a default, so can range check early. + if (start < 0 || this.length < start || this.length < end) { + throw new RangeError('Out of range index') + } + + if (end <= start) { + return this + } + + start = start >>> 0 + end = end === undefined ? this.length : end >>> 0 + + if (!val) val = 0 + + var i + if (typeof val === 'number') { + for (i = start; i < end; ++i) { + this[i] = val + } + } else { + var bytes = Buffer.isBuffer(val) + ? val + : Buffer.from(val, encoding) + var len = bytes.length + if (len === 0) { + throw new TypeError('The value "' + val + + '" is invalid for argument "value"') + } + for (i = 0; i < end - start; ++i) { + this[i + start] = bytes[i % len] + } + } + + return this +} + +// HELPER FUNCTIONS +// ================ + +var INVALID_BASE64_RE = /[^+/0-9A-Za-z-_]/g + +function base64clean (str) { + // Node takes equal signs as end of the Base64 encoding + str = str.split('=')[0] + // Node strips out invalid characters like \n and \t from the string, base64-js does not + str = str.trim().replace(INVALID_BASE64_RE, '') + // Node converts strings with length < 2 to '' + if (str.length < 2) return '' + // Node allows for non-padded base64 strings (missing trailing ===), base64-js does not + while (str.length % 4 !== 0) { + str = str + '=' + } + return str +} + +function toHex (n) { + if (n < 16) return '0' + n.toString(16) + return n.toString(16) +} + +function utf8ToBytes (string, units) { + units = units || Infinity + var codePoint + var length = string.length + var leadSurrogate = null + var bytes = [] + + for (var i = 0; i < length; ++i) { + codePoint = string.charCodeAt(i) + + // is surrogate component + if (codePoint > 0xD7FF && codePoint < 0xE000) { + // last char was a lead + if (!leadSurrogate) { + // no lead yet + if (codePoint > 0xDBFF) { + // unexpected trail + if ((units -= 3) > -1) bytes.push(0xEF, 0xBF, 0xBD) + continue + } else if (i + 1 === length) { + // unpaired lead + if ((units -= 3) > -1) bytes.push(0xEF, 0xBF, 0xBD) + continue + } + + // valid lead + leadSurrogate = codePoint + + continue + } + + // 2 leads in a row + if (codePoint < 0xDC00) { + if ((units -= 3) > -1) bytes.push(0xEF, 0xBF, 0xBD) + leadSurrogate = codePoint + continue + } + + // valid surrogate pair + codePoint = (leadSurrogate - 0xD800 << 10 | codePoint - 0xDC00) + 0x10000 + } else if (leadSurrogate) { + // valid bmp char, but last char was a lead + if ((units -= 3) > -1) bytes.push(0xEF, 0xBF, 0xBD) + } + + leadSurrogate = null + + // encode utf8 + if (codePoint < 0x80) { + if ((units -= 1) < 0) break + bytes.push(codePoint) + } else if (codePoint < 0x800) { + if ((units -= 2) < 0) break + bytes.push( + codePoint >> 0x6 | 0xC0, + codePoint & 0x3F | 0x80 + ) + } else if (codePoint < 0x10000) { + if ((units -= 3) < 0) break + bytes.push( + codePoint >> 0xC | 0xE0, + codePoint >> 0x6 & 0x3F | 0x80, + codePoint & 0x3F | 0x80 + ) + } else if (codePoint < 0x110000) { + if ((units -= 4) < 0) break + bytes.push( + codePoint >> 0x12 | 0xF0, + codePoint >> 0xC & 0x3F | 0x80, + codePoint >> 0x6 & 0x3F | 0x80, + codePoint & 0x3F | 0x80 + ) + } else { + throw new Error('Invalid code point') + } + } + + return bytes +} + +function asciiToBytes (str) { + var byteArray = [] + for (var i = 0; i < str.length; ++i) { + // Node's code seems to be doing this and not & 0x7F.. + byteArray.push(str.charCodeAt(i) & 0xFF) + } + return byteArray +} + +function utf16leToBytes (str, units) { + var c, hi, lo + var byteArray = [] + for (var i = 0; i < str.length; ++i) { + if ((units -= 2) < 0) break + + c = str.charCodeAt(i) + hi = c >> 8 + lo = c % 256 + byteArray.push(lo) + byteArray.push(hi) + } + + return byteArray +} + +function base64ToBytes (str) { + return base64.toByteArray(base64clean(str)) +} + +function blitBuffer (src, dst, offset, length) { + for (var i = 0; i < length; ++i) { + if ((i + offset >= dst.length) || (i >= src.length)) break + dst[i + offset] = src[i] + } + return i +} + +// ArrayBuffer or Uint8Array objects from other contexts (i.e. iframes) do not pass +// the `instanceof` check but they should be treated as of that type. +// See: https://github.com/feross/buffer/issues/166 +function isInstance (obj, type) { + return obj instanceof type || + (obj != null && obj.constructor != null && obj.constructor.name != null && + obj.constructor.name === type.name) +} +function numberIsNaN (obj) { + // For IE11 support + return obj !== obj // eslint-disable-line no-self-compare +} + +}).call(this)}).call(this,require("buffer").Buffer) +},{"base64-js":17,"buffer":64,"ieee754":142}],65:[function(require,module,exports){ +'use strict'; + +var GetIntrinsic = require('get-intrinsic'); + +var callBind = require('./'); + +var $indexOf = callBind(GetIntrinsic('String.prototype.indexOf')); + +module.exports = function callBoundIntrinsic(name, allowMissing) { + var intrinsic = GetIntrinsic(name, !!allowMissing); + if (typeof intrinsic === 'function' && $indexOf(name, '.prototype.') > -1) { + return callBind(intrinsic); + } + return intrinsic; +}; + +},{"./":66,"get-intrinsic":109}],66:[function(require,module,exports){ +'use strict'; + +var bind = require('function-bind'); +var GetIntrinsic = require('get-intrinsic'); + +var $apply = GetIntrinsic('%Function.prototype.apply%'); +var $call = GetIntrinsic('%Function.prototype.call%'); +var $reflectApply = GetIntrinsic('%Reflect.apply%', true) || bind.call($call, $apply); + +var $gOPD = GetIntrinsic('%Object.getOwnPropertyDescriptor%', true); +var $defineProperty = GetIntrinsic('%Object.defineProperty%', true); +var $max = GetIntrinsic('%Math.max%'); + +if ($defineProperty) { + try { + $defineProperty({}, 'a', { value: 1 }); + } catch (e) { + // IE 8 has a broken defineProperty + $defineProperty = null; + } +} + +module.exports = function callBind(originalFunction) { + var func = $reflectApply(bind, $call, arguments); + if ($gOPD && $defineProperty) { + var desc = $gOPD(func, 'length'); + if (desc.configurable) { + // original length, plus the receiver, minus any additional arguments (after the receiver) + $defineProperty( + func, + 'length', + { value: 1 + $max(0, originalFunction.length - (arguments.length - 1)) } + ); + } + } + return func; +}; + +var applyBind = function applyBind() { + return $reflectApply(bind, $apply, arguments); +}; + +if ($defineProperty) { + $defineProperty(module.exports, 'apply', { value: applyBind }); +} else { + module.exports.apply = applyBind; +} + +},{"function-bind":108,"get-intrinsic":109}],67:[function(require,module,exports){ +var Buffer = require('safe-buffer').Buffer +var Transform = require('stream').Transform +var StringDecoder = require('string_decoder').StringDecoder +var inherits = require('inherits') + +function CipherBase (hashMode) { + Transform.call(this) + this.hashMode = typeof hashMode === 'string' + if (this.hashMode) { + this[hashMode] = this._finalOrDigest + } else { + this.final = this._finalOrDigest + } + if (this._final) { + this.__final = this._final + this._final = null + } + this._decoder = null + this._encoding = null +} +inherits(CipherBase, Transform) + +CipherBase.prototype.update = function (data, inputEnc, outputEnc) { + if (typeof data === 'string') { + data = Buffer.from(data, inputEnc) + } + + var outData = this._update(data) + if (this.hashMode) return this + + if (outputEnc) { + outData = this._toString(outData, outputEnc) + } + + return outData +} + +CipherBase.prototype.setAutoPadding = function () {} +CipherBase.prototype.getAuthTag = function () { + throw new Error('trying to get auth tag in unsupported state') +} + +CipherBase.prototype.setAuthTag = function () { + throw new Error('trying to set auth tag in unsupported state') +} + +CipherBase.prototype.setAAD = function () { + throw new Error('trying to set aad in unsupported state') +} + +CipherBase.prototype._transform = function (data, _, next) { + var err + try { + if (this.hashMode) { + this._update(data) + } else { + this.push(this._update(data)) + } + } catch (e) { + err = e + } finally { + next(err) + } +} +CipherBase.prototype._flush = function (done) { + var err + try { + this.push(this.__final()) + } catch (e) { + err = e + } + + done(err) +} +CipherBase.prototype._finalOrDigest = function (outputEnc) { + var outData = this.__final() || Buffer.alloc(0) + if (outputEnc) { + outData = this._toString(outData, outputEnc, true) + } + return outData +} + +CipherBase.prototype._toString = function (value, enc, fin) { + if (!this._decoder) { + this._decoder = new StringDecoder(enc) + this._encoding = enc + } + + if (this._encoding !== enc) throw new Error('can\'t switch encodings') + + var out = this._decoder.write(value) + if (fin) { + out += this._decoder.end() + } + + return out +} + +module.exports = CipherBase + +},{"inherits":143,"safe-buffer":179,"stream":189,"string_decoder":204}],68:[function(require,module,exports){ +(function (Buffer){(function (){ +var elliptic = require('elliptic') +var BN = require('bn.js') + +module.exports = function createECDH (curve) { + return new ECDH(curve) +} + +var aliases = { + secp256k1: { + name: 'secp256k1', + byteLength: 32 + }, + secp224r1: { + name: 'p224', + byteLength: 28 + }, + prime256v1: { + name: 'p256', + byteLength: 32 + }, + prime192v1: { + name: 'p192', + byteLength: 24 + }, + ed25519: { + name: 'ed25519', + byteLength: 32 + }, + secp384r1: { + name: 'p384', + byteLength: 48 + }, + secp521r1: { + name: 'p521', + byteLength: 66 + } +} + +aliases.p224 = aliases.secp224r1 +aliases.p256 = aliases.secp256r1 = aliases.prime256v1 +aliases.p192 = aliases.secp192r1 = aliases.prime192v1 +aliases.p384 = aliases.secp384r1 +aliases.p521 = aliases.secp521r1 + +function ECDH (curve) { + this.curveType = aliases[curve] + if (!this.curveType) { + this.curveType = { + name: curve + } + } + this.curve = new elliptic.ec(this.curveType.name) // eslint-disable-line new-cap + this.keys = void 0 +} + +ECDH.prototype.generateKeys = function (enc, format) { + this.keys = this.curve.genKeyPair() + return this.getPublicKey(enc, format) +} + +ECDH.prototype.computeSecret = function (other, inenc, enc) { + inenc = inenc || 'utf8' + if (!Buffer.isBuffer(other)) { + other = new Buffer(other, inenc) + } + var otherPub = this.curve.keyFromPublic(other).getPublic() + var out = otherPub.mul(this.keys.getPrivate()).getX() + return formatReturnValue(out, enc, this.curveType.byteLength) +} + +ECDH.prototype.getPublicKey = function (enc, format) { + var key = this.keys.getPublic(format === 'compressed', true) + if (format === 'hybrid') { + if (key[key.length - 1] % 2) { + key[0] = 7 + } else { + key[0] = 6 + } + } + return formatReturnValue(key, enc) +} + +ECDH.prototype.getPrivateKey = function (enc) { + return formatReturnValue(this.keys.getPrivate(), enc) +} + +ECDH.prototype.setPublicKey = function (pub, enc) { + enc = enc || 'utf8' + if (!Buffer.isBuffer(pub)) { + pub = new Buffer(pub, enc) + } + this.keys._importPublic(pub) + return this +} + +ECDH.prototype.setPrivateKey = function (priv, enc) { + enc = enc || 'utf8' + if (!Buffer.isBuffer(priv)) { + priv = new Buffer(priv, enc) + } + + var _priv = new BN(priv) + _priv = _priv.toString(16) + this.keys = this.curve.genKeyPair() + this.keys._importPrivate(_priv) + return this +} + +function formatReturnValue (bn, enc, len) { + if (!Array.isArray(bn)) { + bn = bn.toArray() + } + var buf = new Buffer(bn) + if (len && buf.length < len) { + var zeros = new Buffer(len - buf.length) + zeros.fill(0) + buf = Buffer.concat([zeros, buf]) + } + if (!enc) { + return buf + } else { + return buf.toString(enc) + } +} + +}).call(this)}).call(this,require("buffer").Buffer) +},{"bn.js":69,"buffer":64,"elliptic":86}],69:[function(require,module,exports){ +arguments[4][15][0].apply(exports,arguments) +},{"buffer":20,"dup":15}],70:[function(require,module,exports){ +'use strict' +var inherits = require('inherits') +var MD5 = require('md5.js') +var RIPEMD160 = require('ripemd160') +var sha = require('sha.js') +var Base = require('cipher-base') + +function Hash (hash) { + Base.call(this, 'digest') + + this._hash = hash +} + +inherits(Hash, Base) + +Hash.prototype._update = function (data) { + this._hash.update(data) +} + +Hash.prototype._final = function () { + return this._hash.digest() +} + +module.exports = function createHash (alg) { + alg = alg.toLowerCase() + if (alg === 'md5') return new MD5() + if (alg === 'rmd160' || alg === 'ripemd160') return new RIPEMD160() + + return new Hash(sha(alg)) +} + +},{"cipher-base":67,"inherits":143,"md5.js":148,"ripemd160":178,"sha.js":182}],71:[function(require,module,exports){ +var MD5 = require('md5.js') + +module.exports = function (buffer) { + return new MD5().update(buffer).digest() +} + +},{"md5.js":148}],72:[function(require,module,exports){ +'use strict' +var inherits = require('inherits') +var Legacy = require('./legacy') +var Base = require('cipher-base') +var Buffer = require('safe-buffer').Buffer +var md5 = require('create-hash/md5') +var RIPEMD160 = require('ripemd160') + +var sha = require('sha.js') + +var ZEROS = Buffer.alloc(128) + +function Hmac (alg, key) { + Base.call(this, 'digest') + if (typeof key === 'string') { + key = Buffer.from(key) + } + + var blocksize = (alg === 'sha512' || alg === 'sha384') ? 128 : 64 + + this._alg = alg + this._key = key + if (key.length > blocksize) { + var hash = alg === 'rmd160' ? new RIPEMD160() : sha(alg) + key = hash.update(key).digest() + } else if (key.length < blocksize) { + key = Buffer.concat([key, ZEROS], blocksize) + } + + var ipad = this._ipad = Buffer.allocUnsafe(blocksize) + var opad = this._opad = Buffer.allocUnsafe(blocksize) + + for (var i = 0; i < blocksize; i++) { + ipad[i] = key[i] ^ 0x36 + opad[i] = key[i] ^ 0x5C + } + this._hash = alg === 'rmd160' ? new RIPEMD160() : sha(alg) + this._hash.update(ipad) +} + +inherits(Hmac, Base) + +Hmac.prototype._update = function (data) { + this._hash.update(data) +} + +Hmac.prototype._final = function () { + var h = this._hash.digest() + var hash = this._alg === 'rmd160' ? new RIPEMD160() : sha(this._alg) + return hash.update(this._opad).update(h).digest() +} + +module.exports = function createHmac (alg, key) { + alg = alg.toLowerCase() + if (alg === 'rmd160' || alg === 'ripemd160') { + return new Hmac('rmd160', key) + } + if (alg === 'md5') { + return new Legacy(md5, key) + } + return new Hmac(alg, key) +} + +},{"./legacy":73,"cipher-base":67,"create-hash/md5":71,"inherits":143,"ripemd160":178,"safe-buffer":179,"sha.js":182}],73:[function(require,module,exports){ +'use strict' +var inherits = require('inherits') +var Buffer = require('safe-buffer').Buffer + +var Base = require('cipher-base') + +var ZEROS = Buffer.alloc(128) +var blocksize = 64 + +function Hmac (alg, key) { + Base.call(this, 'digest') + if (typeof key === 'string') { + key = Buffer.from(key) + } + + this._alg = alg + this._key = key + + if (key.length > blocksize) { + key = alg(key) + } else if (key.length < blocksize) { + key = Buffer.concat([key, ZEROS], blocksize) + } + + var ipad = this._ipad = Buffer.allocUnsafe(blocksize) + var opad = this._opad = Buffer.allocUnsafe(blocksize) + + for (var i = 0; i < blocksize; i++) { + ipad[i] = key[i] ^ 0x36 + opad[i] = key[i] ^ 0x5C + } + + this._hash = [ipad] +} + +inherits(Hmac, Base) + +Hmac.prototype._update = function (data) { + this._hash.push(data) +} + +Hmac.prototype._final = function () { + var h = this._alg(Buffer.concat(this._hash)) + return this._alg(Buffer.concat([this._opad, h])) +} +module.exports = Hmac + +},{"cipher-base":67,"inherits":143,"safe-buffer":179}],74:[function(require,module,exports){ +'use strict' + +exports.randomBytes = exports.rng = exports.pseudoRandomBytes = exports.prng = require('randombytes') +exports.createHash = exports.Hash = require('create-hash') +exports.createHmac = exports.Hmac = require('create-hmac') + +var algos = require('browserify-sign/algos') +var algoKeys = Object.keys(algos) +var hashes = ['sha1', 'sha224', 'sha256', 'sha384', 'sha512', 'md5', 'rmd160'].concat(algoKeys) +exports.getHashes = function () { + return hashes +} + +var p = require('pbkdf2') +exports.pbkdf2 = p.pbkdf2 +exports.pbkdf2Sync = p.pbkdf2Sync + +var aes = require('browserify-cipher') + +exports.Cipher = aes.Cipher +exports.createCipher = aes.createCipher +exports.Cipheriv = aes.Cipheriv +exports.createCipheriv = aes.createCipheriv +exports.Decipher = aes.Decipher +exports.createDecipher = aes.createDecipher +exports.Decipheriv = aes.Decipheriv +exports.createDecipheriv = aes.createDecipheriv +exports.getCiphers = aes.getCiphers +exports.listCiphers = aes.listCiphers + +var dh = require('diffie-hellman') + +exports.DiffieHellmanGroup = dh.DiffieHellmanGroup +exports.createDiffieHellmanGroup = dh.createDiffieHellmanGroup +exports.getDiffieHellman = dh.getDiffieHellman +exports.createDiffieHellman = dh.createDiffieHellman +exports.DiffieHellman = dh.DiffieHellman + +var sign = require('browserify-sign') + +exports.createSign = sign.createSign +exports.Sign = sign.Sign +exports.createVerify = sign.createVerify +exports.Verify = sign.Verify + +exports.createECDH = require('create-ecdh') + +var publicEncrypt = require('public-encrypt') + +exports.publicEncrypt = publicEncrypt.publicEncrypt +exports.privateEncrypt = publicEncrypt.privateEncrypt +exports.publicDecrypt = publicEncrypt.publicDecrypt +exports.privateDecrypt = publicEncrypt.privateDecrypt + +// the least I can do is make error messages for the rest of the node.js/crypto api. +// ;[ +// 'createCredentials' +// ].forEach(function (name) { +// exports[name] = function () { +// throw new Error([ +// 'sorry, ' + name + ' is not implemented yet', +// 'we accept pull requests', +// 'https://github.com/crypto-browserify/crypto-browserify' +// ].join('\n')) +// } +// }) + +var rf = require('randomfill') + +exports.randomFill = rf.randomFill +exports.randomFillSync = rf.randomFillSync + +exports.createCredentials = function () { + throw new Error([ + 'sorry, createCredentials is not implemented yet', + 'we accept pull requests', + 'https://github.com/crypto-browserify/crypto-browserify' + ].join('\n')) +} + +exports.constants = { + 'DH_CHECK_P_NOT_SAFE_PRIME': 2, + 'DH_CHECK_P_NOT_PRIME': 1, + 'DH_UNABLE_TO_CHECK_GENERATOR': 4, + 'DH_NOT_SUITABLE_GENERATOR': 8, + 'NPN_ENABLED': 1, + 'ALPN_ENABLED': 1, + 'RSA_PKCS1_PADDING': 1, + 'RSA_SSLV23_PADDING': 2, + 'RSA_NO_PADDING': 3, + 'RSA_PKCS1_OAEP_PADDING': 4, + 'RSA_X931_PADDING': 5, + 'RSA_PKCS1_PSS_PADDING': 6, + 'POINT_CONVERSION_COMPRESSED': 2, + 'POINT_CONVERSION_UNCOMPRESSED': 4, + 'POINT_CONVERSION_HYBRID': 6 +} + +},{"browserify-cipher":38,"browserify-sign":45,"browserify-sign/algos":42,"create-ecdh":68,"create-hash":70,"create-hmac":72,"diffie-hellman":81,"pbkdf2":158,"public-encrypt":165,"randombytes":176,"randomfill":177}],75:[function(require,module,exports){ +'use strict'; + +exports.utils = require('./des/utils'); +exports.Cipher = require('./des/cipher'); +exports.DES = require('./des/des'); +exports.CBC = require('./des/cbc'); +exports.EDE = require('./des/ede'); + +},{"./des/cbc":76,"./des/cipher":77,"./des/des":78,"./des/ede":79,"./des/utils":80}],76:[function(require,module,exports){ +'use strict'; + +var assert = require('minimalistic-assert'); +var inherits = require('inherits'); + +var proto = {}; + +function CBCState(iv) { + assert.equal(iv.length, 8, 'Invalid IV length'); + + this.iv = new Array(8); + for (var i = 0; i < this.iv.length; i++) + this.iv[i] = iv[i]; +} + +function instantiate(Base) { + function CBC(options) { + Base.call(this, options); + this._cbcInit(); + } + inherits(CBC, Base); + + var keys = Object.keys(proto); + for (var i = 0; i < keys.length; i++) { + var key = keys[i]; + CBC.prototype[key] = proto[key]; + } + + CBC.create = function create(options) { + return new CBC(options); + }; + + return CBC; +} + +exports.instantiate = instantiate; + +proto._cbcInit = function _cbcInit() { + var state = new CBCState(this.options.iv); + this._cbcState = state; +}; + +proto._update = function _update(inp, inOff, out, outOff) { + var state = this._cbcState; + var superProto = this.constructor.super_.prototype; + + var iv = state.iv; + if (this.type === 'encrypt') { + for (var i = 0; i < this.blockSize; i++) + iv[i] ^= inp[inOff + i]; + + superProto._update.call(this, iv, 0, out, outOff); + + for (var i = 0; i < this.blockSize; i++) + iv[i] = out[outOff + i]; + } else { + superProto._update.call(this, inp, inOff, out, outOff); + + for (var i = 0; i < this.blockSize; i++) + out[outOff + i] ^= iv[i]; + + for (var i = 0; i < this.blockSize; i++) + iv[i] = inp[inOff + i]; + } +}; + +},{"inherits":143,"minimalistic-assert":151}],77:[function(require,module,exports){ +'use strict'; + +var assert = require('minimalistic-assert'); + +function Cipher(options) { + this.options = options; + + this.type = this.options.type; + this.blockSize = 8; + this._init(); + + this.buffer = new Array(this.blockSize); + this.bufferOff = 0; +} +module.exports = Cipher; + +Cipher.prototype._init = function _init() { + // Might be overrided +}; + +Cipher.prototype.update = function update(data) { + if (data.length === 0) + return []; + + if (this.type === 'decrypt') + return this._updateDecrypt(data); + else + return this._updateEncrypt(data); +}; + +Cipher.prototype._buffer = function _buffer(data, off) { + // Append data to buffer + var min = Math.min(this.buffer.length - this.bufferOff, data.length - off); + for (var i = 0; i < min; i++) + this.buffer[this.bufferOff + i] = data[off + i]; + this.bufferOff += min; + + // Shift next + return min; +}; + +Cipher.prototype._flushBuffer = function _flushBuffer(out, off) { + this._update(this.buffer, 0, out, off); + this.bufferOff = 0; + return this.blockSize; +}; + +Cipher.prototype._updateEncrypt = function _updateEncrypt(data) { + var inputOff = 0; + var outputOff = 0; + + var count = ((this.bufferOff + data.length) / this.blockSize) | 0; + var out = new Array(count * this.blockSize); + + if (this.bufferOff !== 0) { + inputOff += this._buffer(data, inputOff); + + if (this.bufferOff === this.buffer.length) + outputOff += this._flushBuffer(out, outputOff); + } + + // Write blocks + var max = data.length - ((data.length - inputOff) % this.blockSize); + for (; inputOff < max; inputOff += this.blockSize) { + this._update(data, inputOff, out, outputOff); + outputOff += this.blockSize; + } + + // Queue rest + for (; inputOff < data.length; inputOff++, this.bufferOff++) + this.buffer[this.bufferOff] = data[inputOff]; + + return out; +}; + +Cipher.prototype._updateDecrypt = function _updateDecrypt(data) { + var inputOff = 0; + var outputOff = 0; + + var count = Math.ceil((this.bufferOff + data.length) / this.blockSize) - 1; + var out = new Array(count * this.blockSize); + + // TODO(indutny): optimize it, this is far from optimal + for (; count > 0; count--) { + inputOff += this._buffer(data, inputOff); + outputOff += this._flushBuffer(out, outputOff); + } + + // Buffer rest of the input + inputOff += this._buffer(data, inputOff); + + return out; +}; + +Cipher.prototype.final = function final(buffer) { + var first; + if (buffer) + first = this.update(buffer); + + var last; + if (this.type === 'encrypt') + last = this._finalEncrypt(); + else + last = this._finalDecrypt(); + + if (first) + return first.concat(last); + else + return last; +}; + +Cipher.prototype._pad = function _pad(buffer, off) { + if (off === 0) + return false; + + while (off < buffer.length) + buffer[off++] = 0; + + return true; +}; + +Cipher.prototype._finalEncrypt = function _finalEncrypt() { + if (!this._pad(this.buffer, this.bufferOff)) + return []; + + var out = new Array(this.blockSize); + this._update(this.buffer, 0, out, 0); + return out; +}; + +Cipher.prototype._unpad = function _unpad(buffer) { + return buffer; +}; + +Cipher.prototype._finalDecrypt = function _finalDecrypt() { + assert.equal(this.bufferOff, this.blockSize, 'Not enough data to decrypt'); + var out = new Array(this.blockSize); + this._flushBuffer(out, 0); + + return this._unpad(out); +}; + +},{"minimalistic-assert":151}],78:[function(require,module,exports){ +'use strict'; + +var assert = require('minimalistic-assert'); +var inherits = require('inherits'); + +var utils = require('./utils'); +var Cipher = require('./cipher'); + +function DESState() { + this.tmp = new Array(2); + this.keys = null; +} + +function DES(options) { + Cipher.call(this, options); + + var state = new DESState(); + this._desState = state; + + this.deriveKeys(state, options.key); +} +inherits(DES, Cipher); +module.exports = DES; + +DES.create = function create(options) { + return new DES(options); +}; + +var shiftTable = [ + 1, 1, 2, 2, 2, 2, 2, 2, + 1, 2, 2, 2, 2, 2, 2, 1 +]; + +DES.prototype.deriveKeys = function deriveKeys(state, key) { + state.keys = new Array(16 * 2); + + assert.equal(key.length, this.blockSize, 'Invalid key length'); + + var kL = utils.readUInt32BE(key, 0); + var kR = utils.readUInt32BE(key, 4); + + utils.pc1(kL, kR, state.tmp, 0); + kL = state.tmp[0]; + kR = state.tmp[1]; + for (var i = 0; i < state.keys.length; i += 2) { + var shift = shiftTable[i >>> 1]; + kL = utils.r28shl(kL, shift); + kR = utils.r28shl(kR, shift); + utils.pc2(kL, kR, state.keys, i); + } +}; + +DES.prototype._update = function _update(inp, inOff, out, outOff) { + var state = this._desState; + + var l = utils.readUInt32BE(inp, inOff); + var r = utils.readUInt32BE(inp, inOff + 4); + + // Initial Permutation + utils.ip(l, r, state.tmp, 0); + l = state.tmp[0]; + r = state.tmp[1]; + + if (this.type === 'encrypt') + this._encrypt(state, l, r, state.tmp, 0); + else + this._decrypt(state, l, r, state.tmp, 0); + + l = state.tmp[0]; + r = state.tmp[1]; + + utils.writeUInt32BE(out, l, outOff); + utils.writeUInt32BE(out, r, outOff + 4); +}; + +DES.prototype._pad = function _pad(buffer, off) { + var value = buffer.length - off; + for (var i = off; i < buffer.length; i++) + buffer[i] = value; + + return true; +}; + +DES.prototype._unpad = function _unpad(buffer) { + var pad = buffer[buffer.length - 1]; + for (var i = buffer.length - pad; i < buffer.length; i++) + assert.equal(buffer[i], pad); + + return buffer.slice(0, buffer.length - pad); +}; + +DES.prototype._encrypt = function _encrypt(state, lStart, rStart, out, off) { + var l = lStart; + var r = rStart; + + // Apply f() x16 times + for (var i = 0; i < state.keys.length; i += 2) { + var keyL = state.keys[i]; + var keyR = state.keys[i + 1]; + + // f(r, k) + utils.expand(r, state.tmp, 0); + + keyL ^= state.tmp[0]; + keyR ^= state.tmp[1]; + var s = utils.substitute(keyL, keyR); + var f = utils.permute(s); + + var t = r; + r = (l ^ f) >>> 0; + l = t; + } + + // Reverse Initial Permutation + utils.rip(r, l, out, off); +}; + +DES.prototype._decrypt = function _decrypt(state, lStart, rStart, out, off) { + var l = rStart; + var r = lStart; + + // Apply f() x16 times + for (var i = state.keys.length - 2; i >= 0; i -= 2) { + var keyL = state.keys[i]; + var keyR = state.keys[i + 1]; + + // f(r, k) + utils.expand(l, state.tmp, 0); + + keyL ^= state.tmp[0]; + keyR ^= state.tmp[1]; + var s = utils.substitute(keyL, keyR); + var f = utils.permute(s); + + var t = l; + l = (r ^ f) >>> 0; + r = t; + } + + // Reverse Initial Permutation + utils.rip(l, r, out, off); +}; + +},{"./cipher":77,"./utils":80,"inherits":143,"minimalistic-assert":151}],79:[function(require,module,exports){ +'use strict'; + +var assert = require('minimalistic-assert'); +var inherits = require('inherits'); + +var Cipher = require('./cipher'); +var DES = require('./des'); + +function EDEState(type, key) { + assert.equal(key.length, 24, 'Invalid key length'); + + var k1 = key.slice(0, 8); + var k2 = key.slice(8, 16); + var k3 = key.slice(16, 24); + + if (type === 'encrypt') { + this.ciphers = [ + DES.create({ type: 'encrypt', key: k1 }), + DES.create({ type: 'decrypt', key: k2 }), + DES.create({ type: 'encrypt', key: k3 }) + ]; + } else { + this.ciphers = [ + DES.create({ type: 'decrypt', key: k3 }), + DES.create({ type: 'encrypt', key: k2 }), + DES.create({ type: 'decrypt', key: k1 }) + ]; + } +} + +function EDE(options) { + Cipher.call(this, options); + + var state = new EDEState(this.type, this.options.key); + this._edeState = state; +} +inherits(EDE, Cipher); + +module.exports = EDE; + +EDE.create = function create(options) { + return new EDE(options); +}; + +EDE.prototype._update = function _update(inp, inOff, out, outOff) { + var state = this._edeState; + + state.ciphers[0]._update(inp, inOff, out, outOff); + state.ciphers[1]._update(out, outOff, out, outOff); + state.ciphers[2]._update(out, outOff, out, outOff); +}; + +EDE.prototype._pad = DES.prototype._pad; +EDE.prototype._unpad = DES.prototype._unpad; + +},{"./cipher":77,"./des":78,"inherits":143,"minimalistic-assert":151}],80:[function(require,module,exports){ +'use strict'; + +exports.readUInt32BE = function readUInt32BE(bytes, off) { + var res = (bytes[0 + off] << 24) | + (bytes[1 + off] << 16) | + (bytes[2 + off] << 8) | + bytes[3 + off]; + return res >>> 0; +}; + +exports.writeUInt32BE = function writeUInt32BE(bytes, value, off) { + bytes[0 + off] = value >>> 24; + bytes[1 + off] = (value >>> 16) & 0xff; + bytes[2 + off] = (value >>> 8) & 0xff; + bytes[3 + off] = value & 0xff; +}; + +exports.ip = function ip(inL, inR, out, off) { + var outL = 0; + var outR = 0; + + for (var i = 6; i >= 0; i -= 2) { + for (var j = 0; j <= 24; j += 8) { + outL <<= 1; + outL |= (inR >>> (j + i)) & 1; + } + for (var j = 0; j <= 24; j += 8) { + outL <<= 1; + outL |= (inL >>> (j + i)) & 1; + } + } + + for (var i = 6; i >= 0; i -= 2) { + for (var j = 1; j <= 25; j += 8) { + outR <<= 1; + outR |= (inR >>> (j + i)) & 1; + } + for (var j = 1; j <= 25; j += 8) { + outR <<= 1; + outR |= (inL >>> (j + i)) & 1; + } + } + + out[off + 0] = outL >>> 0; + out[off + 1] = outR >>> 0; +}; + +exports.rip = function rip(inL, inR, out, off) { + var outL = 0; + var outR = 0; + + for (var i = 0; i < 4; i++) { + for (var j = 24; j >= 0; j -= 8) { + outL <<= 1; + outL |= (inR >>> (j + i)) & 1; + outL <<= 1; + outL |= (inL >>> (j + i)) & 1; + } + } + for (var i = 4; i < 8; i++) { + for (var j = 24; j >= 0; j -= 8) { + outR <<= 1; + outR |= (inR >>> (j + i)) & 1; + outR <<= 1; + outR |= (inL >>> (j + i)) & 1; + } + } + + out[off + 0] = outL >>> 0; + out[off + 1] = outR >>> 0; +}; + +exports.pc1 = function pc1(inL, inR, out, off) { + var outL = 0; + var outR = 0; + + // 7, 15, 23, 31, 39, 47, 55, 63 + // 6, 14, 22, 30, 39, 47, 55, 63 + // 5, 13, 21, 29, 39, 47, 55, 63 + // 4, 12, 20, 28 + for (var i = 7; i >= 5; i--) { + for (var j = 0; j <= 24; j += 8) { + outL <<= 1; + outL |= (inR >> (j + i)) & 1; + } + for (var j = 0; j <= 24; j += 8) { + outL <<= 1; + outL |= (inL >> (j + i)) & 1; + } + } + for (var j = 0; j <= 24; j += 8) { + outL <<= 1; + outL |= (inR >> (j + i)) & 1; + } + + // 1, 9, 17, 25, 33, 41, 49, 57 + // 2, 10, 18, 26, 34, 42, 50, 58 + // 3, 11, 19, 27, 35, 43, 51, 59 + // 36, 44, 52, 60 + for (var i = 1; i <= 3; i++) { + for (var j = 0; j <= 24; j += 8) { + outR <<= 1; + outR |= (inR >> (j + i)) & 1; + } + for (var j = 0; j <= 24; j += 8) { + outR <<= 1; + outR |= (inL >> (j + i)) & 1; + } + } + for (var j = 0; j <= 24; j += 8) { + outR <<= 1; + outR |= (inL >> (j + i)) & 1; + } + + out[off + 0] = outL >>> 0; + out[off + 1] = outR >>> 0; +}; + +exports.r28shl = function r28shl(num, shift) { + return ((num << shift) & 0xfffffff) | (num >>> (28 - shift)); +}; + +var pc2table = [ + // inL => outL + 14, 11, 17, 4, 27, 23, 25, 0, + 13, 22, 7, 18, 5, 9, 16, 24, + 2, 20, 12, 21, 1, 8, 15, 26, + + // inR => outR + 15, 4, 25, 19, 9, 1, 26, 16, + 5, 11, 23, 8, 12, 7, 17, 0, + 22, 3, 10, 14, 6, 20, 27, 24 +]; + +exports.pc2 = function pc2(inL, inR, out, off) { + var outL = 0; + var outR = 0; + + var len = pc2table.length >>> 1; + for (var i = 0; i < len; i++) { + outL <<= 1; + outL |= (inL >>> pc2table[i]) & 0x1; + } + for (var i = len; i < pc2table.length; i++) { + outR <<= 1; + outR |= (inR >>> pc2table[i]) & 0x1; + } + + out[off + 0] = outL >>> 0; + out[off + 1] = outR >>> 0; +}; + +exports.expand = function expand(r, out, off) { + var outL = 0; + var outR = 0; + + outL = ((r & 1) << 5) | (r >>> 27); + for (var i = 23; i >= 15; i -= 4) { + outL <<= 6; + outL |= (r >>> i) & 0x3f; + } + for (var i = 11; i >= 3; i -= 4) { + outR |= (r >>> i) & 0x3f; + outR <<= 6; + } + outR |= ((r & 0x1f) << 1) | (r >>> 31); + + out[off + 0] = outL >>> 0; + out[off + 1] = outR >>> 0; +}; + +var sTable = [ + 14, 0, 4, 15, 13, 7, 1, 4, 2, 14, 15, 2, 11, 13, 8, 1, + 3, 10, 10, 6, 6, 12, 12, 11, 5, 9, 9, 5, 0, 3, 7, 8, + 4, 15, 1, 12, 14, 8, 8, 2, 13, 4, 6, 9, 2, 1, 11, 7, + 15, 5, 12, 11, 9, 3, 7, 14, 3, 10, 10, 0, 5, 6, 0, 13, + + 15, 3, 1, 13, 8, 4, 14, 7, 6, 15, 11, 2, 3, 8, 4, 14, + 9, 12, 7, 0, 2, 1, 13, 10, 12, 6, 0, 9, 5, 11, 10, 5, + 0, 13, 14, 8, 7, 10, 11, 1, 10, 3, 4, 15, 13, 4, 1, 2, + 5, 11, 8, 6, 12, 7, 6, 12, 9, 0, 3, 5, 2, 14, 15, 9, + + 10, 13, 0, 7, 9, 0, 14, 9, 6, 3, 3, 4, 15, 6, 5, 10, + 1, 2, 13, 8, 12, 5, 7, 14, 11, 12, 4, 11, 2, 15, 8, 1, + 13, 1, 6, 10, 4, 13, 9, 0, 8, 6, 15, 9, 3, 8, 0, 7, + 11, 4, 1, 15, 2, 14, 12, 3, 5, 11, 10, 5, 14, 2, 7, 12, + + 7, 13, 13, 8, 14, 11, 3, 5, 0, 6, 6, 15, 9, 0, 10, 3, + 1, 4, 2, 7, 8, 2, 5, 12, 11, 1, 12, 10, 4, 14, 15, 9, + 10, 3, 6, 15, 9, 0, 0, 6, 12, 10, 11, 1, 7, 13, 13, 8, + 15, 9, 1, 4, 3, 5, 14, 11, 5, 12, 2, 7, 8, 2, 4, 14, + + 2, 14, 12, 11, 4, 2, 1, 12, 7, 4, 10, 7, 11, 13, 6, 1, + 8, 5, 5, 0, 3, 15, 15, 10, 13, 3, 0, 9, 14, 8, 9, 6, + 4, 11, 2, 8, 1, 12, 11, 7, 10, 1, 13, 14, 7, 2, 8, 13, + 15, 6, 9, 15, 12, 0, 5, 9, 6, 10, 3, 4, 0, 5, 14, 3, + + 12, 10, 1, 15, 10, 4, 15, 2, 9, 7, 2, 12, 6, 9, 8, 5, + 0, 6, 13, 1, 3, 13, 4, 14, 14, 0, 7, 11, 5, 3, 11, 8, + 9, 4, 14, 3, 15, 2, 5, 12, 2, 9, 8, 5, 12, 15, 3, 10, + 7, 11, 0, 14, 4, 1, 10, 7, 1, 6, 13, 0, 11, 8, 6, 13, + + 4, 13, 11, 0, 2, 11, 14, 7, 15, 4, 0, 9, 8, 1, 13, 10, + 3, 14, 12, 3, 9, 5, 7, 12, 5, 2, 10, 15, 6, 8, 1, 6, + 1, 6, 4, 11, 11, 13, 13, 8, 12, 1, 3, 4, 7, 10, 14, 7, + 10, 9, 15, 5, 6, 0, 8, 15, 0, 14, 5, 2, 9, 3, 2, 12, + + 13, 1, 2, 15, 8, 13, 4, 8, 6, 10, 15, 3, 11, 7, 1, 4, + 10, 12, 9, 5, 3, 6, 14, 11, 5, 0, 0, 14, 12, 9, 7, 2, + 7, 2, 11, 1, 4, 14, 1, 7, 9, 4, 12, 10, 14, 8, 2, 13, + 0, 15, 6, 12, 10, 9, 13, 0, 15, 3, 3, 5, 5, 6, 8, 11 +]; + +exports.substitute = function substitute(inL, inR) { + var out = 0; + for (var i = 0; i < 4; i++) { + var b = (inL >>> (18 - i * 6)) & 0x3f; + var sb = sTable[i * 0x40 + b]; + + out <<= 4; + out |= sb; + } + for (var i = 0; i < 4; i++) { + var b = (inR >>> (18 - i * 6)) & 0x3f; + var sb = sTable[4 * 0x40 + i * 0x40 + b]; + + out <<= 4; + out |= sb; + } + return out >>> 0; +}; + +var permuteTable = [ + 16, 25, 12, 11, 3, 20, 4, 15, 31, 17, 9, 6, 27, 14, 1, 22, + 30, 24, 8, 18, 0, 5, 29, 23, 13, 19, 2, 26, 10, 21, 28, 7 +]; + +exports.permute = function permute(num) { + var out = 0; + for (var i = 0; i < permuteTable.length; i++) { + out <<= 1; + out |= (num >>> permuteTable[i]) & 0x1; + } + return out >>> 0; +}; + +exports.padSplit = function padSplit(num, size, group) { + var str = num.toString(2); + while (str.length < size) + str = '0' + str; + + var out = []; + for (var i = 0; i < size; i += group) + out.push(str.slice(i, i + group)); + return out.join(' '); +}; + +},{}],81:[function(require,module,exports){ +(function (Buffer){(function (){ +var generatePrime = require('./lib/generatePrime') +var primes = require('./lib/primes.json') + +var DH = require('./lib/dh') + +function getDiffieHellman (mod) { + var prime = new Buffer(primes[mod].prime, 'hex') + var gen = new Buffer(primes[mod].gen, 'hex') + + return new DH(prime, gen) +} + +var ENCODINGS = { + 'binary': true, 'hex': true, 'base64': true +} + +function createDiffieHellman (prime, enc, generator, genc) { + if (Buffer.isBuffer(enc) || ENCODINGS[enc] === undefined) { + return createDiffieHellman(prime, 'binary', enc, generator) + } + + enc = enc || 'binary' + genc = genc || 'binary' + generator = generator || new Buffer([2]) + + if (!Buffer.isBuffer(generator)) { + generator = new Buffer(generator, genc) + } + + if (typeof prime === 'number') { + return new DH(generatePrime(prime, generator), generator, true) + } + + if (!Buffer.isBuffer(prime)) { + prime = new Buffer(prime, enc) + } + + return new DH(prime, generator, true) +} + +exports.DiffieHellmanGroup = exports.createDiffieHellmanGroup = exports.getDiffieHellman = getDiffieHellman +exports.createDiffieHellman = exports.DiffieHellman = createDiffieHellman + +}).call(this)}).call(this,require("buffer").Buffer) +},{"./lib/dh":82,"./lib/generatePrime":83,"./lib/primes.json":84,"buffer":64}],82:[function(require,module,exports){ +(function (Buffer){(function (){ +var BN = require('bn.js'); +var MillerRabin = require('miller-rabin'); +var millerRabin = new MillerRabin(); +var TWENTYFOUR = new BN(24); +var ELEVEN = new BN(11); +var TEN = new BN(10); +var THREE = new BN(3); +var SEVEN = new BN(7); +var primes = require('./generatePrime'); +var randomBytes = require('randombytes'); +module.exports = DH; + +function setPublicKey(pub, enc) { + enc = enc || 'utf8'; + if (!Buffer.isBuffer(pub)) { + pub = new Buffer(pub, enc); + } + this._pub = new BN(pub); + return this; +} + +function setPrivateKey(priv, enc) { + enc = enc || 'utf8'; + if (!Buffer.isBuffer(priv)) { + priv = new Buffer(priv, enc); + } + this._priv = new BN(priv); + return this; +} + +var primeCache = {}; +function checkPrime(prime, generator) { + var gen = generator.toString('hex'); + var hex = [gen, prime.toString(16)].join('_'); + if (hex in primeCache) { + return primeCache[hex]; + } + var error = 0; + + if (prime.isEven() || + !primes.simpleSieve || + !primes.fermatTest(prime) || + !millerRabin.test(prime)) { + //not a prime so +1 + error += 1; + + if (gen === '02' || gen === '05') { + // we'd be able to check the generator + // it would fail so +8 + error += 8; + } else { + //we wouldn't be able to test the generator + // so +4 + error += 4; + } + primeCache[hex] = error; + return error; + } + if (!millerRabin.test(prime.shrn(1))) { + //not a safe prime + error += 2; + } + var rem; + switch (gen) { + case '02': + if (prime.mod(TWENTYFOUR).cmp(ELEVEN)) { + // unsuidable generator + error += 8; + } + break; + case '05': + rem = prime.mod(TEN); + if (rem.cmp(THREE) && rem.cmp(SEVEN)) { + // prime mod 10 needs to equal 3 or 7 + error += 8; + } + break; + default: + error += 4; + } + primeCache[hex] = error; + return error; +} + +function DH(prime, generator, malleable) { + this.setGenerator(generator); + this.__prime = new BN(prime); + this._prime = BN.mont(this.__prime); + this._primeLen = prime.length; + this._pub = undefined; + this._priv = undefined; + this._primeCode = undefined; + if (malleable) { + this.setPublicKey = setPublicKey; + this.setPrivateKey = setPrivateKey; + } else { + this._primeCode = 8; + } +} +Object.defineProperty(DH.prototype, 'verifyError', { + enumerable: true, + get: function () { + if (typeof this._primeCode !== 'number') { + this._primeCode = checkPrime(this.__prime, this.__gen); + } + return this._primeCode; + } +}); +DH.prototype.generateKeys = function () { + if (!this._priv) { + this._priv = new BN(randomBytes(this._primeLen)); + } + this._pub = this._gen.toRed(this._prime).redPow(this._priv).fromRed(); + return this.getPublicKey(); +}; + +DH.prototype.computeSecret = function (other) { + other = new BN(other); + other = other.toRed(this._prime); + var secret = other.redPow(this._priv).fromRed(); + var out = new Buffer(secret.toArray()); + var prime = this.getPrime(); + if (out.length < prime.length) { + var front = new Buffer(prime.length - out.length); + front.fill(0); + out = Buffer.concat([front, out]); + } + return out; +}; + +DH.prototype.getPublicKey = function getPublicKey(enc) { + return formatReturnValue(this._pub, enc); +}; + +DH.prototype.getPrivateKey = function getPrivateKey(enc) { + return formatReturnValue(this._priv, enc); +}; + +DH.prototype.getPrime = function (enc) { + return formatReturnValue(this.__prime, enc); +}; + +DH.prototype.getGenerator = function (enc) { + return formatReturnValue(this._gen, enc); +}; + +DH.prototype.setGenerator = function (gen, enc) { + enc = enc || 'utf8'; + if (!Buffer.isBuffer(gen)) { + gen = new Buffer(gen, enc); + } + this.__gen = gen; + this._gen = new BN(gen); + return this; +}; + +function formatReturnValue(bn, enc) { + var buf = new Buffer(bn.toArray()); + if (!enc) { + return buf; + } else { + return buf.toString(enc); + } +} + +}).call(this)}).call(this,require("buffer").Buffer) +},{"./generatePrime":83,"bn.js":85,"buffer":64,"miller-rabin":149,"randombytes":176}],83:[function(require,module,exports){ +var randomBytes = require('randombytes'); +module.exports = findPrime; +findPrime.simpleSieve = simpleSieve; +findPrime.fermatTest = fermatTest; +var BN = require('bn.js'); +var TWENTYFOUR = new BN(24); +var MillerRabin = require('miller-rabin'); +var millerRabin = new MillerRabin(); +var ONE = new BN(1); +var TWO = new BN(2); +var FIVE = new BN(5); +var SIXTEEN = new BN(16); +var EIGHT = new BN(8); +var TEN = new BN(10); +var THREE = new BN(3); +var SEVEN = new BN(7); +var ELEVEN = new BN(11); +var FOUR = new BN(4); +var TWELVE = new BN(12); +var primes = null; + +function _getPrimes() { + if (primes !== null) + return primes; + + var limit = 0x100000; + var res = []; + res[0] = 2; + for (var i = 1, k = 3; k < limit; k += 2) { + var sqrt = Math.ceil(Math.sqrt(k)); + for (var j = 0; j < i && res[j] <= sqrt; j++) + if (k % res[j] === 0) + break; + + if (i !== j && res[j] <= sqrt) + continue; + + res[i++] = k; + } + primes = res; + return res; +} + +function simpleSieve(p) { + var primes = _getPrimes(); + + for (var i = 0; i < primes.length; i++) + if (p.modn(primes[i]) === 0) { + if (p.cmpn(primes[i]) === 0) { + return true; + } else { + return false; + } + } + + return true; +} + +function fermatTest(p) { + var red = BN.mont(p); + return TWO.toRed(red).redPow(p.subn(1)).fromRed().cmpn(1) === 0; +} + +function findPrime(bits, gen) { + if (bits < 16) { + // this is what openssl does + if (gen === 2 || gen === 5) { + return new BN([0x8c, 0x7b]); + } else { + return new BN([0x8c, 0x27]); + } + } + gen = new BN(gen); + + var num, n2; + + while (true) { + num = new BN(randomBytes(Math.ceil(bits / 8))); + while (num.bitLength() > bits) { + num.ishrn(1); + } + if (num.isEven()) { + num.iadd(ONE); + } + if (!num.testn(1)) { + num.iadd(TWO); + } + if (!gen.cmp(TWO)) { + while (num.mod(TWENTYFOUR).cmp(ELEVEN)) { + num.iadd(FOUR); + } + } else if (!gen.cmp(FIVE)) { + while (num.mod(TEN).cmp(THREE)) { + num.iadd(FOUR); + } + } + n2 = num.shrn(1); + if (simpleSieve(n2) && simpleSieve(num) && + fermatTest(n2) && fermatTest(num) && + millerRabin.test(n2) && millerRabin.test(num)) { + return num; + } + } + +} + +},{"bn.js":85,"miller-rabin":149,"randombytes":176}],84:[function(require,module,exports){ +module.exports={ + "modp1": { + "gen": "02", + "prime": "ffffffffffffffffc90fdaa22168c234c4c6628b80dc1cd129024e088a67cc74020bbea63b139b22514a08798e3404ddef9519b3cd3a431b302b0a6df25f14374fe1356d6d51c245e485b576625e7ec6f44c42e9a63a3620ffffffffffffffff" + }, + "modp2": { + "gen": "02", + "prime": "ffffffffffffffffc90fdaa22168c234c4c6628b80dc1cd129024e088a67cc74020bbea63b139b22514a08798e3404ddef9519b3cd3a431b302b0a6df25f14374fe1356d6d51c245e485b576625e7ec6f44c42e9a637ed6b0bff5cb6f406b7edee386bfb5a899fa5ae9f24117c4b1fe649286651ece65381ffffffffffffffff" + }, + "modp5": { + "gen": "02", + "prime": "ffffffffffffffffc90fdaa22168c234c4c6628b80dc1cd129024e088a67cc74020bbea63b139b22514a08798e3404ddef9519b3cd3a431b302b0a6df25f14374fe1356d6d51c245e485b576625e7ec6f44c42e9a637ed6b0bff5cb6f406b7edee386bfb5a899fa5ae9f24117c4b1fe649286651ece45b3dc2007cb8a163bf0598da48361c55d39a69163fa8fd24cf5f83655d23dca3ad961c62f356208552bb9ed529077096966d670c354e4abc9804f1746c08ca237327ffffffffffffffff" + }, + "modp14": { + "gen": "02", + "prime": "ffffffffffffffffc90fdaa22168c234c4c6628b80dc1cd129024e088a67cc74020bbea63b139b22514a08798e3404ddef9519b3cd3a431b302b0a6df25f14374fe1356d6d51c245e485b576625e7ec6f44c42e9a637ed6b0bff5cb6f406b7edee386bfb5a899fa5ae9f24117c4b1fe649286651ece45b3dc2007cb8a163bf0598da48361c55d39a69163fa8fd24cf5f83655d23dca3ad961c62f356208552bb9ed529077096966d670c354e4abc9804f1746c08ca18217c32905e462e36ce3be39e772c180e86039b2783a2ec07a28fb5c55df06f4c52c9de2bcbf6955817183995497cea956ae515d2261898fa051015728e5a8aacaa68ffffffffffffffff" + }, + "modp15": { + "gen": "02", + "prime": "ffffffffffffffffc90fdaa22168c234c4c6628b80dc1cd129024e088a67cc74020bbea63b139b22514a08798e3404ddef9519b3cd3a431b302b0a6df25f14374fe1356d6d51c245e485b576625e7ec6f44c42e9a637ed6b0bff5cb6f406b7edee386bfb5a899fa5ae9f24117c4b1fe649286651ece45b3dc2007cb8a163bf0598da48361c55d39a69163fa8fd24cf5f83655d23dca3ad961c62f356208552bb9ed529077096966d670c354e4abc9804f1746c08ca18217c32905e462e36ce3be39e772c180e86039b2783a2ec07a28fb5c55df06f4c52c9de2bcbf6955817183995497cea956ae515d2261898fa051015728e5a8aaac42dad33170d04507a33a85521abdf1cba64ecfb850458dbef0a8aea71575d060c7db3970f85a6e1e4c7abf5ae8cdb0933d71e8c94e04a25619dcee3d2261ad2ee6bf12ffa06d98a0864d87602733ec86a64521f2b18177b200cbbe117577a615d6c770988c0bad946e208e24fa074e5ab3143db5bfce0fd108e4b82d120a93ad2caffffffffffffffff" + }, + "modp16": { + "gen": "02", + "prime": "ffffffffffffffffc90fdaa22168c234c4c6628b80dc1cd129024e088a67cc74020bbea63b139b22514a08798e3404ddef9519b3cd3a431b302b0a6df25f14374fe1356d6d51c245e485b576625e7ec6f44c42e9a637ed6b0bff5cb6f406b7edee386bfb5a899fa5ae9f24117c4b1fe649286651ece45b3dc2007cb8a163bf0598da48361c55d39a69163fa8fd24cf5f83655d23dca3ad961c62f356208552bb9ed529077096966d670c354e4abc9804f1746c08ca18217c32905e462e36ce3be39e772c180e86039b2783a2ec07a28fb5c55df06f4c52c9de2bcbf6955817183995497cea956ae515d2261898fa051015728e5a8aaac42dad33170d04507a33a85521abdf1cba64ecfb850458dbef0a8aea71575d060c7db3970f85a6e1e4c7abf5ae8cdb0933d71e8c94e04a25619dcee3d2261ad2ee6bf12ffa06d98a0864d87602733ec86a64521f2b18177b200cbbe117577a615d6c770988c0bad946e208e24fa074e5ab3143db5bfce0fd108e4b82d120a92108011a723c12a787e6d788719a10bdba5b2699c327186af4e23c1a946834b6150bda2583e9ca2ad44ce8dbbbc2db04de8ef92e8efc141fbecaa6287c59474e6bc05d99b2964fa090c3a2233ba186515be7ed1f612970cee2d7afb81bdd762170481cd0069127d5b05aa993b4ea988d8fddc186ffb7dc90a6c08f4df435c934063199ffffffffffffffff" + }, + "modp17": { + "gen": "02", + "prime": "ffffffffffffffffc90fdaa22168c234c4c6628b80dc1cd129024e088a67cc74020bbea63b139b22514a08798e3404ddef9519b3cd3a431b302b0a6df25f14374fe1356d6d51c245e485b576625e7ec6f44c42e9a637ed6b0bff5cb6f406b7edee386bfb5a899fa5ae9f24117c4b1fe649286651ece45b3dc2007cb8a163bf0598da48361c55d39a69163fa8fd24cf5f83655d23dca3ad961c62f356208552bb9ed529077096966d670c354e4abc9804f1746c08ca18217c32905e462e36ce3be39e772c180e86039b2783a2ec07a28fb5c55df06f4c52c9de2bcbf6955817183995497cea956ae515d2261898fa051015728e5a8aaac42dad33170d04507a33a85521abdf1cba64ecfb850458dbef0a8aea71575d060c7db3970f85a6e1e4c7abf5ae8cdb0933d71e8c94e04a25619dcee3d2261ad2ee6bf12ffa06d98a0864d87602733ec86a64521f2b18177b200cbbe117577a615d6c770988c0bad946e208e24fa074e5ab3143db5bfce0fd108e4b82d120a92108011a723c12a787e6d788719a10bdba5b2699c327186af4e23c1a946834b6150bda2583e9ca2ad44ce8dbbbc2db04de8ef92e8efc141fbecaa6287c59474e6bc05d99b2964fa090c3a2233ba186515be7ed1f612970cee2d7afb81bdd762170481cd0069127d5b05aa993b4ea988d8fddc186ffb7dc90a6c08f4df435c93402849236c3fab4d27c7026c1d4dcb2602646dec9751e763dba37bdf8ff9406ad9e530ee5db382f413001aeb06a53ed9027d831179727b0865a8918da3edbebcf9b14ed44ce6cbaced4bb1bdb7f1447e6cc254b332051512bd7af426fb8f401378cd2bf5983ca01c64b92ecf032ea15d1721d03f482d7ce6e74fef6d55e702f46980c82b5a84031900b1c9e59e7c97fbec7e8f323a97a7e36cc88be0f1d45b7ff585ac54bd407b22b4154aacc8f6d7ebf48e1d814cc5ed20f8037e0a79715eef29be32806a1d58bb7c5da76f550aa3d8a1fbff0eb19ccb1a313d55cda56c9ec2ef29632387fe8d76e3c0468043e8f663f4860ee12bf2d5b0b7474d6e694f91e6dcc4024ffffffffffffffff" + }, + "modp18": { + "gen": "02", + "prime": "ffffffffffffffffc90fdaa22168c234c4c6628b80dc1cd129024e088a67cc74020bbea63b139b22514a08798e3404ddef9519b3cd3a431b302b0a6df25f14374fe1356d6d51c245e485b576625e7ec6f44c42e9a637ed6b0bff5cb6f406b7edee386bfb5a899fa5ae9f24117c4b1fe649286651ece45b3dc2007cb8a163bf0598da48361c55d39a69163fa8fd24cf5f83655d23dca3ad961c62f356208552bb9ed529077096966d670c354e4abc9804f1746c08ca18217c32905e462e36ce3be39e772c180e86039b2783a2ec07a28fb5c55df06f4c52c9de2bcbf6955817183995497cea956ae515d2261898fa051015728e5a8aaac42dad33170d04507a33a85521abdf1cba64ecfb850458dbef0a8aea71575d060c7db3970f85a6e1e4c7abf5ae8cdb0933d71e8c94e04a25619dcee3d2261ad2ee6bf12ffa06d98a0864d87602733ec86a64521f2b18177b200cbbe117577a615d6c770988c0bad946e208e24fa074e5ab3143db5bfce0fd108e4b82d120a92108011a723c12a787e6d788719a10bdba5b2699c327186af4e23c1a946834b6150bda2583e9ca2ad44ce8dbbbc2db04de8ef92e8efc141fbecaa6287c59474e6bc05d99b2964fa090c3a2233ba186515be7ed1f612970cee2d7afb81bdd762170481cd0069127d5b05aa993b4ea988d8fddc186ffb7dc90a6c08f4df435c93402849236c3fab4d27c7026c1d4dcb2602646dec9751e763dba37bdf8ff9406ad9e530ee5db382f413001aeb06a53ed9027d831179727b0865a8918da3edbebcf9b14ed44ce6cbaced4bb1bdb7f1447e6cc254b332051512bd7af426fb8f401378cd2bf5983ca01c64b92ecf032ea15d1721d03f482d7ce6e74fef6d55e702f46980c82b5a84031900b1c9e59e7c97fbec7e8f323a97a7e36cc88be0f1d45b7ff585ac54bd407b22b4154aacc8f6d7ebf48e1d814cc5ed20f8037e0a79715eef29be32806a1d58bb7c5da76f550aa3d8a1fbff0eb19ccb1a313d55cda56c9ec2ef29632387fe8d76e3c0468043e8f663f4860ee12bf2d5b0b7474d6e694f91e6dbe115974a3926f12fee5e438777cb6a932df8cd8bec4d073b931ba3bc832b68d9dd300741fa7bf8afc47ed2576f6936ba424663aab639c5ae4f5683423b4742bf1c978238f16cbe39d652de3fdb8befc848ad922222e04a4037c0713eb57a81a23f0c73473fc646cea306b4bcbc8862f8385ddfa9d4b7fa2c087e879683303ed5bdd3a062b3cf5b3a278a66d2a13f83f44f82ddf310ee074ab6a364597e899a0255dc164f31cc50846851df9ab48195ded7ea1b1d510bd7ee74d73faf36bc31ecfa268359046f4eb879f924009438b481c6cd7889a002ed5ee382bc9190da6fc026e479558e4475677e9aa9e3050e2765694dfc81f56e880b96e7160c980dd98edd3dfffffffffffffffff" + } +} +},{}],85:[function(require,module,exports){ +arguments[4][15][0].apply(exports,arguments) +},{"buffer":20,"dup":15}],86:[function(require,module,exports){ +'use strict'; + +var elliptic = exports; + +elliptic.version = require('../package.json').version; +elliptic.utils = require('./elliptic/utils'); +elliptic.rand = require('brorand'); +elliptic.curve = require('./elliptic/curve'); +elliptic.curves = require('./elliptic/curves'); + +// Protocols +elliptic.ec = require('./elliptic/ec'); +elliptic.eddsa = require('./elliptic/eddsa'); + +},{"../package.json":102,"./elliptic/curve":89,"./elliptic/curves":92,"./elliptic/ec":93,"./elliptic/eddsa":96,"./elliptic/utils":100,"brorand":19}],87:[function(require,module,exports){ +'use strict'; + +var BN = require('bn.js'); +var utils = require('../utils'); +var getNAF = utils.getNAF; +var getJSF = utils.getJSF; +var assert = utils.assert; + +function BaseCurve(type, conf) { + this.type = type; + this.p = new BN(conf.p, 16); + + // Use Montgomery, when there is no fast reduction for the prime + this.red = conf.prime ? BN.red(conf.prime) : BN.mont(this.p); + + // Useful for many curves + this.zero = new BN(0).toRed(this.red); + this.one = new BN(1).toRed(this.red); + this.two = new BN(2).toRed(this.red); + + // Curve configuration, optional + this.n = conf.n && new BN(conf.n, 16); + this.g = conf.g && this.pointFromJSON(conf.g, conf.gRed); + + // Temporary arrays + this._wnafT1 = new Array(4); + this._wnafT2 = new Array(4); + this._wnafT3 = new Array(4); + this._wnafT4 = new Array(4); + + this._bitLength = this.n ? this.n.bitLength() : 0; + + // Generalized Greg Maxwell's trick + var adjustCount = this.n && this.p.div(this.n); + if (!adjustCount || adjustCount.cmpn(100) > 0) { + this.redN = null; + } else { + this._maxwellTrick = true; + this.redN = this.n.toRed(this.red); + } +} +module.exports = BaseCurve; + +BaseCurve.prototype.point = function point() { + throw new Error('Not implemented'); +}; + +BaseCurve.prototype.validate = function validate() { + throw new Error('Not implemented'); +}; + +BaseCurve.prototype._fixedNafMul = function _fixedNafMul(p, k) { + assert(p.precomputed); + var doubles = p._getDoubles(); + + var naf = getNAF(k, 1, this._bitLength); + var I = (1 << (doubles.step + 1)) - (doubles.step % 2 === 0 ? 2 : 1); + I /= 3; + + // Translate into more windowed form + var repr = []; + var j; + var nafW; + for (j = 0; j < naf.length; j += doubles.step) { + nafW = 0; + for (var l = j + doubles.step - 1; l >= j; l--) + nafW = (nafW << 1) + naf[l]; + repr.push(nafW); + } + + var a = this.jpoint(null, null, null); + var b = this.jpoint(null, null, null); + for (var i = I; i > 0; i--) { + for (j = 0; j < repr.length; j++) { + nafW = repr[j]; + if (nafW === i) + b = b.mixedAdd(doubles.points[j]); + else if (nafW === -i) + b = b.mixedAdd(doubles.points[j].neg()); + } + a = a.add(b); + } + return a.toP(); +}; + +BaseCurve.prototype._wnafMul = function _wnafMul(p, k) { + var w = 4; + + // Precompute window + var nafPoints = p._getNAFPoints(w); + w = nafPoints.wnd; + var wnd = nafPoints.points; + + // Get NAF form + var naf = getNAF(k, w, this._bitLength); + + // Add `this`*(N+1) for every w-NAF index + var acc = this.jpoint(null, null, null); + for (var i = naf.length - 1; i >= 0; i--) { + // Count zeroes + for (var l = 0; i >= 0 && naf[i] === 0; i--) + l++; + if (i >= 0) + l++; + acc = acc.dblp(l); + + if (i < 0) + break; + var z = naf[i]; + assert(z !== 0); + if (p.type === 'affine') { + // J +- P + if (z > 0) + acc = acc.mixedAdd(wnd[(z - 1) >> 1]); + else + acc = acc.mixedAdd(wnd[(-z - 1) >> 1].neg()); + } else { + // J +- J + if (z > 0) + acc = acc.add(wnd[(z - 1) >> 1]); + else + acc = acc.add(wnd[(-z - 1) >> 1].neg()); + } + } + return p.type === 'affine' ? acc.toP() : acc; +}; + +BaseCurve.prototype._wnafMulAdd = function _wnafMulAdd(defW, + points, + coeffs, + len, + jacobianResult) { + var wndWidth = this._wnafT1; + var wnd = this._wnafT2; + var naf = this._wnafT3; + + // Fill all arrays + var max = 0; + var i; + var j; + var p; + for (i = 0; i < len; i++) { + p = points[i]; + var nafPoints = p._getNAFPoints(defW); + wndWidth[i] = nafPoints.wnd; + wnd[i] = nafPoints.points; + } + + // Comb small window NAFs + for (i = len - 1; i >= 1; i -= 2) { + var a = i - 1; + var b = i; + if (wndWidth[a] !== 1 || wndWidth[b] !== 1) { + naf[a] = getNAF(coeffs[a], wndWidth[a], this._bitLength); + naf[b] = getNAF(coeffs[b], wndWidth[b], this._bitLength); + max = Math.max(naf[a].length, max); + max = Math.max(naf[b].length, max); + continue; + } + + var comb = [ + points[a], /* 1 */ + null, /* 3 */ + null, /* 5 */ + points[b], /* 7 */ + ]; + + // Try to avoid Projective points, if possible + if (points[a].y.cmp(points[b].y) === 0) { + comb[1] = points[a].add(points[b]); + comb[2] = points[a].toJ().mixedAdd(points[b].neg()); + } else if (points[a].y.cmp(points[b].y.redNeg()) === 0) { + comb[1] = points[a].toJ().mixedAdd(points[b]); + comb[2] = points[a].add(points[b].neg()); + } else { + comb[1] = points[a].toJ().mixedAdd(points[b]); + comb[2] = points[a].toJ().mixedAdd(points[b].neg()); + } + + var index = [ + -3, /* -1 -1 */ + -1, /* -1 0 */ + -5, /* -1 1 */ + -7, /* 0 -1 */ + 0, /* 0 0 */ + 7, /* 0 1 */ + 5, /* 1 -1 */ + 1, /* 1 0 */ + 3, /* 1 1 */ + ]; + + var jsf = getJSF(coeffs[a], coeffs[b]); + max = Math.max(jsf[0].length, max); + naf[a] = new Array(max); + naf[b] = new Array(max); + for (j = 0; j < max; j++) { + var ja = jsf[0][j] | 0; + var jb = jsf[1][j] | 0; + + naf[a][j] = index[(ja + 1) * 3 + (jb + 1)]; + naf[b][j] = 0; + wnd[a] = comb; + } + } + + var acc = this.jpoint(null, null, null); + var tmp = this._wnafT4; + for (i = max; i >= 0; i--) { + var k = 0; + + while (i >= 0) { + var zero = true; + for (j = 0; j < len; j++) { + tmp[j] = naf[j][i] | 0; + if (tmp[j] !== 0) + zero = false; + } + if (!zero) + break; + k++; + i--; + } + if (i >= 0) + k++; + acc = acc.dblp(k); + if (i < 0) + break; + + for (j = 0; j < len; j++) { + var z = tmp[j]; + p; + if (z === 0) + continue; + else if (z > 0) + p = wnd[j][(z - 1) >> 1]; + else if (z < 0) + p = wnd[j][(-z - 1) >> 1].neg(); + + if (p.type === 'affine') + acc = acc.mixedAdd(p); + else + acc = acc.add(p); + } + } + // Zeroify references + for (i = 0; i < len; i++) + wnd[i] = null; + + if (jacobianResult) + return acc; + else + return acc.toP(); +}; + +function BasePoint(curve, type) { + this.curve = curve; + this.type = type; + this.precomputed = null; +} +BaseCurve.BasePoint = BasePoint; + +BasePoint.prototype.eq = function eq(/*other*/) { + throw new Error('Not implemented'); +}; + +BasePoint.prototype.validate = function validate() { + return this.curve.validate(this); +}; + +BaseCurve.prototype.decodePoint = function decodePoint(bytes, enc) { + bytes = utils.toArray(bytes, enc); + + var len = this.p.byteLength(); + + // uncompressed, hybrid-odd, hybrid-even + if ((bytes[0] === 0x04 || bytes[0] === 0x06 || bytes[0] === 0x07) && + bytes.length - 1 === 2 * len) { + if (bytes[0] === 0x06) + assert(bytes[bytes.length - 1] % 2 === 0); + else if (bytes[0] === 0x07) + assert(bytes[bytes.length - 1] % 2 === 1); + + var res = this.point(bytes.slice(1, 1 + len), + bytes.slice(1 + len, 1 + 2 * len)); + + return res; + } else if ((bytes[0] === 0x02 || bytes[0] === 0x03) && + bytes.length - 1 === len) { + return this.pointFromX(bytes.slice(1, 1 + len), bytes[0] === 0x03); + } + throw new Error('Unknown point format'); +}; + +BasePoint.prototype.encodeCompressed = function encodeCompressed(enc) { + return this.encode(enc, true); +}; + +BasePoint.prototype._encode = function _encode(compact) { + var len = this.curve.p.byteLength(); + var x = this.getX().toArray('be', len); + + if (compact) + return [ this.getY().isEven() ? 0x02 : 0x03 ].concat(x); + + return [ 0x04 ].concat(x, this.getY().toArray('be', len)); +}; + +BasePoint.prototype.encode = function encode(enc, compact) { + return utils.encode(this._encode(compact), enc); +}; + +BasePoint.prototype.precompute = function precompute(power) { + if (this.precomputed) + return this; + + var precomputed = { + doubles: null, + naf: null, + beta: null, + }; + precomputed.naf = this._getNAFPoints(8); + precomputed.doubles = this._getDoubles(4, power); + precomputed.beta = this._getBeta(); + this.precomputed = precomputed; + + return this; +}; + +BasePoint.prototype._hasDoubles = function _hasDoubles(k) { + if (!this.precomputed) + return false; + + var doubles = this.precomputed.doubles; + if (!doubles) + return false; + + return doubles.points.length >= Math.ceil((k.bitLength() + 1) / doubles.step); +}; + +BasePoint.prototype._getDoubles = function _getDoubles(step, power) { + if (this.precomputed && this.precomputed.doubles) + return this.precomputed.doubles; + + var doubles = [ this ]; + var acc = this; + for (var i = 0; i < power; i += step) { + for (var j = 0; j < step; j++) + acc = acc.dbl(); + doubles.push(acc); + } + return { + step: step, + points: doubles, + }; +}; + +BasePoint.prototype._getNAFPoints = function _getNAFPoints(wnd) { + if (this.precomputed && this.precomputed.naf) + return this.precomputed.naf; + + var res = [ this ]; + var max = (1 << wnd) - 1; + var dbl = max === 1 ? null : this.dbl(); + for (var i = 1; i < max; i++) + res[i] = res[i - 1].add(dbl); + return { + wnd: wnd, + points: res, + }; +}; + +BasePoint.prototype._getBeta = function _getBeta() { + return null; +}; + +BasePoint.prototype.dblp = function dblp(k) { + var r = this; + for (var i = 0; i < k; i++) + r = r.dbl(); + return r; +}; + +},{"../utils":100,"bn.js":101}],88:[function(require,module,exports){ +'use strict'; + +var utils = require('../utils'); +var BN = require('bn.js'); +var inherits = require('inherits'); +var Base = require('./base'); + +var assert = utils.assert; + +function EdwardsCurve(conf) { + // NOTE: Important as we are creating point in Base.call() + this.twisted = (conf.a | 0) !== 1; + this.mOneA = this.twisted && (conf.a | 0) === -1; + this.extended = this.mOneA; + + Base.call(this, 'edwards', conf); + + this.a = new BN(conf.a, 16).umod(this.red.m); + this.a = this.a.toRed(this.red); + this.c = new BN(conf.c, 16).toRed(this.red); + this.c2 = this.c.redSqr(); + this.d = new BN(conf.d, 16).toRed(this.red); + this.dd = this.d.redAdd(this.d); + + assert(!this.twisted || this.c.fromRed().cmpn(1) === 0); + this.oneC = (conf.c | 0) === 1; +} +inherits(EdwardsCurve, Base); +module.exports = EdwardsCurve; + +EdwardsCurve.prototype._mulA = function _mulA(num) { + if (this.mOneA) + return num.redNeg(); + else + return this.a.redMul(num); +}; + +EdwardsCurve.prototype._mulC = function _mulC(num) { + if (this.oneC) + return num; + else + return this.c.redMul(num); +}; + +// Just for compatibility with Short curve +EdwardsCurve.prototype.jpoint = function jpoint(x, y, z, t) { + return this.point(x, y, z, t); +}; + +EdwardsCurve.prototype.pointFromX = function pointFromX(x, odd) { + x = new BN(x, 16); + if (!x.red) + x = x.toRed(this.red); + + var x2 = x.redSqr(); + var rhs = this.c2.redSub(this.a.redMul(x2)); + var lhs = this.one.redSub(this.c2.redMul(this.d).redMul(x2)); + + var y2 = rhs.redMul(lhs.redInvm()); + var y = y2.redSqrt(); + if (y.redSqr().redSub(y2).cmp(this.zero) !== 0) + throw new Error('invalid point'); + + var isOdd = y.fromRed().isOdd(); + if (odd && !isOdd || !odd && isOdd) + y = y.redNeg(); + + return this.point(x, y); +}; + +EdwardsCurve.prototype.pointFromY = function pointFromY(y, odd) { + y = new BN(y, 16); + if (!y.red) + y = y.toRed(this.red); + + // x^2 = (y^2 - c^2) / (c^2 d y^2 - a) + var y2 = y.redSqr(); + var lhs = y2.redSub(this.c2); + var rhs = y2.redMul(this.d).redMul(this.c2).redSub(this.a); + var x2 = lhs.redMul(rhs.redInvm()); + + if (x2.cmp(this.zero) === 0) { + if (odd) + throw new Error('invalid point'); + else + return this.point(this.zero, y); + } + + var x = x2.redSqrt(); + if (x.redSqr().redSub(x2).cmp(this.zero) !== 0) + throw new Error('invalid point'); + + if (x.fromRed().isOdd() !== odd) + x = x.redNeg(); + + return this.point(x, y); +}; + +EdwardsCurve.prototype.validate = function validate(point) { + if (point.isInfinity()) + return true; + + // Curve: A * X^2 + Y^2 = C^2 * (1 + D * X^2 * Y^2) + point.normalize(); + + var x2 = point.x.redSqr(); + var y2 = point.y.redSqr(); + var lhs = x2.redMul(this.a).redAdd(y2); + var rhs = this.c2.redMul(this.one.redAdd(this.d.redMul(x2).redMul(y2))); + + return lhs.cmp(rhs) === 0; +}; + +function Point(curve, x, y, z, t) { + Base.BasePoint.call(this, curve, 'projective'); + if (x === null && y === null && z === null) { + this.x = this.curve.zero; + this.y = this.curve.one; + this.z = this.curve.one; + this.t = this.curve.zero; + this.zOne = true; + } else { + this.x = new BN(x, 16); + this.y = new BN(y, 16); + this.z = z ? new BN(z, 16) : this.curve.one; + this.t = t && new BN(t, 16); + if (!this.x.red) + this.x = this.x.toRed(this.curve.red); + if (!this.y.red) + this.y = this.y.toRed(this.curve.red); + if (!this.z.red) + this.z = this.z.toRed(this.curve.red); + if (this.t && !this.t.red) + this.t = this.t.toRed(this.curve.red); + this.zOne = this.z === this.curve.one; + + // Use extended coordinates + if (this.curve.extended && !this.t) { + this.t = this.x.redMul(this.y); + if (!this.zOne) + this.t = this.t.redMul(this.z.redInvm()); + } + } +} +inherits(Point, Base.BasePoint); + +EdwardsCurve.prototype.pointFromJSON = function pointFromJSON(obj) { + return Point.fromJSON(this, obj); +}; + +EdwardsCurve.prototype.point = function point(x, y, z, t) { + return new Point(this, x, y, z, t); +}; + +Point.fromJSON = function fromJSON(curve, obj) { + return new Point(curve, obj[0], obj[1], obj[2]); +}; + +Point.prototype.inspect = function inspect() { + if (this.isInfinity()) + return ''; + return ''; +}; + +Point.prototype.isInfinity = function isInfinity() { + // XXX This code assumes that zero is always zero in red + return this.x.cmpn(0) === 0 && + (this.y.cmp(this.z) === 0 || + (this.zOne && this.y.cmp(this.curve.c) === 0)); +}; + +Point.prototype._extDbl = function _extDbl() { + // hyperelliptic.org/EFD/g1p/auto-twisted-extended-1.html + // #doubling-dbl-2008-hwcd + // 4M + 4S + + // A = X1^2 + var a = this.x.redSqr(); + // B = Y1^2 + var b = this.y.redSqr(); + // C = 2 * Z1^2 + var c = this.z.redSqr(); + c = c.redIAdd(c); + // D = a * A + var d = this.curve._mulA(a); + // E = (X1 + Y1)^2 - A - B + var e = this.x.redAdd(this.y).redSqr().redISub(a).redISub(b); + // G = D + B + var g = d.redAdd(b); + // F = G - C + var f = g.redSub(c); + // H = D - B + var h = d.redSub(b); + // X3 = E * F + var nx = e.redMul(f); + // Y3 = G * H + var ny = g.redMul(h); + // T3 = E * H + var nt = e.redMul(h); + // Z3 = F * G + var nz = f.redMul(g); + return this.curve.point(nx, ny, nz, nt); +}; + +Point.prototype._projDbl = function _projDbl() { + // hyperelliptic.org/EFD/g1p/auto-twisted-projective.html + // #doubling-dbl-2008-bbjlp + // #doubling-dbl-2007-bl + // and others + // Generally 3M + 4S or 2M + 4S + + // B = (X1 + Y1)^2 + var b = this.x.redAdd(this.y).redSqr(); + // C = X1^2 + var c = this.x.redSqr(); + // D = Y1^2 + var d = this.y.redSqr(); + + var nx; + var ny; + var nz; + var e; + var h; + var j; + if (this.curve.twisted) { + // E = a * C + e = this.curve._mulA(c); + // F = E + D + var f = e.redAdd(d); + if (this.zOne) { + // X3 = (B - C - D) * (F - 2) + nx = b.redSub(c).redSub(d).redMul(f.redSub(this.curve.two)); + // Y3 = F * (E - D) + ny = f.redMul(e.redSub(d)); + // Z3 = F^2 - 2 * F + nz = f.redSqr().redSub(f).redSub(f); + } else { + // H = Z1^2 + h = this.z.redSqr(); + // J = F - 2 * H + j = f.redSub(h).redISub(h); + // X3 = (B-C-D)*J + nx = b.redSub(c).redISub(d).redMul(j); + // Y3 = F * (E - D) + ny = f.redMul(e.redSub(d)); + // Z3 = F * J + nz = f.redMul(j); + } + } else { + // E = C + D + e = c.redAdd(d); + // H = (c * Z1)^2 + h = this.curve._mulC(this.z).redSqr(); + // J = E - 2 * H + j = e.redSub(h).redSub(h); + // X3 = c * (B - E) * J + nx = this.curve._mulC(b.redISub(e)).redMul(j); + // Y3 = c * E * (C - D) + ny = this.curve._mulC(e).redMul(c.redISub(d)); + // Z3 = E * J + nz = e.redMul(j); + } + return this.curve.point(nx, ny, nz); +}; + +Point.prototype.dbl = function dbl() { + if (this.isInfinity()) + return this; + + // Double in extended coordinates + if (this.curve.extended) + return this._extDbl(); + else + return this._projDbl(); +}; + +Point.prototype._extAdd = function _extAdd(p) { + // hyperelliptic.org/EFD/g1p/auto-twisted-extended-1.html + // #addition-add-2008-hwcd-3 + // 8M + + // A = (Y1 - X1) * (Y2 - X2) + var a = this.y.redSub(this.x).redMul(p.y.redSub(p.x)); + // B = (Y1 + X1) * (Y2 + X2) + var b = this.y.redAdd(this.x).redMul(p.y.redAdd(p.x)); + // C = T1 * k * T2 + var c = this.t.redMul(this.curve.dd).redMul(p.t); + // D = Z1 * 2 * Z2 + var d = this.z.redMul(p.z.redAdd(p.z)); + // E = B - A + var e = b.redSub(a); + // F = D - C + var f = d.redSub(c); + // G = D + C + var g = d.redAdd(c); + // H = B + A + var h = b.redAdd(a); + // X3 = E * F + var nx = e.redMul(f); + // Y3 = G * H + var ny = g.redMul(h); + // T3 = E * H + var nt = e.redMul(h); + // Z3 = F * G + var nz = f.redMul(g); + return this.curve.point(nx, ny, nz, nt); +}; + +Point.prototype._projAdd = function _projAdd(p) { + // hyperelliptic.org/EFD/g1p/auto-twisted-projective.html + // #addition-add-2008-bbjlp + // #addition-add-2007-bl + // 10M + 1S + + // A = Z1 * Z2 + var a = this.z.redMul(p.z); + // B = A^2 + var b = a.redSqr(); + // C = X1 * X2 + var c = this.x.redMul(p.x); + // D = Y1 * Y2 + var d = this.y.redMul(p.y); + // E = d * C * D + var e = this.curve.d.redMul(c).redMul(d); + // F = B - E + var f = b.redSub(e); + // G = B + E + var g = b.redAdd(e); + // X3 = A * F * ((X1 + Y1) * (X2 + Y2) - C - D) + var tmp = this.x.redAdd(this.y).redMul(p.x.redAdd(p.y)).redISub(c).redISub(d); + var nx = a.redMul(f).redMul(tmp); + var ny; + var nz; + if (this.curve.twisted) { + // Y3 = A * G * (D - a * C) + ny = a.redMul(g).redMul(d.redSub(this.curve._mulA(c))); + // Z3 = F * G + nz = f.redMul(g); + } else { + // Y3 = A * G * (D - C) + ny = a.redMul(g).redMul(d.redSub(c)); + // Z3 = c * F * G + nz = this.curve._mulC(f).redMul(g); + } + return this.curve.point(nx, ny, nz); +}; + +Point.prototype.add = function add(p) { + if (this.isInfinity()) + return p; + if (p.isInfinity()) + return this; + + if (this.curve.extended) + return this._extAdd(p); + else + return this._projAdd(p); +}; + +Point.prototype.mul = function mul(k) { + if (this._hasDoubles(k)) + return this.curve._fixedNafMul(this, k); + else + return this.curve._wnafMul(this, k); +}; + +Point.prototype.mulAdd = function mulAdd(k1, p, k2) { + return this.curve._wnafMulAdd(1, [ this, p ], [ k1, k2 ], 2, false); +}; + +Point.prototype.jmulAdd = function jmulAdd(k1, p, k2) { + return this.curve._wnafMulAdd(1, [ this, p ], [ k1, k2 ], 2, true); +}; + +Point.prototype.normalize = function normalize() { + if (this.zOne) + return this; + + // Normalize coordinates + var zi = this.z.redInvm(); + this.x = this.x.redMul(zi); + this.y = this.y.redMul(zi); + if (this.t) + this.t = this.t.redMul(zi); + this.z = this.curve.one; + this.zOne = true; + return this; +}; + +Point.prototype.neg = function neg() { + return this.curve.point(this.x.redNeg(), + this.y, + this.z, + this.t && this.t.redNeg()); +}; + +Point.prototype.getX = function getX() { + this.normalize(); + return this.x.fromRed(); +}; + +Point.prototype.getY = function getY() { + this.normalize(); + return this.y.fromRed(); +}; + +Point.prototype.eq = function eq(other) { + return this === other || + this.getX().cmp(other.getX()) === 0 && + this.getY().cmp(other.getY()) === 0; +}; + +Point.prototype.eqXToP = function eqXToP(x) { + var rx = x.toRed(this.curve.red).redMul(this.z); + if (this.x.cmp(rx) === 0) + return true; + + var xc = x.clone(); + var t = this.curve.redN.redMul(this.z); + for (;;) { + xc.iadd(this.curve.n); + if (xc.cmp(this.curve.p) >= 0) + return false; + + rx.redIAdd(t); + if (this.x.cmp(rx) === 0) + return true; + } +}; + +// Compatibility with BaseCurve +Point.prototype.toP = Point.prototype.normalize; +Point.prototype.mixedAdd = Point.prototype.add; + +},{"../utils":100,"./base":87,"bn.js":101,"inherits":143}],89:[function(require,module,exports){ +'use strict'; + +var curve = exports; + +curve.base = require('./base'); +curve.short = require('./short'); +curve.mont = require('./mont'); +curve.edwards = require('./edwards'); + +},{"./base":87,"./edwards":88,"./mont":90,"./short":91}],90:[function(require,module,exports){ +'use strict'; + +var BN = require('bn.js'); +var inherits = require('inherits'); +var Base = require('./base'); + +var utils = require('../utils'); + +function MontCurve(conf) { + Base.call(this, 'mont', conf); + + this.a = new BN(conf.a, 16).toRed(this.red); + this.b = new BN(conf.b, 16).toRed(this.red); + this.i4 = new BN(4).toRed(this.red).redInvm(); + this.two = new BN(2).toRed(this.red); + this.a24 = this.i4.redMul(this.a.redAdd(this.two)); +} +inherits(MontCurve, Base); +module.exports = MontCurve; + +MontCurve.prototype.validate = function validate(point) { + var x = point.normalize().x; + var x2 = x.redSqr(); + var rhs = x2.redMul(x).redAdd(x2.redMul(this.a)).redAdd(x); + var y = rhs.redSqrt(); + + return y.redSqr().cmp(rhs) === 0; +}; + +function Point(curve, x, z) { + Base.BasePoint.call(this, curve, 'projective'); + if (x === null && z === null) { + this.x = this.curve.one; + this.z = this.curve.zero; + } else { + this.x = new BN(x, 16); + this.z = new BN(z, 16); + if (!this.x.red) + this.x = this.x.toRed(this.curve.red); + if (!this.z.red) + this.z = this.z.toRed(this.curve.red); + } +} +inherits(Point, Base.BasePoint); + +MontCurve.prototype.decodePoint = function decodePoint(bytes, enc) { + return this.point(utils.toArray(bytes, enc), 1); +}; + +MontCurve.prototype.point = function point(x, z) { + return new Point(this, x, z); +}; + +MontCurve.prototype.pointFromJSON = function pointFromJSON(obj) { + return Point.fromJSON(this, obj); +}; + +Point.prototype.precompute = function precompute() { + // No-op +}; + +Point.prototype._encode = function _encode() { + return this.getX().toArray('be', this.curve.p.byteLength()); +}; + +Point.fromJSON = function fromJSON(curve, obj) { + return new Point(curve, obj[0], obj[1] || curve.one); +}; + +Point.prototype.inspect = function inspect() { + if (this.isInfinity()) + return ''; + return ''; +}; + +Point.prototype.isInfinity = function isInfinity() { + // XXX This code assumes that zero is always zero in red + return this.z.cmpn(0) === 0; +}; + +Point.prototype.dbl = function dbl() { + // http://hyperelliptic.org/EFD/g1p/auto-montgom-xz.html#doubling-dbl-1987-m-3 + // 2M + 2S + 4A + + // A = X1 + Z1 + var a = this.x.redAdd(this.z); + // AA = A^2 + var aa = a.redSqr(); + // B = X1 - Z1 + var b = this.x.redSub(this.z); + // BB = B^2 + var bb = b.redSqr(); + // C = AA - BB + var c = aa.redSub(bb); + // X3 = AA * BB + var nx = aa.redMul(bb); + // Z3 = C * (BB + A24 * C) + var nz = c.redMul(bb.redAdd(this.curve.a24.redMul(c))); + return this.curve.point(nx, nz); +}; + +Point.prototype.add = function add() { + throw new Error('Not supported on Montgomery curve'); +}; + +Point.prototype.diffAdd = function diffAdd(p, diff) { + // http://hyperelliptic.org/EFD/g1p/auto-montgom-xz.html#diffadd-dadd-1987-m-3 + // 4M + 2S + 6A + + // A = X2 + Z2 + var a = this.x.redAdd(this.z); + // B = X2 - Z2 + var b = this.x.redSub(this.z); + // C = X3 + Z3 + var c = p.x.redAdd(p.z); + // D = X3 - Z3 + var d = p.x.redSub(p.z); + // DA = D * A + var da = d.redMul(a); + // CB = C * B + var cb = c.redMul(b); + // X5 = Z1 * (DA + CB)^2 + var nx = diff.z.redMul(da.redAdd(cb).redSqr()); + // Z5 = X1 * (DA - CB)^2 + var nz = diff.x.redMul(da.redISub(cb).redSqr()); + return this.curve.point(nx, nz); +}; + +Point.prototype.mul = function mul(k) { + var t = k.clone(); + var a = this; // (N / 2) * Q + Q + var b = this.curve.point(null, null); // (N / 2) * Q + var c = this; // Q + + for (var bits = []; t.cmpn(0) !== 0; t.iushrn(1)) + bits.push(t.andln(1)); + + for (var i = bits.length - 1; i >= 0; i--) { + if (bits[i] === 0) { + // N * Q + Q = ((N / 2) * Q + Q)) + (N / 2) * Q + a = a.diffAdd(b, c); + // N * Q = 2 * ((N / 2) * Q + Q)) + b = b.dbl(); + } else { + // N * Q = ((N / 2) * Q + Q) + ((N / 2) * Q) + b = a.diffAdd(b, c); + // N * Q + Q = 2 * ((N / 2) * Q + Q) + a = a.dbl(); + } + } + return b; +}; + +Point.prototype.mulAdd = function mulAdd() { + throw new Error('Not supported on Montgomery curve'); +}; + +Point.prototype.jumlAdd = function jumlAdd() { + throw new Error('Not supported on Montgomery curve'); +}; + +Point.prototype.eq = function eq(other) { + return this.getX().cmp(other.getX()) === 0; +}; + +Point.prototype.normalize = function normalize() { + this.x = this.x.redMul(this.z.redInvm()); + this.z = this.curve.one; + return this; +}; + +Point.prototype.getX = function getX() { + // Normalize coordinates + this.normalize(); + + return this.x.fromRed(); +}; + +},{"../utils":100,"./base":87,"bn.js":101,"inherits":143}],91:[function(require,module,exports){ +'use strict'; + +var utils = require('../utils'); +var BN = require('bn.js'); +var inherits = require('inherits'); +var Base = require('./base'); + +var assert = utils.assert; + +function ShortCurve(conf) { + Base.call(this, 'short', conf); + + this.a = new BN(conf.a, 16).toRed(this.red); + this.b = new BN(conf.b, 16).toRed(this.red); + this.tinv = this.two.redInvm(); + + this.zeroA = this.a.fromRed().cmpn(0) === 0; + this.threeA = this.a.fromRed().sub(this.p).cmpn(-3) === 0; + + // If the curve is endomorphic, precalculate beta and lambda + this.endo = this._getEndomorphism(conf); + this._endoWnafT1 = new Array(4); + this._endoWnafT2 = new Array(4); +} +inherits(ShortCurve, Base); +module.exports = ShortCurve; + +ShortCurve.prototype._getEndomorphism = function _getEndomorphism(conf) { + // No efficient endomorphism + if (!this.zeroA || !this.g || !this.n || this.p.modn(3) !== 1) + return; + + // Compute beta and lambda, that lambda * P = (beta * Px; Py) + var beta; + var lambda; + if (conf.beta) { + beta = new BN(conf.beta, 16).toRed(this.red); + } else { + var betas = this._getEndoRoots(this.p); + // Choose the smallest beta + beta = betas[0].cmp(betas[1]) < 0 ? betas[0] : betas[1]; + beta = beta.toRed(this.red); + } + if (conf.lambda) { + lambda = new BN(conf.lambda, 16); + } else { + // Choose the lambda that is matching selected beta + var lambdas = this._getEndoRoots(this.n); + if (this.g.mul(lambdas[0]).x.cmp(this.g.x.redMul(beta)) === 0) { + lambda = lambdas[0]; + } else { + lambda = lambdas[1]; + assert(this.g.mul(lambda).x.cmp(this.g.x.redMul(beta)) === 0); + } + } + + // Get basis vectors, used for balanced length-two representation + var basis; + if (conf.basis) { + basis = conf.basis.map(function(vec) { + return { + a: new BN(vec.a, 16), + b: new BN(vec.b, 16), + }; + }); + } else { + basis = this._getEndoBasis(lambda); + } + + return { + beta: beta, + lambda: lambda, + basis: basis, + }; +}; + +ShortCurve.prototype._getEndoRoots = function _getEndoRoots(num) { + // Find roots of for x^2 + x + 1 in F + // Root = (-1 +- Sqrt(-3)) / 2 + // + var red = num === this.p ? this.red : BN.mont(num); + var tinv = new BN(2).toRed(red).redInvm(); + var ntinv = tinv.redNeg(); + + var s = new BN(3).toRed(red).redNeg().redSqrt().redMul(tinv); + + var l1 = ntinv.redAdd(s).fromRed(); + var l2 = ntinv.redSub(s).fromRed(); + return [ l1, l2 ]; +}; + +ShortCurve.prototype._getEndoBasis = function _getEndoBasis(lambda) { + // aprxSqrt >= sqrt(this.n) + var aprxSqrt = this.n.ushrn(Math.floor(this.n.bitLength() / 2)); + + // 3.74 + // Run EGCD, until r(L + 1) < aprxSqrt + var u = lambda; + var v = this.n.clone(); + var x1 = new BN(1); + var y1 = new BN(0); + var x2 = new BN(0); + var y2 = new BN(1); + + // NOTE: all vectors are roots of: a + b * lambda = 0 (mod n) + var a0; + var b0; + // First vector + var a1; + var b1; + // Second vector + var a2; + var b2; + + var prevR; + var i = 0; + var r; + var x; + while (u.cmpn(0) !== 0) { + var q = v.div(u); + r = v.sub(q.mul(u)); + x = x2.sub(q.mul(x1)); + var y = y2.sub(q.mul(y1)); + + if (!a1 && r.cmp(aprxSqrt) < 0) { + a0 = prevR.neg(); + b0 = x1; + a1 = r.neg(); + b1 = x; + } else if (a1 && ++i === 2) { + break; + } + prevR = r; + + v = u; + u = r; + x2 = x1; + x1 = x; + y2 = y1; + y1 = y; + } + a2 = r.neg(); + b2 = x; + + var len1 = a1.sqr().add(b1.sqr()); + var len2 = a2.sqr().add(b2.sqr()); + if (len2.cmp(len1) >= 0) { + a2 = a0; + b2 = b0; + } + + // Normalize signs + if (a1.negative) { + a1 = a1.neg(); + b1 = b1.neg(); + } + if (a2.negative) { + a2 = a2.neg(); + b2 = b2.neg(); + } + + return [ + { a: a1, b: b1 }, + { a: a2, b: b2 }, + ]; +}; + +ShortCurve.prototype._endoSplit = function _endoSplit(k) { + var basis = this.endo.basis; + var v1 = basis[0]; + var v2 = basis[1]; + + var c1 = v2.b.mul(k).divRound(this.n); + var c2 = v1.b.neg().mul(k).divRound(this.n); + + var p1 = c1.mul(v1.a); + var p2 = c2.mul(v2.a); + var q1 = c1.mul(v1.b); + var q2 = c2.mul(v2.b); + + // Calculate answer + var k1 = k.sub(p1).sub(p2); + var k2 = q1.add(q2).neg(); + return { k1: k1, k2: k2 }; +}; + +ShortCurve.prototype.pointFromX = function pointFromX(x, odd) { + x = new BN(x, 16); + if (!x.red) + x = x.toRed(this.red); + + var y2 = x.redSqr().redMul(x).redIAdd(x.redMul(this.a)).redIAdd(this.b); + var y = y2.redSqrt(); + if (y.redSqr().redSub(y2).cmp(this.zero) !== 0) + throw new Error('invalid point'); + + // XXX Is there any way to tell if the number is odd without converting it + // to non-red form? + var isOdd = y.fromRed().isOdd(); + if (odd && !isOdd || !odd && isOdd) + y = y.redNeg(); + + return this.point(x, y); +}; + +ShortCurve.prototype.validate = function validate(point) { + if (point.inf) + return true; + + var x = point.x; + var y = point.y; + + var ax = this.a.redMul(x); + var rhs = x.redSqr().redMul(x).redIAdd(ax).redIAdd(this.b); + return y.redSqr().redISub(rhs).cmpn(0) === 0; +}; + +ShortCurve.prototype._endoWnafMulAdd = + function _endoWnafMulAdd(points, coeffs, jacobianResult) { + var npoints = this._endoWnafT1; + var ncoeffs = this._endoWnafT2; + for (var i = 0; i < points.length; i++) { + var split = this._endoSplit(coeffs[i]); + var p = points[i]; + var beta = p._getBeta(); + + if (split.k1.negative) { + split.k1.ineg(); + p = p.neg(true); + } + if (split.k2.negative) { + split.k2.ineg(); + beta = beta.neg(true); + } + + npoints[i * 2] = p; + npoints[i * 2 + 1] = beta; + ncoeffs[i * 2] = split.k1; + ncoeffs[i * 2 + 1] = split.k2; + } + var res = this._wnafMulAdd(1, npoints, ncoeffs, i * 2, jacobianResult); + + // Clean-up references to points and coefficients + for (var j = 0; j < i * 2; j++) { + npoints[j] = null; + ncoeffs[j] = null; + } + return res; + }; + +function Point(curve, x, y, isRed) { + Base.BasePoint.call(this, curve, 'affine'); + if (x === null && y === null) { + this.x = null; + this.y = null; + this.inf = true; + } else { + this.x = new BN(x, 16); + this.y = new BN(y, 16); + // Force redgomery representation when loading from JSON + if (isRed) { + this.x.forceRed(this.curve.red); + this.y.forceRed(this.curve.red); + } + if (!this.x.red) + this.x = this.x.toRed(this.curve.red); + if (!this.y.red) + this.y = this.y.toRed(this.curve.red); + this.inf = false; + } +} +inherits(Point, Base.BasePoint); + +ShortCurve.prototype.point = function point(x, y, isRed) { + return new Point(this, x, y, isRed); +}; + +ShortCurve.prototype.pointFromJSON = function pointFromJSON(obj, red) { + return Point.fromJSON(this, obj, red); +}; + +Point.prototype._getBeta = function _getBeta() { + if (!this.curve.endo) + return; + + var pre = this.precomputed; + if (pre && pre.beta) + return pre.beta; + + var beta = this.curve.point(this.x.redMul(this.curve.endo.beta), this.y); + if (pre) { + var curve = this.curve; + var endoMul = function(p) { + return curve.point(p.x.redMul(curve.endo.beta), p.y); + }; + pre.beta = beta; + beta.precomputed = { + beta: null, + naf: pre.naf && { + wnd: pre.naf.wnd, + points: pre.naf.points.map(endoMul), + }, + doubles: pre.doubles && { + step: pre.doubles.step, + points: pre.doubles.points.map(endoMul), + }, + }; + } + return beta; +}; + +Point.prototype.toJSON = function toJSON() { + if (!this.precomputed) + return [ this.x, this.y ]; + + return [ this.x, this.y, this.precomputed && { + doubles: this.precomputed.doubles && { + step: this.precomputed.doubles.step, + points: this.precomputed.doubles.points.slice(1), + }, + naf: this.precomputed.naf && { + wnd: this.precomputed.naf.wnd, + points: this.precomputed.naf.points.slice(1), + }, + } ]; +}; + +Point.fromJSON = function fromJSON(curve, obj, red) { + if (typeof obj === 'string') + obj = JSON.parse(obj); + var res = curve.point(obj[0], obj[1], red); + if (!obj[2]) + return res; + + function obj2point(obj) { + return curve.point(obj[0], obj[1], red); + } + + var pre = obj[2]; + res.precomputed = { + beta: null, + doubles: pre.doubles && { + step: pre.doubles.step, + points: [ res ].concat(pre.doubles.points.map(obj2point)), + }, + naf: pre.naf && { + wnd: pre.naf.wnd, + points: [ res ].concat(pre.naf.points.map(obj2point)), + }, + }; + return res; +}; + +Point.prototype.inspect = function inspect() { + if (this.isInfinity()) + return ''; + return ''; +}; + +Point.prototype.isInfinity = function isInfinity() { + return this.inf; +}; + +Point.prototype.add = function add(p) { + // O + P = P + if (this.inf) + return p; + + // P + O = P + if (p.inf) + return this; + + // P + P = 2P + if (this.eq(p)) + return this.dbl(); + + // P + (-P) = O + if (this.neg().eq(p)) + return this.curve.point(null, null); + + // P + Q = O + if (this.x.cmp(p.x) === 0) + return this.curve.point(null, null); + + var c = this.y.redSub(p.y); + if (c.cmpn(0) !== 0) + c = c.redMul(this.x.redSub(p.x).redInvm()); + var nx = c.redSqr().redISub(this.x).redISub(p.x); + var ny = c.redMul(this.x.redSub(nx)).redISub(this.y); + return this.curve.point(nx, ny); +}; + +Point.prototype.dbl = function dbl() { + if (this.inf) + return this; + + // 2P = O + var ys1 = this.y.redAdd(this.y); + if (ys1.cmpn(0) === 0) + return this.curve.point(null, null); + + var a = this.curve.a; + + var x2 = this.x.redSqr(); + var dyinv = ys1.redInvm(); + var c = x2.redAdd(x2).redIAdd(x2).redIAdd(a).redMul(dyinv); + + var nx = c.redSqr().redISub(this.x.redAdd(this.x)); + var ny = c.redMul(this.x.redSub(nx)).redISub(this.y); + return this.curve.point(nx, ny); +}; + +Point.prototype.getX = function getX() { + return this.x.fromRed(); +}; + +Point.prototype.getY = function getY() { + return this.y.fromRed(); +}; + +Point.prototype.mul = function mul(k) { + k = new BN(k, 16); + if (this.isInfinity()) + return this; + else if (this._hasDoubles(k)) + return this.curve._fixedNafMul(this, k); + else if (this.curve.endo) + return this.curve._endoWnafMulAdd([ this ], [ k ]); + else + return this.curve._wnafMul(this, k); +}; + +Point.prototype.mulAdd = function mulAdd(k1, p2, k2) { + var points = [ this, p2 ]; + var coeffs = [ k1, k2 ]; + if (this.curve.endo) + return this.curve._endoWnafMulAdd(points, coeffs); + else + return this.curve._wnafMulAdd(1, points, coeffs, 2); +}; + +Point.prototype.jmulAdd = function jmulAdd(k1, p2, k2) { + var points = [ this, p2 ]; + var coeffs = [ k1, k2 ]; + if (this.curve.endo) + return this.curve._endoWnafMulAdd(points, coeffs, true); + else + return this.curve._wnafMulAdd(1, points, coeffs, 2, true); +}; + +Point.prototype.eq = function eq(p) { + return this === p || + this.inf === p.inf && + (this.inf || this.x.cmp(p.x) === 0 && this.y.cmp(p.y) === 0); +}; + +Point.prototype.neg = function neg(_precompute) { + if (this.inf) + return this; + + var res = this.curve.point(this.x, this.y.redNeg()); + if (_precompute && this.precomputed) { + var pre = this.precomputed; + var negate = function(p) { + return p.neg(); + }; + res.precomputed = { + naf: pre.naf && { + wnd: pre.naf.wnd, + points: pre.naf.points.map(negate), + }, + doubles: pre.doubles && { + step: pre.doubles.step, + points: pre.doubles.points.map(negate), + }, + }; + } + return res; +}; + +Point.prototype.toJ = function toJ() { + if (this.inf) + return this.curve.jpoint(null, null, null); + + var res = this.curve.jpoint(this.x, this.y, this.curve.one); + return res; +}; + +function JPoint(curve, x, y, z) { + Base.BasePoint.call(this, curve, 'jacobian'); + if (x === null && y === null && z === null) { + this.x = this.curve.one; + this.y = this.curve.one; + this.z = new BN(0); + } else { + this.x = new BN(x, 16); + this.y = new BN(y, 16); + this.z = new BN(z, 16); + } + if (!this.x.red) + this.x = this.x.toRed(this.curve.red); + if (!this.y.red) + this.y = this.y.toRed(this.curve.red); + if (!this.z.red) + this.z = this.z.toRed(this.curve.red); + + this.zOne = this.z === this.curve.one; +} +inherits(JPoint, Base.BasePoint); + +ShortCurve.prototype.jpoint = function jpoint(x, y, z) { + return new JPoint(this, x, y, z); +}; + +JPoint.prototype.toP = function toP() { + if (this.isInfinity()) + return this.curve.point(null, null); + + var zinv = this.z.redInvm(); + var zinv2 = zinv.redSqr(); + var ax = this.x.redMul(zinv2); + var ay = this.y.redMul(zinv2).redMul(zinv); + + return this.curve.point(ax, ay); +}; + +JPoint.prototype.neg = function neg() { + return this.curve.jpoint(this.x, this.y.redNeg(), this.z); +}; + +JPoint.prototype.add = function add(p) { + // O + P = P + if (this.isInfinity()) + return p; + + // P + O = P + if (p.isInfinity()) + return this; + + // 12M + 4S + 7A + var pz2 = p.z.redSqr(); + var z2 = this.z.redSqr(); + var u1 = this.x.redMul(pz2); + var u2 = p.x.redMul(z2); + var s1 = this.y.redMul(pz2.redMul(p.z)); + var s2 = p.y.redMul(z2.redMul(this.z)); + + var h = u1.redSub(u2); + var r = s1.redSub(s2); + if (h.cmpn(0) === 0) { + if (r.cmpn(0) !== 0) + return this.curve.jpoint(null, null, null); + else + return this.dbl(); + } + + var h2 = h.redSqr(); + var h3 = h2.redMul(h); + var v = u1.redMul(h2); + + var nx = r.redSqr().redIAdd(h3).redISub(v).redISub(v); + var ny = r.redMul(v.redISub(nx)).redISub(s1.redMul(h3)); + var nz = this.z.redMul(p.z).redMul(h); + + return this.curve.jpoint(nx, ny, nz); +}; + +JPoint.prototype.mixedAdd = function mixedAdd(p) { + // O + P = P + if (this.isInfinity()) + return p.toJ(); + + // P + O = P + if (p.isInfinity()) + return this; + + // 8M + 3S + 7A + var z2 = this.z.redSqr(); + var u1 = this.x; + var u2 = p.x.redMul(z2); + var s1 = this.y; + var s2 = p.y.redMul(z2).redMul(this.z); + + var h = u1.redSub(u2); + var r = s1.redSub(s2); + if (h.cmpn(0) === 0) { + if (r.cmpn(0) !== 0) + return this.curve.jpoint(null, null, null); + else + return this.dbl(); + } + + var h2 = h.redSqr(); + var h3 = h2.redMul(h); + var v = u1.redMul(h2); + + var nx = r.redSqr().redIAdd(h3).redISub(v).redISub(v); + var ny = r.redMul(v.redISub(nx)).redISub(s1.redMul(h3)); + var nz = this.z.redMul(h); + + return this.curve.jpoint(nx, ny, nz); +}; + +JPoint.prototype.dblp = function dblp(pow) { + if (pow === 0) + return this; + if (this.isInfinity()) + return this; + if (!pow) + return this.dbl(); + + var i; + if (this.curve.zeroA || this.curve.threeA) { + var r = this; + for (i = 0; i < pow; i++) + r = r.dbl(); + return r; + } + + // 1M + 2S + 1A + N * (4S + 5M + 8A) + // N = 1 => 6M + 6S + 9A + var a = this.curve.a; + var tinv = this.curve.tinv; + + var jx = this.x; + var jy = this.y; + var jz = this.z; + var jz4 = jz.redSqr().redSqr(); + + // Reuse results + var jyd = jy.redAdd(jy); + for (i = 0; i < pow; i++) { + var jx2 = jx.redSqr(); + var jyd2 = jyd.redSqr(); + var jyd4 = jyd2.redSqr(); + var c = jx2.redAdd(jx2).redIAdd(jx2).redIAdd(a.redMul(jz4)); + + var t1 = jx.redMul(jyd2); + var nx = c.redSqr().redISub(t1.redAdd(t1)); + var t2 = t1.redISub(nx); + var dny = c.redMul(t2); + dny = dny.redIAdd(dny).redISub(jyd4); + var nz = jyd.redMul(jz); + if (i + 1 < pow) + jz4 = jz4.redMul(jyd4); + + jx = nx; + jz = nz; + jyd = dny; + } + + return this.curve.jpoint(jx, jyd.redMul(tinv), jz); +}; + +JPoint.prototype.dbl = function dbl() { + if (this.isInfinity()) + return this; + + if (this.curve.zeroA) + return this._zeroDbl(); + else if (this.curve.threeA) + return this._threeDbl(); + else + return this._dbl(); +}; + +JPoint.prototype._zeroDbl = function _zeroDbl() { + var nx; + var ny; + var nz; + // Z = 1 + if (this.zOne) { + // hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html + // #doubling-mdbl-2007-bl + // 1M + 5S + 14A + + // XX = X1^2 + var xx = this.x.redSqr(); + // YY = Y1^2 + var yy = this.y.redSqr(); + // YYYY = YY^2 + var yyyy = yy.redSqr(); + // S = 2 * ((X1 + YY)^2 - XX - YYYY) + var s = this.x.redAdd(yy).redSqr().redISub(xx).redISub(yyyy); + s = s.redIAdd(s); + // M = 3 * XX + a; a = 0 + var m = xx.redAdd(xx).redIAdd(xx); + // T = M ^ 2 - 2*S + var t = m.redSqr().redISub(s).redISub(s); + + // 8 * YYYY + var yyyy8 = yyyy.redIAdd(yyyy); + yyyy8 = yyyy8.redIAdd(yyyy8); + yyyy8 = yyyy8.redIAdd(yyyy8); + + // X3 = T + nx = t; + // Y3 = M * (S - T) - 8 * YYYY + ny = m.redMul(s.redISub(t)).redISub(yyyy8); + // Z3 = 2*Y1 + nz = this.y.redAdd(this.y); + } else { + // hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html + // #doubling-dbl-2009-l + // 2M + 5S + 13A + + // A = X1^2 + var a = this.x.redSqr(); + // B = Y1^2 + var b = this.y.redSqr(); + // C = B^2 + var c = b.redSqr(); + // D = 2 * ((X1 + B)^2 - A - C) + var d = this.x.redAdd(b).redSqr().redISub(a).redISub(c); + d = d.redIAdd(d); + // E = 3 * A + var e = a.redAdd(a).redIAdd(a); + // F = E^2 + var f = e.redSqr(); + + // 8 * C + var c8 = c.redIAdd(c); + c8 = c8.redIAdd(c8); + c8 = c8.redIAdd(c8); + + // X3 = F - 2 * D + nx = f.redISub(d).redISub(d); + // Y3 = E * (D - X3) - 8 * C + ny = e.redMul(d.redISub(nx)).redISub(c8); + // Z3 = 2 * Y1 * Z1 + nz = this.y.redMul(this.z); + nz = nz.redIAdd(nz); + } + + return this.curve.jpoint(nx, ny, nz); +}; + +JPoint.prototype._threeDbl = function _threeDbl() { + var nx; + var ny; + var nz; + // Z = 1 + if (this.zOne) { + // hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-3.html + // #doubling-mdbl-2007-bl + // 1M + 5S + 15A + + // XX = X1^2 + var xx = this.x.redSqr(); + // YY = Y1^2 + var yy = this.y.redSqr(); + // YYYY = YY^2 + var yyyy = yy.redSqr(); + // S = 2 * ((X1 + YY)^2 - XX - YYYY) + var s = this.x.redAdd(yy).redSqr().redISub(xx).redISub(yyyy); + s = s.redIAdd(s); + // M = 3 * XX + a + var m = xx.redAdd(xx).redIAdd(xx).redIAdd(this.curve.a); + // T = M^2 - 2 * S + var t = m.redSqr().redISub(s).redISub(s); + // X3 = T + nx = t; + // Y3 = M * (S - T) - 8 * YYYY + var yyyy8 = yyyy.redIAdd(yyyy); + yyyy8 = yyyy8.redIAdd(yyyy8); + yyyy8 = yyyy8.redIAdd(yyyy8); + ny = m.redMul(s.redISub(t)).redISub(yyyy8); + // Z3 = 2 * Y1 + nz = this.y.redAdd(this.y); + } else { + // hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-3.html#doubling-dbl-2001-b + // 3M + 5S + + // delta = Z1^2 + var delta = this.z.redSqr(); + // gamma = Y1^2 + var gamma = this.y.redSqr(); + // beta = X1 * gamma + var beta = this.x.redMul(gamma); + // alpha = 3 * (X1 - delta) * (X1 + delta) + var alpha = this.x.redSub(delta).redMul(this.x.redAdd(delta)); + alpha = alpha.redAdd(alpha).redIAdd(alpha); + // X3 = alpha^2 - 8 * beta + var beta4 = beta.redIAdd(beta); + beta4 = beta4.redIAdd(beta4); + var beta8 = beta4.redAdd(beta4); + nx = alpha.redSqr().redISub(beta8); + // Z3 = (Y1 + Z1)^2 - gamma - delta + nz = this.y.redAdd(this.z).redSqr().redISub(gamma).redISub(delta); + // Y3 = alpha * (4 * beta - X3) - 8 * gamma^2 + var ggamma8 = gamma.redSqr(); + ggamma8 = ggamma8.redIAdd(ggamma8); + ggamma8 = ggamma8.redIAdd(ggamma8); + ggamma8 = ggamma8.redIAdd(ggamma8); + ny = alpha.redMul(beta4.redISub(nx)).redISub(ggamma8); + } + + return this.curve.jpoint(nx, ny, nz); +}; + +JPoint.prototype._dbl = function _dbl() { + var a = this.curve.a; + + // 4M + 6S + 10A + var jx = this.x; + var jy = this.y; + var jz = this.z; + var jz4 = jz.redSqr().redSqr(); + + var jx2 = jx.redSqr(); + var jy2 = jy.redSqr(); + + var c = jx2.redAdd(jx2).redIAdd(jx2).redIAdd(a.redMul(jz4)); + + var jxd4 = jx.redAdd(jx); + jxd4 = jxd4.redIAdd(jxd4); + var t1 = jxd4.redMul(jy2); + var nx = c.redSqr().redISub(t1.redAdd(t1)); + var t2 = t1.redISub(nx); + + var jyd8 = jy2.redSqr(); + jyd8 = jyd8.redIAdd(jyd8); + jyd8 = jyd8.redIAdd(jyd8); + jyd8 = jyd8.redIAdd(jyd8); + var ny = c.redMul(t2).redISub(jyd8); + var nz = jy.redAdd(jy).redMul(jz); + + return this.curve.jpoint(nx, ny, nz); +}; + +JPoint.prototype.trpl = function trpl() { + if (!this.curve.zeroA) + return this.dbl().add(this); + + // hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html#tripling-tpl-2007-bl + // 5M + 10S + ... + + // XX = X1^2 + var xx = this.x.redSqr(); + // YY = Y1^2 + var yy = this.y.redSqr(); + // ZZ = Z1^2 + var zz = this.z.redSqr(); + // YYYY = YY^2 + var yyyy = yy.redSqr(); + // M = 3 * XX + a * ZZ2; a = 0 + var m = xx.redAdd(xx).redIAdd(xx); + // MM = M^2 + var mm = m.redSqr(); + // E = 6 * ((X1 + YY)^2 - XX - YYYY) - MM + var e = this.x.redAdd(yy).redSqr().redISub(xx).redISub(yyyy); + e = e.redIAdd(e); + e = e.redAdd(e).redIAdd(e); + e = e.redISub(mm); + // EE = E^2 + var ee = e.redSqr(); + // T = 16*YYYY + var t = yyyy.redIAdd(yyyy); + t = t.redIAdd(t); + t = t.redIAdd(t); + t = t.redIAdd(t); + // U = (M + E)^2 - MM - EE - T + var u = m.redIAdd(e).redSqr().redISub(mm).redISub(ee).redISub(t); + // X3 = 4 * (X1 * EE - 4 * YY * U) + var yyu4 = yy.redMul(u); + yyu4 = yyu4.redIAdd(yyu4); + yyu4 = yyu4.redIAdd(yyu4); + var nx = this.x.redMul(ee).redISub(yyu4); + nx = nx.redIAdd(nx); + nx = nx.redIAdd(nx); + // Y3 = 8 * Y1 * (U * (T - U) - E * EE) + var ny = this.y.redMul(u.redMul(t.redISub(u)).redISub(e.redMul(ee))); + ny = ny.redIAdd(ny); + ny = ny.redIAdd(ny); + ny = ny.redIAdd(ny); + // Z3 = (Z1 + E)^2 - ZZ - EE + var nz = this.z.redAdd(e).redSqr().redISub(zz).redISub(ee); + + return this.curve.jpoint(nx, ny, nz); +}; + +JPoint.prototype.mul = function mul(k, kbase) { + k = new BN(k, kbase); + + return this.curve._wnafMul(this, k); +}; + +JPoint.prototype.eq = function eq(p) { + if (p.type === 'affine') + return this.eq(p.toJ()); + + if (this === p) + return true; + + // x1 * z2^2 == x2 * z1^2 + var z2 = this.z.redSqr(); + var pz2 = p.z.redSqr(); + if (this.x.redMul(pz2).redISub(p.x.redMul(z2)).cmpn(0) !== 0) + return false; + + // y1 * z2^3 == y2 * z1^3 + var z3 = z2.redMul(this.z); + var pz3 = pz2.redMul(p.z); + return this.y.redMul(pz3).redISub(p.y.redMul(z3)).cmpn(0) === 0; +}; + +JPoint.prototype.eqXToP = function eqXToP(x) { + var zs = this.z.redSqr(); + var rx = x.toRed(this.curve.red).redMul(zs); + if (this.x.cmp(rx) === 0) + return true; + + var xc = x.clone(); + var t = this.curve.redN.redMul(zs); + for (;;) { + xc.iadd(this.curve.n); + if (xc.cmp(this.curve.p) >= 0) + return false; + + rx.redIAdd(t); + if (this.x.cmp(rx) === 0) + return true; + } +}; + +JPoint.prototype.inspect = function inspect() { + if (this.isInfinity()) + return ''; + return ''; +}; + +JPoint.prototype.isInfinity = function isInfinity() { + // XXX This code assumes that zero is always zero in red + return this.z.cmpn(0) === 0; +}; + +},{"../utils":100,"./base":87,"bn.js":101,"inherits":143}],92:[function(require,module,exports){ +'use strict'; + +var curves = exports; + +var hash = require('hash.js'); +var curve = require('./curve'); +var utils = require('./utils'); + +var assert = utils.assert; + +function PresetCurve(options) { + if (options.type === 'short') + this.curve = new curve.short(options); + else if (options.type === 'edwards') + this.curve = new curve.edwards(options); + else + this.curve = new curve.mont(options); + this.g = this.curve.g; + this.n = this.curve.n; + this.hash = options.hash; + + assert(this.g.validate(), 'Invalid curve'); + assert(this.g.mul(this.n).isInfinity(), 'Invalid curve, G*N != O'); +} +curves.PresetCurve = PresetCurve; + +function defineCurve(name, options) { + Object.defineProperty(curves, name, { + configurable: true, + enumerable: true, + get: function() { + var curve = new PresetCurve(options); + Object.defineProperty(curves, name, { + configurable: true, + enumerable: true, + value: curve, + }); + return curve; + }, + }); +} + +defineCurve('p192', { + type: 'short', + prime: 'p192', + p: 'ffffffff ffffffff ffffffff fffffffe ffffffff ffffffff', + a: 'ffffffff ffffffff ffffffff fffffffe ffffffff fffffffc', + b: '64210519 e59c80e7 0fa7e9ab 72243049 feb8deec c146b9b1', + n: 'ffffffff ffffffff ffffffff 99def836 146bc9b1 b4d22831', + hash: hash.sha256, + gRed: false, + g: [ + '188da80e b03090f6 7cbf20eb 43a18800 f4ff0afd 82ff1012', + '07192b95 ffc8da78 631011ed 6b24cdd5 73f977a1 1e794811', + ], +}); + +defineCurve('p224', { + type: 'short', + prime: 'p224', + p: 'ffffffff ffffffff ffffffff ffffffff 00000000 00000000 00000001', + a: 'ffffffff ffffffff ffffffff fffffffe ffffffff ffffffff fffffffe', + b: 'b4050a85 0c04b3ab f5413256 5044b0b7 d7bfd8ba 270b3943 2355ffb4', + n: 'ffffffff ffffffff ffffffff ffff16a2 e0b8f03e 13dd2945 5c5c2a3d', + hash: hash.sha256, + gRed: false, + g: [ + 'b70e0cbd 6bb4bf7f 321390b9 4a03c1d3 56c21122 343280d6 115c1d21', + 'bd376388 b5f723fb 4c22dfe6 cd4375a0 5a074764 44d58199 85007e34', + ], +}); + +defineCurve('p256', { + type: 'short', + prime: null, + p: 'ffffffff 00000001 00000000 00000000 00000000 ffffffff ffffffff ffffffff', + a: 'ffffffff 00000001 00000000 00000000 00000000 ffffffff ffffffff fffffffc', + b: '5ac635d8 aa3a93e7 b3ebbd55 769886bc 651d06b0 cc53b0f6 3bce3c3e 27d2604b', + n: 'ffffffff 00000000 ffffffff ffffffff bce6faad a7179e84 f3b9cac2 fc632551', + hash: hash.sha256, + gRed: false, + g: [ + '6b17d1f2 e12c4247 f8bce6e5 63a440f2 77037d81 2deb33a0 f4a13945 d898c296', + '4fe342e2 fe1a7f9b 8ee7eb4a 7c0f9e16 2bce3357 6b315ece cbb64068 37bf51f5', + ], +}); + +defineCurve('p384', { + type: 'short', + prime: null, + p: 'ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ' + + 'fffffffe ffffffff 00000000 00000000 ffffffff', + a: 'ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ' + + 'fffffffe ffffffff 00000000 00000000 fffffffc', + b: 'b3312fa7 e23ee7e4 988e056b e3f82d19 181d9c6e fe814112 0314088f ' + + '5013875a c656398d 8a2ed19d 2a85c8ed d3ec2aef', + n: 'ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff c7634d81 ' + + 'f4372ddf 581a0db2 48b0a77a ecec196a ccc52973', + hash: hash.sha384, + gRed: false, + g: [ + 'aa87ca22 be8b0537 8eb1c71e f320ad74 6e1d3b62 8ba79b98 59f741e0 82542a38 ' + + '5502f25d bf55296c 3a545e38 72760ab7', + '3617de4a 96262c6f 5d9e98bf 9292dc29 f8f41dbd 289a147c e9da3113 b5f0b8c0 ' + + '0a60b1ce 1d7e819d 7a431d7c 90ea0e5f', + ], +}); + +defineCurve('p521', { + type: 'short', + prime: null, + p: '000001ff ffffffff ffffffff ffffffff ffffffff ffffffff ' + + 'ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ' + + 'ffffffff ffffffff ffffffff ffffffff ffffffff', + a: '000001ff ffffffff ffffffff ffffffff ffffffff ffffffff ' + + 'ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ' + + 'ffffffff ffffffff ffffffff ffffffff fffffffc', + b: '00000051 953eb961 8e1c9a1f 929a21a0 b68540ee a2da725b ' + + '99b315f3 b8b48991 8ef109e1 56193951 ec7e937b 1652c0bd ' + + '3bb1bf07 3573df88 3d2c34f1 ef451fd4 6b503f00', + n: '000001ff ffffffff ffffffff ffffffff ffffffff ffffffff ' + + 'ffffffff ffffffff fffffffa 51868783 bf2f966b 7fcc0148 ' + + 'f709a5d0 3bb5c9b8 899c47ae bb6fb71e 91386409', + hash: hash.sha512, + gRed: false, + g: [ + '000000c6 858e06b7 0404e9cd 9e3ecb66 2395b442 9c648139 ' + + '053fb521 f828af60 6b4d3dba a14b5e77 efe75928 fe1dc127 ' + + 'a2ffa8de 3348b3c1 856a429b f97e7e31 c2e5bd66', + '00000118 39296a78 9a3bc004 5c8a5fb4 2c7d1bd9 98f54449 ' + + '579b4468 17afbd17 273e662c 97ee7299 5ef42640 c550b901 ' + + '3fad0761 353c7086 a272c240 88be9476 9fd16650', + ], +}); + +defineCurve('curve25519', { + type: 'mont', + prime: 'p25519', + p: '7fffffffffffffff ffffffffffffffff ffffffffffffffff ffffffffffffffed', + a: '76d06', + b: '1', + n: '1000000000000000 0000000000000000 14def9dea2f79cd6 5812631a5cf5d3ed', + hash: hash.sha256, + gRed: false, + g: [ + '9', + ], +}); + +defineCurve('ed25519', { + type: 'edwards', + prime: 'p25519', + p: '7fffffffffffffff ffffffffffffffff ffffffffffffffff ffffffffffffffed', + a: '-1', + c: '1', + // -121665 * (121666^(-1)) (mod P) + d: '52036cee2b6ffe73 8cc740797779e898 00700a4d4141d8ab 75eb4dca135978a3', + n: '1000000000000000 0000000000000000 14def9dea2f79cd6 5812631a5cf5d3ed', + hash: hash.sha256, + gRed: false, + g: [ + '216936d3cd6e53fec0a4e231fdd6dc5c692cc7609525a7b2c9562d608f25d51a', + + // 4/5 + '6666666666666666666666666666666666666666666666666666666666666658', + ], +}); + +var pre; +try { + pre = require('./precomputed/secp256k1'); +} catch (e) { + pre = undefined; +} + +defineCurve('secp256k1', { + type: 'short', + prime: 'k256', + p: 'ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff fffffffe fffffc2f', + a: '0', + b: '7', + n: 'ffffffff ffffffff ffffffff fffffffe baaedce6 af48a03b bfd25e8c d0364141', + h: '1', + hash: hash.sha256, + + // Precomputed endomorphism + beta: '7ae96a2b657c07106e64479eac3434e99cf0497512f58995c1396c28719501ee', + lambda: '5363ad4cc05c30e0a5261c028812645a122e22ea20816678df02967c1b23bd72', + basis: [ + { + a: '3086d221a7d46bcde86c90e49284eb15', + b: '-e4437ed6010e88286f547fa90abfe4c3', + }, + { + a: '114ca50f7a8e2f3f657c1108d9d44cfd8', + b: '3086d221a7d46bcde86c90e49284eb15', + }, + ], + + gRed: false, + g: [ + '79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798', + '483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8', + pre, + ], +}); + +},{"./curve":89,"./precomputed/secp256k1":99,"./utils":100,"hash.js":129}],93:[function(require,module,exports){ +'use strict'; + +var BN = require('bn.js'); +var HmacDRBG = require('hmac-drbg'); +var utils = require('../utils'); +var curves = require('../curves'); +var rand = require('brorand'); +var assert = utils.assert; + +var KeyPair = require('./key'); +var Signature = require('./signature'); + +function EC(options) { + if (!(this instanceof EC)) + return new EC(options); + + // Shortcut `elliptic.ec(curve-name)` + if (typeof options === 'string') { + assert(Object.prototype.hasOwnProperty.call(curves, options), + 'Unknown curve ' + options); + + options = curves[options]; + } + + // Shortcut for `elliptic.ec(elliptic.curves.curveName)` + if (options instanceof curves.PresetCurve) + options = { curve: options }; + + this.curve = options.curve.curve; + this.n = this.curve.n; + this.nh = this.n.ushrn(1); + this.g = this.curve.g; + + // Point on curve + this.g = options.curve.g; + this.g.precompute(options.curve.n.bitLength() + 1); + + // Hash for function for DRBG + this.hash = options.hash || options.curve.hash; +} +module.exports = EC; + +EC.prototype.keyPair = function keyPair(options) { + return new KeyPair(this, options); +}; + +EC.prototype.keyFromPrivate = function keyFromPrivate(priv, enc) { + return KeyPair.fromPrivate(this, priv, enc); +}; + +EC.prototype.keyFromPublic = function keyFromPublic(pub, enc) { + return KeyPair.fromPublic(this, pub, enc); +}; + +EC.prototype.genKeyPair = function genKeyPair(options) { + if (!options) + options = {}; + + // Instantiate Hmac_DRBG + var drbg = new HmacDRBG({ + hash: this.hash, + pers: options.pers, + persEnc: options.persEnc || 'utf8', + entropy: options.entropy || rand(this.hash.hmacStrength), + entropyEnc: options.entropy && options.entropyEnc || 'utf8', + nonce: this.n.toArray(), + }); + + var bytes = this.n.byteLength(); + var ns2 = this.n.sub(new BN(2)); + for (;;) { + var priv = new BN(drbg.generate(bytes)); + if (priv.cmp(ns2) > 0) + continue; + + priv.iaddn(1); + return this.keyFromPrivate(priv); + } +}; + +EC.prototype._truncateToN = function _truncateToN(msg, truncOnly) { + var delta = msg.byteLength() * 8 - this.n.bitLength(); + if (delta > 0) + msg = msg.ushrn(delta); + if (!truncOnly && msg.cmp(this.n) >= 0) + return msg.sub(this.n); + else + return msg; +}; + +EC.prototype.sign = function sign(msg, key, enc, options) { + if (typeof enc === 'object') { + options = enc; + enc = null; + } + if (!options) + options = {}; + + key = this.keyFromPrivate(key, enc); + msg = this._truncateToN(new BN(msg, 16)); + + // Zero-extend key to provide enough entropy + var bytes = this.n.byteLength(); + var bkey = key.getPrivate().toArray('be', bytes); + + // Zero-extend nonce to have the same byte size as N + var nonce = msg.toArray('be', bytes); + + // Instantiate Hmac_DRBG + var drbg = new HmacDRBG({ + hash: this.hash, + entropy: bkey, + nonce: nonce, + pers: options.pers, + persEnc: options.persEnc || 'utf8', + }); + + // Number of bytes to generate + var ns1 = this.n.sub(new BN(1)); + + for (var iter = 0; ; iter++) { + var k = options.k ? + options.k(iter) : + new BN(drbg.generate(this.n.byteLength())); + k = this._truncateToN(k, true); + if (k.cmpn(1) <= 0 || k.cmp(ns1) >= 0) + continue; + + var kp = this.g.mul(k); + if (kp.isInfinity()) + continue; + + var kpX = kp.getX(); + var r = kpX.umod(this.n); + if (r.cmpn(0) === 0) + continue; + + var s = k.invm(this.n).mul(r.mul(key.getPrivate()).iadd(msg)); + s = s.umod(this.n); + if (s.cmpn(0) === 0) + continue; + + var recoveryParam = (kp.getY().isOdd() ? 1 : 0) | + (kpX.cmp(r) !== 0 ? 2 : 0); + + // Use complement of `s`, if it is > `n / 2` + if (options.canonical && s.cmp(this.nh) > 0) { + s = this.n.sub(s); + recoveryParam ^= 1; + } + + return new Signature({ r: r, s: s, recoveryParam: recoveryParam }); + } +}; + +EC.prototype.verify = function verify(msg, signature, key, enc) { + msg = this._truncateToN(new BN(msg, 16)); + key = this.keyFromPublic(key, enc); + signature = new Signature(signature, 'hex'); + + // Perform primitive values validation + var r = signature.r; + var s = signature.s; + if (r.cmpn(1) < 0 || r.cmp(this.n) >= 0) + return false; + if (s.cmpn(1) < 0 || s.cmp(this.n) >= 0) + return false; + + // Validate signature + var sinv = s.invm(this.n); + var u1 = sinv.mul(msg).umod(this.n); + var u2 = sinv.mul(r).umod(this.n); + var p; + + if (!this.curve._maxwellTrick) { + p = this.g.mulAdd(u1, key.getPublic(), u2); + if (p.isInfinity()) + return false; + + return p.getX().umod(this.n).cmp(r) === 0; + } + + // NOTE: Greg Maxwell's trick, inspired by: + // https://git.io/vad3K + + p = this.g.jmulAdd(u1, key.getPublic(), u2); + if (p.isInfinity()) + return false; + + // Compare `p.x` of Jacobian point with `r`, + // this will do `p.x == r * p.z^2` instead of multiplying `p.x` by the + // inverse of `p.z^2` + return p.eqXToP(r); +}; + +EC.prototype.recoverPubKey = function(msg, signature, j, enc) { + assert((3 & j) === j, 'The recovery param is more than two bits'); + signature = new Signature(signature, enc); + + var n = this.n; + var e = new BN(msg); + var r = signature.r; + var s = signature.s; + + // A set LSB signifies that the y-coordinate is odd + var isYOdd = j & 1; + var isSecondKey = j >> 1; + if (r.cmp(this.curve.p.umod(this.curve.n)) >= 0 && isSecondKey) + throw new Error('Unable to find sencond key candinate'); + + // 1.1. Let x = r + jn. + if (isSecondKey) + r = this.curve.pointFromX(r.add(this.curve.n), isYOdd); + else + r = this.curve.pointFromX(r, isYOdd); + + var rInv = signature.r.invm(n); + var s1 = n.sub(e).mul(rInv).umod(n); + var s2 = s.mul(rInv).umod(n); + + // 1.6.1 Compute Q = r^-1 (sR - eG) + // Q = r^-1 (sR + -eG) + return this.g.mulAdd(s1, r, s2); +}; + +EC.prototype.getKeyRecoveryParam = function(e, signature, Q, enc) { + signature = new Signature(signature, enc); + if (signature.recoveryParam !== null) + return signature.recoveryParam; + + for (var i = 0; i < 4; i++) { + var Qprime; + try { + Qprime = this.recoverPubKey(e, signature, i); + } catch (e) { + continue; + } + + if (Qprime.eq(Q)) + return i; + } + throw new Error('Unable to find valid recovery factor'); +}; + +},{"../curves":92,"../utils":100,"./key":94,"./signature":95,"bn.js":101,"brorand":19,"hmac-drbg":141}],94:[function(require,module,exports){ +'use strict'; + +var BN = require('bn.js'); +var utils = require('../utils'); +var assert = utils.assert; + +function KeyPair(ec, options) { + this.ec = ec; + this.priv = null; + this.pub = null; + + // KeyPair(ec, { priv: ..., pub: ... }) + if (options.priv) + this._importPrivate(options.priv, options.privEnc); + if (options.pub) + this._importPublic(options.pub, options.pubEnc); +} +module.exports = KeyPair; + +KeyPair.fromPublic = function fromPublic(ec, pub, enc) { + if (pub instanceof KeyPair) + return pub; + + return new KeyPair(ec, { + pub: pub, + pubEnc: enc, + }); +}; + +KeyPair.fromPrivate = function fromPrivate(ec, priv, enc) { + if (priv instanceof KeyPair) + return priv; + + return new KeyPair(ec, { + priv: priv, + privEnc: enc, + }); +}; + +KeyPair.prototype.validate = function validate() { + var pub = this.getPublic(); + + if (pub.isInfinity()) + return { result: false, reason: 'Invalid public key' }; + if (!pub.validate()) + return { result: false, reason: 'Public key is not a point' }; + if (!pub.mul(this.ec.curve.n).isInfinity()) + return { result: false, reason: 'Public key * N != O' }; + + return { result: true, reason: null }; +}; + +KeyPair.prototype.getPublic = function getPublic(compact, enc) { + // compact is optional argument + if (typeof compact === 'string') { + enc = compact; + compact = null; + } + + if (!this.pub) + this.pub = this.ec.g.mul(this.priv); + + if (!enc) + return this.pub; + + return this.pub.encode(enc, compact); +}; + +KeyPair.prototype.getPrivate = function getPrivate(enc) { + if (enc === 'hex') + return this.priv.toString(16, 2); + else + return this.priv; +}; + +KeyPair.prototype._importPrivate = function _importPrivate(key, enc) { + this.priv = new BN(key, enc || 16); + + // Ensure that the priv won't be bigger than n, otherwise we may fail + // in fixed multiplication method + this.priv = this.priv.umod(this.ec.curve.n); +}; + +KeyPair.prototype._importPublic = function _importPublic(key, enc) { + if (key.x || key.y) { + // Montgomery points only have an `x` coordinate. + // Weierstrass/Edwards points on the other hand have both `x` and + // `y` coordinates. + if (this.ec.curve.type === 'mont') { + assert(key.x, 'Need x coordinate'); + } else if (this.ec.curve.type === 'short' || + this.ec.curve.type === 'edwards') { + assert(key.x && key.y, 'Need both x and y coordinate'); + } + this.pub = this.ec.curve.point(key.x, key.y); + return; + } + this.pub = this.ec.curve.decodePoint(key, enc); +}; + +// ECDH +KeyPair.prototype.derive = function derive(pub) { + if(!pub.validate()) { + assert(pub.validate(), 'public point not validated'); + } + return pub.mul(this.priv).getX(); +}; + +// ECDSA +KeyPair.prototype.sign = function sign(msg, enc, options) { + return this.ec.sign(msg, this, enc, options); +}; + +KeyPair.prototype.verify = function verify(msg, signature) { + return this.ec.verify(msg, signature, this); +}; + +KeyPair.prototype.inspect = function inspect() { + return ''; +}; + +},{"../utils":100,"bn.js":101}],95:[function(require,module,exports){ +'use strict'; + +var BN = require('bn.js'); + +var utils = require('../utils'); +var assert = utils.assert; + +function Signature(options, enc) { + if (options instanceof Signature) + return options; + + if (this._importDER(options, enc)) + return; + + assert(options.r && options.s, 'Signature without r or s'); + this.r = new BN(options.r, 16); + this.s = new BN(options.s, 16); + if (options.recoveryParam === undefined) + this.recoveryParam = null; + else + this.recoveryParam = options.recoveryParam; +} +module.exports = Signature; + +function Position() { + this.place = 0; +} + +function getLength(buf, p) { + var initial = buf[p.place++]; + if (!(initial & 0x80)) { + return initial; + } + var octetLen = initial & 0xf; + + // Indefinite length or overflow + if (octetLen === 0 || octetLen > 4) { + return false; + } + + var val = 0; + for (var i = 0, off = p.place; i < octetLen; i++, off++) { + val <<= 8; + val |= buf[off]; + val >>>= 0; + } + + // Leading zeroes + if (val <= 0x7f) { + return false; + } + + p.place = off; + return val; +} + +function rmPadding(buf) { + var i = 0; + var len = buf.length - 1; + while (!buf[i] && !(buf[i + 1] & 0x80) && i < len) { + i++; + } + if (i === 0) { + return buf; + } + return buf.slice(i); +} + +Signature.prototype._importDER = function _importDER(data, enc) { + data = utils.toArray(data, enc); + var p = new Position(); + if (data[p.place++] !== 0x30) { + return false; + } + var len = getLength(data, p); + if (len === false) { + return false; + } + if ((len + p.place) !== data.length) { + return false; + } + if (data[p.place++] !== 0x02) { + return false; + } + var rlen = getLength(data, p); + if (rlen === false) { + return false; + } + var r = data.slice(p.place, rlen + p.place); + p.place += rlen; + if (data[p.place++] !== 0x02) { + return false; + } + var slen = getLength(data, p); + if (slen === false) { + return false; + } + if (data.length !== slen + p.place) { + return false; + } + var s = data.slice(p.place, slen + p.place); + if (r[0] === 0) { + if (r[1] & 0x80) { + r = r.slice(1); + } else { + // Leading zeroes + return false; + } + } + if (s[0] === 0) { + if (s[1] & 0x80) { + s = s.slice(1); + } else { + // Leading zeroes + return false; + } + } + + this.r = new BN(r); + this.s = new BN(s); + this.recoveryParam = null; + + return true; +}; + +function constructLength(arr, len) { + if (len < 0x80) { + arr.push(len); + return; + } + var octets = 1 + (Math.log(len) / Math.LN2 >>> 3); + arr.push(octets | 0x80); + while (--octets) { + arr.push((len >>> (octets << 3)) & 0xff); + } + arr.push(len); +} + +Signature.prototype.toDER = function toDER(enc) { + var r = this.r.toArray(); + var s = this.s.toArray(); + + // Pad values + if (r[0] & 0x80) + r = [ 0 ].concat(r); + // Pad values + if (s[0] & 0x80) + s = [ 0 ].concat(s); + + r = rmPadding(r); + s = rmPadding(s); + + while (!s[0] && !(s[1] & 0x80)) { + s = s.slice(1); + } + var arr = [ 0x02 ]; + constructLength(arr, r.length); + arr = arr.concat(r); + arr.push(0x02); + constructLength(arr, s.length); + var backHalf = arr.concat(s); + var res = [ 0x30 ]; + constructLength(res, backHalf.length); + res = res.concat(backHalf); + return utils.encode(res, enc); +}; + +},{"../utils":100,"bn.js":101}],96:[function(require,module,exports){ +'use strict'; + +var hash = require('hash.js'); +var curves = require('../curves'); +var utils = require('../utils'); +var assert = utils.assert; +var parseBytes = utils.parseBytes; +var KeyPair = require('./key'); +var Signature = require('./signature'); + +function EDDSA(curve) { + assert(curve === 'ed25519', 'only tested with ed25519 so far'); + + if (!(this instanceof EDDSA)) + return new EDDSA(curve); + + curve = curves[curve].curve; + this.curve = curve; + this.g = curve.g; + this.g.precompute(curve.n.bitLength() + 1); + + this.pointClass = curve.point().constructor; + this.encodingLength = Math.ceil(curve.n.bitLength() / 8); + this.hash = hash.sha512; +} + +module.exports = EDDSA; + +/** +* @param {Array|String} message - message bytes +* @param {Array|String|KeyPair} secret - secret bytes or a keypair +* @returns {Signature} - signature +*/ +EDDSA.prototype.sign = function sign(message, secret) { + message = parseBytes(message); + var key = this.keyFromSecret(secret); + var r = this.hashInt(key.messagePrefix(), message); + var R = this.g.mul(r); + var Rencoded = this.encodePoint(R); + var s_ = this.hashInt(Rencoded, key.pubBytes(), message) + .mul(key.priv()); + var S = r.add(s_).umod(this.curve.n); + return this.makeSignature({ R: R, S: S, Rencoded: Rencoded }); +}; + +/** +* @param {Array} message - message bytes +* @param {Array|String|Signature} sig - sig bytes +* @param {Array|String|Point|KeyPair} pub - public key +* @returns {Boolean} - true if public key matches sig of message +*/ +EDDSA.prototype.verify = function verify(message, sig, pub) { + message = parseBytes(message); + sig = this.makeSignature(sig); + var key = this.keyFromPublic(pub); + var h = this.hashInt(sig.Rencoded(), key.pubBytes(), message); + var SG = this.g.mul(sig.S()); + var RplusAh = sig.R().add(key.pub().mul(h)); + return RplusAh.eq(SG); +}; + +EDDSA.prototype.hashInt = function hashInt() { + var hash = this.hash(); + for (var i = 0; i < arguments.length; i++) + hash.update(arguments[i]); + return utils.intFromLE(hash.digest()).umod(this.curve.n); +}; + +EDDSA.prototype.keyFromPublic = function keyFromPublic(pub) { + return KeyPair.fromPublic(this, pub); +}; + +EDDSA.prototype.keyFromSecret = function keyFromSecret(secret) { + return KeyPair.fromSecret(this, secret); +}; + +EDDSA.prototype.makeSignature = function makeSignature(sig) { + if (sig instanceof Signature) + return sig; + return new Signature(this, sig); +}; + +/** +* * https://tools.ietf.org/html/draft-josefsson-eddsa-ed25519-03#section-5.2 +* +* EDDSA defines methods for encoding and decoding points and integers. These are +* helper convenience methods, that pass along to utility functions implied +* parameters. +* +*/ +EDDSA.prototype.encodePoint = function encodePoint(point) { + var enc = point.getY().toArray('le', this.encodingLength); + enc[this.encodingLength - 1] |= point.getX().isOdd() ? 0x80 : 0; + return enc; +}; + +EDDSA.prototype.decodePoint = function decodePoint(bytes) { + bytes = utils.parseBytes(bytes); + + var lastIx = bytes.length - 1; + var normed = bytes.slice(0, lastIx).concat(bytes[lastIx] & ~0x80); + var xIsOdd = (bytes[lastIx] & 0x80) !== 0; + + var y = utils.intFromLE(normed); + return this.curve.pointFromY(y, xIsOdd); +}; + +EDDSA.prototype.encodeInt = function encodeInt(num) { + return num.toArray('le', this.encodingLength); +}; + +EDDSA.prototype.decodeInt = function decodeInt(bytes) { + return utils.intFromLE(bytes); +}; + +EDDSA.prototype.isPoint = function isPoint(val) { + return val instanceof this.pointClass; +}; + +},{"../curves":92,"../utils":100,"./key":97,"./signature":98,"hash.js":129}],97:[function(require,module,exports){ +'use strict'; + +var utils = require('../utils'); +var assert = utils.assert; +var parseBytes = utils.parseBytes; +var cachedProperty = utils.cachedProperty; + +/** +* @param {EDDSA} eddsa - instance +* @param {Object} params - public/private key parameters +* +* @param {Array} [params.secret] - secret seed bytes +* @param {Point} [params.pub] - public key point (aka `A` in eddsa terms) +* @param {Array} [params.pub] - public key point encoded as bytes +* +*/ +function KeyPair(eddsa, params) { + this.eddsa = eddsa; + this._secret = parseBytes(params.secret); + if (eddsa.isPoint(params.pub)) + this._pub = params.pub; + else + this._pubBytes = parseBytes(params.pub); +} + +KeyPair.fromPublic = function fromPublic(eddsa, pub) { + if (pub instanceof KeyPair) + return pub; + return new KeyPair(eddsa, { pub: pub }); +}; + +KeyPair.fromSecret = function fromSecret(eddsa, secret) { + if (secret instanceof KeyPair) + return secret; + return new KeyPair(eddsa, { secret: secret }); +}; + +KeyPair.prototype.secret = function secret() { + return this._secret; +}; + +cachedProperty(KeyPair, 'pubBytes', function pubBytes() { + return this.eddsa.encodePoint(this.pub()); +}); + +cachedProperty(KeyPair, 'pub', function pub() { + if (this._pubBytes) + return this.eddsa.decodePoint(this._pubBytes); + return this.eddsa.g.mul(this.priv()); +}); + +cachedProperty(KeyPair, 'privBytes', function privBytes() { + var eddsa = this.eddsa; + var hash = this.hash(); + var lastIx = eddsa.encodingLength - 1; + + var a = hash.slice(0, eddsa.encodingLength); + a[0] &= 248; + a[lastIx] &= 127; + a[lastIx] |= 64; + + return a; +}); + +cachedProperty(KeyPair, 'priv', function priv() { + return this.eddsa.decodeInt(this.privBytes()); +}); + +cachedProperty(KeyPair, 'hash', function hash() { + return this.eddsa.hash().update(this.secret()).digest(); +}); + +cachedProperty(KeyPair, 'messagePrefix', function messagePrefix() { + return this.hash().slice(this.eddsa.encodingLength); +}); + +KeyPair.prototype.sign = function sign(message) { + assert(this._secret, 'KeyPair can only verify'); + return this.eddsa.sign(message, this); +}; + +KeyPair.prototype.verify = function verify(message, sig) { + return this.eddsa.verify(message, sig, this); +}; + +KeyPair.prototype.getSecret = function getSecret(enc) { + assert(this._secret, 'KeyPair is public only'); + return utils.encode(this.secret(), enc); +}; + +KeyPair.prototype.getPublic = function getPublic(enc) { + return utils.encode(this.pubBytes(), enc); +}; + +module.exports = KeyPair; + +},{"../utils":100}],98:[function(require,module,exports){ +'use strict'; + +var BN = require('bn.js'); +var utils = require('../utils'); +var assert = utils.assert; +var cachedProperty = utils.cachedProperty; +var parseBytes = utils.parseBytes; + +/** +* @param {EDDSA} eddsa - eddsa instance +* @param {Array|Object} sig - +* @param {Array|Point} [sig.R] - R point as Point or bytes +* @param {Array|bn} [sig.S] - S scalar as bn or bytes +* @param {Array} [sig.Rencoded] - R point encoded +* @param {Array} [sig.Sencoded] - S scalar encoded +*/ +function Signature(eddsa, sig) { + this.eddsa = eddsa; + + if (typeof sig !== 'object') + sig = parseBytes(sig); + + if (Array.isArray(sig)) { + sig = { + R: sig.slice(0, eddsa.encodingLength), + S: sig.slice(eddsa.encodingLength), + }; + } + + assert(sig.R && sig.S, 'Signature without R or S'); + + if (eddsa.isPoint(sig.R)) + this._R = sig.R; + if (sig.S instanceof BN) + this._S = sig.S; + + this._Rencoded = Array.isArray(sig.R) ? sig.R : sig.Rencoded; + this._Sencoded = Array.isArray(sig.S) ? sig.S : sig.Sencoded; +} + +cachedProperty(Signature, 'S', function S() { + return this.eddsa.decodeInt(this.Sencoded()); +}); + +cachedProperty(Signature, 'R', function R() { + return this.eddsa.decodePoint(this.Rencoded()); +}); + +cachedProperty(Signature, 'Rencoded', function Rencoded() { + return this.eddsa.encodePoint(this.R()); +}); + +cachedProperty(Signature, 'Sencoded', function Sencoded() { + return this.eddsa.encodeInt(this.S()); +}); + +Signature.prototype.toBytes = function toBytes() { + return this.Rencoded().concat(this.Sencoded()); +}; + +Signature.prototype.toHex = function toHex() { + return utils.encode(this.toBytes(), 'hex').toUpperCase(); +}; + +module.exports = Signature; + +},{"../utils":100,"bn.js":101}],99:[function(require,module,exports){ +module.exports = { + doubles: { + step: 4, + points: [ + [ + 'e60fce93b59e9ec53011aabc21c23e97b2a31369b87a5ae9c44ee89e2a6dec0a', + 'f7e3507399e595929db99f34f57937101296891e44d23f0be1f32cce69616821', + ], + [ + '8282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508', + '11f8a8098557dfe45e8256e830b60ace62d613ac2f7b17bed31b6eaff6e26caf', + ], + [ + '175e159f728b865a72f99cc6c6fc846de0b93833fd2222ed73fce5b551e5b739', + 'd3506e0d9e3c79eba4ef97a51ff71f5eacb5955add24345c6efa6ffee9fed695', + ], + [ + '363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640', + '4e273adfc732221953b445397f3363145b9a89008199ecb62003c7f3bee9de9', + ], + [ + '8b4b5f165df3c2be8c6244b5b745638843e4a781a15bcd1b69f79a55dffdf80c', + '4aad0a6f68d308b4b3fbd7813ab0da04f9e336546162ee56b3eff0c65fd4fd36', + ], + [ + '723cbaa6e5db996d6bf771c00bd548c7b700dbffa6c0e77bcb6115925232fcda', + '96e867b5595cc498a921137488824d6e2660a0653779494801dc069d9eb39f5f', + ], + [ + 'eebfa4d493bebf98ba5feec812c2d3b50947961237a919839a533eca0e7dd7fa', + '5d9a8ca3970ef0f269ee7edaf178089d9ae4cdc3a711f712ddfd4fdae1de8999', + ], + [ + '100f44da696e71672791d0a09b7bde459f1215a29b3c03bfefd7835b39a48db0', + 'cdd9e13192a00b772ec8f3300c090666b7ff4a18ff5195ac0fbd5cd62bc65a09', + ], + [ + 'e1031be262c7ed1b1dc9227a4a04c017a77f8d4464f3b3852c8acde6e534fd2d', + '9d7061928940405e6bb6a4176597535af292dd419e1ced79a44f18f29456a00d', + ], + [ + 'feea6cae46d55b530ac2839f143bd7ec5cf8b266a41d6af52d5e688d9094696d', + 'e57c6b6c97dce1bab06e4e12bf3ecd5c981c8957cc41442d3155debf18090088', + ], + [ + 'da67a91d91049cdcb367be4be6ffca3cfeed657d808583de33fa978bc1ec6cb1', + '9bacaa35481642bc41f463f7ec9780e5dec7adc508f740a17e9ea8e27a68be1d', + ], + [ + '53904faa0b334cdda6e000935ef22151ec08d0f7bb11069f57545ccc1a37b7c0', + '5bc087d0bc80106d88c9eccac20d3c1c13999981e14434699dcb096b022771c8', + ], + [ + '8e7bcd0bd35983a7719cca7764ca906779b53a043a9b8bcaeff959f43ad86047', + '10b7770b2a3da4b3940310420ca9514579e88e2e47fd68b3ea10047e8460372a', + ], + [ + '385eed34c1cdff21e6d0818689b81bde71a7f4f18397e6690a841e1599c43862', + '283bebc3e8ea23f56701de19e9ebf4576b304eec2086dc8cc0458fe5542e5453', + ], + [ + '6f9d9b803ecf191637c73a4413dfa180fddf84a5947fbc9c606ed86c3fac3a7', + '7c80c68e603059ba69b8e2a30e45c4d47ea4dd2f5c281002d86890603a842160', + ], + [ + '3322d401243c4e2582a2147c104d6ecbf774d163db0f5e5313b7e0e742d0e6bd', + '56e70797e9664ef5bfb019bc4ddaf9b72805f63ea2873af624f3a2e96c28b2a0', + ], + [ + '85672c7d2de0b7da2bd1770d89665868741b3f9af7643397721d74d28134ab83', + '7c481b9b5b43b2eb6374049bfa62c2e5e77f17fcc5298f44c8e3094f790313a6', + ], + [ + '948bf809b1988a46b06c9f1919413b10f9226c60f668832ffd959af60c82a0a', + '53a562856dcb6646dc6b74c5d1c3418c6d4dff08c97cd2bed4cb7f88d8c8e589', + ], + [ + '6260ce7f461801c34f067ce0f02873a8f1b0e44dfc69752accecd819f38fd8e8', + 'bc2da82b6fa5b571a7f09049776a1ef7ecd292238051c198c1a84e95b2b4ae17', + ], + [ + 'e5037de0afc1d8d43d8348414bbf4103043ec8f575bfdc432953cc8d2037fa2d', + '4571534baa94d3b5f9f98d09fb990bddbd5f5b03ec481f10e0e5dc841d755bda', + ], + [ + 'e06372b0f4a207adf5ea905e8f1771b4e7e8dbd1c6a6c5b725866a0ae4fce725', + '7a908974bce18cfe12a27bb2ad5a488cd7484a7787104870b27034f94eee31dd', + ], + [ + '213c7a715cd5d45358d0bbf9dc0ce02204b10bdde2a3f58540ad6908d0559754', + '4b6dad0b5ae462507013ad06245ba190bb4850f5f36a7eeddff2c27534b458f2', + ], + [ + '4e7c272a7af4b34e8dbb9352a5419a87e2838c70adc62cddf0cc3a3b08fbd53c', + '17749c766c9d0b18e16fd09f6def681b530b9614bff7dd33e0b3941817dcaae6', + ], + [ + 'fea74e3dbe778b1b10f238ad61686aa5c76e3db2be43057632427e2840fb27b6', + '6e0568db9b0b13297cf674deccb6af93126b596b973f7b77701d3db7f23cb96f', + ], + [ + '76e64113f677cf0e10a2570d599968d31544e179b760432952c02a4417bdde39', + 'c90ddf8dee4e95cf577066d70681f0d35e2a33d2b56d2032b4b1752d1901ac01', + ], + [ + 'c738c56b03b2abe1e8281baa743f8f9a8f7cc643df26cbee3ab150242bcbb891', + '893fb578951ad2537f718f2eacbfbbbb82314eef7880cfe917e735d9699a84c3', + ], + [ + 'd895626548b65b81e264c7637c972877d1d72e5f3a925014372e9f6588f6c14b', + 'febfaa38f2bc7eae728ec60818c340eb03428d632bb067e179363ed75d7d991f', + ], + [ + 'b8da94032a957518eb0f6433571e8761ceffc73693e84edd49150a564f676e03', + '2804dfa44805a1e4d7c99cc9762808b092cc584d95ff3b511488e4e74efdf6e7', + ], + [ + 'e80fea14441fb33a7d8adab9475d7fab2019effb5156a792f1a11778e3c0df5d', + 'eed1de7f638e00771e89768ca3ca94472d155e80af322ea9fcb4291b6ac9ec78', + ], + [ + 'a301697bdfcd704313ba48e51d567543f2a182031efd6915ddc07bbcc4e16070', + '7370f91cfb67e4f5081809fa25d40f9b1735dbf7c0a11a130c0d1a041e177ea1', + ], + [ + '90ad85b389d6b936463f9d0512678de208cc330b11307fffab7ac63e3fb04ed4', + 'e507a3620a38261affdcbd9427222b839aefabe1582894d991d4d48cb6ef150', + ], + [ + '8f68b9d2f63b5f339239c1ad981f162ee88c5678723ea3351b7b444c9ec4c0da', + '662a9f2dba063986de1d90c2b6be215dbbea2cfe95510bfdf23cbf79501fff82', + ], + [ + 'e4f3fb0176af85d65ff99ff9198c36091f48e86503681e3e6686fd5053231e11', + '1e63633ad0ef4f1c1661a6d0ea02b7286cc7e74ec951d1c9822c38576feb73bc', + ], + [ + '8c00fa9b18ebf331eb961537a45a4266c7034f2f0d4e1d0716fb6eae20eae29e', + 'efa47267fea521a1a9dc343a3736c974c2fadafa81e36c54e7d2a4c66702414b', + ], + [ + 'e7a26ce69dd4829f3e10cec0a9e98ed3143d084f308b92c0997fddfc60cb3e41', + '2a758e300fa7984b471b006a1aafbb18d0a6b2c0420e83e20e8a9421cf2cfd51', + ], + [ + 'b6459e0ee3662ec8d23540c223bcbdc571cbcb967d79424f3cf29eb3de6b80ef', + '67c876d06f3e06de1dadf16e5661db3c4b3ae6d48e35b2ff30bf0b61a71ba45', + ], + [ + 'd68a80c8280bb840793234aa118f06231d6f1fc67e73c5a5deda0f5b496943e8', + 'db8ba9fff4b586d00c4b1f9177b0e28b5b0e7b8f7845295a294c84266b133120', + ], + [ + '324aed7df65c804252dc0270907a30b09612aeb973449cea4095980fc28d3d5d', + '648a365774b61f2ff130c0c35aec1f4f19213b0c7e332843967224af96ab7c84', + ], + [ + '4df9c14919cde61f6d51dfdbe5fee5dceec4143ba8d1ca888e8bd373fd054c96', + '35ec51092d8728050974c23a1d85d4b5d506cdc288490192ebac06cad10d5d', + ], + [ + '9c3919a84a474870faed8a9c1cc66021523489054d7f0308cbfc99c8ac1f98cd', + 'ddb84f0f4a4ddd57584f044bf260e641905326f76c64c8e6be7e5e03d4fc599d', + ], + [ + '6057170b1dd12fdf8de05f281d8e06bb91e1493a8b91d4cc5a21382120a959e5', + '9a1af0b26a6a4807add9a2daf71df262465152bc3ee24c65e899be932385a2a8', + ], + [ + 'a576df8e23a08411421439a4518da31880cef0fba7d4df12b1a6973eecb94266', + '40a6bf20e76640b2c92b97afe58cd82c432e10a7f514d9f3ee8be11ae1b28ec8', + ], + [ + '7778a78c28dec3e30a05fe9629de8c38bb30d1f5cf9a3a208f763889be58ad71', + '34626d9ab5a5b22ff7098e12f2ff580087b38411ff24ac563b513fc1fd9f43ac', + ], + [ + '928955ee637a84463729fd30e7afd2ed5f96274e5ad7e5cb09eda9c06d903ac', + 'c25621003d3f42a827b78a13093a95eeac3d26efa8a8d83fc5180e935bcd091f', + ], + [ + '85d0fef3ec6db109399064f3a0e3b2855645b4a907ad354527aae75163d82751', + '1f03648413a38c0be29d496e582cf5663e8751e96877331582c237a24eb1f962', + ], + [ + 'ff2b0dce97eece97c1c9b6041798b85dfdfb6d8882da20308f5404824526087e', + '493d13fef524ba188af4c4dc54d07936c7b7ed6fb90e2ceb2c951e01f0c29907', + ], + [ + '827fbbe4b1e880ea9ed2b2e6301b212b57f1ee148cd6dd28780e5e2cf856e241', + 'c60f9c923c727b0b71bef2c67d1d12687ff7a63186903166d605b68baec293ec', + ], + [ + 'eaa649f21f51bdbae7be4ae34ce6e5217a58fdce7f47f9aa7f3b58fa2120e2b3', + 'be3279ed5bbbb03ac69a80f89879aa5a01a6b965f13f7e59d47a5305ba5ad93d', + ], + [ + 'e4a42d43c5cf169d9391df6decf42ee541b6d8f0c9a137401e23632dda34d24f', + '4d9f92e716d1c73526fc99ccfb8ad34ce886eedfa8d8e4f13a7f7131deba9414', + ], + [ + '1ec80fef360cbdd954160fadab352b6b92b53576a88fea4947173b9d4300bf19', + 'aeefe93756b5340d2f3a4958a7abbf5e0146e77f6295a07b671cdc1cc107cefd', + ], + [ + '146a778c04670c2f91b00af4680dfa8bce3490717d58ba889ddb5928366642be', + 'b318e0ec3354028add669827f9d4b2870aaa971d2f7e5ed1d0b297483d83efd0', + ], + [ + 'fa50c0f61d22e5f07e3acebb1aa07b128d0012209a28b9776d76a8793180eef9', + '6b84c6922397eba9b72cd2872281a68a5e683293a57a213b38cd8d7d3f4f2811', + ], + [ + 'da1d61d0ca721a11b1a5bf6b7d88e8421a288ab5d5bba5220e53d32b5f067ec2', + '8157f55a7c99306c79c0766161c91e2966a73899d279b48a655fba0f1ad836f1', + ], + [ + 'a8e282ff0c9706907215ff98e8fd416615311de0446f1e062a73b0610d064e13', + '7f97355b8db81c09abfb7f3c5b2515888b679a3e50dd6bd6cef7c73111f4cc0c', + ], + [ + '174a53b9c9a285872d39e56e6913cab15d59b1fa512508c022f382de8319497c', + 'ccc9dc37abfc9c1657b4155f2c47f9e6646b3a1d8cb9854383da13ac079afa73', + ], + [ + '959396981943785c3d3e57edf5018cdbe039e730e4918b3d884fdff09475b7ba', + '2e7e552888c331dd8ba0386a4b9cd6849c653f64c8709385e9b8abf87524f2fd', + ], + [ + 'd2a63a50ae401e56d645a1153b109a8fcca0a43d561fba2dbb51340c9d82b151', + 'e82d86fb6443fcb7565aee58b2948220a70f750af484ca52d4142174dcf89405', + ], + [ + '64587e2335471eb890ee7896d7cfdc866bacbdbd3839317b3436f9b45617e073', + 'd99fcdd5bf6902e2ae96dd6447c299a185b90a39133aeab358299e5e9faf6589', + ], + [ + '8481bde0e4e4d885b3a546d3e549de042f0aa6cea250e7fd358d6c86dd45e458', + '38ee7b8cba5404dd84a25bf39cecb2ca900a79c42b262e556d64b1b59779057e', + ], + [ + '13464a57a78102aa62b6979ae817f4637ffcfed3c4b1ce30bcd6303f6caf666b', + '69be159004614580ef7e433453ccb0ca48f300a81d0942e13f495a907f6ecc27', + ], + [ + 'bc4a9df5b713fe2e9aef430bcc1dc97a0cd9ccede2f28588cada3a0d2d83f366', + 'd3a81ca6e785c06383937adf4b798caa6e8a9fbfa547b16d758d666581f33c1', + ], + [ + '8c28a97bf8298bc0d23d8c749452a32e694b65e30a9472a3954ab30fe5324caa', + '40a30463a3305193378fedf31f7cc0eb7ae784f0451cb9459e71dc73cbef9482', + ], + [ + '8ea9666139527a8c1dd94ce4f071fd23c8b350c5a4bb33748c4ba111faccae0', + '620efabbc8ee2782e24e7c0cfb95c5d735b783be9cf0f8e955af34a30e62b945', + ], + [ + 'dd3625faef5ba06074669716bbd3788d89bdde815959968092f76cc4eb9a9787', + '7a188fa3520e30d461da2501045731ca941461982883395937f68d00c644a573', + ], + [ + 'f710d79d9eb962297e4f6232b40e8f7feb2bc63814614d692c12de752408221e', + 'ea98e67232d3b3295d3b535532115ccac8612c721851617526ae47a9c77bfc82', + ], + ], + }, + naf: { + wnd: 7, + points: [ + [ + 'f9308a019258c31049344f85f89d5229b531c845836f99b08601f113bce036f9', + '388f7b0f632de8140fe337e62a37f3566500a99934c2231b6cb9fd7584b8e672', + ], + [ + '2f8bde4d1a07209355b4a7250a5c5128e88b84bddc619ab7cba8d569b240efe4', + 'd8ac222636e5e3d6d4dba9dda6c9c426f788271bab0d6840dca87d3aa6ac62d6', + ], + [ + '5cbdf0646e5db4eaa398f365f2ea7a0e3d419b7e0330e39ce92bddedcac4f9bc', + '6aebca40ba255960a3178d6d861a54dba813d0b813fde7b5a5082628087264da', + ], + [ + 'acd484e2f0c7f65309ad178a9f559abde09796974c57e714c35f110dfc27ccbe', + 'cc338921b0a7d9fd64380971763b61e9add888a4375f8e0f05cc262ac64f9c37', + ], + [ + '774ae7f858a9411e5ef4246b70c65aac5649980be5c17891bbec17895da008cb', + 'd984a032eb6b5e190243dd56d7b7b365372db1e2dff9d6a8301d74c9c953c61b', + ], + [ + 'f28773c2d975288bc7d1d205c3748651b075fbc6610e58cddeeddf8f19405aa8', + 'ab0902e8d880a89758212eb65cdaf473a1a06da521fa91f29b5cb52db03ed81', + ], + [ + 'd7924d4f7d43ea965a465ae3095ff41131e5946f3c85f79e44adbcf8e27e080e', + '581e2872a86c72a683842ec228cc6defea40af2bd896d3a5c504dc9ff6a26b58', + ], + [ + 'defdea4cdb677750a420fee807eacf21eb9898ae79b9768766e4faa04a2d4a34', + '4211ab0694635168e997b0ead2a93daeced1f4a04a95c0f6cfb199f69e56eb77', + ], + [ + '2b4ea0a797a443d293ef5cff444f4979f06acfebd7e86d277475656138385b6c', + '85e89bc037945d93b343083b5a1c86131a01f60c50269763b570c854e5c09b7a', + ], + [ + '352bbf4a4cdd12564f93fa332ce333301d9ad40271f8107181340aef25be59d5', + '321eb4075348f534d59c18259dda3e1f4a1b3b2e71b1039c67bd3d8bcf81998c', + ], + [ + '2fa2104d6b38d11b0230010559879124e42ab8dfeff5ff29dc9cdadd4ecacc3f', + '2de1068295dd865b64569335bd5dd80181d70ecfc882648423ba76b532b7d67', + ], + [ + '9248279b09b4d68dab21a9b066edda83263c3d84e09572e269ca0cd7f5453714', + '73016f7bf234aade5d1aa71bdea2b1ff3fc0de2a887912ffe54a32ce97cb3402', + ], + [ + 'daed4f2be3a8bf278e70132fb0beb7522f570e144bf615c07e996d443dee8729', + 'a69dce4a7d6c98e8d4a1aca87ef8d7003f83c230f3afa726ab40e52290be1c55', + ], + [ + 'c44d12c7065d812e8acf28d7cbb19f9011ecd9e9fdf281b0e6a3b5e87d22e7db', + '2119a460ce326cdc76c45926c982fdac0e106e861edf61c5a039063f0e0e6482', + ], + [ + '6a245bf6dc698504c89a20cfded60853152b695336c28063b61c65cbd269e6b4', + 'e022cf42c2bd4a708b3f5126f16a24ad8b33ba48d0423b6efd5e6348100d8a82', + ], + [ + '1697ffa6fd9de627c077e3d2fe541084ce13300b0bec1146f95ae57f0d0bd6a5', + 'b9c398f186806f5d27561506e4557433a2cf15009e498ae7adee9d63d01b2396', + ], + [ + '605bdb019981718b986d0f07e834cb0d9deb8360ffb7f61df982345ef27a7479', + '2972d2de4f8d20681a78d93ec96fe23c26bfae84fb14db43b01e1e9056b8c49', + ], + [ + '62d14dab4150bf497402fdc45a215e10dcb01c354959b10cfe31c7e9d87ff33d', + '80fc06bd8cc5b01098088a1950eed0db01aa132967ab472235f5642483b25eaf', + ], + [ + '80c60ad0040f27dade5b4b06c408e56b2c50e9f56b9b8b425e555c2f86308b6f', + '1c38303f1cc5c30f26e66bad7fe72f70a65eed4cbe7024eb1aa01f56430bd57a', + ], + [ + '7a9375ad6167ad54aa74c6348cc54d344cc5dc9487d847049d5eabb0fa03c8fb', + 'd0e3fa9eca8726909559e0d79269046bdc59ea10c70ce2b02d499ec224dc7f7', + ], + [ + 'd528ecd9b696b54c907a9ed045447a79bb408ec39b68df504bb51f459bc3ffc9', + 'eecf41253136e5f99966f21881fd656ebc4345405c520dbc063465b521409933', + ], + [ + '49370a4b5f43412ea25f514e8ecdad05266115e4a7ecb1387231808f8b45963', + '758f3f41afd6ed428b3081b0512fd62a54c3f3afbb5b6764b653052a12949c9a', + ], + [ + '77f230936ee88cbbd73df930d64702ef881d811e0e1498e2f1c13eb1fc345d74', + '958ef42a7886b6400a08266e9ba1b37896c95330d97077cbbe8eb3c7671c60d6', + ], + [ + 'f2dac991cc4ce4b9ea44887e5c7c0bce58c80074ab9d4dbaeb28531b7739f530', + 'e0dedc9b3b2f8dad4da1f32dec2531df9eb5fbeb0598e4fd1a117dba703a3c37', + ], + [ + '463b3d9f662621fb1b4be8fbbe2520125a216cdfc9dae3debcba4850c690d45b', + '5ed430d78c296c3543114306dd8622d7c622e27c970a1de31cb377b01af7307e', + ], + [ + 'f16f804244e46e2a09232d4aff3b59976b98fac14328a2d1a32496b49998f247', + 'cedabd9b82203f7e13d206fcdf4e33d92a6c53c26e5cce26d6579962c4e31df6', + ], + [ + 'caf754272dc84563b0352b7a14311af55d245315ace27c65369e15f7151d41d1', + 'cb474660ef35f5f2a41b643fa5e460575f4fa9b7962232a5c32f908318a04476', + ], + [ + '2600ca4b282cb986f85d0f1709979d8b44a09c07cb86d7c124497bc86f082120', + '4119b88753c15bd6a693b03fcddbb45d5ac6be74ab5f0ef44b0be9475a7e4b40', + ], + [ + '7635ca72d7e8432c338ec53cd12220bc01c48685e24f7dc8c602a7746998e435', + '91b649609489d613d1d5e590f78e6d74ecfc061d57048bad9e76f302c5b9c61', + ], + [ + '754e3239f325570cdbbf4a87deee8a66b7f2b33479d468fbc1a50743bf56cc18', + '673fb86e5bda30fb3cd0ed304ea49a023ee33d0197a695d0c5d98093c536683', + ], + [ + 'e3e6bd1071a1e96aff57859c82d570f0330800661d1c952f9fe2694691d9b9e8', + '59c9e0bba394e76f40c0aa58379a3cb6a5a2283993e90c4167002af4920e37f5', + ], + [ + '186b483d056a033826ae73d88f732985c4ccb1f32ba35f4b4cc47fdcf04aa6eb', + '3b952d32c67cf77e2e17446e204180ab21fb8090895138b4a4a797f86e80888b', + ], + [ + 'df9d70a6b9876ce544c98561f4be4f725442e6d2b737d9c91a8321724ce0963f', + '55eb2dafd84d6ccd5f862b785dc39d4ab157222720ef9da217b8c45cf2ba2417', + ], + [ + '5edd5cc23c51e87a497ca815d5dce0f8ab52554f849ed8995de64c5f34ce7143', + 'efae9c8dbc14130661e8cec030c89ad0c13c66c0d17a2905cdc706ab7399a868', + ], + [ + '290798c2b6476830da12fe02287e9e777aa3fba1c355b17a722d362f84614fba', + 'e38da76dcd440621988d00bcf79af25d5b29c094db2a23146d003afd41943e7a', + ], + [ + 'af3c423a95d9f5b3054754efa150ac39cd29552fe360257362dfdecef4053b45', + 'f98a3fd831eb2b749a93b0e6f35cfb40c8cd5aa667a15581bc2feded498fd9c6', + ], + [ + '766dbb24d134e745cccaa28c99bf274906bb66b26dcf98df8d2fed50d884249a', + '744b1152eacbe5e38dcc887980da38b897584a65fa06cedd2c924f97cbac5996', + ], + [ + '59dbf46f8c94759ba21277c33784f41645f7b44f6c596a58ce92e666191abe3e', + 'c534ad44175fbc300f4ea6ce648309a042ce739a7919798cd85e216c4a307f6e', + ], + [ + 'f13ada95103c4537305e691e74e9a4a8dd647e711a95e73cb62dc6018cfd87b8', + 'e13817b44ee14de663bf4bc808341f326949e21a6a75c2570778419bdaf5733d', + ], + [ + '7754b4fa0e8aced06d4167a2c59cca4cda1869c06ebadfb6488550015a88522c', + '30e93e864e669d82224b967c3020b8fa8d1e4e350b6cbcc537a48b57841163a2', + ], + [ + '948dcadf5990e048aa3874d46abef9d701858f95de8041d2a6828c99e2262519', + 'e491a42537f6e597d5d28a3224b1bc25df9154efbd2ef1d2cbba2cae5347d57e', + ], + [ + '7962414450c76c1689c7b48f8202ec37fb224cf5ac0bfa1570328a8a3d7c77ab', + '100b610ec4ffb4760d5c1fc133ef6f6b12507a051f04ac5760afa5b29db83437', + ], + [ + '3514087834964b54b15b160644d915485a16977225b8847bb0dd085137ec47ca', + 'ef0afbb2056205448e1652c48e8127fc6039e77c15c2378b7e7d15a0de293311', + ], + [ + 'd3cc30ad6b483e4bc79ce2c9dd8bc54993e947eb8df787b442943d3f7b527eaf', + '8b378a22d827278d89c5e9be8f9508ae3c2ad46290358630afb34db04eede0a4', + ], + [ + '1624d84780732860ce1c78fcbfefe08b2b29823db913f6493975ba0ff4847610', + '68651cf9b6da903e0914448c6cd9d4ca896878f5282be4c8cc06e2a404078575', + ], + [ + '733ce80da955a8a26902c95633e62a985192474b5af207da6df7b4fd5fc61cd4', + 'f5435a2bd2badf7d485a4d8b8db9fcce3e1ef8e0201e4578c54673bc1dc5ea1d', + ], + [ + '15d9441254945064cf1a1c33bbd3b49f8966c5092171e699ef258dfab81c045c', + 'd56eb30b69463e7234f5137b73b84177434800bacebfc685fc37bbe9efe4070d', + ], + [ + 'a1d0fcf2ec9de675b612136e5ce70d271c21417c9d2b8aaaac138599d0717940', + 'edd77f50bcb5a3cab2e90737309667f2641462a54070f3d519212d39c197a629', + ], + [ + 'e22fbe15c0af8ccc5780c0735f84dbe9a790badee8245c06c7ca37331cb36980', + 'a855babad5cd60c88b430a69f53a1a7a38289154964799be43d06d77d31da06', + ], + [ + '311091dd9860e8e20ee13473c1155f5f69635e394704eaa74009452246cfa9b3', + '66db656f87d1f04fffd1f04788c06830871ec5a64feee685bd80f0b1286d8374', + ], + [ + '34c1fd04d301be89b31c0442d3e6ac24883928b45a9340781867d4232ec2dbdf', + '9414685e97b1b5954bd46f730174136d57f1ceeb487443dc5321857ba73abee', + ], + [ + 'f219ea5d6b54701c1c14de5b557eb42a8d13f3abbcd08affcc2a5e6b049b8d63', + '4cb95957e83d40b0f73af4544cccf6b1f4b08d3c07b27fb8d8c2962a400766d1', + ], + [ + 'd7b8740f74a8fbaab1f683db8f45de26543a5490bca627087236912469a0b448', + 'fa77968128d9c92ee1010f337ad4717eff15db5ed3c049b3411e0315eaa4593b', + ], + [ + '32d31c222f8f6f0ef86f7c98d3a3335ead5bcd32abdd94289fe4d3091aa824bf', + '5f3032f5892156e39ccd3d7915b9e1da2e6dac9e6f26e961118d14b8462e1661', + ], + [ + '7461f371914ab32671045a155d9831ea8793d77cd59592c4340f86cbc18347b5', + '8ec0ba238b96bec0cbdddcae0aa442542eee1ff50c986ea6b39847b3cc092ff6', + ], + [ + 'ee079adb1df1860074356a25aa38206a6d716b2c3e67453d287698bad7b2b2d6', + '8dc2412aafe3be5c4c5f37e0ecc5f9f6a446989af04c4e25ebaac479ec1c8c1e', + ], + [ + '16ec93e447ec83f0467b18302ee620f7e65de331874c9dc72bfd8616ba9da6b5', + '5e4631150e62fb40d0e8c2a7ca5804a39d58186a50e497139626778e25b0674d', + ], + [ + 'eaa5f980c245f6f038978290afa70b6bd8855897f98b6aa485b96065d537bd99', + 'f65f5d3e292c2e0819a528391c994624d784869d7e6ea67fb18041024edc07dc', + ], + [ + '78c9407544ac132692ee1910a02439958ae04877151342ea96c4b6b35a49f51', + 'f3e0319169eb9b85d5404795539a5e68fa1fbd583c064d2462b675f194a3ddb4', + ], + [ + '494f4be219a1a77016dcd838431aea0001cdc8ae7a6fc688726578d9702857a5', + '42242a969283a5f339ba7f075e36ba2af925ce30d767ed6e55f4b031880d562c', + ], + [ + 'a598a8030da6d86c6bc7f2f5144ea549d28211ea58faa70ebf4c1e665c1fe9b5', + '204b5d6f84822c307e4b4a7140737aec23fc63b65b35f86a10026dbd2d864e6b', + ], + [ + 'c41916365abb2b5d09192f5f2dbeafec208f020f12570a184dbadc3e58595997', + '4f14351d0087efa49d245b328984989d5caf9450f34bfc0ed16e96b58fa9913', + ], + [ + '841d6063a586fa475a724604da03bc5b92a2e0d2e0a36acfe4c73a5514742881', + '73867f59c0659e81904f9a1c7543698e62562d6744c169ce7a36de01a8d6154', + ], + [ + '5e95bb399a6971d376026947f89bde2f282b33810928be4ded112ac4d70e20d5', + '39f23f366809085beebfc71181313775a99c9aed7d8ba38b161384c746012865', + ], + [ + '36e4641a53948fd476c39f8a99fd974e5ec07564b5315d8bf99471bca0ef2f66', + 'd2424b1b1abe4eb8164227b085c9aa9456ea13493fd563e06fd51cf5694c78fc', + ], + [ + '336581ea7bfbbb290c191a2f507a41cf5643842170e914faeab27c2c579f726', + 'ead12168595fe1be99252129b6e56b3391f7ab1410cd1e0ef3dcdcabd2fda224', + ], + [ + '8ab89816dadfd6b6a1f2634fcf00ec8403781025ed6890c4849742706bd43ede', + '6fdcef09f2f6d0a044e654aef624136f503d459c3e89845858a47a9129cdd24e', + ], + [ + '1e33f1a746c9c5778133344d9299fcaa20b0938e8acff2544bb40284b8c5fb94', + '60660257dd11b3aa9c8ed618d24edff2306d320f1d03010e33a7d2057f3b3b6', + ], + [ + '85b7c1dcb3cec1b7ee7f30ded79dd20a0ed1f4cc18cbcfcfa410361fd8f08f31', + '3d98a9cdd026dd43f39048f25a8847f4fcafad1895d7a633c6fed3c35e999511', + ], + [ + '29df9fbd8d9e46509275f4b125d6d45d7fbe9a3b878a7af872a2800661ac5f51', + 'b4c4fe99c775a606e2d8862179139ffda61dc861c019e55cd2876eb2a27d84b', + ], + [ + 'a0b1cae06b0a847a3fea6e671aaf8adfdfe58ca2f768105c8082b2e449fce252', + 'ae434102edde0958ec4b19d917a6a28e6b72da1834aff0e650f049503a296cf2', + ], + [ + '4e8ceafb9b3e9a136dc7ff67e840295b499dfb3b2133e4ba113f2e4c0e121e5', + 'cf2174118c8b6d7a4b48f6d534ce5c79422c086a63460502b827ce62a326683c', + ], + [ + 'd24a44e047e19b6f5afb81c7ca2f69080a5076689a010919f42725c2b789a33b', + '6fb8d5591b466f8fc63db50f1c0f1c69013f996887b8244d2cdec417afea8fa3', + ], + [ + 'ea01606a7a6c9cdd249fdfcfacb99584001edd28abbab77b5104e98e8e3b35d4', + '322af4908c7312b0cfbfe369f7a7b3cdb7d4494bc2823700cfd652188a3ea98d', + ], + [ + 'af8addbf2b661c8a6c6328655eb96651252007d8c5ea31be4ad196de8ce2131f', + '6749e67c029b85f52a034eafd096836b2520818680e26ac8f3dfbcdb71749700', + ], + [ + 'e3ae1974566ca06cc516d47e0fb165a674a3dabcfca15e722f0e3450f45889', + '2aeabe7e4531510116217f07bf4d07300de97e4874f81f533420a72eeb0bd6a4', + ], + [ + '591ee355313d99721cf6993ffed1e3e301993ff3ed258802075ea8ced397e246', + 'b0ea558a113c30bea60fc4775460c7901ff0b053d25ca2bdeee98f1a4be5d196', + ], + [ + '11396d55fda54c49f19aa97318d8da61fa8584e47b084945077cf03255b52984', + '998c74a8cd45ac01289d5833a7beb4744ff536b01b257be4c5767bea93ea57a4', + ], + [ + '3c5d2a1ba39c5a1790000738c9e0c40b8dcdfd5468754b6405540157e017aa7a', + 'b2284279995a34e2f9d4de7396fc18b80f9b8b9fdd270f6661f79ca4c81bd257', + ], + [ + 'cc8704b8a60a0defa3a99a7299f2e9c3fbc395afb04ac078425ef8a1793cc030', + 'bdd46039feed17881d1e0862db347f8cf395b74fc4bcdc4e940b74e3ac1f1b13', + ], + [ + 'c533e4f7ea8555aacd9777ac5cad29b97dd4defccc53ee7ea204119b2889b197', + '6f0a256bc5efdf429a2fb6242f1a43a2d9b925bb4a4b3a26bb8e0f45eb596096', + ], + [ + 'c14f8f2ccb27d6f109f6d08d03cc96a69ba8c34eec07bbcf566d48e33da6593', + 'c359d6923bb398f7fd4473e16fe1c28475b740dd098075e6c0e8649113dc3a38', + ], + [ + 'a6cbc3046bc6a450bac24789fa17115a4c9739ed75f8f21ce441f72e0b90e6ef', + '21ae7f4680e889bb130619e2c0f95a360ceb573c70603139862afd617fa9b9f', + ], + [ + '347d6d9a02c48927ebfb86c1359b1caf130a3c0267d11ce6344b39f99d43cc38', + '60ea7f61a353524d1c987f6ecec92f086d565ab687870cb12689ff1e31c74448', + ], + [ + 'da6545d2181db8d983f7dcb375ef5866d47c67b1bf31c8cf855ef7437b72656a', + '49b96715ab6878a79e78f07ce5680c5d6673051b4935bd897fea824b77dc208a', + ], + [ + 'c40747cc9d012cb1a13b8148309c6de7ec25d6945d657146b9d5994b8feb1111', + '5ca560753be2a12fc6de6caf2cb489565db936156b9514e1bb5e83037e0fa2d4', + ], + [ + '4e42c8ec82c99798ccf3a610be870e78338c7f713348bd34c8203ef4037f3502', + '7571d74ee5e0fb92a7a8b33a07783341a5492144cc54bcc40a94473693606437', + ], + [ + '3775ab7089bc6af823aba2e1af70b236d251cadb0c86743287522a1b3b0dedea', + 'be52d107bcfa09d8bcb9736a828cfa7fac8db17bf7a76a2c42ad961409018cf7', + ], + [ + 'cee31cbf7e34ec379d94fb814d3d775ad954595d1314ba8846959e3e82f74e26', + '8fd64a14c06b589c26b947ae2bcf6bfa0149ef0be14ed4d80f448a01c43b1c6d', + ], + [ + 'b4f9eaea09b6917619f6ea6a4eb5464efddb58fd45b1ebefcdc1a01d08b47986', + '39e5c9925b5a54b07433a4f18c61726f8bb131c012ca542eb24a8ac07200682a', + ], + [ + 'd4263dfc3d2df923a0179a48966d30ce84e2515afc3dccc1b77907792ebcc60e', + '62dfaf07a0f78feb30e30d6295853ce189e127760ad6cf7fae164e122a208d54', + ], + [ + '48457524820fa65a4f8d35eb6930857c0032acc0a4a2de422233eeda897612c4', + '25a748ab367979d98733c38a1fa1c2e7dc6cc07db2d60a9ae7a76aaa49bd0f77', + ], + [ + 'dfeeef1881101f2cb11644f3a2afdfc2045e19919152923f367a1767c11cceda', + 'ecfb7056cf1de042f9420bab396793c0c390bde74b4bbdff16a83ae09a9a7517', + ], + [ + '6d7ef6b17543f8373c573f44e1f389835d89bcbc6062ced36c82df83b8fae859', + 'cd450ec335438986dfefa10c57fea9bcc521a0959b2d80bbf74b190dca712d10', + ], + [ + 'e75605d59102a5a2684500d3b991f2e3f3c88b93225547035af25af66e04541f', + 'f5c54754a8f71ee540b9b48728473e314f729ac5308b06938360990e2bfad125', + ], + [ + 'eb98660f4c4dfaa06a2be453d5020bc99a0c2e60abe388457dd43fefb1ed620c', + '6cb9a8876d9cb8520609af3add26cd20a0a7cd8a9411131ce85f44100099223e', + ], + [ + '13e87b027d8514d35939f2e6892b19922154596941888336dc3563e3b8dba942', + 'fef5a3c68059a6dec5d624114bf1e91aac2b9da568d6abeb2570d55646b8adf1', + ], + [ + 'ee163026e9fd6fe017c38f06a5be6fc125424b371ce2708e7bf4491691e5764a', + '1acb250f255dd61c43d94ccc670d0f58f49ae3fa15b96623e5430da0ad6c62b2', + ], + [ + 'b268f5ef9ad51e4d78de3a750c2dc89b1e626d43505867999932e5db33af3d80', + '5f310d4b3c99b9ebb19f77d41c1dee018cf0d34fd4191614003e945a1216e423', + ], + [ + 'ff07f3118a9df035e9fad85eb6c7bfe42b02f01ca99ceea3bf7ffdba93c4750d', + '438136d603e858a3a5c440c38eccbaddc1d2942114e2eddd4740d098ced1f0d8', + ], + [ + '8d8b9855c7c052a34146fd20ffb658bea4b9f69e0d825ebec16e8c3ce2b526a1', + 'cdb559eedc2d79f926baf44fb84ea4d44bcf50fee51d7ceb30e2e7f463036758', + ], + [ + '52db0b5384dfbf05bfa9d472d7ae26dfe4b851ceca91b1eba54263180da32b63', + 'c3b997d050ee5d423ebaf66a6db9f57b3180c902875679de924b69d84a7b375', + ], + [ + 'e62f9490d3d51da6395efd24e80919cc7d0f29c3f3fa48c6fff543becbd43352', + '6d89ad7ba4876b0b22c2ca280c682862f342c8591f1daf5170e07bfd9ccafa7d', + ], + [ + '7f30ea2476b399b4957509c88f77d0191afa2ff5cb7b14fd6d8e7d65aaab1193', + 'ca5ef7d4b231c94c3b15389a5f6311e9daff7bb67b103e9880ef4bff637acaec', + ], + [ + '5098ff1e1d9f14fb46a210fada6c903fef0fb7b4a1dd1d9ac60a0361800b7a00', + '9731141d81fc8f8084d37c6e7542006b3ee1b40d60dfe5362a5b132fd17ddc0', + ], + [ + '32b78c7de9ee512a72895be6b9cbefa6e2f3c4ccce445c96b9f2c81e2778ad58', + 'ee1849f513df71e32efc3896ee28260c73bb80547ae2275ba497237794c8753c', + ], + [ + 'e2cb74fddc8e9fbcd076eef2a7c72b0ce37d50f08269dfc074b581550547a4f7', + 'd3aa2ed71c9dd2247a62df062736eb0baddea9e36122d2be8641abcb005cc4a4', + ], + [ + '8438447566d4d7bedadc299496ab357426009a35f235cb141be0d99cd10ae3a8', + 'c4e1020916980a4da5d01ac5e6ad330734ef0d7906631c4f2390426b2edd791f', + ], + [ + '4162d488b89402039b584c6fc6c308870587d9c46f660b878ab65c82c711d67e', + '67163e903236289f776f22c25fb8a3afc1732f2b84b4e95dbda47ae5a0852649', + ], + [ + '3fad3fa84caf0f34f0f89bfd2dcf54fc175d767aec3e50684f3ba4a4bf5f683d', + 'cd1bc7cb6cc407bb2f0ca647c718a730cf71872e7d0d2a53fa20efcdfe61826', + ], + [ + '674f2600a3007a00568c1a7ce05d0816c1fb84bf1370798f1c69532faeb1a86b', + '299d21f9413f33b3edf43b257004580b70db57da0b182259e09eecc69e0d38a5', + ], + [ + 'd32f4da54ade74abb81b815ad1fb3b263d82d6c692714bcff87d29bd5ee9f08f', + 'f9429e738b8e53b968e99016c059707782e14f4535359d582fc416910b3eea87', + ], + [ + '30e4e670435385556e593657135845d36fbb6931f72b08cb1ed954f1e3ce3ff6', + '462f9bce619898638499350113bbc9b10a878d35da70740dc695a559eb88db7b', + ], + [ + 'be2062003c51cc3004682904330e4dee7f3dcd10b01e580bf1971b04d4cad297', + '62188bc49d61e5428573d48a74e1c655b1c61090905682a0d5558ed72dccb9bc', + ], + [ + '93144423ace3451ed29e0fb9ac2af211cb6e84a601df5993c419859fff5df04a', + '7c10dfb164c3425f5c71a3f9d7992038f1065224f72bb9d1d902a6d13037b47c', + ], + [ + 'b015f8044f5fcbdcf21ca26d6c34fb8197829205c7b7d2a7cb66418c157b112c', + 'ab8c1e086d04e813744a655b2df8d5f83b3cdc6faa3088c1d3aea1454e3a1d5f', + ], + [ + 'd5e9e1da649d97d89e4868117a465a3a4f8a18de57a140d36b3f2af341a21b52', + '4cb04437f391ed73111a13cc1d4dd0db1693465c2240480d8955e8592f27447a', + ], + [ + 'd3ae41047dd7ca065dbf8ed77b992439983005cd72e16d6f996a5316d36966bb', + 'bd1aeb21ad22ebb22a10f0303417c6d964f8cdd7df0aca614b10dc14d125ac46', + ], + [ + '463e2763d885f958fc66cdd22800f0a487197d0a82e377b49f80af87c897b065', + 'bfefacdb0e5d0fd7df3a311a94de062b26b80c61fbc97508b79992671ef7ca7f', + ], + [ + '7985fdfd127c0567c6f53ec1bb63ec3158e597c40bfe747c83cddfc910641917', + '603c12daf3d9862ef2b25fe1de289aed24ed291e0ec6708703a5bd567f32ed03', + ], + [ + '74a1ad6b5f76e39db2dd249410eac7f99e74c59cb83d2d0ed5ff1543da7703e9', + 'cc6157ef18c9c63cd6193d83631bbea0093e0968942e8c33d5737fd790e0db08', + ], + [ + '30682a50703375f602d416664ba19b7fc9bab42c72747463a71d0896b22f6da3', + '553e04f6b018b4fa6c8f39e7f311d3176290d0e0f19ca73f17714d9977a22ff8', + ], + [ + '9e2158f0d7c0d5f26c3791efefa79597654e7a2b2464f52b1ee6c1347769ef57', + '712fcdd1b9053f09003a3481fa7762e9ffd7c8ef35a38509e2fbf2629008373', + ], + [ + '176e26989a43c9cfeba4029c202538c28172e566e3c4fce7322857f3be327d66', + 'ed8cc9d04b29eb877d270b4878dc43c19aefd31f4eee09ee7b47834c1fa4b1c3', + ], + [ + '75d46efea3771e6e68abb89a13ad747ecf1892393dfc4f1b7004788c50374da8', + '9852390a99507679fd0b86fd2b39a868d7efc22151346e1a3ca4726586a6bed8', + ], + [ + '809a20c67d64900ffb698c4c825f6d5f2310fb0451c869345b7319f645605721', + '9e994980d9917e22b76b061927fa04143d096ccc54963e6a5ebfa5f3f8e286c1', + ], + [ + '1b38903a43f7f114ed4500b4eac7083fdefece1cf29c63528d563446f972c180', + '4036edc931a60ae889353f77fd53de4a2708b26b6f5da72ad3394119daf408f9', + ], + ], + }, +}; + +},{}],100:[function(require,module,exports){ +'use strict'; + +var utils = exports; +var BN = require('bn.js'); +var minAssert = require('minimalistic-assert'); +var minUtils = require('minimalistic-crypto-utils'); + +utils.assert = minAssert; +utils.toArray = minUtils.toArray; +utils.zero2 = minUtils.zero2; +utils.toHex = minUtils.toHex; +utils.encode = minUtils.encode; + +// Represent num in a w-NAF form +function getNAF(num, w, bits) { + var naf = new Array(Math.max(num.bitLength(), bits) + 1); + naf.fill(0); + + var ws = 1 << (w + 1); + var k = num.clone(); + + for (var i = 0; i < naf.length; i++) { + var z; + var mod = k.andln(ws - 1); + if (k.isOdd()) { + if (mod > (ws >> 1) - 1) + z = (ws >> 1) - mod; + else + z = mod; + k.isubn(z); + } else { + z = 0; + } + + naf[i] = z; + k.iushrn(1); + } + + return naf; +} +utils.getNAF = getNAF; + +// Represent k1, k2 in a Joint Sparse Form +function getJSF(k1, k2) { + var jsf = [ + [], + [], + ]; + + k1 = k1.clone(); + k2 = k2.clone(); + var d1 = 0; + var d2 = 0; + var m8; + while (k1.cmpn(-d1) > 0 || k2.cmpn(-d2) > 0) { + // First phase + var m14 = (k1.andln(3) + d1) & 3; + var m24 = (k2.andln(3) + d2) & 3; + if (m14 === 3) + m14 = -1; + if (m24 === 3) + m24 = -1; + var u1; + if ((m14 & 1) === 0) { + u1 = 0; + } else { + m8 = (k1.andln(7) + d1) & 7; + if ((m8 === 3 || m8 === 5) && m24 === 2) + u1 = -m14; + else + u1 = m14; + } + jsf[0].push(u1); + + var u2; + if ((m24 & 1) === 0) { + u2 = 0; + } else { + m8 = (k2.andln(7) + d2) & 7; + if ((m8 === 3 || m8 === 5) && m14 === 2) + u2 = -m24; + else + u2 = m24; + } + jsf[1].push(u2); + + // Second phase + if (2 * d1 === u1 + 1) + d1 = 1 - d1; + if (2 * d2 === u2 + 1) + d2 = 1 - d2; + k1.iushrn(1); + k2.iushrn(1); + } + + return jsf; +} +utils.getJSF = getJSF; + +function cachedProperty(obj, name, computer) { + var key = '_' + name; + obj.prototype[name] = function cachedProperty() { + return this[key] !== undefined ? this[key] : + this[key] = computer.call(this); + }; +} +utils.cachedProperty = cachedProperty; + +function parseBytes(bytes) { + return typeof bytes === 'string' ? utils.toArray(bytes, 'hex') : + bytes; +} +utils.parseBytes = parseBytes; + +function intFromLE(bytes) { + return new BN(bytes, 'hex', 'le'); +} +utils.intFromLE = intFromLE; + + +},{"bn.js":101,"minimalistic-assert":151,"minimalistic-crypto-utils":152}],101:[function(require,module,exports){ +arguments[4][15][0].apply(exports,arguments) +},{"buffer":20,"dup":15}],102:[function(require,module,exports){ +module.exports={ + "_from": "elliptic@^6.5.3", + "_id": "elliptic@6.5.4", + "_inBundle": false, + "_integrity": "sha512-iLhC6ULemrljPZb+QutR5TQGB+pdW6KGD5RSegS+8sorOZT+rdQFbsQFJgvN3eRqNALqJer4oQ16YvJHlU8hzQ==", + "_location": "/browserify/elliptic", + "_phantomChildren": {}, + "_requested": { + "type": "range", + "registry": true, + "raw": "elliptic@^6.5.3", + "name": "elliptic", + "escapedName": "elliptic", + "rawSpec": "^6.5.3", + "saveSpec": null, + "fetchSpec": "^6.5.3" + }, + "_requiredBy": [ + "/browserify/browserify-sign", + "/browserify/create-ecdh" + ], + "_resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.5.4.tgz", + "_shasum": "da37cebd31e79a1367e941b592ed1fbebd58abbb", + "_spec": "elliptic@^6.5.3", + "_where": "/home/default2/.nvm/versions/node/v14.16.1/lib/node_modules/browserify/node_modules/browserify-sign", + "author": { + "name": "Fedor Indutny", + "email": "fedor@indutny.com" + }, + "bugs": { + "url": "https://github.com/indutny/elliptic/issues" + }, + "bundleDependencies": false, + "dependencies": { + "bn.js": "^4.11.9", + "brorand": "^1.1.0", + "hash.js": "^1.0.0", + "hmac-drbg": "^1.0.1", + "inherits": "^2.0.4", + "minimalistic-assert": "^1.0.1", + "minimalistic-crypto-utils": "^1.0.1" + }, + "deprecated": false, + "description": "EC cryptography", + "devDependencies": { + "brfs": "^2.0.2", + "coveralls": "^3.1.0", + "eslint": "^7.6.0", + "grunt": "^1.2.1", + "grunt-browserify": "^5.3.0", + "grunt-cli": "^1.3.2", + "grunt-contrib-connect": "^3.0.0", + "grunt-contrib-copy": "^1.0.0", + "grunt-contrib-uglify": "^5.0.0", + "grunt-mocha-istanbul": "^5.0.2", + "grunt-saucelabs": "^9.0.1", + "istanbul": "^0.4.5", + "mocha": "^8.0.1" + }, + "files": [ + "lib" + ], + "homepage": "https://github.com/indutny/elliptic", + "keywords": [ + "EC", + "Elliptic", + "curve", + "Cryptography" + ], + "license": "MIT", + "main": "lib/elliptic.js", + "name": "elliptic", + "repository": { + "type": "git", + "url": "git+ssh://git@github.com/indutny/elliptic.git" + }, + "scripts": { + "lint": "eslint lib test", + "lint:fix": "npm run lint -- --fix", + "test": "npm run lint && npm run unit", + "unit": "istanbul test _mocha --reporter=spec test/index.js", + "version": "grunt dist && git add dist/" + }, + "version": "6.5.4" +} + +},{}],103:[function(require,module,exports){ +'use strict'; + +var GetIntrinsic = require('get-intrinsic'); + +var $gOPD = GetIntrinsic('%Object.getOwnPropertyDescriptor%'); +if ($gOPD) { + try { + $gOPD([], 'length'); + } catch (e) { + // IE 8 has a broken gOPD + $gOPD = null; + } +} + +module.exports = $gOPD; + +},{"get-intrinsic":109}],104:[function(require,module,exports){ +// Copyright Joyent, Inc. and other Node contributors. +// +// 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. + +'use strict'; + +var R = typeof Reflect === 'object' ? Reflect : null +var ReflectApply = R && typeof R.apply === 'function' + ? R.apply + : function ReflectApply(target, receiver, args) { + return Function.prototype.apply.call(target, receiver, args); + } + +var ReflectOwnKeys +if (R && typeof R.ownKeys === 'function') { + ReflectOwnKeys = R.ownKeys +} else if (Object.getOwnPropertySymbols) { + ReflectOwnKeys = function ReflectOwnKeys(target) { + return Object.getOwnPropertyNames(target) + .concat(Object.getOwnPropertySymbols(target)); + }; +} else { + ReflectOwnKeys = function ReflectOwnKeys(target) { + return Object.getOwnPropertyNames(target); + }; +} + +function ProcessEmitWarning(warning) { + if (console && console.warn) console.warn(warning); +} + +var NumberIsNaN = Number.isNaN || function NumberIsNaN(value) { + return value !== value; +} + +function EventEmitter() { + EventEmitter.init.call(this); +} +module.exports = EventEmitter; +module.exports.once = once; + +// Backwards-compat with node 0.10.x +EventEmitter.EventEmitter = EventEmitter; + +EventEmitter.prototype._events = undefined; +EventEmitter.prototype._eventsCount = 0; +EventEmitter.prototype._maxListeners = undefined; + +// By default EventEmitters will print a warning if more than 10 listeners are +// added to it. This is a useful default which helps finding memory leaks. +var defaultMaxListeners = 10; + +function checkListener(listener) { + if (typeof listener !== 'function') { + throw new TypeError('The "listener" argument must be of type Function. Received type ' + typeof listener); + } +} + +Object.defineProperty(EventEmitter, 'defaultMaxListeners', { + enumerable: true, + get: function() { + return defaultMaxListeners; + }, + set: function(arg) { + if (typeof arg !== 'number' || arg < 0 || NumberIsNaN(arg)) { + throw new RangeError('The value of "defaultMaxListeners" is out of range. It must be a non-negative number. Received ' + arg + '.'); + } + defaultMaxListeners = arg; + } +}); + +EventEmitter.init = function() { + + if (this._events === undefined || + this._events === Object.getPrototypeOf(this)._events) { + this._events = Object.create(null); + this._eventsCount = 0; + } + + this._maxListeners = this._maxListeners || undefined; +}; + +// Obviously not all Emitters should be limited to 10. This function allows +// that to be increased. Set to zero for unlimited. +EventEmitter.prototype.setMaxListeners = function setMaxListeners(n) { + if (typeof n !== 'number' || n < 0 || NumberIsNaN(n)) { + throw new RangeError('The value of "n" is out of range. It must be a non-negative number. Received ' + n + '.'); + } + this._maxListeners = n; + return this; +}; + +function _getMaxListeners(that) { + if (that._maxListeners === undefined) + return EventEmitter.defaultMaxListeners; + return that._maxListeners; +} + +EventEmitter.prototype.getMaxListeners = function getMaxListeners() { + return _getMaxListeners(this); +}; + +EventEmitter.prototype.emit = function emit(type) { + var args = []; + for (var i = 1; i < arguments.length; i++) args.push(arguments[i]); + var doError = (type === 'error'); + + var events = this._events; + if (events !== undefined) + doError = (doError && events.error === undefined); + else if (!doError) + return false; + + // If there is no 'error' event listener then throw. + if (doError) { + var er; + if (args.length > 0) + er = args[0]; + if (er instanceof Error) { + // Note: The comments on the `throw` lines are intentional, they show + // up in Node's output if this results in an unhandled exception. + throw er; // Unhandled 'error' event + } + // At least give some kind of context to the user + var err = new Error('Unhandled error.' + (er ? ' (' + er.message + ')' : '')); + err.context = er; + throw err; // Unhandled 'error' event + } + + var handler = events[type]; + + if (handler === undefined) + return false; + + if (typeof handler === 'function') { + ReflectApply(handler, this, args); + } else { + var len = handler.length; + var listeners = arrayClone(handler, len); + for (var i = 0; i < len; ++i) + ReflectApply(listeners[i], this, args); + } + + return true; +}; + +function _addListener(target, type, listener, prepend) { + var m; + var events; + var existing; + + checkListener(listener); + + events = target._events; + if (events === undefined) { + events = target._events = Object.create(null); + target._eventsCount = 0; + } else { + // To avoid recursion in the case that type === "newListener"! Before + // adding it to the listeners, first emit "newListener". + if (events.newListener !== undefined) { + target.emit('newListener', type, + listener.listener ? listener.listener : listener); + + // Re-assign `events` because a newListener handler could have caused the + // this._events to be assigned to a new object + events = target._events; + } + existing = events[type]; + } + + if (existing === undefined) { + // Optimize the case of one listener. Don't need the extra array object. + existing = events[type] = listener; + ++target._eventsCount; + } else { + if (typeof existing === 'function') { + // Adding the second element, need to change to array. + existing = events[type] = + prepend ? [listener, existing] : [existing, listener]; + // If we've already got an array, just append. + } else if (prepend) { + existing.unshift(listener); + } else { + existing.push(listener); + } + + // Check for listener leak + m = _getMaxListeners(target); + if (m > 0 && existing.length > m && !existing.warned) { + existing.warned = true; + // No error code for this since it is a Warning + // eslint-disable-next-line no-restricted-syntax + var w = new Error('Possible EventEmitter memory leak detected. ' + + existing.length + ' ' + String(type) + ' listeners ' + + 'added. Use emitter.setMaxListeners() to ' + + 'increase limit'); + w.name = 'MaxListenersExceededWarning'; + w.emitter = target; + w.type = type; + w.count = existing.length; + ProcessEmitWarning(w); + } + } + + return target; +} + +EventEmitter.prototype.addListener = function addListener(type, listener) { + return _addListener(this, type, listener, false); +}; + +EventEmitter.prototype.on = EventEmitter.prototype.addListener; + +EventEmitter.prototype.prependListener = + function prependListener(type, listener) { + return _addListener(this, type, listener, true); + }; + +function onceWrapper() { + if (!this.fired) { + this.target.removeListener(this.type, this.wrapFn); + this.fired = true; + if (arguments.length === 0) + return this.listener.call(this.target); + return this.listener.apply(this.target, arguments); + } +} + +function _onceWrap(target, type, listener) { + var state = { fired: false, wrapFn: undefined, target: target, type: type, listener: listener }; + var wrapped = onceWrapper.bind(state); + wrapped.listener = listener; + state.wrapFn = wrapped; + return wrapped; +} + +EventEmitter.prototype.once = function once(type, listener) { + checkListener(listener); + this.on(type, _onceWrap(this, type, listener)); + return this; +}; + +EventEmitter.prototype.prependOnceListener = + function prependOnceListener(type, listener) { + checkListener(listener); + this.prependListener(type, _onceWrap(this, type, listener)); + return this; + }; + +// Emits a 'removeListener' event if and only if the listener was removed. +EventEmitter.prototype.removeListener = + function removeListener(type, listener) { + var list, events, position, i, originalListener; + + checkListener(listener); + + events = this._events; + if (events === undefined) + return this; + + list = events[type]; + if (list === undefined) + return this; + + if (list === listener || list.listener === listener) { + if (--this._eventsCount === 0) + this._events = Object.create(null); + else { + delete events[type]; + if (events.removeListener) + this.emit('removeListener', type, list.listener || listener); + } + } else if (typeof list !== 'function') { + position = -1; + + for (i = list.length - 1; i >= 0; i--) { + if (list[i] === listener || list[i].listener === listener) { + originalListener = list[i].listener; + position = i; + break; + } + } + + if (position < 0) + return this; + + if (position === 0) + list.shift(); + else { + spliceOne(list, position); + } + + if (list.length === 1) + events[type] = list[0]; + + if (events.removeListener !== undefined) + this.emit('removeListener', type, originalListener || listener); + } + + return this; + }; + +EventEmitter.prototype.off = EventEmitter.prototype.removeListener; + +EventEmitter.prototype.removeAllListeners = + function removeAllListeners(type) { + var listeners, events, i; + + events = this._events; + if (events === undefined) + return this; + + // not listening for removeListener, no need to emit + if (events.removeListener === undefined) { + if (arguments.length === 0) { + this._events = Object.create(null); + this._eventsCount = 0; + } else if (events[type] !== undefined) { + if (--this._eventsCount === 0) + this._events = Object.create(null); + else + delete events[type]; + } + return this; + } + + // emit removeListener for all listeners on all events + if (arguments.length === 0) { + var keys = Object.keys(events); + var key; + for (i = 0; i < keys.length; ++i) { + key = keys[i]; + if (key === 'removeListener') continue; + this.removeAllListeners(key); + } + this.removeAllListeners('removeListener'); + this._events = Object.create(null); + this._eventsCount = 0; + return this; + } + + listeners = events[type]; + + if (typeof listeners === 'function') { + this.removeListener(type, listeners); + } else if (listeners !== undefined) { + // LIFO order + for (i = listeners.length - 1; i >= 0; i--) { + this.removeListener(type, listeners[i]); + } + } + + return this; + }; + +function _listeners(target, type, unwrap) { + var events = target._events; + + if (events === undefined) + return []; + + var evlistener = events[type]; + if (evlistener === undefined) + return []; + + if (typeof evlistener === 'function') + return unwrap ? [evlistener.listener || evlistener] : [evlistener]; + + return unwrap ? + unwrapListeners(evlistener) : arrayClone(evlistener, evlistener.length); +} + +EventEmitter.prototype.listeners = function listeners(type) { + return _listeners(this, type, true); +}; + +EventEmitter.prototype.rawListeners = function rawListeners(type) { + return _listeners(this, type, false); +}; + +EventEmitter.listenerCount = function(emitter, type) { + if (typeof emitter.listenerCount === 'function') { + return emitter.listenerCount(type); + } else { + return listenerCount.call(emitter, type); + } +}; + +EventEmitter.prototype.listenerCount = listenerCount; +function listenerCount(type) { + var events = this._events; + + if (events !== undefined) { + var evlistener = events[type]; + + if (typeof evlistener === 'function') { + return 1; + } else if (evlistener !== undefined) { + return evlistener.length; + } + } + + return 0; +} + +EventEmitter.prototype.eventNames = function eventNames() { + return this._eventsCount > 0 ? ReflectOwnKeys(this._events) : []; +}; + +function arrayClone(arr, n) { + var copy = new Array(n); + for (var i = 0; i < n; ++i) + copy[i] = arr[i]; + return copy; +} + +function spliceOne(list, index) { + for (; index + 1 < list.length; index++) + list[index] = list[index + 1]; + list.pop(); +} + +function unwrapListeners(arr) { + var ret = new Array(arr.length); + for (var i = 0; i < ret.length; ++i) { + ret[i] = arr[i].listener || arr[i]; + } + return ret; +} + +function once(emitter, name) { + return new Promise(function (resolve, reject) { + function errorListener(err) { + emitter.removeListener(name, resolver); + reject(err); + } + + function resolver() { + if (typeof emitter.removeListener === 'function') { + emitter.removeListener('error', errorListener); + } + resolve([].slice.call(arguments)); + }; + + eventTargetAgnosticAddListener(emitter, name, resolver, { once: true }); + if (name !== 'error') { + addErrorHandlerIfEventEmitter(emitter, errorListener, { once: true }); + } + }); +} + +function addErrorHandlerIfEventEmitter(emitter, handler, flags) { + if (typeof emitter.on === 'function') { + eventTargetAgnosticAddListener(emitter, 'error', handler, flags); + } +} + +function eventTargetAgnosticAddListener(emitter, name, listener, flags) { + if (typeof emitter.on === 'function') { + if (flags.once) { + emitter.once(name, listener); + } else { + emitter.on(name, listener); + } + } else if (typeof emitter.addEventListener === 'function') { + // EventTarget does not have `error` event semantics like Node + // EventEmitters, we do not listen for `error` events here. + emitter.addEventListener(name, function wrapListener(arg) { + // IE does not have builtin `{ once: true }` support so we + // have to do it manually. + if (flags.once) { + emitter.removeEventListener(name, wrapListener); + } + listener(arg); + }); + } else { + throw new TypeError('The "emitter" argument must be of type EventEmitter. Received type ' + typeof emitter); + } +} + +},{}],105:[function(require,module,exports){ +var Buffer = require('safe-buffer').Buffer +var MD5 = require('md5.js') + +/* eslint-disable camelcase */ +function EVP_BytesToKey (password, salt, keyBits, ivLen) { + if (!Buffer.isBuffer(password)) password = Buffer.from(password, 'binary') + if (salt) { + if (!Buffer.isBuffer(salt)) salt = Buffer.from(salt, 'binary') + if (salt.length !== 8) throw new RangeError('salt should be Buffer with 8 byte length') + } + + var keyLen = keyBits / 8 + var key = Buffer.alloc(keyLen) + var iv = Buffer.alloc(ivLen || 0) + var tmp = Buffer.alloc(0) + + while (keyLen > 0 || ivLen > 0) { + var hash = new MD5() + hash.update(tmp) + hash.update(password) + if (salt) hash.update(salt) + tmp = hash.digest() + + var used = 0 + + if (keyLen > 0) { + var keyStart = key.length - keyLen + used = Math.min(keyLen, tmp.length) + tmp.copy(key, keyStart, 0, used) + keyLen -= used + } + + if (used < tmp.length && ivLen > 0) { + var ivStart = iv.length - ivLen + var length = Math.min(ivLen, tmp.length - used) + tmp.copy(iv, ivStart, used, used + length) + ivLen -= length + } + } + + tmp.fill(0) + return { key: key, iv: iv } +} + +module.exports = EVP_BytesToKey + +},{"md5.js":148,"safe-buffer":179}],106:[function(require,module,exports){ + +var hasOwn = Object.prototype.hasOwnProperty; +var toString = Object.prototype.toString; + +module.exports = function forEach (obj, fn, ctx) { + if (toString.call(fn) !== '[object Function]') { + throw new TypeError('iterator must be a function'); + } + var l = obj.length; + if (l === +l) { + for (var i = 0; i < l; i++) { + fn.call(ctx, obj[i], i, obj); + } + } else { + for (var k in obj) { + if (hasOwn.call(obj, k)) { + fn.call(ctx, obj[k], k, obj); + } + } + } +}; + + +},{}],107:[function(require,module,exports){ +'use strict'; + +/* eslint no-invalid-this: 1 */ + +var ERROR_MESSAGE = 'Function.prototype.bind called on incompatible '; +var slice = Array.prototype.slice; +var toStr = Object.prototype.toString; +var funcType = '[object Function]'; + +module.exports = function bind(that) { + var target = this; + if (typeof target !== 'function' || toStr.call(target) !== funcType) { + throw new TypeError(ERROR_MESSAGE + target); + } + var args = slice.call(arguments, 1); + + var bound; + var binder = function () { + if (this instanceof bound) { + var result = target.apply( + this, + args.concat(slice.call(arguments)) + ); + if (Object(result) === result) { + return result; + } + return this; + } else { + return target.apply( + that, + args.concat(slice.call(arguments)) + ); + } + }; + + var boundLength = Math.max(0, target.length - args.length); + var boundArgs = []; + for (var i = 0; i < boundLength; i++) { + boundArgs.push('$' + i); + } + + bound = Function('binder', 'return function (' + boundArgs.join(',') + '){ return binder.apply(this,arguments); }')(binder); + + if (target.prototype) { + var Empty = function Empty() {}; + Empty.prototype = target.prototype; + bound.prototype = new Empty(); + Empty.prototype = null; + } + + return bound; +}; + +},{}],108:[function(require,module,exports){ +'use strict'; + +var implementation = require('./implementation'); + +module.exports = Function.prototype.bind || implementation; + +},{"./implementation":107}],109:[function(require,module,exports){ +'use strict'; + +var undefined; + +var $SyntaxError = SyntaxError; +var $Function = Function; +var $TypeError = TypeError; + +// eslint-disable-next-line consistent-return +var getEvalledConstructor = function (expressionSyntax) { + try { + return $Function('"use strict"; return (' + expressionSyntax + ').constructor;')(); + } catch (e) {} +}; + +var $gOPD = Object.getOwnPropertyDescriptor; +if ($gOPD) { + try { + $gOPD({}, ''); + } catch (e) { + $gOPD = null; // this is IE 8, which has a broken gOPD + } +} + +var throwTypeError = function () { + throw new $TypeError(); +}; +var ThrowTypeError = $gOPD + ? (function () { + try { + // eslint-disable-next-line no-unused-expressions, no-caller, no-restricted-properties + arguments.callee; // IE 8 does not throw here + return throwTypeError; + } catch (calleeThrows) { + try { + // IE 8 throws on Object.getOwnPropertyDescriptor(arguments, '') + return $gOPD(arguments, 'callee').get; + } catch (gOPDthrows) { + return throwTypeError; + } + } + }()) + : throwTypeError; + +var hasSymbols = require('has-symbols')(); + +var getProto = Object.getPrototypeOf || function (x) { return x.__proto__; }; // eslint-disable-line no-proto + +var needsEval = {}; + +var TypedArray = typeof Uint8Array === 'undefined' ? undefined : getProto(Uint8Array); + +var INTRINSICS = { + '%AggregateError%': typeof AggregateError === 'undefined' ? undefined : AggregateError, + '%Array%': Array, + '%ArrayBuffer%': typeof ArrayBuffer === 'undefined' ? undefined : ArrayBuffer, + '%ArrayIteratorPrototype%': hasSymbols ? getProto([][Symbol.iterator]()) : undefined, + '%AsyncFromSyncIteratorPrototype%': undefined, + '%AsyncFunction%': needsEval, + '%AsyncGenerator%': needsEval, + '%AsyncGeneratorFunction%': needsEval, + '%AsyncIteratorPrototype%': needsEval, + '%Atomics%': typeof Atomics === 'undefined' ? undefined : Atomics, + '%BigInt%': typeof BigInt === 'undefined' ? undefined : BigInt, + '%Boolean%': Boolean, + '%DataView%': typeof DataView === 'undefined' ? undefined : DataView, + '%Date%': Date, + '%decodeURI%': decodeURI, + '%decodeURIComponent%': decodeURIComponent, + '%encodeURI%': encodeURI, + '%encodeURIComponent%': encodeURIComponent, + '%Error%': Error, + '%eval%': eval, // eslint-disable-line no-eval + '%EvalError%': EvalError, + '%Float32Array%': typeof Float32Array === 'undefined' ? undefined : Float32Array, + '%Float64Array%': typeof Float64Array === 'undefined' ? undefined : Float64Array, + '%FinalizationRegistry%': typeof FinalizationRegistry === 'undefined' ? undefined : FinalizationRegistry, + '%Function%': $Function, + '%GeneratorFunction%': needsEval, + '%Int8Array%': typeof Int8Array === 'undefined' ? undefined : Int8Array, + '%Int16Array%': typeof Int16Array === 'undefined' ? undefined : Int16Array, + '%Int32Array%': typeof Int32Array === 'undefined' ? undefined : Int32Array, + '%isFinite%': isFinite, + '%isNaN%': isNaN, + '%IteratorPrototype%': hasSymbols ? getProto(getProto([][Symbol.iterator]())) : undefined, + '%JSON%': typeof JSON === 'object' ? JSON : undefined, + '%Map%': typeof Map === 'undefined' ? undefined : Map, + '%MapIteratorPrototype%': typeof Map === 'undefined' || !hasSymbols ? undefined : getProto(new Map()[Symbol.iterator]()), + '%Math%': Math, + '%Number%': Number, + '%Object%': Object, + '%parseFloat%': parseFloat, + '%parseInt%': parseInt, + '%Promise%': typeof Promise === 'undefined' ? undefined : Promise, + '%Proxy%': typeof Proxy === 'undefined' ? undefined : Proxy, + '%RangeError%': RangeError, + '%ReferenceError%': ReferenceError, + '%Reflect%': typeof Reflect === 'undefined' ? undefined : Reflect, + '%RegExp%': RegExp, + '%Set%': typeof Set === 'undefined' ? undefined : Set, + '%SetIteratorPrototype%': typeof Set === 'undefined' || !hasSymbols ? undefined : getProto(new Set()[Symbol.iterator]()), + '%SharedArrayBuffer%': typeof SharedArrayBuffer === 'undefined' ? undefined : SharedArrayBuffer, + '%String%': String, + '%StringIteratorPrototype%': hasSymbols ? getProto(''[Symbol.iterator]()) : undefined, + '%Symbol%': hasSymbols ? Symbol : undefined, + '%SyntaxError%': $SyntaxError, + '%ThrowTypeError%': ThrowTypeError, + '%TypedArray%': TypedArray, + '%TypeError%': $TypeError, + '%Uint8Array%': typeof Uint8Array === 'undefined' ? undefined : Uint8Array, + '%Uint8ClampedArray%': typeof Uint8ClampedArray === 'undefined' ? undefined : Uint8ClampedArray, + '%Uint16Array%': typeof Uint16Array === 'undefined' ? undefined : Uint16Array, + '%Uint32Array%': typeof Uint32Array === 'undefined' ? undefined : Uint32Array, + '%URIError%': URIError, + '%WeakMap%': typeof WeakMap === 'undefined' ? undefined : WeakMap, + '%WeakRef%': typeof WeakRef === 'undefined' ? undefined : WeakRef, + '%WeakSet%': typeof WeakSet === 'undefined' ? undefined : WeakSet +}; + +var doEval = function doEval(name) { + var value; + if (name === '%AsyncFunction%') { + value = getEvalledConstructor('async function () {}'); + } else if (name === '%GeneratorFunction%') { + value = getEvalledConstructor('function* () {}'); + } else if (name === '%AsyncGeneratorFunction%') { + value = getEvalledConstructor('async function* () {}'); + } else if (name === '%AsyncGenerator%') { + var fn = doEval('%AsyncGeneratorFunction%'); + if (fn) { + value = fn.prototype; + } + } else if (name === '%AsyncIteratorPrototype%') { + var gen = doEval('%AsyncGenerator%'); + if (gen) { + value = getProto(gen.prototype); + } + } + + INTRINSICS[name] = value; + + return value; +}; + +var LEGACY_ALIASES = { + '%ArrayBufferPrototype%': ['ArrayBuffer', 'prototype'], + '%ArrayPrototype%': ['Array', 'prototype'], + '%ArrayProto_entries%': ['Array', 'prototype', 'entries'], + '%ArrayProto_forEach%': ['Array', 'prototype', 'forEach'], + '%ArrayProto_keys%': ['Array', 'prototype', 'keys'], + '%ArrayProto_values%': ['Array', 'prototype', 'values'], + '%AsyncFunctionPrototype%': ['AsyncFunction', 'prototype'], + '%AsyncGenerator%': ['AsyncGeneratorFunction', 'prototype'], + '%AsyncGeneratorPrototype%': ['AsyncGeneratorFunction', 'prototype', 'prototype'], + '%BooleanPrototype%': ['Boolean', 'prototype'], + '%DataViewPrototype%': ['DataView', 'prototype'], + '%DatePrototype%': ['Date', 'prototype'], + '%ErrorPrototype%': ['Error', 'prototype'], + '%EvalErrorPrototype%': ['EvalError', 'prototype'], + '%Float32ArrayPrototype%': ['Float32Array', 'prototype'], + '%Float64ArrayPrototype%': ['Float64Array', 'prototype'], + '%FunctionPrototype%': ['Function', 'prototype'], + '%Generator%': ['GeneratorFunction', 'prototype'], + '%GeneratorPrototype%': ['GeneratorFunction', 'prototype', 'prototype'], + '%Int8ArrayPrototype%': ['Int8Array', 'prototype'], + '%Int16ArrayPrototype%': ['Int16Array', 'prototype'], + '%Int32ArrayPrototype%': ['Int32Array', 'prototype'], + '%JSONParse%': ['JSON', 'parse'], + '%JSONStringify%': ['JSON', 'stringify'], + '%MapPrototype%': ['Map', 'prototype'], + '%NumberPrototype%': ['Number', 'prototype'], + '%ObjectPrototype%': ['Object', 'prototype'], + '%ObjProto_toString%': ['Object', 'prototype', 'toString'], + '%ObjProto_valueOf%': ['Object', 'prototype', 'valueOf'], + '%PromisePrototype%': ['Promise', 'prototype'], + '%PromiseProto_then%': ['Promise', 'prototype', 'then'], + '%Promise_all%': ['Promise', 'all'], + '%Promise_reject%': ['Promise', 'reject'], + '%Promise_resolve%': ['Promise', 'resolve'], + '%RangeErrorPrototype%': ['RangeError', 'prototype'], + '%ReferenceErrorPrototype%': ['ReferenceError', 'prototype'], + '%RegExpPrototype%': ['RegExp', 'prototype'], + '%SetPrototype%': ['Set', 'prototype'], + '%SharedArrayBufferPrototype%': ['SharedArrayBuffer', 'prototype'], + '%StringPrototype%': ['String', 'prototype'], + '%SymbolPrototype%': ['Symbol', 'prototype'], + '%SyntaxErrorPrototype%': ['SyntaxError', 'prototype'], + '%TypedArrayPrototype%': ['TypedArray', 'prototype'], + '%TypeErrorPrototype%': ['TypeError', 'prototype'], + '%Uint8ArrayPrototype%': ['Uint8Array', 'prototype'], + '%Uint8ClampedArrayPrototype%': ['Uint8ClampedArray', 'prototype'], + '%Uint16ArrayPrototype%': ['Uint16Array', 'prototype'], + '%Uint32ArrayPrototype%': ['Uint32Array', 'prototype'], + '%URIErrorPrototype%': ['URIError', 'prototype'], + '%WeakMapPrototype%': ['WeakMap', 'prototype'], + '%WeakSetPrototype%': ['WeakSet', 'prototype'] +}; + +var bind = require('function-bind'); +var hasOwn = require('has'); +var $concat = bind.call(Function.call, Array.prototype.concat); +var $spliceApply = bind.call(Function.apply, Array.prototype.splice); +var $replace = bind.call(Function.call, String.prototype.replace); +var $strSlice = bind.call(Function.call, String.prototype.slice); + +/* adapted from https://github.com/lodash/lodash/blob/4.17.15/dist/lodash.js#L6735-L6744 */ +var rePropName = /[^%.[\]]+|\[(?:(-?\d+(?:\.\d+)?)|(["'])((?:(?!\2)[^\\]|\\.)*?)\2)\]|(?=(?:\.|\[\])(?:\.|\[\]|%$))/g; +var reEscapeChar = /\\(\\)?/g; /** Used to match backslashes in property paths. */ +var stringToPath = function stringToPath(string) { + var first = $strSlice(string, 0, 1); + var last = $strSlice(string, -1); + if (first === '%' && last !== '%') { + throw new $SyntaxError('invalid intrinsic syntax, expected closing `%`'); + } else if (last === '%' && first !== '%') { + throw new $SyntaxError('invalid intrinsic syntax, expected opening `%`'); + } + var result = []; + $replace(string, rePropName, function (match, number, quote, subString) { + result[result.length] = quote ? $replace(subString, reEscapeChar, '$1') : number || match; + }); + return result; +}; +/* end adaptation */ + +var getBaseIntrinsic = function getBaseIntrinsic(name, allowMissing) { + var intrinsicName = name; + var alias; + if (hasOwn(LEGACY_ALIASES, intrinsicName)) { + alias = LEGACY_ALIASES[intrinsicName]; + intrinsicName = '%' + alias[0] + '%'; + } + + if (hasOwn(INTRINSICS, intrinsicName)) { + var value = INTRINSICS[intrinsicName]; + if (value === needsEval) { + value = doEval(intrinsicName); + } + if (typeof value === 'undefined' && !allowMissing) { + throw new $TypeError('intrinsic ' + name + ' exists, but is not available. Please file an issue!'); + } + + return { + alias: alias, + name: intrinsicName, + value: value + }; + } + + throw new $SyntaxError('intrinsic ' + name + ' does not exist!'); +}; + +module.exports = function GetIntrinsic(name, allowMissing) { + if (typeof name !== 'string' || name.length === 0) { + throw new $TypeError('intrinsic name must be a non-empty string'); + } + if (arguments.length > 1 && typeof allowMissing !== 'boolean') { + throw new $TypeError('"allowMissing" argument must be a boolean'); + } + + var parts = stringToPath(name); + var intrinsicBaseName = parts.length > 0 ? parts[0] : ''; + + var intrinsic = getBaseIntrinsic('%' + intrinsicBaseName + '%', allowMissing); + var intrinsicRealName = intrinsic.name; + var value = intrinsic.value; + var skipFurtherCaching = false; + + var alias = intrinsic.alias; + if (alias) { + intrinsicBaseName = alias[0]; + $spliceApply(parts, $concat([0, 1], alias)); + } + + for (var i = 1, isOwn = true; i < parts.length; i += 1) { + var part = parts[i]; + var first = $strSlice(part, 0, 1); + var last = $strSlice(part, -1); + if ( + ( + (first === '"' || first === "'" || first === '`') + || (last === '"' || last === "'" || last === '`') + ) + && first !== last + ) { + throw new $SyntaxError('property names with quotes must have matching quotes'); + } + if (part === 'constructor' || !isOwn) { + skipFurtherCaching = true; + } + + intrinsicBaseName += '.' + part; + intrinsicRealName = '%' + intrinsicBaseName + '%'; + + if (hasOwn(INTRINSICS, intrinsicRealName)) { + value = INTRINSICS[intrinsicRealName]; + } else if (value != null) { + if (!(part in value)) { + if (!allowMissing) { + throw new $TypeError('base intrinsic for ' + name + ' exists, but the property is not available.'); + } + return void undefined; + } + if ($gOPD && (i + 1) >= parts.length) { + var desc = $gOPD(value, part); + isOwn = !!desc; + + // By convention, when a data property is converted to an accessor + // property to emulate a data property that does not suffer from + // the override mistake, that accessor's getter is marked with + // an `originalValue` property. Here, when we detect this, we + // uphold the illusion by pretending to see that original data + // property, i.e., returning the value rather than the getter + // itself. + if (isOwn && 'get' in desc && !('originalValue' in desc.get)) { + value = desc.get; + } else { + value = value[part]; + } + } else { + isOwn = hasOwn(value, part); + value = value[part]; + } + + if (isOwn && !skipFurtherCaching) { + INTRINSICS[intrinsicRealName] = value; + } + } + } + return value; +}; + +},{"function-bind":108,"has":112,"has-symbols":110}],110:[function(require,module,exports){ +'use strict'; + +var origSymbol = typeof Symbol !== 'undefined' && Symbol; +var hasSymbolSham = require('./shams'); + +module.exports = function hasNativeSymbols() { + if (typeof origSymbol !== 'function') { return false; } + if (typeof Symbol !== 'function') { return false; } + if (typeof origSymbol('foo') !== 'symbol') { return false; } + if (typeof Symbol('bar') !== 'symbol') { return false; } + + return hasSymbolSham(); +}; + +},{"./shams":111}],111:[function(require,module,exports){ +'use strict'; + +/* eslint complexity: [2, 18], max-statements: [2, 33] */ +module.exports = function hasSymbols() { + if (typeof Symbol !== 'function' || typeof Object.getOwnPropertySymbols !== 'function') { return false; } + if (typeof Symbol.iterator === 'symbol') { return true; } + + var obj = {}; + var sym = Symbol('test'); + var symObj = Object(sym); + if (typeof sym === 'string') { return false; } + + if (Object.prototype.toString.call(sym) !== '[object Symbol]') { return false; } + if (Object.prototype.toString.call(symObj) !== '[object Symbol]') { return false; } + + // temp disabled per https://github.com/ljharb/object.assign/issues/17 + // if (sym instanceof Symbol) { return false; } + // temp disabled per https://github.com/WebReflection/get-own-property-symbols/issues/4 + // if (!(symObj instanceof Symbol)) { return false; } + + // if (typeof Symbol.prototype.toString !== 'function') { return false; } + // if (String(sym) !== Symbol.prototype.toString.call(sym)) { return false; } + + var symVal = 42; + obj[sym] = symVal; + for (sym in obj) { return false; } // eslint-disable-line no-restricted-syntax, no-unreachable-loop + if (typeof Object.keys === 'function' && Object.keys(obj).length !== 0) { return false; } + + if (typeof Object.getOwnPropertyNames === 'function' && Object.getOwnPropertyNames(obj).length !== 0) { return false; } + + var syms = Object.getOwnPropertySymbols(obj); + if (syms.length !== 1 || syms[0] !== sym) { return false; } + + if (!Object.prototype.propertyIsEnumerable.call(obj, sym)) { return false; } + + if (typeof Object.getOwnPropertyDescriptor === 'function') { + var descriptor = Object.getOwnPropertyDescriptor(obj, sym); + if (descriptor.value !== symVal || descriptor.enumerable !== true) { return false; } + } + + return true; +}; + +},{}],112:[function(require,module,exports){ +'use strict'; + +var bind = require('function-bind'); + +module.exports = bind.call(Function.call, Object.prototype.hasOwnProperty); + +},{"function-bind":108}],113:[function(require,module,exports){ +'use strict' +var Buffer = require('safe-buffer').Buffer +var Transform = require('readable-stream').Transform +var inherits = require('inherits') + +function throwIfNotStringOrBuffer (val, prefix) { + if (!Buffer.isBuffer(val) && typeof val !== 'string') { + throw new TypeError(prefix + ' must be a string or a buffer') + } +} + +function HashBase (blockSize) { + Transform.call(this) + + this._block = Buffer.allocUnsafe(blockSize) + this._blockSize = blockSize + this._blockOffset = 0 + this._length = [0, 0, 0, 0] + + this._finalized = false +} + +inherits(HashBase, Transform) + +HashBase.prototype._transform = function (chunk, encoding, callback) { + var error = null + try { + this.update(chunk, encoding) + } catch (err) { + error = err + } + + callback(error) +} + +HashBase.prototype._flush = function (callback) { + var error = null + try { + this.push(this.digest()) + } catch (err) { + error = err + } + + callback(error) +} + +HashBase.prototype.update = function (data, encoding) { + throwIfNotStringOrBuffer(data, 'Data') + if (this._finalized) throw new Error('Digest already called') + if (!Buffer.isBuffer(data)) data = Buffer.from(data, encoding) + + // consume data + var block = this._block + var offset = 0 + while (this._blockOffset + data.length - offset >= this._blockSize) { + for (var i = this._blockOffset; i < this._blockSize;) block[i++] = data[offset++] + this._update() + this._blockOffset = 0 + } + while (offset < data.length) block[this._blockOffset++] = data[offset++] + + // update length + for (var j = 0, carry = data.length * 8; carry > 0; ++j) { + this._length[j] += carry + carry = (this._length[j] / 0x0100000000) | 0 + if (carry > 0) this._length[j] -= 0x0100000000 * carry + } + + return this +} + +HashBase.prototype._update = function () { + throw new Error('_update is not implemented') +} + +HashBase.prototype.digest = function (encoding) { + if (this._finalized) throw new Error('Digest already called') + this._finalized = true + + var digest = this._digest() + if (encoding !== undefined) digest = digest.toString(encoding) + + // reset state + this._block.fill(0) + this._blockOffset = 0 + for (var i = 0; i < 4; ++i) this._length[i] = 0 + + return digest +} + +HashBase.prototype._digest = function () { + throw new Error('_digest is not implemented') +} + +module.exports = HashBase + +},{"inherits":143,"readable-stream":128,"safe-buffer":179}],114:[function(require,module,exports){ +arguments[4][48][0].apply(exports,arguments) +},{"dup":48}],115:[function(require,module,exports){ +arguments[4][49][0].apply(exports,arguments) +},{"./_stream_readable":117,"./_stream_writable":119,"_process":164,"dup":49,"inherits":143}],116:[function(require,module,exports){ +arguments[4][50][0].apply(exports,arguments) +},{"./_stream_transform":118,"dup":50,"inherits":143}],117:[function(require,module,exports){ +arguments[4][51][0].apply(exports,arguments) +},{"../errors":114,"./_stream_duplex":115,"./internal/streams/async_iterator":120,"./internal/streams/buffer_list":121,"./internal/streams/destroy":122,"./internal/streams/from":124,"./internal/streams/state":126,"./internal/streams/stream":127,"_process":164,"buffer":64,"dup":51,"events":104,"inherits":143,"string_decoder/":204,"util":20}],118:[function(require,module,exports){ +arguments[4][52][0].apply(exports,arguments) +},{"../errors":114,"./_stream_duplex":115,"dup":52,"inherits":143}],119:[function(require,module,exports){ +arguments[4][53][0].apply(exports,arguments) +},{"../errors":114,"./_stream_duplex":115,"./internal/streams/destroy":122,"./internal/streams/state":126,"./internal/streams/stream":127,"_process":164,"buffer":64,"dup":53,"inherits":143,"util-deprecate":207}],120:[function(require,module,exports){ +arguments[4][54][0].apply(exports,arguments) +},{"./end-of-stream":123,"_process":164,"dup":54}],121:[function(require,module,exports){ +arguments[4][55][0].apply(exports,arguments) +},{"buffer":64,"dup":55,"util":20}],122:[function(require,module,exports){ +arguments[4][56][0].apply(exports,arguments) +},{"_process":164,"dup":56}],123:[function(require,module,exports){ +arguments[4][57][0].apply(exports,arguments) +},{"../../../errors":114,"dup":57}],124:[function(require,module,exports){ +arguments[4][58][0].apply(exports,arguments) +},{"dup":58}],125:[function(require,module,exports){ +arguments[4][59][0].apply(exports,arguments) +},{"../../../errors":114,"./end-of-stream":123,"dup":59}],126:[function(require,module,exports){ +arguments[4][60][0].apply(exports,arguments) +},{"../../../errors":114,"dup":60}],127:[function(require,module,exports){ +arguments[4][61][0].apply(exports,arguments) +},{"dup":61,"events":104}],128:[function(require,module,exports){ +arguments[4][62][0].apply(exports,arguments) +},{"./lib/_stream_duplex.js":115,"./lib/_stream_passthrough.js":116,"./lib/_stream_readable.js":117,"./lib/_stream_transform.js":118,"./lib/_stream_writable.js":119,"./lib/internal/streams/end-of-stream.js":123,"./lib/internal/streams/pipeline.js":125,"dup":62}],129:[function(require,module,exports){ +var hash = exports; + +hash.utils = require('./hash/utils'); +hash.common = require('./hash/common'); +hash.sha = require('./hash/sha'); +hash.ripemd = require('./hash/ripemd'); +hash.hmac = require('./hash/hmac'); + +// Proxy hash functions to the main object +hash.sha1 = hash.sha.sha1; +hash.sha256 = hash.sha.sha256; +hash.sha224 = hash.sha.sha224; +hash.sha384 = hash.sha.sha384; +hash.sha512 = hash.sha.sha512; +hash.ripemd160 = hash.ripemd.ripemd160; + +},{"./hash/common":130,"./hash/hmac":131,"./hash/ripemd":132,"./hash/sha":133,"./hash/utils":140}],130:[function(require,module,exports){ +'use strict'; + +var utils = require('./utils'); +var assert = require('minimalistic-assert'); + +function BlockHash() { + this.pending = null; + this.pendingTotal = 0; + this.blockSize = this.constructor.blockSize; + this.outSize = this.constructor.outSize; + this.hmacStrength = this.constructor.hmacStrength; + this.padLength = this.constructor.padLength / 8; + this.endian = 'big'; + + this._delta8 = this.blockSize / 8; + this._delta32 = this.blockSize / 32; +} +exports.BlockHash = BlockHash; + +BlockHash.prototype.update = function update(msg, enc) { + // Convert message to array, pad it, and join into 32bit blocks + msg = utils.toArray(msg, enc); + if (!this.pending) + this.pending = msg; + else + this.pending = this.pending.concat(msg); + this.pendingTotal += msg.length; + + // Enough data, try updating + if (this.pending.length >= this._delta8) { + msg = this.pending; + + // Process pending data in blocks + var r = msg.length % this._delta8; + this.pending = msg.slice(msg.length - r, msg.length); + if (this.pending.length === 0) + this.pending = null; + + msg = utils.join32(msg, 0, msg.length - r, this.endian); + for (var i = 0; i < msg.length; i += this._delta32) + this._update(msg, i, i + this._delta32); + } + + return this; +}; + +BlockHash.prototype.digest = function digest(enc) { + this.update(this._pad()); + assert(this.pending === null); + + return this._digest(enc); +}; + +BlockHash.prototype._pad = function pad() { + var len = this.pendingTotal; + var bytes = this._delta8; + var k = bytes - ((len + this.padLength) % bytes); + var res = new Array(k + this.padLength); + res[0] = 0x80; + for (var i = 1; i < k; i++) + res[i] = 0; + + // Append length + len <<= 3; + if (this.endian === 'big') { + for (var t = 8; t < this.padLength; t++) + res[i++] = 0; + + res[i++] = 0; + res[i++] = 0; + res[i++] = 0; + res[i++] = 0; + res[i++] = (len >>> 24) & 0xff; + res[i++] = (len >>> 16) & 0xff; + res[i++] = (len >>> 8) & 0xff; + res[i++] = len & 0xff; + } else { + res[i++] = len & 0xff; + res[i++] = (len >>> 8) & 0xff; + res[i++] = (len >>> 16) & 0xff; + res[i++] = (len >>> 24) & 0xff; + res[i++] = 0; + res[i++] = 0; + res[i++] = 0; + res[i++] = 0; + + for (t = 8; t < this.padLength; t++) + res[i++] = 0; + } + + return res; +}; + +},{"./utils":140,"minimalistic-assert":151}],131:[function(require,module,exports){ +'use strict'; + +var utils = require('./utils'); +var assert = require('minimalistic-assert'); + +function Hmac(hash, key, enc) { + if (!(this instanceof Hmac)) + return new Hmac(hash, key, enc); + this.Hash = hash; + this.blockSize = hash.blockSize / 8; + this.outSize = hash.outSize / 8; + this.inner = null; + this.outer = null; + + this._init(utils.toArray(key, enc)); +} +module.exports = Hmac; + +Hmac.prototype._init = function init(key) { + // Shorten key, if needed + if (key.length > this.blockSize) + key = new this.Hash().update(key).digest(); + assert(key.length <= this.blockSize); + + // Add padding to key + for (var i = key.length; i < this.blockSize; i++) + key.push(0); + + for (i = 0; i < key.length; i++) + key[i] ^= 0x36; + this.inner = new this.Hash().update(key); + + // 0x36 ^ 0x5c = 0x6a + for (i = 0; i < key.length; i++) + key[i] ^= 0x6a; + this.outer = new this.Hash().update(key); +}; + +Hmac.prototype.update = function update(msg, enc) { + this.inner.update(msg, enc); + return this; +}; + +Hmac.prototype.digest = function digest(enc) { + this.outer.update(this.inner.digest()); + return this.outer.digest(enc); +}; + +},{"./utils":140,"minimalistic-assert":151}],132:[function(require,module,exports){ +'use strict'; + +var utils = require('./utils'); +var common = require('./common'); + +var rotl32 = utils.rotl32; +var sum32 = utils.sum32; +var sum32_3 = utils.sum32_3; +var sum32_4 = utils.sum32_4; +var BlockHash = common.BlockHash; + +function RIPEMD160() { + if (!(this instanceof RIPEMD160)) + return new RIPEMD160(); + + BlockHash.call(this); + + this.h = [ 0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476, 0xc3d2e1f0 ]; + this.endian = 'little'; +} +utils.inherits(RIPEMD160, BlockHash); +exports.ripemd160 = RIPEMD160; + +RIPEMD160.blockSize = 512; +RIPEMD160.outSize = 160; +RIPEMD160.hmacStrength = 192; +RIPEMD160.padLength = 64; + +RIPEMD160.prototype._update = function update(msg, start) { + var A = this.h[0]; + var B = this.h[1]; + var C = this.h[2]; + var D = this.h[3]; + var E = this.h[4]; + var Ah = A; + var Bh = B; + var Ch = C; + var Dh = D; + var Eh = E; + for (var j = 0; j < 80; j++) { + var T = sum32( + rotl32( + sum32_4(A, f(j, B, C, D), msg[r[j] + start], K(j)), + s[j]), + E); + A = E; + E = D; + D = rotl32(C, 10); + C = B; + B = T; + T = sum32( + rotl32( + sum32_4(Ah, f(79 - j, Bh, Ch, Dh), msg[rh[j] + start], Kh(j)), + sh[j]), + Eh); + Ah = Eh; + Eh = Dh; + Dh = rotl32(Ch, 10); + Ch = Bh; + Bh = T; + } + T = sum32_3(this.h[1], C, Dh); + this.h[1] = sum32_3(this.h[2], D, Eh); + this.h[2] = sum32_3(this.h[3], E, Ah); + this.h[3] = sum32_3(this.h[4], A, Bh); + this.h[4] = sum32_3(this.h[0], B, Ch); + this.h[0] = T; +}; + +RIPEMD160.prototype._digest = function digest(enc) { + if (enc === 'hex') + return utils.toHex32(this.h, 'little'); + else + return utils.split32(this.h, 'little'); +}; + +function f(j, x, y, z) { + if (j <= 15) + return x ^ y ^ z; + else if (j <= 31) + return (x & y) | ((~x) & z); + else if (j <= 47) + return (x | (~y)) ^ z; + else if (j <= 63) + return (x & z) | (y & (~z)); + else + return x ^ (y | (~z)); +} + +function K(j) { + if (j <= 15) + return 0x00000000; + else if (j <= 31) + return 0x5a827999; + else if (j <= 47) + return 0x6ed9eba1; + else if (j <= 63) + return 0x8f1bbcdc; + else + return 0xa953fd4e; +} + +function Kh(j) { + if (j <= 15) + return 0x50a28be6; + else if (j <= 31) + return 0x5c4dd124; + else if (j <= 47) + return 0x6d703ef3; + else if (j <= 63) + return 0x7a6d76e9; + else + return 0x00000000; +} + +var r = [ + 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 rh = [ + 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 s = [ + 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 sh = [ + 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 +]; + +},{"./common":130,"./utils":140}],133:[function(require,module,exports){ +'use strict'; + +exports.sha1 = require('./sha/1'); +exports.sha224 = require('./sha/224'); +exports.sha256 = require('./sha/256'); +exports.sha384 = require('./sha/384'); +exports.sha512 = require('./sha/512'); + +},{"./sha/1":134,"./sha/224":135,"./sha/256":136,"./sha/384":137,"./sha/512":138}],134:[function(require,module,exports){ +'use strict'; + +var utils = require('../utils'); +var common = require('../common'); +var shaCommon = require('./common'); + +var rotl32 = utils.rotl32; +var sum32 = utils.sum32; +var sum32_5 = utils.sum32_5; +var ft_1 = shaCommon.ft_1; +var BlockHash = common.BlockHash; + +var sha1_K = [ + 0x5A827999, 0x6ED9EBA1, + 0x8F1BBCDC, 0xCA62C1D6 +]; + +function SHA1() { + if (!(this instanceof SHA1)) + return new SHA1(); + + BlockHash.call(this); + this.h = [ + 0x67452301, 0xefcdab89, 0x98badcfe, + 0x10325476, 0xc3d2e1f0 ]; + this.W = new Array(80); +} + +utils.inherits(SHA1, BlockHash); +module.exports = SHA1; + +SHA1.blockSize = 512; +SHA1.outSize = 160; +SHA1.hmacStrength = 80; +SHA1.padLength = 64; + +SHA1.prototype._update = function _update(msg, start) { + var W = this.W; + + for (var i = 0; i < 16; i++) + W[i] = msg[start + i]; + + for(; i < W.length; i++) + W[i] = rotl32(W[i - 3] ^ W[i - 8] ^ W[i - 14] ^ W[i - 16], 1); + + var a = this.h[0]; + var b = this.h[1]; + var c = this.h[2]; + var d = this.h[3]; + var e = this.h[4]; + + for (i = 0; i < W.length; i++) { + var s = ~~(i / 20); + var t = sum32_5(rotl32(a, 5), ft_1(s, b, c, d), e, W[i], sha1_K[s]); + e = d; + d = c; + c = rotl32(b, 30); + b = a; + a = t; + } + + this.h[0] = sum32(this.h[0], a); + this.h[1] = sum32(this.h[1], b); + this.h[2] = sum32(this.h[2], c); + this.h[3] = sum32(this.h[3], d); + this.h[4] = sum32(this.h[4], e); +}; + +SHA1.prototype._digest = function digest(enc) { + if (enc === 'hex') + return utils.toHex32(this.h, 'big'); + else + return utils.split32(this.h, 'big'); +}; + +},{"../common":130,"../utils":140,"./common":139}],135:[function(require,module,exports){ +'use strict'; + +var utils = require('../utils'); +var SHA256 = require('./256'); + +function SHA224() { + if (!(this instanceof SHA224)) + return new SHA224(); + + SHA256.call(this); + this.h = [ + 0xc1059ed8, 0x367cd507, 0x3070dd17, 0xf70e5939, + 0xffc00b31, 0x68581511, 0x64f98fa7, 0xbefa4fa4 ]; +} +utils.inherits(SHA224, SHA256); +module.exports = SHA224; + +SHA224.blockSize = 512; +SHA224.outSize = 224; +SHA224.hmacStrength = 192; +SHA224.padLength = 64; + +SHA224.prototype._digest = function digest(enc) { + // Just truncate output + if (enc === 'hex') + return utils.toHex32(this.h.slice(0, 7), 'big'); + else + return utils.split32(this.h.slice(0, 7), 'big'); +}; + + +},{"../utils":140,"./256":136}],136:[function(require,module,exports){ +'use strict'; + +var utils = require('../utils'); +var common = require('../common'); +var shaCommon = require('./common'); +var assert = require('minimalistic-assert'); + +var sum32 = utils.sum32; +var sum32_4 = utils.sum32_4; +var sum32_5 = utils.sum32_5; +var ch32 = shaCommon.ch32; +var maj32 = shaCommon.maj32; +var s0_256 = shaCommon.s0_256; +var s1_256 = shaCommon.s1_256; +var g0_256 = shaCommon.g0_256; +var g1_256 = shaCommon.g1_256; + +var BlockHash = common.BlockHash; + +var sha256_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 +]; + +function SHA256() { + if (!(this instanceof SHA256)) + return new SHA256(); + + BlockHash.call(this); + this.h = [ + 0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, + 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19 + ]; + this.k = sha256_K; + this.W = new Array(64); +} +utils.inherits(SHA256, BlockHash); +module.exports = SHA256; + +SHA256.blockSize = 512; +SHA256.outSize = 256; +SHA256.hmacStrength = 192; +SHA256.padLength = 64; + +SHA256.prototype._update = function _update(msg, start) { + var W = this.W; + + for (var i = 0; i < 16; i++) + W[i] = msg[start + i]; + for (; i < W.length; i++) + W[i] = sum32_4(g1_256(W[i - 2]), W[i - 7], g0_256(W[i - 15]), W[i - 16]); + + var a = this.h[0]; + var b = this.h[1]; + var c = this.h[2]; + var d = this.h[3]; + var e = this.h[4]; + var f = this.h[5]; + var g = this.h[6]; + var h = this.h[7]; + + assert(this.k.length === W.length); + for (i = 0; i < W.length; i++) { + var T1 = sum32_5(h, s1_256(e), ch32(e, f, g), this.k[i], W[i]); + var T2 = sum32(s0_256(a), maj32(a, b, c)); + h = g; + g = f; + f = e; + e = sum32(d, T1); + d = c; + c = b; + b = a; + a = sum32(T1, T2); + } + + this.h[0] = sum32(this.h[0], a); + this.h[1] = sum32(this.h[1], b); + this.h[2] = sum32(this.h[2], c); + this.h[3] = sum32(this.h[3], d); + this.h[4] = sum32(this.h[4], e); + this.h[5] = sum32(this.h[5], f); + this.h[6] = sum32(this.h[6], g); + this.h[7] = sum32(this.h[7], h); +}; + +SHA256.prototype._digest = function digest(enc) { + if (enc === 'hex') + return utils.toHex32(this.h, 'big'); + else + return utils.split32(this.h, 'big'); +}; + +},{"../common":130,"../utils":140,"./common":139,"minimalistic-assert":151}],137:[function(require,module,exports){ +'use strict'; + +var utils = require('../utils'); + +var SHA512 = require('./512'); + +function SHA384() { + if (!(this instanceof SHA384)) + return new SHA384(); + + SHA512.call(this); + this.h = [ + 0xcbbb9d5d, 0xc1059ed8, + 0x629a292a, 0x367cd507, + 0x9159015a, 0x3070dd17, + 0x152fecd8, 0xf70e5939, + 0x67332667, 0xffc00b31, + 0x8eb44a87, 0x68581511, + 0xdb0c2e0d, 0x64f98fa7, + 0x47b5481d, 0xbefa4fa4 ]; +} +utils.inherits(SHA384, SHA512); +module.exports = SHA384; + +SHA384.blockSize = 1024; +SHA384.outSize = 384; +SHA384.hmacStrength = 192; +SHA384.padLength = 128; + +SHA384.prototype._digest = function digest(enc) { + if (enc === 'hex') + return utils.toHex32(this.h.slice(0, 12), 'big'); + else + return utils.split32(this.h.slice(0, 12), 'big'); +}; + +},{"../utils":140,"./512":138}],138:[function(require,module,exports){ +'use strict'; + +var utils = require('../utils'); +var common = require('../common'); +var assert = require('minimalistic-assert'); + +var rotr64_hi = utils.rotr64_hi; +var rotr64_lo = utils.rotr64_lo; +var shr64_hi = utils.shr64_hi; +var shr64_lo = utils.shr64_lo; +var sum64 = utils.sum64; +var sum64_hi = utils.sum64_hi; +var sum64_lo = utils.sum64_lo; +var sum64_4_hi = utils.sum64_4_hi; +var sum64_4_lo = utils.sum64_4_lo; +var sum64_5_hi = utils.sum64_5_hi; +var sum64_5_lo = utils.sum64_5_lo; + +var BlockHash = common.BlockHash; + +var sha512_K = [ + 0x428a2f98, 0xd728ae22, 0x71374491, 0x23ef65cd, + 0xb5c0fbcf, 0xec4d3b2f, 0xe9b5dba5, 0x8189dbbc, + 0x3956c25b, 0xf348b538, 0x59f111f1, 0xb605d019, + 0x923f82a4, 0xaf194f9b, 0xab1c5ed5, 0xda6d8118, + 0xd807aa98, 0xa3030242, 0x12835b01, 0x45706fbe, + 0x243185be, 0x4ee4b28c, 0x550c7dc3, 0xd5ffb4e2, + 0x72be5d74, 0xf27b896f, 0x80deb1fe, 0x3b1696b1, + 0x9bdc06a7, 0x25c71235, 0xc19bf174, 0xcf692694, + 0xe49b69c1, 0x9ef14ad2, 0xefbe4786, 0x384f25e3, + 0x0fc19dc6, 0x8b8cd5b5, 0x240ca1cc, 0x77ac9c65, + 0x2de92c6f, 0x592b0275, 0x4a7484aa, 0x6ea6e483, + 0x5cb0a9dc, 0xbd41fbd4, 0x76f988da, 0x831153b5, + 0x983e5152, 0xee66dfab, 0xa831c66d, 0x2db43210, + 0xb00327c8, 0x98fb213f, 0xbf597fc7, 0xbeef0ee4, + 0xc6e00bf3, 0x3da88fc2, 0xd5a79147, 0x930aa725, + 0x06ca6351, 0xe003826f, 0x14292967, 0x0a0e6e70, + 0x27b70a85, 0x46d22ffc, 0x2e1b2138, 0x5c26c926, + 0x4d2c6dfc, 0x5ac42aed, 0x53380d13, 0x9d95b3df, + 0x650a7354, 0x8baf63de, 0x766a0abb, 0x3c77b2a8, + 0x81c2c92e, 0x47edaee6, 0x92722c85, 0x1482353b, + 0xa2bfe8a1, 0x4cf10364, 0xa81a664b, 0xbc423001, + 0xc24b8b70, 0xd0f89791, 0xc76c51a3, 0x0654be30, + 0xd192e819, 0xd6ef5218, 0xd6990624, 0x5565a910, + 0xf40e3585, 0x5771202a, 0x106aa070, 0x32bbd1b8, + 0x19a4c116, 0xb8d2d0c8, 0x1e376c08, 0x5141ab53, + 0x2748774c, 0xdf8eeb99, 0x34b0bcb5, 0xe19b48a8, + 0x391c0cb3, 0xc5c95a63, 0x4ed8aa4a, 0xe3418acb, + 0x5b9cca4f, 0x7763e373, 0x682e6ff3, 0xd6b2b8a3, + 0x748f82ee, 0x5defb2fc, 0x78a5636f, 0x43172f60, + 0x84c87814, 0xa1f0ab72, 0x8cc70208, 0x1a6439ec, + 0x90befffa, 0x23631e28, 0xa4506ceb, 0xde82bde9, + 0xbef9a3f7, 0xb2c67915, 0xc67178f2, 0xe372532b, + 0xca273ece, 0xea26619c, 0xd186b8c7, 0x21c0c207, + 0xeada7dd6, 0xcde0eb1e, 0xf57d4f7f, 0xee6ed178, + 0x06f067aa, 0x72176fba, 0x0a637dc5, 0xa2c898a6, + 0x113f9804, 0xbef90dae, 0x1b710b35, 0x131c471b, + 0x28db77f5, 0x23047d84, 0x32caab7b, 0x40c72493, + 0x3c9ebe0a, 0x15c9bebc, 0x431d67c4, 0x9c100d4c, + 0x4cc5d4be, 0xcb3e42b6, 0x597f299c, 0xfc657e2a, + 0x5fcb6fab, 0x3ad6faec, 0x6c44198c, 0x4a475817 +]; + +function SHA512() { + if (!(this instanceof SHA512)) + return new SHA512(); + + BlockHash.call(this); + this.h = [ + 0x6a09e667, 0xf3bcc908, + 0xbb67ae85, 0x84caa73b, + 0x3c6ef372, 0xfe94f82b, + 0xa54ff53a, 0x5f1d36f1, + 0x510e527f, 0xade682d1, + 0x9b05688c, 0x2b3e6c1f, + 0x1f83d9ab, 0xfb41bd6b, + 0x5be0cd19, 0x137e2179 ]; + this.k = sha512_K; + this.W = new Array(160); +} +utils.inherits(SHA512, BlockHash); +module.exports = SHA512; + +SHA512.blockSize = 1024; +SHA512.outSize = 512; +SHA512.hmacStrength = 192; +SHA512.padLength = 128; + +SHA512.prototype._prepareBlock = function _prepareBlock(msg, start) { + var W = this.W; + + // 32 x 32bit words + for (var i = 0; i < 32; i++) + W[i] = msg[start + i]; + for (; i < W.length; i += 2) { + var c0_hi = g1_512_hi(W[i - 4], W[i - 3]); // i - 2 + var c0_lo = g1_512_lo(W[i - 4], W[i - 3]); + var c1_hi = W[i - 14]; // i - 7 + var c1_lo = W[i - 13]; + var c2_hi = g0_512_hi(W[i - 30], W[i - 29]); // i - 15 + var c2_lo = g0_512_lo(W[i - 30], W[i - 29]); + var c3_hi = W[i - 32]; // i - 16 + var c3_lo = W[i - 31]; + + W[i] = sum64_4_hi( + c0_hi, c0_lo, + c1_hi, c1_lo, + c2_hi, c2_lo, + c3_hi, c3_lo); + W[i + 1] = sum64_4_lo( + c0_hi, c0_lo, + c1_hi, c1_lo, + c2_hi, c2_lo, + c3_hi, c3_lo); + } +}; + +SHA512.prototype._update = function _update(msg, start) { + this._prepareBlock(msg, start); + + var W = this.W; + + var ah = this.h[0]; + var al = this.h[1]; + var bh = this.h[2]; + var bl = this.h[3]; + var ch = this.h[4]; + var cl = this.h[5]; + var dh = this.h[6]; + var dl = this.h[7]; + var eh = this.h[8]; + var el = this.h[9]; + var fh = this.h[10]; + var fl = this.h[11]; + var gh = this.h[12]; + var gl = this.h[13]; + var hh = this.h[14]; + var hl = this.h[15]; + + assert(this.k.length === W.length); + for (var i = 0; i < W.length; i += 2) { + var c0_hi = hh; + var c0_lo = hl; + var c1_hi = s1_512_hi(eh, el); + var c1_lo = s1_512_lo(eh, el); + var c2_hi = ch64_hi(eh, el, fh, fl, gh, gl); + var c2_lo = ch64_lo(eh, el, fh, fl, gh, gl); + var c3_hi = this.k[i]; + var c3_lo = this.k[i + 1]; + var c4_hi = W[i]; + var c4_lo = W[i + 1]; + + var T1_hi = sum64_5_hi( + c0_hi, c0_lo, + c1_hi, c1_lo, + c2_hi, c2_lo, + c3_hi, c3_lo, + c4_hi, c4_lo); + var T1_lo = sum64_5_lo( + c0_hi, c0_lo, + c1_hi, c1_lo, + c2_hi, c2_lo, + c3_hi, c3_lo, + c4_hi, c4_lo); + + c0_hi = s0_512_hi(ah, al); + c0_lo = s0_512_lo(ah, al); + c1_hi = maj64_hi(ah, al, bh, bl, ch, cl); + c1_lo = maj64_lo(ah, al, bh, bl, ch, cl); + + var T2_hi = sum64_hi(c0_hi, c0_lo, c1_hi, c1_lo); + var T2_lo = sum64_lo(c0_hi, c0_lo, c1_hi, c1_lo); + + hh = gh; + hl = gl; + + gh = fh; + gl = fl; + + fh = eh; + fl = el; + + eh = sum64_hi(dh, dl, T1_hi, T1_lo); + el = sum64_lo(dl, dl, T1_hi, T1_lo); + + dh = ch; + dl = cl; + + ch = bh; + cl = bl; + + bh = ah; + bl = al; + + ah = sum64_hi(T1_hi, T1_lo, T2_hi, T2_lo); + al = sum64_lo(T1_hi, T1_lo, T2_hi, T2_lo); + } + + sum64(this.h, 0, ah, al); + sum64(this.h, 2, bh, bl); + sum64(this.h, 4, ch, cl); + sum64(this.h, 6, dh, dl); + sum64(this.h, 8, eh, el); + sum64(this.h, 10, fh, fl); + sum64(this.h, 12, gh, gl); + sum64(this.h, 14, hh, hl); +}; + +SHA512.prototype._digest = function digest(enc) { + if (enc === 'hex') + return utils.toHex32(this.h, 'big'); + else + return utils.split32(this.h, 'big'); +}; + +function ch64_hi(xh, xl, yh, yl, zh) { + var r = (xh & yh) ^ ((~xh) & zh); + if (r < 0) + r += 0x100000000; + return r; +} + +function ch64_lo(xh, xl, yh, yl, zh, zl) { + var r = (xl & yl) ^ ((~xl) & zl); + if (r < 0) + r += 0x100000000; + return r; +} + +function maj64_hi(xh, xl, yh, yl, zh) { + var r = (xh & yh) ^ (xh & zh) ^ (yh & zh); + if (r < 0) + r += 0x100000000; + return r; +} + +function maj64_lo(xh, xl, yh, yl, zh, zl) { + var r = (xl & yl) ^ (xl & zl) ^ (yl & zl); + if (r < 0) + r += 0x100000000; + return r; +} + +function s0_512_hi(xh, xl) { + var c0_hi = rotr64_hi(xh, xl, 28); + var c1_hi = rotr64_hi(xl, xh, 2); // 34 + var c2_hi = rotr64_hi(xl, xh, 7); // 39 + + var r = c0_hi ^ c1_hi ^ c2_hi; + if (r < 0) + r += 0x100000000; + return r; +} + +function s0_512_lo(xh, xl) { + var c0_lo = rotr64_lo(xh, xl, 28); + var c1_lo = rotr64_lo(xl, xh, 2); // 34 + var c2_lo = rotr64_lo(xl, xh, 7); // 39 + + var r = c0_lo ^ c1_lo ^ c2_lo; + if (r < 0) + r += 0x100000000; + return r; +} + +function s1_512_hi(xh, xl) { + var c0_hi = rotr64_hi(xh, xl, 14); + var c1_hi = rotr64_hi(xh, xl, 18); + var c2_hi = rotr64_hi(xl, xh, 9); // 41 + + var r = c0_hi ^ c1_hi ^ c2_hi; + if (r < 0) + r += 0x100000000; + return r; +} + +function s1_512_lo(xh, xl) { + var c0_lo = rotr64_lo(xh, xl, 14); + var c1_lo = rotr64_lo(xh, xl, 18); + var c2_lo = rotr64_lo(xl, xh, 9); // 41 + + var r = c0_lo ^ c1_lo ^ c2_lo; + if (r < 0) + r += 0x100000000; + return r; +} + +function g0_512_hi(xh, xl) { + var c0_hi = rotr64_hi(xh, xl, 1); + var c1_hi = rotr64_hi(xh, xl, 8); + var c2_hi = shr64_hi(xh, xl, 7); + + var r = c0_hi ^ c1_hi ^ c2_hi; + if (r < 0) + r += 0x100000000; + return r; +} + +function g0_512_lo(xh, xl) { + var c0_lo = rotr64_lo(xh, xl, 1); + var c1_lo = rotr64_lo(xh, xl, 8); + var c2_lo = shr64_lo(xh, xl, 7); + + var r = c0_lo ^ c1_lo ^ c2_lo; + if (r < 0) + r += 0x100000000; + return r; +} + +function g1_512_hi(xh, xl) { + var c0_hi = rotr64_hi(xh, xl, 19); + var c1_hi = rotr64_hi(xl, xh, 29); // 61 + var c2_hi = shr64_hi(xh, xl, 6); + + var r = c0_hi ^ c1_hi ^ c2_hi; + if (r < 0) + r += 0x100000000; + return r; +} + +function g1_512_lo(xh, xl) { + var c0_lo = rotr64_lo(xh, xl, 19); + var c1_lo = rotr64_lo(xl, xh, 29); // 61 + var c2_lo = shr64_lo(xh, xl, 6); + + var r = c0_lo ^ c1_lo ^ c2_lo; + if (r < 0) + r += 0x100000000; + return r; +} + +},{"../common":130,"../utils":140,"minimalistic-assert":151}],139:[function(require,module,exports){ +'use strict'; + +var utils = require('../utils'); +var rotr32 = utils.rotr32; + +function ft_1(s, x, y, z) { + if (s === 0) + return ch32(x, y, z); + if (s === 1 || s === 3) + return p32(x, y, z); + if (s === 2) + return maj32(x, y, z); +} +exports.ft_1 = ft_1; + +function ch32(x, y, z) { + return (x & y) ^ ((~x) & z); +} +exports.ch32 = ch32; + +function maj32(x, y, z) { + return (x & y) ^ (x & z) ^ (y & z); +} +exports.maj32 = maj32; + +function p32(x, y, z) { + return x ^ y ^ z; +} +exports.p32 = p32; + +function s0_256(x) { + return rotr32(x, 2) ^ rotr32(x, 13) ^ rotr32(x, 22); +} +exports.s0_256 = s0_256; + +function s1_256(x) { + return rotr32(x, 6) ^ rotr32(x, 11) ^ rotr32(x, 25); +} +exports.s1_256 = s1_256; + +function g0_256(x) { + return rotr32(x, 7) ^ rotr32(x, 18) ^ (x >>> 3); +} +exports.g0_256 = g0_256; + +function g1_256(x) { + return rotr32(x, 17) ^ rotr32(x, 19) ^ (x >>> 10); +} +exports.g1_256 = g1_256; + +},{"../utils":140}],140:[function(require,module,exports){ +'use strict'; + +var assert = require('minimalistic-assert'); +var inherits = require('inherits'); + +exports.inherits = inherits; + +function isSurrogatePair(msg, i) { + if ((msg.charCodeAt(i) & 0xFC00) !== 0xD800) { + return false; + } + if (i < 0 || i + 1 >= msg.length) { + return false; + } + return (msg.charCodeAt(i + 1) & 0xFC00) === 0xDC00; +} + +function toArray(msg, enc) { + if (Array.isArray(msg)) + return msg.slice(); + if (!msg) + return []; + var res = []; + if (typeof msg === 'string') { + if (!enc) { + // Inspired by stringToUtf8ByteArray() in closure-library by Google + // https://github.com/google/closure-library/blob/8598d87242af59aac233270742c8984e2b2bdbe0/closure/goog/crypt/crypt.js#L117-L143 + // Apache License 2.0 + // https://github.com/google/closure-library/blob/master/LICENSE + var p = 0; + for (var i = 0; i < msg.length; i++) { + var c = msg.charCodeAt(i); + if (c < 128) { + res[p++] = c; + } else if (c < 2048) { + res[p++] = (c >> 6) | 192; + res[p++] = (c & 63) | 128; + } else if (isSurrogatePair(msg, i)) { + c = 0x10000 + ((c & 0x03FF) << 10) + (msg.charCodeAt(++i) & 0x03FF); + res[p++] = (c >> 18) | 240; + res[p++] = ((c >> 12) & 63) | 128; + res[p++] = ((c >> 6) & 63) | 128; + res[p++] = (c & 63) | 128; + } else { + res[p++] = (c >> 12) | 224; + res[p++] = ((c >> 6) & 63) | 128; + res[p++] = (c & 63) | 128; + } + } + } else if (enc === 'hex') { + msg = msg.replace(/[^a-z0-9]+/ig, ''); + if (msg.length % 2 !== 0) + msg = '0' + msg; + for (i = 0; i < msg.length; i += 2) + res.push(parseInt(msg[i] + msg[i + 1], 16)); + } + } else { + for (i = 0; i < msg.length; i++) + res[i] = msg[i] | 0; + } + return res; +} +exports.toArray = toArray; + +function toHex(msg) { + var res = ''; + for (var i = 0; i < msg.length; i++) + res += zero2(msg[i].toString(16)); + return res; +} +exports.toHex = toHex; + +function htonl(w) { + var res = (w >>> 24) | + ((w >>> 8) & 0xff00) | + ((w << 8) & 0xff0000) | + ((w & 0xff) << 24); + return res >>> 0; +} +exports.htonl = htonl; + +function toHex32(msg, endian) { + var res = ''; + for (var i = 0; i < msg.length; i++) { + var w = msg[i]; + if (endian === 'little') + w = htonl(w); + res += zero8(w.toString(16)); + } + return res; +} +exports.toHex32 = toHex32; + +function zero2(word) { + if (word.length === 1) + return '0' + word; + else + return word; +} +exports.zero2 = zero2; + +function zero8(word) { + if (word.length === 7) + return '0' + word; + else if (word.length === 6) + return '00' + word; + else if (word.length === 5) + return '000' + word; + else if (word.length === 4) + return '0000' + word; + else if (word.length === 3) + return '00000' + word; + else if (word.length === 2) + return '000000' + word; + else if (word.length === 1) + return '0000000' + word; + else + return word; +} +exports.zero8 = zero8; + +function join32(msg, start, end, endian) { + var len = end - start; + assert(len % 4 === 0); + var res = new Array(len / 4); + for (var i = 0, k = start; i < res.length; i++, k += 4) { + var w; + if (endian === 'big') + w = (msg[k] << 24) | (msg[k + 1] << 16) | (msg[k + 2] << 8) | msg[k + 3]; + else + w = (msg[k + 3] << 24) | (msg[k + 2] << 16) | (msg[k + 1] << 8) | msg[k]; + res[i] = w >>> 0; + } + return res; +} +exports.join32 = join32; + +function split32(msg, endian) { + var res = new Array(msg.length * 4); + for (var i = 0, k = 0; i < msg.length; i++, k += 4) { + var m = msg[i]; + if (endian === 'big') { + res[k] = m >>> 24; + res[k + 1] = (m >>> 16) & 0xff; + res[k + 2] = (m >>> 8) & 0xff; + res[k + 3] = m & 0xff; + } else { + res[k + 3] = m >>> 24; + res[k + 2] = (m >>> 16) & 0xff; + res[k + 1] = (m >>> 8) & 0xff; + res[k] = m & 0xff; + } + } + return res; +} +exports.split32 = split32; + +function rotr32(w, b) { + return (w >>> b) | (w << (32 - b)); +} +exports.rotr32 = rotr32; + +function rotl32(w, b) { + return (w << b) | (w >>> (32 - b)); +} +exports.rotl32 = rotl32; + +function sum32(a, b) { + return (a + b) >>> 0; +} +exports.sum32 = sum32; + +function sum32_3(a, b, c) { + return (a + b + c) >>> 0; +} +exports.sum32_3 = sum32_3; + +function sum32_4(a, b, c, d) { + return (a + b + c + d) >>> 0; +} +exports.sum32_4 = sum32_4; + +function sum32_5(a, b, c, d, e) { + return (a + b + c + d + e) >>> 0; +} +exports.sum32_5 = sum32_5; + +function sum64(buf, pos, ah, al) { + var bh = buf[pos]; + var bl = buf[pos + 1]; + + var lo = (al + bl) >>> 0; + var hi = (lo < al ? 1 : 0) + ah + bh; + buf[pos] = hi >>> 0; + buf[pos + 1] = lo; +} +exports.sum64 = sum64; + +function sum64_hi(ah, al, bh, bl) { + var lo = (al + bl) >>> 0; + var hi = (lo < al ? 1 : 0) + ah + bh; + return hi >>> 0; +} +exports.sum64_hi = sum64_hi; + +function sum64_lo(ah, al, bh, bl) { + var lo = al + bl; + return lo >>> 0; +} +exports.sum64_lo = sum64_lo; + +function sum64_4_hi(ah, al, bh, bl, ch, cl, dh, dl) { + var carry = 0; + var lo = al; + lo = (lo + bl) >>> 0; + carry += lo < al ? 1 : 0; + lo = (lo + cl) >>> 0; + carry += lo < cl ? 1 : 0; + lo = (lo + dl) >>> 0; + carry += lo < dl ? 1 : 0; + + var hi = ah + bh + ch + dh + carry; + return hi >>> 0; +} +exports.sum64_4_hi = sum64_4_hi; + +function sum64_4_lo(ah, al, bh, bl, ch, cl, dh, dl) { + var lo = al + bl + cl + dl; + return lo >>> 0; +} +exports.sum64_4_lo = sum64_4_lo; + +function sum64_5_hi(ah, al, bh, bl, ch, cl, dh, dl, eh, el) { + var carry = 0; + var lo = al; + lo = (lo + bl) >>> 0; + carry += lo < al ? 1 : 0; + lo = (lo + cl) >>> 0; + carry += lo < cl ? 1 : 0; + lo = (lo + dl) >>> 0; + carry += lo < dl ? 1 : 0; + lo = (lo + el) >>> 0; + carry += lo < el ? 1 : 0; + + var hi = ah + bh + ch + dh + eh + carry; + return hi >>> 0; +} +exports.sum64_5_hi = sum64_5_hi; + +function sum64_5_lo(ah, al, bh, bl, ch, cl, dh, dl, eh, el) { + var lo = al + bl + cl + dl + el; + + return lo >>> 0; +} +exports.sum64_5_lo = sum64_5_lo; + +function rotr64_hi(ah, al, num) { + var r = (al << (32 - num)) | (ah >>> num); + return r >>> 0; +} +exports.rotr64_hi = rotr64_hi; + +function rotr64_lo(ah, al, num) { + var r = (ah << (32 - num)) | (al >>> num); + return r >>> 0; +} +exports.rotr64_lo = rotr64_lo; + +function shr64_hi(ah, al, num) { + return ah >>> num; +} +exports.shr64_hi = shr64_hi; + +function shr64_lo(ah, al, num) { + var r = (ah << (32 - num)) | (al >>> num); + return r >>> 0; +} +exports.shr64_lo = shr64_lo; + +},{"inherits":143,"minimalistic-assert":151}],141:[function(require,module,exports){ +'use strict'; + +var hash = require('hash.js'); +var utils = require('minimalistic-crypto-utils'); +var assert = require('minimalistic-assert'); + +function HmacDRBG(options) { + if (!(this instanceof HmacDRBG)) + return new HmacDRBG(options); + this.hash = options.hash; + this.predResist = !!options.predResist; + + this.outLen = this.hash.outSize; + this.minEntropy = options.minEntropy || this.hash.hmacStrength; + + this._reseed = null; + this.reseedInterval = null; + this.K = null; + this.V = null; + + var entropy = utils.toArray(options.entropy, options.entropyEnc || 'hex'); + var nonce = utils.toArray(options.nonce, options.nonceEnc || 'hex'); + var pers = utils.toArray(options.pers, options.persEnc || 'hex'); + assert(entropy.length >= (this.minEntropy / 8), + 'Not enough entropy. Minimum is: ' + this.minEntropy + ' bits'); + this._init(entropy, nonce, pers); +} +module.exports = HmacDRBG; + +HmacDRBG.prototype._init = function init(entropy, nonce, pers) { + var seed = entropy.concat(nonce).concat(pers); + + this.K = new Array(this.outLen / 8); + this.V = new Array(this.outLen / 8); + for (var i = 0; i < this.V.length; i++) { + this.K[i] = 0x00; + this.V[i] = 0x01; + } + + this._update(seed); + this._reseed = 1; + this.reseedInterval = 0x1000000000000; // 2^48 +}; + +HmacDRBG.prototype._hmac = function hmac() { + return new hash.hmac(this.hash, this.K); +}; + +HmacDRBG.prototype._update = function update(seed) { + var kmac = this._hmac() + .update(this.V) + .update([ 0x00 ]); + if (seed) + kmac = kmac.update(seed); + this.K = kmac.digest(); + this.V = this._hmac().update(this.V).digest(); + if (!seed) + return; + + this.K = this._hmac() + .update(this.V) + .update([ 0x01 ]) + .update(seed) + .digest(); + this.V = this._hmac().update(this.V).digest(); +}; + +HmacDRBG.prototype.reseed = function reseed(entropy, entropyEnc, add, addEnc) { + // Optional entropy enc + if (typeof entropyEnc !== 'string') { + addEnc = add; + add = entropyEnc; + entropyEnc = null; + } + + entropy = utils.toArray(entropy, entropyEnc); + add = utils.toArray(add, addEnc); + + assert(entropy.length >= (this.minEntropy / 8), + 'Not enough entropy. Minimum is: ' + this.minEntropy + ' bits'); + + this._update(entropy.concat(add || [])); + this._reseed = 1; +}; + +HmacDRBG.prototype.generate = function generate(len, enc, add, addEnc) { + if (this._reseed > this.reseedInterval) + throw new Error('Reseed is required'); + + // Optional encoding + if (typeof enc !== 'string') { + addEnc = add; + add = enc; + enc = null; + } + + // Optional additional data + if (add) { + add = utils.toArray(add, addEnc || 'hex'); + this._update(add); + } + + var temp = []; + while (temp.length < len) { + this.V = this._hmac().update(this.V).digest(); + temp = temp.concat(this.V); + } + + var res = temp.slice(0, len); + this._update(add); + this._reseed++; + return utils.encode(res, enc); +}; + +},{"hash.js":129,"minimalistic-assert":151,"minimalistic-crypto-utils":152}],142:[function(require,module,exports){ +/*! ieee754. BSD-3-Clause License. Feross Aboukhadijeh */ +exports.read = function (buffer, offset, isLE, mLen, nBytes) { + var e, m + var eLen = (nBytes * 8) - mLen - 1 + var eMax = (1 << eLen) - 1 + var eBias = eMax >> 1 + var nBits = -7 + var i = isLE ? (nBytes - 1) : 0 + var d = isLE ? -1 : 1 + var s = buffer[offset + i] + + i += d + + e = s & ((1 << (-nBits)) - 1) + s >>= (-nBits) + nBits += eLen + for (; nBits > 0; e = (e * 256) + buffer[offset + i], i += d, nBits -= 8) {} + + m = e & ((1 << (-nBits)) - 1) + e >>= (-nBits) + nBits += mLen + for (; nBits > 0; m = (m * 256) + buffer[offset + i], i += d, nBits -= 8) {} + + if (e === 0) { + e = 1 - eBias + } else if (e === eMax) { + return m ? NaN : ((s ? -1 : 1) * Infinity) + } else { + m = m + Math.pow(2, mLen) + e = e - eBias + } + return (s ? -1 : 1) * m * Math.pow(2, e - mLen) +} + +exports.write = function (buffer, value, offset, isLE, mLen, nBytes) { + var e, m, c + var eLen = (nBytes * 8) - mLen - 1 + var eMax = (1 << eLen) - 1 + var eBias = eMax >> 1 + var rt = (mLen === 23 ? Math.pow(2, -24) - Math.pow(2, -77) : 0) + var i = isLE ? 0 : (nBytes - 1) + var d = isLE ? 1 : -1 + var s = value < 0 || (value === 0 && 1 / value < 0) ? 1 : 0 + + value = Math.abs(value) + + if (isNaN(value) || value === Infinity) { + m = isNaN(value) ? 1 : 0 + e = eMax + } else { + e = Math.floor(Math.log(value) / Math.LN2) + if (value * (c = Math.pow(2, -e)) < 1) { + e-- + c *= 2 + } + if (e + eBias >= 1) { + value += rt / c + } else { + value += rt * Math.pow(2, 1 - eBias) + } + if (value * c >= 2) { + e++ + c /= 2 + } + + if (e + eBias >= eMax) { + m = 0 + e = eMax + } else if (e + eBias >= 1) { + m = ((value * c) - 1) * Math.pow(2, mLen) + e = e + eBias + } else { + m = value * Math.pow(2, eBias - 1) * Math.pow(2, mLen) + e = 0 + } + } + + for (; mLen >= 8; buffer[offset + i] = m & 0xff, i += d, m /= 256, mLen -= 8) {} + + e = (e << mLen) | m + eLen += mLen + for (; eLen > 0; buffer[offset + i] = e & 0xff, i += d, e /= 256, eLen -= 8) {} + + buffer[offset + i - d] |= s * 128 +} + +},{}],143:[function(require,module,exports){ +if (typeof Object.create === 'function') { + // implementation from standard node.js 'util' module + module.exports = function inherits(ctor, superCtor) { + if (superCtor) { + ctor.super_ = superCtor + ctor.prototype = Object.create(superCtor.prototype, { + constructor: { + value: ctor, + enumerable: false, + writable: true, + configurable: true + } + }) + } + }; +} else { + // old school shim for old browsers + module.exports = function inherits(ctor, superCtor) { + if (superCtor) { + ctor.super_ = superCtor + var TempCtor = function () {} + TempCtor.prototype = superCtor.prototype + ctor.prototype = new TempCtor() + ctor.prototype.constructor = ctor + } + } +} + +},{}],144:[function(require,module,exports){ +'use strict'; + +var hasToStringTag = typeof Symbol === 'function' && typeof Symbol.toStringTag === 'symbol'; +var callBound = require('call-bind/callBound'); + +var $toString = callBound('Object.prototype.toString'); + +var isStandardArguments = function isArguments(value) { + if (hasToStringTag && value && typeof value === 'object' && Symbol.toStringTag in value) { + return false; + } + return $toString(value) === '[object Arguments]'; +}; + +var isLegacyArguments = function isArguments(value) { + if (isStandardArguments(value)) { + return true; + } + return value !== null && + typeof value === 'object' && + typeof value.length === 'number' && + value.length >= 0 && + $toString(value) !== '[object Array]' && + $toString(value.callee) === '[object Function]'; +}; + +var supportsStandardArguments = (function () { + return isStandardArguments(arguments); +}()); + +isStandardArguments.isLegacyArguments = isLegacyArguments; // for tests + +module.exports = supportsStandardArguments ? isStandardArguments : isLegacyArguments; + +},{"call-bind/callBound":65}],145:[function(require,module,exports){ +/*! + * Determine if an object is a Buffer + * + * @author Feross Aboukhadijeh + * @license MIT + */ + +// The _isBuffer check is for Safari 5-7 support, because it's missing +// Object.prototype.constructor. Remove this eventually +module.exports = function (obj) { + return obj != null && (isBuffer(obj) || isSlowBuffer(obj) || !!obj._isBuffer) +} + +function isBuffer (obj) { + return !!obj.constructor && typeof obj.constructor.isBuffer === 'function' && obj.constructor.isBuffer(obj) +} + +// For Node v0.10 support. Remove this eventually. +function isSlowBuffer (obj) { + return typeof obj.readFloatLE === 'function' && typeof obj.slice === 'function' && isBuffer(obj.slice(0, 0)) +} + +},{}],146:[function(require,module,exports){ +'use strict'; + +var toStr = Object.prototype.toString; +var fnToStr = Function.prototype.toString; +var isFnRegex = /^\s*(?:function)?\*/; +var hasToStringTag = typeof Symbol === 'function' && typeof Symbol.toStringTag === 'symbol'; +var getProto = Object.getPrototypeOf; +var getGeneratorFunc = function () { // eslint-disable-line consistent-return + if (!hasToStringTag) { + return false; + } + try { + return Function('return function*() {}')(); + } catch (e) { + } +}; +var GeneratorFunction; + +module.exports = function isGeneratorFunction(fn) { + if (typeof fn !== 'function') { + return false; + } + if (isFnRegex.test(fnToStr.call(fn))) { + return true; + } + if (!hasToStringTag) { + var str = toStr.call(fn); + return str === '[object GeneratorFunction]'; + } + if (!getProto) { + return false; + } + if (typeof GeneratorFunction === 'undefined') { + var generatorFunc = getGeneratorFunc(); + GeneratorFunction = generatorFunc ? getProto(generatorFunc) : false; + } + return getProto(fn) === GeneratorFunction; +}; + +},{}],147:[function(require,module,exports){ +(function (global){(function (){ +'use strict'; + +var forEach = require('foreach'); +var availableTypedArrays = require('available-typed-arrays'); +var callBound = require('call-bind/callBound'); + +var $toString = callBound('Object.prototype.toString'); +var hasSymbols = require('has-symbols')(); +var hasToStringTag = hasSymbols && typeof Symbol.toStringTag === 'symbol'; + +var typedArrays = availableTypedArrays(); + +var $indexOf = callBound('Array.prototype.indexOf', true) || function indexOf(array, value) { + for (var i = 0; i < array.length; i += 1) { + if (array[i] === value) { + return i; + } + } + return -1; +}; +var $slice = callBound('String.prototype.slice'); +var toStrTags = {}; +var gOPD = require('es-abstract/helpers/getOwnPropertyDescriptor'); +var getPrototypeOf = Object.getPrototypeOf; // require('getprototypeof'); +if (hasToStringTag && gOPD && getPrototypeOf) { + forEach(typedArrays, function (typedArray) { + var arr = new global[typedArray](); + if (!(Symbol.toStringTag in arr)) { + throw new EvalError('this engine has support for Symbol.toStringTag, but ' + typedArray + ' does not have the property! Please report this.'); + } + var proto = getPrototypeOf(arr); + var descriptor = gOPD(proto, Symbol.toStringTag); + if (!descriptor) { + var superProto = getPrototypeOf(proto); + descriptor = gOPD(superProto, Symbol.toStringTag); + } + toStrTags[typedArray] = descriptor.get; + }); +} + +var tryTypedArrays = function tryAllTypedArrays(value) { + var anyTrue = false; + forEach(toStrTags, function (getter, typedArray) { + if (!anyTrue) { + try { + anyTrue = getter.call(value) === typedArray; + } catch (e) { /**/ } + } + }); + return anyTrue; +}; + +module.exports = function isTypedArray(value) { + if (!value || typeof value !== 'object') { return false; } + if (!hasToStringTag) { + var tag = $slice($toString(value), 8, -1); + return $indexOf(typedArrays, tag) > -1; + } + if (!gOPD) { return false; } + return tryTypedArrays(value); +}; + +}).call(this)}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) +},{"available-typed-arrays":16,"call-bind/callBound":65,"es-abstract/helpers/getOwnPropertyDescriptor":103,"foreach":106,"has-symbols":110}],148:[function(require,module,exports){ +'use strict' +var inherits = require('inherits') +var HashBase = require('hash-base') +var Buffer = require('safe-buffer').Buffer + +var ARRAY16 = new Array(16) + +function MD5 () { + HashBase.call(this, 64) + + // state + this._a = 0x67452301 + this._b = 0xefcdab89 + this._c = 0x98badcfe + this._d = 0x10325476 +} + +inherits(MD5, HashBase) + +MD5.prototype._update = function () { + var M = ARRAY16 + for (var i = 0; i < 16; ++i) M[i] = this._block.readInt32LE(i * 4) + + var a = this._a + var b = this._b + var c = this._c + var d = this._d + + a = fnF(a, b, c, d, M[0], 0xd76aa478, 7) + d = fnF(d, a, b, c, M[1], 0xe8c7b756, 12) + c = fnF(c, d, a, b, M[2], 0x242070db, 17) + b = fnF(b, c, d, a, M[3], 0xc1bdceee, 22) + a = fnF(a, b, c, d, M[4], 0xf57c0faf, 7) + d = fnF(d, a, b, c, M[5], 0x4787c62a, 12) + c = fnF(c, d, a, b, M[6], 0xa8304613, 17) + b = fnF(b, c, d, a, M[7], 0xfd469501, 22) + a = fnF(a, b, c, d, M[8], 0x698098d8, 7) + d = fnF(d, a, b, c, M[9], 0x8b44f7af, 12) + c = fnF(c, d, a, b, M[10], 0xffff5bb1, 17) + b = fnF(b, c, d, a, M[11], 0x895cd7be, 22) + a = fnF(a, b, c, d, M[12], 0x6b901122, 7) + d = fnF(d, a, b, c, M[13], 0xfd987193, 12) + c = fnF(c, d, a, b, M[14], 0xa679438e, 17) + b = fnF(b, c, d, a, M[15], 0x49b40821, 22) + + a = fnG(a, b, c, d, M[1], 0xf61e2562, 5) + d = fnG(d, a, b, c, M[6], 0xc040b340, 9) + c = fnG(c, d, a, b, M[11], 0x265e5a51, 14) + b = fnG(b, c, d, a, M[0], 0xe9b6c7aa, 20) + a = fnG(a, b, c, d, M[5], 0xd62f105d, 5) + d = fnG(d, a, b, c, M[10], 0x02441453, 9) + c = fnG(c, d, a, b, M[15], 0xd8a1e681, 14) + b = fnG(b, c, d, a, M[4], 0xe7d3fbc8, 20) + a = fnG(a, b, c, d, M[9], 0x21e1cde6, 5) + d = fnG(d, a, b, c, M[14], 0xc33707d6, 9) + c = fnG(c, d, a, b, M[3], 0xf4d50d87, 14) + b = fnG(b, c, d, a, M[8], 0x455a14ed, 20) + a = fnG(a, b, c, d, M[13], 0xa9e3e905, 5) + d = fnG(d, a, b, c, M[2], 0xfcefa3f8, 9) + c = fnG(c, d, a, b, M[7], 0x676f02d9, 14) + b = fnG(b, c, d, a, M[12], 0x8d2a4c8a, 20) + + a = fnH(a, b, c, d, M[5], 0xfffa3942, 4) + d = fnH(d, a, b, c, M[8], 0x8771f681, 11) + c = fnH(c, d, a, b, M[11], 0x6d9d6122, 16) + b = fnH(b, c, d, a, M[14], 0xfde5380c, 23) + a = fnH(a, b, c, d, M[1], 0xa4beea44, 4) + d = fnH(d, a, b, c, M[4], 0x4bdecfa9, 11) + c = fnH(c, d, a, b, M[7], 0xf6bb4b60, 16) + b = fnH(b, c, d, a, M[10], 0xbebfbc70, 23) + a = fnH(a, b, c, d, M[13], 0x289b7ec6, 4) + d = fnH(d, a, b, c, M[0], 0xeaa127fa, 11) + c = fnH(c, d, a, b, M[3], 0xd4ef3085, 16) + b = fnH(b, c, d, a, M[6], 0x04881d05, 23) + a = fnH(a, b, c, d, M[9], 0xd9d4d039, 4) + d = fnH(d, a, b, c, M[12], 0xe6db99e5, 11) + c = fnH(c, d, a, b, M[15], 0x1fa27cf8, 16) + b = fnH(b, c, d, a, M[2], 0xc4ac5665, 23) + + a = fnI(a, b, c, d, M[0], 0xf4292244, 6) + d = fnI(d, a, b, c, M[7], 0x432aff97, 10) + c = fnI(c, d, a, b, M[14], 0xab9423a7, 15) + b = fnI(b, c, d, a, M[5], 0xfc93a039, 21) + a = fnI(a, b, c, d, M[12], 0x655b59c3, 6) + d = fnI(d, a, b, c, M[3], 0x8f0ccc92, 10) + c = fnI(c, d, a, b, M[10], 0xffeff47d, 15) + b = fnI(b, c, d, a, M[1], 0x85845dd1, 21) + a = fnI(a, b, c, d, M[8], 0x6fa87e4f, 6) + d = fnI(d, a, b, c, M[15], 0xfe2ce6e0, 10) + c = fnI(c, d, a, b, M[6], 0xa3014314, 15) + b = fnI(b, c, d, a, M[13], 0x4e0811a1, 21) + a = fnI(a, b, c, d, M[4], 0xf7537e82, 6) + d = fnI(d, a, b, c, M[11], 0xbd3af235, 10) + c = fnI(c, d, a, b, M[2], 0x2ad7d2bb, 15) + b = fnI(b, c, d, a, M[9], 0xeb86d391, 21) + + this._a = (this._a + a) | 0 + this._b = (this._b + b) | 0 + this._c = (this._c + c) | 0 + this._d = (this._d + d) | 0 +} + +MD5.prototype._digest = function () { + // create padding and handle blocks + this._block[this._blockOffset++] = 0x80 + if (this._blockOffset > 56) { + this._block.fill(0, this._blockOffset, 64) + this._update() + this._blockOffset = 0 + } + + this._block.fill(0, this._blockOffset, 56) + this._block.writeUInt32LE(this._length[0], 56) + this._block.writeUInt32LE(this._length[1], 60) + this._update() + + // produce result + var buffer = Buffer.allocUnsafe(16) + buffer.writeInt32LE(this._a, 0) + buffer.writeInt32LE(this._b, 4) + buffer.writeInt32LE(this._c, 8) + buffer.writeInt32LE(this._d, 12) + return buffer +} + +function rotl (x, n) { + return (x << n) | (x >>> (32 - n)) +} + +function fnF (a, b, c, d, m, k, s) { + return (rotl((a + ((b & c) | ((~b) & d)) + m + k) | 0, s) + b) | 0 +} + +function fnG (a, b, c, d, m, k, s) { + return (rotl((a + ((b & d) | (c & (~d))) + m + k) | 0, s) + b) | 0 +} + +function fnH (a, b, c, d, m, k, s) { + return (rotl((a + (b ^ c ^ d) + m + k) | 0, s) + b) | 0 +} + +function fnI (a, b, c, d, m, k, s) { + return (rotl((a + ((c ^ (b | (~d)))) + m + k) | 0, s) + b) | 0 +} + +module.exports = MD5 + +},{"hash-base":113,"inherits":143,"safe-buffer":179}],149:[function(require,module,exports){ +var bn = require('bn.js'); +var brorand = require('brorand'); + +function MillerRabin(rand) { + this.rand = rand || new brorand.Rand(); +} +module.exports = MillerRabin; + +MillerRabin.create = function create(rand) { + return new MillerRabin(rand); +}; + +MillerRabin.prototype._randbelow = function _randbelow(n) { + var len = n.bitLength(); + var min_bytes = Math.ceil(len / 8); + + // Generage random bytes until a number less than n is found. + // This ensures that 0..n-1 have an equal probability of being selected. + do + var a = new bn(this.rand.generate(min_bytes)); + while (a.cmp(n) >= 0); + + return a; +}; + +MillerRabin.prototype._randrange = function _randrange(start, stop) { + // Generate a random number greater than or equal to start and less than stop. + var size = stop.sub(start); + return start.add(this._randbelow(size)); +}; + +MillerRabin.prototype.test = function test(n, k, cb) { + var len = n.bitLength(); + var red = bn.mont(n); + var rone = new bn(1).toRed(red); + + if (!k) + k = Math.max(1, (len / 48) | 0); + + // Find d and s, (n - 1) = (2 ^ s) * d; + var n1 = n.subn(1); + for (var s = 0; !n1.testn(s); s++) {} + var d = n.shrn(s); + + var rn1 = n1.toRed(red); + + var prime = true; + for (; k > 0; k--) { + var a = this._randrange(new bn(2), n1); + if (cb) + cb(a); + + var x = a.toRed(red).redPow(d); + if (x.cmp(rone) === 0 || x.cmp(rn1) === 0) + continue; + + for (var i = 1; i < s; i++) { + x = x.redSqr(); + + if (x.cmp(rone) === 0) + return false; + if (x.cmp(rn1) === 0) + break; + } + + if (i === s) + return false; + } + + return prime; +}; + +MillerRabin.prototype.getDivisor = function getDivisor(n, k) { + var len = n.bitLength(); + var red = bn.mont(n); + var rone = new bn(1).toRed(red); + + if (!k) + k = Math.max(1, (len / 48) | 0); + + // Find d and s, (n - 1) = (2 ^ s) * d; + var n1 = n.subn(1); + for (var s = 0; !n1.testn(s); s++) {} + var d = n.shrn(s); + + var rn1 = n1.toRed(red); + + for (; k > 0; k--) { + var a = this._randrange(new bn(2), n1); + + var g = n.gcd(a); + if (g.cmpn(1) !== 0) + return g; + + var x = a.toRed(red).redPow(d); + if (x.cmp(rone) === 0 || x.cmp(rn1) === 0) + continue; + + for (var i = 1; i < s; i++) { + x = x.redSqr(); + + if (x.cmp(rone) === 0) + return x.fromRed().subn(1).gcd(n); + if (x.cmp(rn1) === 0) + break; + } + + if (i === s) { + x = x.redSqr(); + return x.fromRed().subn(1).gcd(n); + } + } + + return false; +}; + +},{"bn.js":150,"brorand":19}],150:[function(require,module,exports){ +arguments[4][15][0].apply(exports,arguments) +},{"buffer":20,"dup":15}],151:[function(require,module,exports){ +module.exports = assert; + +function assert(val, msg) { + if (!val) + throw new Error(msg || 'Assertion failed'); +} + +assert.equal = function assertEqual(l, r, msg) { + if (l != r) + throw new Error(msg || ('Assertion failed: ' + l + ' != ' + r)); +}; + +},{}],152:[function(require,module,exports){ +'use strict'; + +var utils = exports; + +function toArray(msg, enc) { + if (Array.isArray(msg)) + return msg.slice(); + if (!msg) + return []; + var res = []; + if (typeof msg !== 'string') { + for (var i = 0; i < msg.length; i++) + res[i] = msg[i] | 0; + return res; + } + if (enc === 'hex') { + msg = msg.replace(/[^a-z0-9]+/ig, ''); + if (msg.length % 2 !== 0) + msg = '0' + msg; + for (var i = 0; i < msg.length; i += 2) + res.push(parseInt(msg[i] + msg[i + 1], 16)); + } else { + for (var i = 0; i < msg.length; i++) { + var c = msg.charCodeAt(i); + var hi = c >> 8; + var lo = c & 0xff; + if (hi) + res.push(hi, lo); + else + res.push(lo); + } + } + return res; +} +utils.toArray = toArray; + +function zero2(word) { + if (word.length === 1) + return '0' + word; + else + return word; +} +utils.zero2 = zero2; + +function toHex(msg) { + var res = ''; + for (var i = 0; i < msg.length; i++) + res += zero2(msg[i].toString(16)); + return res; +} +utils.toHex = toHex; + +utils.encode = function encode(arr, enc) { + if (enc === 'hex') + return toHex(arr); + else + return arr; +}; + +},{}],153:[function(require,module,exports){ +module.exports={"2.16.840.1.101.3.4.1.1": "aes-128-ecb", +"2.16.840.1.101.3.4.1.2": "aes-128-cbc", +"2.16.840.1.101.3.4.1.3": "aes-128-ofb", +"2.16.840.1.101.3.4.1.4": "aes-128-cfb", +"2.16.840.1.101.3.4.1.21": "aes-192-ecb", +"2.16.840.1.101.3.4.1.22": "aes-192-cbc", +"2.16.840.1.101.3.4.1.23": "aes-192-ofb", +"2.16.840.1.101.3.4.1.24": "aes-192-cfb", +"2.16.840.1.101.3.4.1.41": "aes-256-ecb", +"2.16.840.1.101.3.4.1.42": "aes-256-cbc", +"2.16.840.1.101.3.4.1.43": "aes-256-ofb", +"2.16.840.1.101.3.4.1.44": "aes-256-cfb" +} +},{}],154:[function(require,module,exports){ +// from https://github.com/indutny/self-signed/blob/gh-pages/lib/asn1.js +// Fedor, you are amazing. +'use strict' + +var asn1 = require('asn1.js') + +exports.certificate = require('./certificate') + +var RSAPrivateKey = asn1.define('RSAPrivateKey', function () { + this.seq().obj( + this.key('version').int(), + this.key('modulus').int(), + this.key('publicExponent').int(), + this.key('privateExponent').int(), + this.key('prime1').int(), + this.key('prime2').int(), + this.key('exponent1').int(), + this.key('exponent2').int(), + this.key('coefficient').int() + ) +}) +exports.RSAPrivateKey = RSAPrivateKey + +var RSAPublicKey = asn1.define('RSAPublicKey', function () { + this.seq().obj( + this.key('modulus').int(), + this.key('publicExponent').int() + ) +}) +exports.RSAPublicKey = RSAPublicKey + +var PublicKey = asn1.define('SubjectPublicKeyInfo', function () { + this.seq().obj( + this.key('algorithm').use(AlgorithmIdentifier), + this.key('subjectPublicKey').bitstr() + ) +}) +exports.PublicKey = PublicKey + +var AlgorithmIdentifier = asn1.define('AlgorithmIdentifier', function () { + this.seq().obj( + this.key('algorithm').objid(), + this.key('none').null_().optional(), + this.key('curve').objid().optional(), + this.key('params').seq().obj( + this.key('p').int(), + this.key('q').int(), + this.key('g').int() + ).optional() + ) +}) + +var PrivateKeyInfo = asn1.define('PrivateKeyInfo', function () { + this.seq().obj( + this.key('version').int(), + this.key('algorithm').use(AlgorithmIdentifier), + this.key('subjectPrivateKey').octstr() + ) +}) +exports.PrivateKey = PrivateKeyInfo +var EncryptedPrivateKeyInfo = asn1.define('EncryptedPrivateKeyInfo', function () { + this.seq().obj( + this.key('algorithm').seq().obj( + this.key('id').objid(), + this.key('decrypt').seq().obj( + this.key('kde').seq().obj( + this.key('id').objid(), + this.key('kdeparams').seq().obj( + this.key('salt').octstr(), + this.key('iters').int() + ) + ), + this.key('cipher').seq().obj( + this.key('algo').objid(), + this.key('iv').octstr() + ) + ) + ), + this.key('subjectPrivateKey').octstr() + ) +}) + +exports.EncryptedPrivateKey = EncryptedPrivateKeyInfo + +var DSAPrivateKey = asn1.define('DSAPrivateKey', function () { + this.seq().obj( + this.key('version').int(), + this.key('p').int(), + this.key('q').int(), + this.key('g').int(), + this.key('pub_key').int(), + this.key('priv_key').int() + ) +}) +exports.DSAPrivateKey = DSAPrivateKey + +exports.DSAparam = asn1.define('DSAparam', function () { + this.int() +}) + +var ECPrivateKey = asn1.define('ECPrivateKey', function () { + this.seq().obj( + this.key('version').int(), + this.key('privateKey').octstr(), + this.key('parameters').optional().explicit(0).use(ECParameters), + this.key('publicKey').optional().explicit(1).bitstr() + ) +}) +exports.ECPrivateKey = ECPrivateKey + +var ECParameters = asn1.define('ECParameters', function () { + this.choice({ + namedCurve: this.objid() + }) +}) + +exports.signature = asn1.define('signature', function () { + this.seq().obj( + this.key('r').int(), + this.key('s').int() + ) +}) + +},{"./certificate":155,"asn1.js":1}],155:[function(require,module,exports){ +// from https://github.com/Rantanen/node-dtls/blob/25a7dc861bda38cfeac93a723500eea4f0ac2e86/Certificate.js +// thanks to @Rantanen + +'use strict' + +var asn = require('asn1.js') + +var Time = asn.define('Time', function () { + this.choice({ + utcTime: this.utctime(), + generalTime: this.gentime() + }) +}) + +var AttributeTypeValue = asn.define('AttributeTypeValue', function () { + this.seq().obj( + this.key('type').objid(), + this.key('value').any() + ) +}) + +var AlgorithmIdentifier = asn.define('AlgorithmIdentifier', function () { + this.seq().obj( + this.key('algorithm').objid(), + this.key('parameters').optional(), + this.key('curve').objid().optional() + ) +}) + +var SubjectPublicKeyInfo = asn.define('SubjectPublicKeyInfo', function () { + this.seq().obj( + this.key('algorithm').use(AlgorithmIdentifier), + this.key('subjectPublicKey').bitstr() + ) +}) + +var RelativeDistinguishedName = asn.define('RelativeDistinguishedName', function () { + this.setof(AttributeTypeValue) +}) + +var RDNSequence = asn.define('RDNSequence', function () { + this.seqof(RelativeDistinguishedName) +}) + +var Name = asn.define('Name', function () { + this.choice({ + rdnSequence: this.use(RDNSequence) + }) +}) + +var Validity = asn.define('Validity', function () { + this.seq().obj( + this.key('notBefore').use(Time), + this.key('notAfter').use(Time) + ) +}) + +var Extension = asn.define('Extension', function () { + this.seq().obj( + this.key('extnID').objid(), + this.key('critical').bool().def(false), + this.key('extnValue').octstr() + ) +}) + +var TBSCertificate = asn.define('TBSCertificate', function () { + this.seq().obj( + this.key('version').explicit(0).int().optional(), + this.key('serialNumber').int(), + this.key('signature').use(AlgorithmIdentifier), + this.key('issuer').use(Name), + this.key('validity').use(Validity), + this.key('subject').use(Name), + this.key('subjectPublicKeyInfo').use(SubjectPublicKeyInfo), + this.key('issuerUniqueID').implicit(1).bitstr().optional(), + this.key('subjectUniqueID').implicit(2).bitstr().optional(), + this.key('extensions').explicit(3).seqof(Extension).optional() + ) +}) + +var X509Certificate = asn.define('X509Certificate', function () { + this.seq().obj( + this.key('tbsCertificate').use(TBSCertificate), + this.key('signatureAlgorithm').use(AlgorithmIdentifier), + this.key('signatureValue').bitstr() + ) +}) + +module.exports = X509Certificate + +},{"asn1.js":1}],156:[function(require,module,exports){ +// adapted from https://github.com/apatil/pemstrip +var findProc = /Proc-Type: 4,ENCRYPTED[\n\r]+DEK-Info: AES-((?:128)|(?:192)|(?:256))-CBC,([0-9A-H]+)[\n\r]+([0-9A-z\n\r+/=]+)[\n\r]+/m +var startRegex = /^-----BEGIN ((?:.*? KEY)|CERTIFICATE)-----/m +var fullRegex = /^-----BEGIN ((?:.*? KEY)|CERTIFICATE)-----([0-9A-z\n\r+/=]+)-----END \1-----$/m +var evp = require('evp_bytestokey') +var ciphers = require('browserify-aes') +var Buffer = require('safe-buffer').Buffer +module.exports = function (okey, password) { + var key = okey.toString() + var match = key.match(findProc) + var decrypted + if (!match) { + var match2 = key.match(fullRegex) + decrypted = Buffer.from(match2[2].replace(/[\r\n]/g, ''), 'base64') + } else { + var suite = 'aes' + match[1] + var iv = Buffer.from(match[2], 'hex') + var cipherText = Buffer.from(match[3].replace(/[\r\n]/g, ''), 'base64') + var cipherKey = evp(password, iv.slice(0, 8), parseInt(match[1], 10)).key + var out = [] + var cipher = ciphers.createDecipheriv(suite, cipherKey, iv) + out.push(cipher.update(cipherText)) + out.push(cipher.final()) + decrypted = Buffer.concat(out) + } + var tag = key.match(startRegex)[1] + return { + tag: tag, + data: decrypted + } +} + +},{"browserify-aes":23,"evp_bytestokey":105,"safe-buffer":179}],157:[function(require,module,exports){ +var asn1 = require('./asn1') +var aesid = require('./aesid.json') +var fixProc = require('./fixProc') +var ciphers = require('browserify-aes') +var compat = require('pbkdf2') +var Buffer = require('safe-buffer').Buffer +module.exports = parseKeys + +function parseKeys (buffer) { + var password + if (typeof buffer === 'object' && !Buffer.isBuffer(buffer)) { + password = buffer.passphrase + buffer = buffer.key + } + if (typeof buffer === 'string') { + buffer = Buffer.from(buffer) + } + + var stripped = fixProc(buffer, password) + + var type = stripped.tag + var data = stripped.data + var subtype, ndata + switch (type) { + case 'CERTIFICATE': + ndata = asn1.certificate.decode(data, 'der').tbsCertificate.subjectPublicKeyInfo + // falls through + case 'PUBLIC KEY': + if (!ndata) { + ndata = asn1.PublicKey.decode(data, 'der') + } + subtype = ndata.algorithm.algorithm.join('.') + switch (subtype) { + case '1.2.840.113549.1.1.1': + return asn1.RSAPublicKey.decode(ndata.subjectPublicKey.data, 'der') + case '1.2.840.10045.2.1': + ndata.subjectPrivateKey = ndata.subjectPublicKey + return { + type: 'ec', + data: ndata + } + case '1.2.840.10040.4.1': + ndata.algorithm.params.pub_key = asn1.DSAparam.decode(ndata.subjectPublicKey.data, 'der') + return { + type: 'dsa', + data: ndata.algorithm.params + } + default: throw new Error('unknown key id ' + subtype) + } + // throw new Error('unknown key type ' + type) + case 'ENCRYPTED PRIVATE KEY': + data = asn1.EncryptedPrivateKey.decode(data, 'der') + data = decrypt(data, password) + // falls through + case 'PRIVATE KEY': + ndata = asn1.PrivateKey.decode(data, 'der') + subtype = ndata.algorithm.algorithm.join('.') + switch (subtype) { + case '1.2.840.113549.1.1.1': + return asn1.RSAPrivateKey.decode(ndata.subjectPrivateKey, 'der') + case '1.2.840.10045.2.1': + return { + curve: ndata.algorithm.curve, + privateKey: asn1.ECPrivateKey.decode(ndata.subjectPrivateKey, 'der').privateKey + } + case '1.2.840.10040.4.1': + ndata.algorithm.params.priv_key = asn1.DSAparam.decode(ndata.subjectPrivateKey, 'der') + return { + type: 'dsa', + params: ndata.algorithm.params + } + default: throw new Error('unknown key id ' + subtype) + } + // throw new Error('unknown key type ' + type) + case 'RSA PUBLIC KEY': + return asn1.RSAPublicKey.decode(data, 'der') + case 'RSA PRIVATE KEY': + return asn1.RSAPrivateKey.decode(data, 'der') + case 'DSA PRIVATE KEY': + return { + type: 'dsa', + params: asn1.DSAPrivateKey.decode(data, 'der') + } + case 'EC PRIVATE KEY': + data = asn1.ECPrivateKey.decode(data, 'der') + return { + curve: data.parameters.value, + privateKey: data.privateKey + } + default: throw new Error('unknown key type ' + type) + } +} +parseKeys.signature = asn1.signature +function decrypt (data, password) { + var salt = data.algorithm.decrypt.kde.kdeparams.salt + var iters = parseInt(data.algorithm.decrypt.kde.kdeparams.iters.toString(), 10) + var algo = aesid[data.algorithm.decrypt.cipher.algo.join('.')] + var iv = data.algorithm.decrypt.cipher.iv + var cipherText = data.subjectPrivateKey + var keylen = parseInt(algo.split('-')[1], 10) / 8 + var key = compat.pbkdf2Sync(password, salt, iters, keylen, 'sha1') + var cipher = ciphers.createDecipheriv(algo, key, iv) + var out = [] + out.push(cipher.update(cipherText)) + out.push(cipher.final()) + return Buffer.concat(out) +} + +},{"./aesid.json":153,"./asn1":154,"./fixProc":156,"browserify-aes":23,"pbkdf2":158,"safe-buffer":179}],158:[function(require,module,exports){ +exports.pbkdf2 = require('./lib/async') +exports.pbkdf2Sync = require('./lib/sync') + +},{"./lib/async":159,"./lib/sync":162}],159:[function(require,module,exports){ +(function (global){(function (){ +var Buffer = require('safe-buffer').Buffer + +var checkParameters = require('./precondition') +var defaultEncoding = require('./default-encoding') +var sync = require('./sync') +var toBuffer = require('./to-buffer') + +var ZERO_BUF +var subtle = global.crypto && global.crypto.subtle +var toBrowser = { + sha: 'SHA-1', + 'sha-1': 'SHA-1', + sha1: 'SHA-1', + sha256: 'SHA-256', + 'sha-256': 'SHA-256', + sha384: 'SHA-384', + 'sha-384': 'SHA-384', + 'sha-512': 'SHA-512', + sha512: 'SHA-512' +} +var checks = [] +function checkNative (algo) { + if (global.process && !global.process.browser) { + return Promise.resolve(false) + } + if (!subtle || !subtle.importKey || !subtle.deriveBits) { + return Promise.resolve(false) + } + if (checks[algo] !== undefined) { + return checks[algo] + } + ZERO_BUF = ZERO_BUF || Buffer.alloc(8) + var prom = browserPbkdf2(ZERO_BUF, ZERO_BUF, 10, 128, algo) + .then(function () { + return true + }).catch(function () { + return false + }) + checks[algo] = prom + return prom +} +var nextTick +function getNextTick () { + if (nextTick) { + return nextTick + } + if (global.process && global.process.nextTick) { + nextTick = global.process.nextTick + } else if (global.queueMicrotask) { + nextTick = global.queueMicrotask + } else if (global.setImmediate) { + nextTick = global.setImmediate + } else { + nextTick = global.setTimeout + } + return nextTick +} +function browserPbkdf2 (password, salt, iterations, length, algo) { + return subtle.importKey( + 'raw', password, { name: 'PBKDF2' }, false, ['deriveBits'] + ).then(function (key) { + return subtle.deriveBits({ + name: 'PBKDF2', + salt: salt, + iterations: iterations, + hash: { + name: algo + } + }, key, length << 3) + }).then(function (res) { + return Buffer.from(res) + }) +} + +function resolvePromise (promise, callback) { + promise.then(function (out) { + getNextTick()(function () { + callback(null, out) + }) + }, function (e) { + getNextTick()(function () { + callback(e) + }) + }) +} +module.exports = function (password, salt, iterations, keylen, digest, callback) { + if (typeof digest === 'function') { + callback = digest + digest = undefined + } + + digest = digest || 'sha1' + var algo = toBrowser[digest.toLowerCase()] + + if (!algo || typeof global.Promise !== 'function') { + getNextTick()(function () { + var out + try { + out = sync(password, salt, iterations, keylen, digest) + } catch (e) { + return callback(e) + } + callback(null, out) + }) + return + } + + checkParameters(iterations, keylen) + password = toBuffer(password, defaultEncoding, 'Password') + salt = toBuffer(salt, defaultEncoding, 'Salt') + if (typeof callback !== 'function') throw new Error('No callback provided to pbkdf2') + + resolvePromise(checkNative(algo).then(function (resp) { + if (resp) return browserPbkdf2(password, salt, iterations, keylen, algo) + + return sync(password, salt, iterations, keylen, digest) + }), callback) +} + +}).call(this)}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) +},{"./default-encoding":160,"./precondition":161,"./sync":162,"./to-buffer":163,"safe-buffer":179}],160:[function(require,module,exports){ +(function (process,global){(function (){ +var defaultEncoding +/* istanbul ignore next */ +if (global.process && global.process.browser) { + defaultEncoding = 'utf-8' +} else if (global.process && global.process.version) { + var pVersionMajor = parseInt(process.version.split('.')[0].slice(1), 10) + + defaultEncoding = pVersionMajor >= 6 ? 'utf-8' : 'binary' +} else { + defaultEncoding = 'utf-8' +} +module.exports = defaultEncoding + +}).call(this)}).call(this,require('_process'),typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) +},{"_process":164}],161:[function(require,module,exports){ +var MAX_ALLOC = Math.pow(2, 30) - 1 // default in iojs + +module.exports = function (iterations, keylen) { + if (typeof iterations !== 'number') { + throw new TypeError('Iterations not a number') + } + + if (iterations < 0) { + throw new TypeError('Bad iterations') + } + + if (typeof keylen !== 'number') { + throw new TypeError('Key length not a number') + } + + if (keylen < 0 || keylen > MAX_ALLOC || keylen !== keylen) { /* eslint no-self-compare: 0 */ + throw new TypeError('Bad key length') + } +} + +},{}],162:[function(require,module,exports){ +var md5 = require('create-hash/md5') +var RIPEMD160 = require('ripemd160') +var sha = require('sha.js') +var Buffer = require('safe-buffer').Buffer + +var checkParameters = require('./precondition') +var defaultEncoding = require('./default-encoding') +var toBuffer = require('./to-buffer') + +var ZEROS = Buffer.alloc(128) +var sizes = { + md5: 16, + sha1: 20, + sha224: 28, + sha256: 32, + sha384: 48, + sha512: 64, + rmd160: 20, + ripemd160: 20 +} + +function Hmac (alg, key, saltLen) { + var hash = getDigest(alg) + var blocksize = (alg === 'sha512' || alg === 'sha384') ? 128 : 64 + + if (key.length > blocksize) { + key = hash(key) + } else if (key.length < blocksize) { + key = Buffer.concat([key, ZEROS], blocksize) + } + + var ipad = Buffer.allocUnsafe(blocksize + sizes[alg]) + var opad = Buffer.allocUnsafe(blocksize + sizes[alg]) + for (var i = 0; i < blocksize; i++) { + ipad[i] = key[i] ^ 0x36 + opad[i] = key[i] ^ 0x5C + } + + var ipad1 = Buffer.allocUnsafe(blocksize + saltLen + 4) + ipad.copy(ipad1, 0, 0, blocksize) + this.ipad1 = ipad1 + this.ipad2 = ipad + this.opad = opad + this.alg = alg + this.blocksize = blocksize + this.hash = hash + this.size = sizes[alg] +} + +Hmac.prototype.run = function (data, ipad) { + data.copy(ipad, this.blocksize) + var h = this.hash(ipad) + h.copy(this.opad, this.blocksize) + return this.hash(this.opad) +} + +function getDigest (alg) { + function shaFunc (data) { + return sha(alg).update(data).digest() + } + function rmd160Func (data) { + return new RIPEMD160().update(data).digest() + } + + if (alg === 'rmd160' || alg === 'ripemd160') return rmd160Func + if (alg === 'md5') return md5 + return shaFunc +} + +function pbkdf2 (password, salt, iterations, keylen, digest) { + checkParameters(iterations, keylen) + password = toBuffer(password, defaultEncoding, 'Password') + salt = toBuffer(salt, defaultEncoding, 'Salt') + + digest = digest || 'sha1' + + var hmac = new Hmac(digest, password, salt.length) + + var DK = Buffer.allocUnsafe(keylen) + var block1 = Buffer.allocUnsafe(salt.length + 4) + salt.copy(block1, 0, 0, salt.length) + + var destPos = 0 + var hLen = sizes[digest] + var l = Math.ceil(keylen / hLen) + + for (var i = 1; i <= l; i++) { + block1.writeUInt32BE(i, salt.length) + + var T = hmac.run(block1, hmac.ipad1) + var U = T + + for (var j = 1; j < iterations; j++) { + U = hmac.run(U, hmac.ipad2) + for (var k = 0; k < hLen; k++) T[k] ^= U[k] + } + + T.copy(DK, destPos) + destPos += hLen + } + + return DK +} + +module.exports = pbkdf2 + +},{"./default-encoding":160,"./precondition":161,"./to-buffer":163,"create-hash/md5":71,"ripemd160":178,"safe-buffer":179,"sha.js":182}],163:[function(require,module,exports){ +var Buffer = require('safe-buffer').Buffer + +module.exports = function (thing, encoding, name) { + if (Buffer.isBuffer(thing)) { + return thing + } else if (typeof thing === 'string') { + return Buffer.from(thing, encoding) + } else if (ArrayBuffer.isView(thing)) { + return Buffer.from(thing.buffer) + } else { + throw new TypeError(name + ' must be a string, a Buffer, a typed array or a DataView') + } +} + +},{"safe-buffer":179}],164:[function(require,module,exports){ +// shim for using process in browser +var process = module.exports = {}; + +// cached from whatever global is present so that test runners that stub it +// don't break things. But we need to wrap it in a try catch in case it is +// wrapped in strict mode code which doesn't define any globals. It's inside a +// function because try/catches deoptimize in certain engines. + +var cachedSetTimeout; +var cachedClearTimeout; + +function defaultSetTimout() { + throw new Error('setTimeout has not been defined'); +} +function defaultClearTimeout () { + throw new Error('clearTimeout has not been defined'); +} +(function () { + try { + if (typeof setTimeout === 'function') { + cachedSetTimeout = setTimeout; + } else { + cachedSetTimeout = defaultSetTimout; + } + } catch (e) { + cachedSetTimeout = defaultSetTimout; + } + try { + if (typeof clearTimeout === 'function') { + cachedClearTimeout = clearTimeout; + } else { + cachedClearTimeout = defaultClearTimeout; + } + } catch (e) { + cachedClearTimeout = defaultClearTimeout; + } +} ()) +function runTimeout(fun) { + if (cachedSetTimeout === setTimeout) { + //normal enviroments in sane situations + return setTimeout(fun, 0); + } + // if setTimeout wasn't available but was latter defined + if ((cachedSetTimeout === defaultSetTimout || !cachedSetTimeout) && setTimeout) { + cachedSetTimeout = setTimeout; + return setTimeout(fun, 0); + } + try { + // when when somebody has screwed with setTimeout but no I.E. maddness + return cachedSetTimeout(fun, 0); + } catch(e){ + try { + // When we are in I.E. but the script has been evaled so I.E. doesn't trust the global object when called normally + return cachedSetTimeout.call(null, fun, 0); + } catch(e){ + // same as above but when it's a version of I.E. that must have the global object for 'this', hopfully our context correct otherwise it will throw a global error + return cachedSetTimeout.call(this, fun, 0); + } + } + + +} +function runClearTimeout(marker) { + if (cachedClearTimeout === clearTimeout) { + //normal enviroments in sane situations + return clearTimeout(marker); + } + // if clearTimeout wasn't available but was latter defined + if ((cachedClearTimeout === defaultClearTimeout || !cachedClearTimeout) && clearTimeout) { + cachedClearTimeout = clearTimeout; + return clearTimeout(marker); + } + try { + // when when somebody has screwed with setTimeout but no I.E. maddness + return cachedClearTimeout(marker); + } catch (e){ + try { + // When we are in I.E. but the script has been evaled so I.E. doesn't trust the global object when called normally + return cachedClearTimeout.call(null, marker); + } catch (e){ + // same as above but when it's a version of I.E. that must have the global object for 'this', hopfully our context correct otherwise it will throw a global error. + // Some versions of I.E. have different rules for clearTimeout vs setTimeout + return cachedClearTimeout.call(this, marker); + } + } + + + +} +var queue = []; +var draining = false; +var currentQueue; +var queueIndex = -1; + +function cleanUpNextTick() { + if (!draining || !currentQueue) { + return; + } + draining = false; + if (currentQueue.length) { + queue = currentQueue.concat(queue); + } else { + queueIndex = -1; + } + if (queue.length) { + drainQueue(); + } +} + +function drainQueue() { + if (draining) { + return; + } + var timeout = runTimeout(cleanUpNextTick); + draining = true; + + var len = queue.length; + while(len) { + currentQueue = queue; + queue = []; + while (++queueIndex < len) { + if (currentQueue) { + currentQueue[queueIndex].run(); + } + } + queueIndex = -1; + len = queue.length; + } + currentQueue = null; + draining = false; + runClearTimeout(timeout); +} + +process.nextTick = function (fun) { + var args = new Array(arguments.length - 1); + if (arguments.length > 1) { + for (var i = 1; i < arguments.length; i++) { + args[i - 1] = arguments[i]; + } + } + queue.push(new Item(fun, args)); + if (queue.length === 1 && !draining) { + runTimeout(drainQueue); + } +}; + +// v8 likes predictible objects +function Item(fun, array) { + this.fun = fun; + this.array = array; +} +Item.prototype.run = function () { + this.fun.apply(null, this.array); +}; +process.title = 'browser'; +process.browser = true; +process.env = {}; +process.argv = []; +process.version = ''; // empty string to avoid regexp issues +process.versions = {}; + +function noop() {} + +process.on = noop; +process.addListener = noop; +process.once = noop; +process.off = noop; +process.removeListener = noop; +process.removeAllListeners = noop; +process.emit = noop; +process.prependListener = noop; +process.prependOnceListener = noop; + +process.listeners = function (name) { return [] } + +process.binding = function (name) { + throw new Error('process.binding is not supported'); +}; + +process.cwd = function () { return '/' }; +process.chdir = function (dir) { + throw new Error('process.chdir is not supported'); +}; +process.umask = function() { return 0; }; + +},{}],165:[function(require,module,exports){ +exports.publicEncrypt = require('./publicEncrypt') +exports.privateDecrypt = require('./privateDecrypt') + +exports.privateEncrypt = function privateEncrypt (key, buf) { + return exports.publicEncrypt(key, buf, true) +} + +exports.publicDecrypt = function publicDecrypt (key, buf) { + return exports.privateDecrypt(key, buf, true) +} + +},{"./privateDecrypt":168,"./publicEncrypt":169}],166:[function(require,module,exports){ +var createHash = require('create-hash') +var Buffer = require('safe-buffer').Buffer + +module.exports = function (seed, len) { + var t = Buffer.alloc(0) + var i = 0 + var c + while (t.length < len) { + c = i2ops(i++) + t = Buffer.concat([t, createHash('sha1').update(seed).update(c).digest()]) + } + return t.slice(0, len) +} + +function i2ops (c) { + var out = Buffer.allocUnsafe(4) + out.writeUInt32BE(c, 0) + return out +} + +},{"create-hash":70,"safe-buffer":179}],167:[function(require,module,exports){ +arguments[4][15][0].apply(exports,arguments) +},{"buffer":20,"dup":15}],168:[function(require,module,exports){ +var parseKeys = require('parse-asn1') +var mgf = require('./mgf') +var xor = require('./xor') +var BN = require('bn.js') +var crt = require('browserify-rsa') +var createHash = require('create-hash') +var withPublic = require('./withPublic') +var Buffer = require('safe-buffer').Buffer + +module.exports = function privateDecrypt (privateKey, enc, reverse) { + var padding + if (privateKey.padding) { + padding = privateKey.padding + } else if (reverse) { + padding = 1 + } else { + padding = 4 + } + + var key = parseKeys(privateKey) + var k = key.modulus.byteLength() + if (enc.length > k || new BN(enc).cmp(key.modulus) >= 0) { + throw new Error('decryption error') + } + var msg + if (reverse) { + msg = withPublic(new BN(enc), key) + } else { + msg = crt(enc, key) + } + var zBuffer = Buffer.alloc(k - msg.length) + msg = Buffer.concat([zBuffer, msg], k) + if (padding === 4) { + return oaep(key, msg) + } else if (padding === 1) { + return pkcs1(key, msg, reverse) + } else if (padding === 3) { + return msg + } else { + throw new Error('unknown padding') + } +} + +function oaep (key, msg) { + var k = key.modulus.byteLength() + var iHash = createHash('sha1').update(Buffer.alloc(0)).digest() + var hLen = iHash.length + if (msg[0] !== 0) { + throw new Error('decryption error') + } + var maskedSeed = msg.slice(1, hLen + 1) + var maskedDb = msg.slice(hLen + 1) + var seed = xor(maskedSeed, mgf(maskedDb, hLen)) + var db = xor(maskedDb, mgf(seed, k - hLen - 1)) + if (compare(iHash, db.slice(0, hLen))) { + throw new Error('decryption error') + } + var i = hLen + while (db[i] === 0) { + i++ + } + if (db[i++] !== 1) { + throw new Error('decryption error') + } + return db.slice(i) +} + +function pkcs1 (key, msg, reverse) { + var p1 = msg.slice(0, 2) + var i = 2 + var status = 0 + while (msg[i++] !== 0) { + if (i >= msg.length) { + status++ + break + } + } + var ps = msg.slice(2, i - 1) + + if ((p1.toString('hex') !== '0002' && !reverse) || (p1.toString('hex') !== '0001' && reverse)) { + status++ + } + if (ps.length < 8) { + status++ + } + if (status) { + throw new Error('decryption error') + } + return msg.slice(i) +} +function compare (a, b) { + a = Buffer.from(a) + b = Buffer.from(b) + var dif = 0 + var len = a.length + if (a.length !== b.length) { + dif++ + len = Math.min(a.length, b.length) + } + var i = -1 + while (++i < len) { + dif += (a[i] ^ b[i]) + } + return dif +} + +},{"./mgf":166,"./withPublic":170,"./xor":171,"bn.js":167,"browserify-rsa":41,"create-hash":70,"parse-asn1":157,"safe-buffer":179}],169:[function(require,module,exports){ +var parseKeys = require('parse-asn1') +var randomBytes = require('randombytes') +var createHash = require('create-hash') +var mgf = require('./mgf') +var xor = require('./xor') +var BN = require('bn.js') +var withPublic = require('./withPublic') +var crt = require('browserify-rsa') +var Buffer = require('safe-buffer').Buffer + +module.exports = function publicEncrypt (publicKey, msg, reverse) { + var padding + if (publicKey.padding) { + padding = publicKey.padding + } else if (reverse) { + padding = 1 + } else { + padding = 4 + } + var key = parseKeys(publicKey) + var paddedMsg + if (padding === 4) { + paddedMsg = oaep(key, msg) + } else if (padding === 1) { + paddedMsg = pkcs1(key, msg, reverse) + } else if (padding === 3) { + paddedMsg = new BN(msg) + if (paddedMsg.cmp(key.modulus) >= 0) { + throw new Error('data too long for modulus') + } + } else { + throw new Error('unknown padding') + } + if (reverse) { + return crt(paddedMsg, key) + } else { + return withPublic(paddedMsg, key) + } +} + +function oaep (key, msg) { + var k = key.modulus.byteLength() + var mLen = msg.length + var iHash = createHash('sha1').update(Buffer.alloc(0)).digest() + var hLen = iHash.length + var hLen2 = 2 * hLen + if (mLen > k - hLen2 - 2) { + throw new Error('message too long') + } + var ps = Buffer.alloc(k - mLen - hLen2 - 2) + var dblen = k - hLen - 1 + var seed = randomBytes(hLen) + var maskedDb = xor(Buffer.concat([iHash, ps, Buffer.alloc(1, 1), msg], dblen), mgf(seed, dblen)) + var maskedSeed = xor(seed, mgf(maskedDb, hLen)) + return new BN(Buffer.concat([Buffer.alloc(1), maskedSeed, maskedDb], k)) +} +function pkcs1 (key, msg, reverse) { + var mLen = msg.length + var k = key.modulus.byteLength() + if (mLen > k - 11) { + throw new Error('message too long') + } + var ps + if (reverse) { + ps = Buffer.alloc(k - mLen - 3, 0xff) + } else { + ps = nonZero(k - mLen - 3) + } + return new BN(Buffer.concat([Buffer.from([0, reverse ? 1 : 2]), ps, Buffer.alloc(1), msg], k)) +} +function nonZero (len) { + var out = Buffer.allocUnsafe(len) + var i = 0 + var cache = randomBytes(len * 2) + var cur = 0 + var num + while (i < len) { + if (cur === cache.length) { + cache = randomBytes(len * 2) + cur = 0 + } + num = cache[cur++] + if (num) { + out[i++] = num + } + } + return out +} + +},{"./mgf":166,"./withPublic":170,"./xor":171,"bn.js":167,"browserify-rsa":41,"create-hash":70,"parse-asn1":157,"randombytes":176,"safe-buffer":179}],170:[function(require,module,exports){ +var BN = require('bn.js') +var Buffer = require('safe-buffer').Buffer + +function withPublic (paddedMsg, key) { + return Buffer.from(paddedMsg + .toRed(BN.mont(key.modulus)) + .redPow(new BN(key.publicExponent)) + .fromRed() + .toArray()) +} + +module.exports = withPublic + +},{"bn.js":167,"safe-buffer":179}],171:[function(require,module,exports){ +module.exports = function xor (a, b) { + var len = a.length + var i = -1 + while (++i < len) { + a[i] ^= b[i] + } + return a +} + +},{}],172:[function(require,module,exports){ +(function (global){(function (){ +/*! https://mths.be/punycode v1.4.1 by @mathias */ +;(function(root) { + + /** Detect free variables */ + var freeExports = typeof exports == 'object' && exports && + !exports.nodeType && exports; + var freeModule = typeof module == 'object' && module && + !module.nodeType && module; + var freeGlobal = typeof global == 'object' && global; + if ( + freeGlobal.global === freeGlobal || + freeGlobal.window === freeGlobal || + freeGlobal.self === freeGlobal + ) { + root = freeGlobal; + } + + /** + * The `punycode` object. + * @name punycode + * @type Object + */ + var punycode, + + /** Highest positive signed 32-bit float value */ + maxInt = 2147483647, // aka. 0x7FFFFFFF or 2^31-1 + + /** Bootstring parameters */ + base = 36, + tMin = 1, + tMax = 26, + skew = 38, + damp = 700, + initialBias = 72, + initialN = 128, // 0x80 + delimiter = '-', // '\x2D' + + /** Regular expressions */ + regexPunycode = /^xn--/, + regexNonASCII = /[^\x20-\x7E]/, // unprintable ASCII chars + non-ASCII chars + regexSeparators = /[\x2E\u3002\uFF0E\uFF61]/g, // RFC 3490 separators + + /** Error messages */ + errors = { + 'overflow': 'Overflow: input needs wider integers to process', + 'not-basic': 'Illegal input >= 0x80 (not a basic code point)', + 'invalid-input': 'Invalid input' + }, + + /** Convenience shortcuts */ + baseMinusTMin = base - tMin, + floor = Math.floor, + stringFromCharCode = String.fromCharCode, + + /** Temporary variable */ + key; + + /*--------------------------------------------------------------------------*/ + + /** + * A generic error utility function. + * @private + * @param {String} type The error type. + * @returns {Error} Throws a `RangeError` with the applicable error message. + */ + function error(type) { + throw new RangeError(errors[type]); + } + + /** + * A generic `Array#map` utility function. + * @private + * @param {Array} array The array to iterate over. + * @param {Function} callback The function that gets called for every array + * item. + * @returns {Array} A new array of values returned by the callback function. + */ + function map(array, fn) { + var length = array.length; + var result = []; + while (length--) { + result[length] = fn(array[length]); + } + return result; + } + + /** + * A simple `Array#map`-like wrapper to work with domain name strings or email + * addresses. + * @private + * @param {String} domain The domain name or email address. + * @param {Function} callback The function that gets called for every + * character. + * @returns {Array} A new string of characters returned by the callback + * function. + */ + function mapDomain(string, fn) { + var parts = string.split('@'); + var result = ''; + if (parts.length > 1) { + // In email addresses, only the domain name should be punycoded. Leave + // the local part (i.e. everything up to `@`) intact. + result = parts[0] + '@'; + string = parts[1]; + } + // Avoid `split(regex)` for IE8 compatibility. See #17. + string = string.replace(regexSeparators, '\x2E'); + var labels = string.split('.'); + var encoded = map(labels, fn).join('.'); + return result + encoded; + } + + /** + * Creates an array containing the numeric code points of each Unicode + * character in the string. While JavaScript uses UCS-2 internally, + * this function will convert a pair of surrogate halves (each of which + * UCS-2 exposes as separate characters) into a single code point, + * matching UTF-16. + * @see `punycode.ucs2.encode` + * @see + * @memberOf punycode.ucs2 + * @name decode + * @param {String} string The Unicode input string (UCS-2). + * @returns {Array} The new array of code points. + */ + function ucs2decode(string) { + var output = [], + counter = 0, + length = string.length, + value, + extra; + while (counter < length) { + value = string.charCodeAt(counter++); + if (value >= 0xD800 && value <= 0xDBFF && counter < length) { + // high surrogate, and there is a next character + extra = string.charCodeAt(counter++); + if ((extra & 0xFC00) == 0xDC00) { // low surrogate + output.push(((value & 0x3FF) << 10) + (extra & 0x3FF) + 0x10000); + } else { + // unmatched surrogate; only append this code unit, in case the next + // code unit is the high surrogate of a surrogate pair + output.push(value); + counter--; + } + } else { + output.push(value); + } + } + return output; + } + + /** + * Creates a string based on an array of numeric code points. + * @see `punycode.ucs2.decode` + * @memberOf punycode.ucs2 + * @name encode + * @param {Array} codePoints The array of numeric code points. + * @returns {String} The new Unicode string (UCS-2). + */ + function ucs2encode(array) { + return map(array, function(value) { + var output = ''; + if (value > 0xFFFF) { + value -= 0x10000; + output += stringFromCharCode(value >>> 10 & 0x3FF | 0xD800); + value = 0xDC00 | value & 0x3FF; + } + output += stringFromCharCode(value); + return output; + }).join(''); + } + + /** + * Converts a basic code point into a digit/integer. + * @see `digitToBasic()` + * @private + * @param {Number} codePoint The basic numeric code point value. + * @returns {Number} The numeric value of a basic code point (for use in + * representing integers) in the range `0` to `base - 1`, or `base` if + * the code point does not represent a value. + */ + function basicToDigit(codePoint) { + if (codePoint - 48 < 10) { + return codePoint - 22; + } + if (codePoint - 65 < 26) { + return codePoint - 65; + } + if (codePoint - 97 < 26) { + return codePoint - 97; + } + return base; + } + + /** + * Converts a digit/integer into a basic code point. + * @see `basicToDigit()` + * @private + * @param {Number} digit The numeric value of a basic code point. + * @returns {Number} The basic code point whose value (when used for + * representing integers) is `digit`, which needs to be in the range + * `0` to `base - 1`. If `flag` is non-zero, the uppercase form is + * used; else, the lowercase form is used. The behavior is undefined + * if `flag` is non-zero and `digit` has no uppercase form. + */ + function digitToBasic(digit, flag) { + // 0..25 map to ASCII a..z or A..Z + // 26..35 map to ASCII 0..9 + return digit + 22 + 75 * (digit < 26) - ((flag != 0) << 5); + } + + /** + * Bias adaptation function as per section 3.4 of RFC 3492. + * https://tools.ietf.org/html/rfc3492#section-3.4 + * @private + */ + function adapt(delta, numPoints, firstTime) { + var k = 0; + delta = firstTime ? floor(delta / damp) : delta >> 1; + delta += floor(delta / numPoints); + for (/* no initialization */; delta > baseMinusTMin * tMax >> 1; k += base) { + delta = floor(delta / baseMinusTMin); + } + return floor(k + (baseMinusTMin + 1) * delta / (delta + skew)); + } + + /** + * Converts a Punycode string of ASCII-only symbols to a string of Unicode + * symbols. + * @memberOf punycode + * @param {String} input The Punycode string of ASCII-only symbols. + * @returns {String} The resulting string of Unicode symbols. + */ + function decode(input) { + // Don't use UCS-2 + var output = [], + inputLength = input.length, + out, + i = 0, + n = initialN, + bias = initialBias, + basic, + j, + index, + oldi, + w, + k, + digit, + t, + /** Cached calculation results */ + baseMinusT; + + // Handle the basic code points: let `basic` be the number of input code + // points before the last delimiter, or `0` if there is none, then copy + // the first basic code points to the output. + + basic = input.lastIndexOf(delimiter); + if (basic < 0) { + basic = 0; + } + + for (j = 0; j < basic; ++j) { + // if it's not a basic code point + if (input.charCodeAt(j) >= 0x80) { + error('not-basic'); + } + output.push(input.charCodeAt(j)); + } + + // Main decoding loop: start just after the last delimiter if any basic code + // points were copied; start at the beginning otherwise. + + for (index = basic > 0 ? basic + 1 : 0; index < inputLength; /* no final expression */) { + + // `index` is the index of the next character to be consumed. + // Decode a generalized variable-length integer into `delta`, + // which gets added to `i`. The overflow checking is easier + // if we increase `i` as we go, then subtract off its starting + // value at the end to obtain `delta`. + for (oldi = i, w = 1, k = base; /* no condition */; k += base) { + + if (index >= inputLength) { + error('invalid-input'); + } + + digit = basicToDigit(input.charCodeAt(index++)); + + if (digit >= base || digit > floor((maxInt - i) / w)) { + error('overflow'); + } + + i += digit * w; + t = k <= bias ? tMin : (k >= bias + tMax ? tMax : k - bias); + + if (digit < t) { + break; + } + + baseMinusT = base - t; + if (w > floor(maxInt / baseMinusT)) { + error('overflow'); + } + + w *= baseMinusT; + + } + + out = output.length + 1; + bias = adapt(i - oldi, out, oldi == 0); + + // `i` was supposed to wrap around from `out` to `0`, + // incrementing `n` each time, so we'll fix that now: + if (floor(i / out) > maxInt - n) { + error('overflow'); + } + + n += floor(i / out); + i %= out; + + // Insert `n` at position `i` of the output + output.splice(i++, 0, n); + + } + + return ucs2encode(output); + } + + /** + * Converts a string of Unicode symbols (e.g. a domain name label) to a + * Punycode string of ASCII-only symbols. + * @memberOf punycode + * @param {String} input The string of Unicode symbols. + * @returns {String} The resulting Punycode string of ASCII-only symbols. + */ + function encode(input) { + var n, + delta, + handledCPCount, + basicLength, + bias, + j, + m, + q, + k, + t, + currentValue, + output = [], + /** `inputLength` will hold the number of code points in `input`. */ + inputLength, + /** Cached calculation results */ + handledCPCountPlusOne, + baseMinusT, + qMinusT; + + // Convert the input in UCS-2 to Unicode + input = ucs2decode(input); + + // Cache the length + inputLength = input.length; + + // Initialize the state + n = initialN; + delta = 0; + bias = initialBias; + + // Handle the basic code points + for (j = 0; j < inputLength; ++j) { + currentValue = input[j]; + if (currentValue < 0x80) { + output.push(stringFromCharCode(currentValue)); + } + } + + handledCPCount = basicLength = output.length; + + // `handledCPCount` is the number of code points that have been handled; + // `basicLength` is the number of basic code points. + + // Finish the basic string - if it is not empty - with a delimiter + if (basicLength) { + output.push(delimiter); + } + + // Main encoding loop: + while (handledCPCount < inputLength) { + + // All non-basic code points < n have been handled already. Find the next + // larger one: + for (m = maxInt, j = 0; j < inputLength; ++j) { + currentValue = input[j]; + if (currentValue >= n && currentValue < m) { + m = currentValue; + } + } + + // Increase `delta` enough to advance the decoder's state to , + // but guard against overflow + handledCPCountPlusOne = handledCPCount + 1; + if (m - n > floor((maxInt - delta) / handledCPCountPlusOne)) { + error('overflow'); + } + + delta += (m - n) * handledCPCountPlusOne; + n = m; + + for (j = 0; j < inputLength; ++j) { + currentValue = input[j]; + + if (currentValue < n && ++delta > maxInt) { + error('overflow'); + } + + if (currentValue == n) { + // Represent delta as a generalized variable-length integer + for (q = delta, k = base; /* no condition */; k += base) { + t = k <= bias ? tMin : (k >= bias + tMax ? tMax : k - bias); + if (q < t) { + break; + } + qMinusT = q - t; + baseMinusT = base - t; + output.push( + stringFromCharCode(digitToBasic(t + qMinusT % baseMinusT, 0)) + ); + q = floor(qMinusT / baseMinusT); + } + + output.push(stringFromCharCode(digitToBasic(q, 0))); + bias = adapt(delta, handledCPCountPlusOne, handledCPCount == basicLength); + delta = 0; + ++handledCPCount; + } + } + + ++delta; + ++n; + + } + return output.join(''); + } + + /** + * Converts a Punycode string representing a domain name or an email address + * to Unicode. Only the Punycoded parts of the input will be converted, i.e. + * it doesn't matter if you call it on a string that has already been + * converted to Unicode. + * @memberOf punycode + * @param {String} input The Punycoded domain name or email address to + * convert to Unicode. + * @returns {String} The Unicode representation of the given Punycode + * string. + */ + function toUnicode(input) { + return mapDomain(input, function(string) { + return regexPunycode.test(string) + ? decode(string.slice(4).toLowerCase()) + : string; + }); + } + + /** + * Converts a Unicode string representing a domain name or an email address to + * Punycode. Only the non-ASCII parts of the domain name will be converted, + * i.e. it doesn't matter if you call it with a domain that's already in + * ASCII. + * @memberOf punycode + * @param {String} input The domain name or email address to convert, as a + * Unicode string. + * @returns {String} The Punycode representation of the given domain name or + * email address. + */ + function toASCII(input) { + return mapDomain(input, function(string) { + return regexNonASCII.test(string) + ? 'xn--' + encode(string) + : string; + }); + } + + /*--------------------------------------------------------------------------*/ + + /** Define the public API */ + punycode = { + /** + * A string representing the current Punycode.js version number. + * @memberOf punycode + * @type String + */ + 'version': '1.4.1', + /** + * An object of methods to convert from JavaScript's internal character + * representation (UCS-2) to Unicode code points, and back. + * @see + * @memberOf punycode + * @type Object + */ + 'ucs2': { + 'decode': ucs2decode, + 'encode': ucs2encode + }, + 'decode': decode, + 'encode': encode, + 'toASCII': toASCII, + 'toUnicode': toUnicode + }; + + /** Expose `punycode` */ + // Some AMD build optimizers, like r.js, check for specific condition patterns + // like the following: + if ( + typeof define == 'function' && + typeof define.amd == 'object' && + define.amd + ) { + define('punycode', function() { + return punycode; + }); + } else if (freeExports && freeModule) { + if (module.exports == freeExports) { + // in Node.js, io.js, or RingoJS v0.8.0+ + freeModule.exports = punycode; + } else { + // in Narwhal or RingoJS v0.7.0- + for (key in punycode) { + punycode.hasOwnProperty(key) && (freeExports[key] = punycode[key]); + } + } + } else { + // in Rhino or a web browser + root.punycode = punycode; + } + +}(this)); + +}).call(this)}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) +},{}],173:[function(require,module,exports){ +// Copyright Joyent, Inc. and other Node contributors. +// +// 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. + +'use strict'; + +// If obj.hasOwnProperty has been overridden, then calling +// obj.hasOwnProperty(prop) will break. +// See: https://github.com/joyent/node/issues/1707 +function hasOwnProperty(obj, prop) { + return Object.prototype.hasOwnProperty.call(obj, prop); +} + +module.exports = function(qs, sep, eq, options) { + sep = sep || '&'; + eq = eq || '='; + var obj = {}; + + if (typeof qs !== 'string' || qs.length === 0) { + return obj; + } + + var regexp = /\+/g; + qs = qs.split(sep); + + var maxKeys = 1000; + if (options && typeof options.maxKeys === 'number') { + maxKeys = options.maxKeys; + } + + var len = qs.length; + // maxKeys <= 0 means that we should not limit keys count + if (maxKeys > 0 && len > maxKeys) { + len = maxKeys; + } + + for (var i = 0; i < len; ++i) { + var x = qs[i].replace(regexp, '%20'), + idx = x.indexOf(eq), + kstr, vstr, k, v; + + if (idx >= 0) { + kstr = x.substr(0, idx); + vstr = x.substr(idx + 1); + } else { + kstr = x; + vstr = ''; + } + + k = decodeURIComponent(kstr); + v = decodeURIComponent(vstr); + + if (!hasOwnProperty(obj, k)) { + obj[k] = v; + } else if (isArray(obj[k])) { + obj[k].push(v); + } else { + obj[k] = [obj[k], v]; + } + } + + return obj; +}; + +var isArray = Array.isArray || function (xs) { + return Object.prototype.toString.call(xs) === '[object Array]'; +}; + +},{}],174:[function(require,module,exports){ +// Copyright Joyent, Inc. and other Node contributors. +// +// 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. + +'use strict'; + +var stringifyPrimitive = function(v) { + switch (typeof v) { + case 'string': + return v; + + case 'boolean': + return v ? 'true' : 'false'; + + case 'number': + return isFinite(v) ? v : ''; + + default: + return ''; + } +}; + +module.exports = function(obj, sep, eq, name) { + sep = sep || '&'; + eq = eq || '='; + if (obj === null) { + obj = undefined; + } + + if (typeof obj === 'object') { + return map(objectKeys(obj), function(k) { + var ks = encodeURIComponent(stringifyPrimitive(k)) + eq; + if (isArray(obj[k])) { + return map(obj[k], function(v) { + return ks + encodeURIComponent(stringifyPrimitive(v)); + }).join(sep); + } else { + return ks + encodeURIComponent(stringifyPrimitive(obj[k])); + } + }).join(sep); + + } + + if (!name) return ''; + return encodeURIComponent(stringifyPrimitive(name)) + eq + + encodeURIComponent(stringifyPrimitive(obj)); +}; + +var isArray = Array.isArray || function (xs) { + return Object.prototype.toString.call(xs) === '[object Array]'; +}; + +function map (xs, f) { + if (xs.map) return xs.map(f); + var res = []; + for (var i = 0; i < xs.length; i++) { + res.push(f(xs[i], i)); + } + return res; +} + +var objectKeys = Object.keys || function (obj) { + var res = []; + for (var key in obj) { + if (Object.prototype.hasOwnProperty.call(obj, key)) res.push(key); + } + return res; +}; + +},{}],175:[function(require,module,exports){ +'use strict'; + +exports.decode = exports.parse = require('./decode'); +exports.encode = exports.stringify = require('./encode'); + +},{"./decode":173,"./encode":174}],176:[function(require,module,exports){ +(function (process,global){(function (){ +'use strict' + +// limit of Crypto.getRandomValues() +// https://developer.mozilla.org/en-US/docs/Web/API/Crypto/getRandomValues +var MAX_BYTES = 65536 + +// Node supports requesting up to this number of bytes +// https://github.com/nodejs/node/blob/master/lib/internal/crypto/random.js#L48 +var MAX_UINT32 = 4294967295 + +function oldBrowser () { + throw new Error('Secure random number generation is not supported by this browser.\nUse Chrome, Firefox or Internet Explorer 11') +} + +var Buffer = require('safe-buffer').Buffer +var crypto = global.crypto || global.msCrypto + +if (crypto && crypto.getRandomValues) { + module.exports = randomBytes +} else { + module.exports = oldBrowser +} + +function randomBytes (size, cb) { + // phantomjs needs to throw + if (size > MAX_UINT32) throw new RangeError('requested too many random bytes') + + var bytes = Buffer.allocUnsafe(size) + + if (size > 0) { // getRandomValues fails on IE if size == 0 + if (size > MAX_BYTES) { // this is the max bytes crypto.getRandomValues + // can do at once see https://developer.mozilla.org/en-US/docs/Web/API/window.crypto.getRandomValues + for (var generated = 0; generated < size; generated += MAX_BYTES) { + // buffer.slice automatically checks if the end is past the end of + // the buffer so we don't have to here + crypto.getRandomValues(bytes.slice(generated, generated + MAX_BYTES)) + } + } else { + crypto.getRandomValues(bytes) + } + } + + if (typeof cb === 'function') { + return process.nextTick(function () { + cb(null, bytes) + }) + } + + return bytes +} + +}).call(this)}).call(this,require('_process'),typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) +},{"_process":164,"safe-buffer":179}],177:[function(require,module,exports){ +(function (process,global){(function (){ +'use strict' + +function oldBrowser () { + throw new Error('secure random number generation not supported by this browser\nuse chrome, FireFox or Internet Explorer 11') +} +var safeBuffer = require('safe-buffer') +var randombytes = require('randombytes') +var Buffer = safeBuffer.Buffer +var kBufferMaxLength = safeBuffer.kMaxLength +var crypto = global.crypto || global.msCrypto +var kMaxUint32 = Math.pow(2, 32) - 1 +function assertOffset (offset, length) { + if (typeof offset !== 'number' || offset !== offset) { // eslint-disable-line no-self-compare + throw new TypeError('offset must be a number') + } + + if (offset > kMaxUint32 || offset < 0) { + throw new TypeError('offset must be a uint32') + } + + if (offset > kBufferMaxLength || offset > length) { + throw new RangeError('offset out of range') + } +} + +function assertSize (size, offset, length) { + if (typeof size !== 'number' || size !== size) { // eslint-disable-line no-self-compare + throw new TypeError('size must be a number') + } + + if (size > kMaxUint32 || size < 0) { + throw new TypeError('size must be a uint32') + } + + if (size + offset > length || size > kBufferMaxLength) { + throw new RangeError('buffer too small') + } +} +if ((crypto && crypto.getRandomValues) || !process.browser) { + exports.randomFill = randomFill + exports.randomFillSync = randomFillSync +} else { + exports.randomFill = oldBrowser + exports.randomFillSync = oldBrowser +} +function randomFill (buf, offset, size, cb) { + if (!Buffer.isBuffer(buf) && !(buf instanceof global.Uint8Array)) { + throw new TypeError('"buf" argument must be a Buffer or Uint8Array') + } + + if (typeof offset === 'function') { + cb = offset + offset = 0 + size = buf.length + } else if (typeof size === 'function') { + cb = size + size = buf.length - offset + } else if (typeof cb !== 'function') { + throw new TypeError('"cb" argument must be a function') + } + assertOffset(offset, buf.length) + assertSize(size, offset, buf.length) + return actualFill(buf, offset, size, cb) +} + +function actualFill (buf, offset, size, cb) { + if (process.browser) { + var ourBuf = buf.buffer + var uint = new Uint8Array(ourBuf, offset, size) + crypto.getRandomValues(uint) + if (cb) { + process.nextTick(function () { + cb(null, buf) + }) + return + } + return buf + } + if (cb) { + randombytes(size, function (err, bytes) { + if (err) { + return cb(err) + } + bytes.copy(buf, offset) + cb(null, buf) + }) + return + } + var bytes = randombytes(size) + bytes.copy(buf, offset) + return buf +} +function randomFillSync (buf, offset, size) { + if (typeof offset === 'undefined') { + offset = 0 + } + if (!Buffer.isBuffer(buf) && !(buf instanceof global.Uint8Array)) { + throw new TypeError('"buf" argument must be a Buffer or Uint8Array') + } + + assertOffset(offset, buf.length) + + if (size === undefined) size = buf.length - offset + + assertSize(size, offset, buf.length) + + return actualFill(buf, offset, size) +} + +}).call(this)}).call(this,require('_process'),typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) +},{"_process":164,"randombytes":176,"safe-buffer":179}],178:[function(require,module,exports){ +'use strict' +var Buffer = require('buffer').Buffer +var inherits = require('inherits') +var HashBase = require('hash-base') + +var ARRAY16 = new Array(16) + +var zl = [ + 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 zr = [ + 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 sl = [ + 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 sr = [ + 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 +] + +var hl = [0x00000000, 0x5a827999, 0x6ed9eba1, 0x8f1bbcdc, 0xa953fd4e] +var hr = [0x50a28be6, 0x5c4dd124, 0x6d703ef3, 0x7a6d76e9, 0x00000000] + +function RIPEMD160 () { + HashBase.call(this, 64) + + // state + this._a = 0x67452301 + this._b = 0xefcdab89 + this._c = 0x98badcfe + this._d = 0x10325476 + this._e = 0xc3d2e1f0 +} + +inherits(RIPEMD160, HashBase) + +RIPEMD160.prototype._update = function () { + var words = ARRAY16 + for (var j = 0; j < 16; ++j) words[j] = this._block.readInt32LE(j * 4) + + var al = this._a | 0 + var bl = this._b | 0 + var cl = this._c | 0 + var dl = this._d | 0 + var el = this._e | 0 + + var ar = this._a | 0 + var br = this._b | 0 + var cr = this._c | 0 + var dr = this._d | 0 + var er = this._e | 0 + + // computation + for (var i = 0; i < 80; i += 1) { + var tl + var tr + if (i < 16) { + tl = fn1(al, bl, cl, dl, el, words[zl[i]], hl[0], sl[i]) + tr = fn5(ar, br, cr, dr, er, words[zr[i]], hr[0], sr[i]) + } else if (i < 32) { + tl = fn2(al, bl, cl, dl, el, words[zl[i]], hl[1], sl[i]) + tr = fn4(ar, br, cr, dr, er, words[zr[i]], hr[1], sr[i]) + } else if (i < 48) { + tl = fn3(al, bl, cl, dl, el, words[zl[i]], hl[2], sl[i]) + tr = fn3(ar, br, cr, dr, er, words[zr[i]], hr[2], sr[i]) + } else if (i < 64) { + tl = fn4(al, bl, cl, dl, el, words[zl[i]], hl[3], sl[i]) + tr = fn2(ar, br, cr, dr, er, words[zr[i]], hr[3], sr[i]) + } else { // if (i<80) { + tl = fn5(al, bl, cl, dl, el, words[zl[i]], hl[4], sl[i]) + tr = fn1(ar, br, cr, dr, er, words[zr[i]], hr[4], sr[i]) + } + + al = el + el = dl + dl = rotl(cl, 10) + cl = bl + bl = tl + + ar = er + er = dr + dr = rotl(cr, 10) + cr = br + br = tr + } + + // update state + var t = (this._b + cl + dr) | 0 + this._b = (this._c + dl + er) | 0 + this._c = (this._d + el + ar) | 0 + this._d = (this._e + al + br) | 0 + this._e = (this._a + bl + cr) | 0 + this._a = t +} + +RIPEMD160.prototype._digest = function () { + // create padding and handle blocks + this._block[this._blockOffset++] = 0x80 + if (this._blockOffset > 56) { + this._block.fill(0, this._blockOffset, 64) + this._update() + this._blockOffset = 0 + } + + this._block.fill(0, this._blockOffset, 56) + this._block.writeUInt32LE(this._length[0], 56) + this._block.writeUInt32LE(this._length[1], 60) + this._update() + + // produce result + var buffer = Buffer.alloc ? Buffer.alloc(20) : new Buffer(20) + buffer.writeInt32LE(this._a, 0) + buffer.writeInt32LE(this._b, 4) + buffer.writeInt32LE(this._c, 8) + buffer.writeInt32LE(this._d, 12) + buffer.writeInt32LE(this._e, 16) + return buffer +} + +function rotl (x, n) { + return (x << n) | (x >>> (32 - n)) +} + +function fn1 (a, b, c, d, e, m, k, s) { + return (rotl((a + (b ^ c ^ d) + m + k) | 0, s) + e) | 0 +} + +function fn2 (a, b, c, d, e, m, k, s) { + return (rotl((a + ((b & c) | ((~b) & d)) + m + k) | 0, s) + e) | 0 +} + +function fn3 (a, b, c, d, e, m, k, s) { + return (rotl((a + ((b | (~c)) ^ d) + m + k) | 0, s) + e) | 0 +} + +function fn4 (a, b, c, d, e, m, k, s) { + return (rotl((a + ((b & d) | (c & (~d))) + m + k) | 0, s) + e) | 0 +} + +function fn5 (a, b, c, d, e, m, k, s) { + return (rotl((a + (b ^ (c | (~d))) + m + k) | 0, s) + e) | 0 +} + +module.exports = RIPEMD160 + +},{"buffer":64,"hash-base":113,"inherits":143}],179:[function(require,module,exports){ +/*! safe-buffer. MIT License. Feross Aboukhadijeh */ +/* eslint-disable node/no-deprecated-api */ +var buffer = require('buffer') +var Buffer = buffer.Buffer + +// alternative to using Object.keys for old browsers +function copyProps (src, dst) { + for (var key in src) { + dst[key] = src[key] + } +} +if (Buffer.from && Buffer.alloc && Buffer.allocUnsafe && Buffer.allocUnsafeSlow) { + module.exports = buffer +} else { + // Copy properties from require('buffer') + copyProps(buffer, exports) + exports.Buffer = SafeBuffer +} + +function SafeBuffer (arg, encodingOrOffset, length) { + return Buffer(arg, encodingOrOffset, length) +} + +SafeBuffer.prototype = Object.create(Buffer.prototype) + +// Copy static methods from Buffer +copyProps(Buffer, SafeBuffer) + +SafeBuffer.from = function (arg, encodingOrOffset, length) { + if (typeof arg === 'number') { + throw new TypeError('Argument must not be a number') + } + return Buffer(arg, encodingOrOffset, length) +} + +SafeBuffer.alloc = function (size, fill, encoding) { + if (typeof size !== 'number') { + throw new TypeError('Argument must be a number') + } + var buf = Buffer(size) + if (fill !== undefined) { + if (typeof encoding === 'string') { + buf.fill(fill, encoding) + } else { + buf.fill(fill) + } + } else { + buf.fill(0) + } + return buf +} + +SafeBuffer.allocUnsafe = function (size) { + if (typeof size !== 'number') { + throw new TypeError('Argument must be a number') + } + return Buffer(size) +} + +SafeBuffer.allocUnsafeSlow = function (size) { + if (typeof size !== 'number') { + throw new TypeError('Argument must be a number') + } + return buffer.SlowBuffer(size) +} + +},{"buffer":64}],180:[function(require,module,exports){ +(function (process){(function (){ +/* eslint-disable node/no-deprecated-api */ + +'use strict' + +var buffer = require('buffer') +var Buffer = buffer.Buffer + +var safer = {} + +var key + +for (key in buffer) { + if (!buffer.hasOwnProperty(key)) continue + if (key === 'SlowBuffer' || key === 'Buffer') continue + safer[key] = buffer[key] +} + +var Safer = safer.Buffer = {} +for (key in Buffer) { + if (!Buffer.hasOwnProperty(key)) continue + if (key === 'allocUnsafe' || key === 'allocUnsafeSlow') continue + Safer[key] = Buffer[key] +} + +safer.Buffer.prototype = Buffer.prototype + +if (!Safer.from || Safer.from === Uint8Array.from) { + Safer.from = function (value, encodingOrOffset, length) { + if (typeof value === 'number') { + throw new TypeError('The "value" argument must not be of type number. Received type ' + typeof value) + } + if (value && typeof value.length === 'undefined') { + throw new TypeError('The first argument must be one of type string, Buffer, ArrayBuffer, Array, or Array-like Object. Received type ' + typeof value) + } + return Buffer(value, encodingOrOffset, length) + } +} + +if (!Safer.alloc) { + Safer.alloc = function (size, fill, encoding) { + if (typeof size !== 'number') { + throw new TypeError('The "size" argument must be of type number. Received type ' + typeof size) + } + if (size < 0 || size >= 2 * (1 << 30)) { + throw new RangeError('The value "' + size + '" is invalid for option "size"') + } + var buf = Buffer(size) + if (!fill || fill.length === 0) { + buf.fill(0) + } else if (typeof encoding === 'string') { + buf.fill(fill, encoding) + } else { + buf.fill(fill) + } + return buf + } +} + +if (!safer.kStringMaxLength) { + try { + safer.kStringMaxLength = process.binding('buffer').kStringMaxLength + } catch (e) { + // we can't determine kStringMaxLength in environments where process.binding + // is unsupported, so let's not set it + } +} + +if (!safer.constants) { + safer.constants = { + MAX_LENGTH: safer.kMaxLength + } + if (safer.kStringMaxLength) { + safer.constants.MAX_STRING_LENGTH = safer.kStringMaxLength + } +} + +module.exports = safer + +}).call(this)}).call(this,require('_process')) +},{"_process":164,"buffer":64}],181:[function(require,module,exports){ +var Buffer = require('safe-buffer').Buffer + +// prototype class for hash functions +function Hash (blockSize, finalSize) { + this._block = Buffer.alloc(blockSize) + this._finalSize = finalSize + this._blockSize = blockSize + this._len = 0 +} + +Hash.prototype.update = function (data, enc) { + if (typeof data === 'string') { + enc = enc || 'utf8' + data = Buffer.from(data, enc) + } + + var block = this._block + var blockSize = this._blockSize + var length = data.length + var accum = this._len + + for (var offset = 0; offset < length;) { + var assigned = accum % blockSize + var remainder = Math.min(length - offset, blockSize - assigned) + + for (var i = 0; i < remainder; i++) { + block[assigned + i] = data[offset + i] + } + + accum += remainder + offset += remainder + + if ((accum % blockSize) === 0) { + this._update(block) + } + } + + this._len += length + return this +} + +Hash.prototype.digest = function (enc) { + var rem = this._len % this._blockSize + + this._block[rem] = 0x80 + + // zero (rem + 1) trailing bits, where (rem + 1) is the smallest + // non-negative solution to the equation (length + 1 + (rem + 1)) === finalSize mod blockSize + this._block.fill(0, rem + 1) + + if (rem >= this._finalSize) { + this._update(this._block) + this._block.fill(0) + } + + var bits = this._len * 8 + + // uint32 + if (bits <= 0xffffffff) { + this._block.writeUInt32BE(bits, this._blockSize - 4) + + // uint64 + } else { + var lowBits = (bits & 0xffffffff) >>> 0 + var highBits = (bits - lowBits) / 0x100000000 + + this._block.writeUInt32BE(highBits, this._blockSize - 8) + this._block.writeUInt32BE(lowBits, this._blockSize - 4) + } + + this._update(this._block) + var hash = this._hash() + + return enc ? hash.toString(enc) : hash +} + +Hash.prototype._update = function () { + throw new Error('_update must be implemented by subclass') +} + +module.exports = Hash + +},{"safe-buffer":179}],182:[function(require,module,exports){ +var exports = module.exports = function SHA (algorithm) { + algorithm = algorithm.toLowerCase() + + var Algorithm = exports[algorithm] + if (!Algorithm) throw new Error(algorithm + ' is not supported (we accept pull requests)') + + return new Algorithm() +} + +exports.sha = require('./sha') +exports.sha1 = require('./sha1') +exports.sha224 = require('./sha224') +exports.sha256 = require('./sha256') +exports.sha384 = require('./sha384') +exports.sha512 = require('./sha512') + +},{"./sha":183,"./sha1":184,"./sha224":185,"./sha256":186,"./sha384":187,"./sha512":188}],183:[function(require,module,exports){ +/* + * A JavaScript implementation of the Secure Hash Algorithm, SHA-0, as defined + * in FIPS PUB 180-1 + * This source code is derived from sha1.js of the same repository. + * The difference between SHA-0 and SHA-1 is just a bitwise rotate left + * operation was added. + */ + +var inherits = require('inherits') +var Hash = require('./hash') +var Buffer = require('safe-buffer').Buffer + +var K = [ + 0x5a827999, 0x6ed9eba1, 0x8f1bbcdc | 0, 0xca62c1d6 | 0 +] + +var W = new Array(80) + +function Sha () { + this.init() + this._w = W + + Hash.call(this, 64, 56) +} + +inherits(Sha, Hash) + +Sha.prototype.init = function () { + this._a = 0x67452301 + this._b = 0xefcdab89 + this._c = 0x98badcfe + this._d = 0x10325476 + this._e = 0xc3d2e1f0 + + return this +} + +function rotl5 (num) { + return (num << 5) | (num >>> 27) +} + +function rotl30 (num) { + return (num << 30) | (num >>> 2) +} + +function ft (s, b, c, d) { + if (s === 0) return (b & c) | ((~b) & d) + if (s === 2) return (b & c) | (b & d) | (c & d) + return b ^ c ^ d +} + +Sha.prototype._update = function (M) { + var W = this._w + + var a = this._a | 0 + var b = this._b | 0 + var c = this._c | 0 + var d = this._d | 0 + var e = this._e | 0 + + for (var i = 0; i < 16; ++i) W[i] = M.readInt32BE(i * 4) + for (; i < 80; ++i) W[i] = W[i - 3] ^ W[i - 8] ^ W[i - 14] ^ W[i - 16] + + for (var j = 0; j < 80; ++j) { + var s = ~~(j / 20) + var t = (rotl5(a) + ft(s, b, c, d) + e + W[j] + K[s]) | 0 + + e = d + d = c + c = rotl30(b) + b = a + a = t + } + + this._a = (a + this._a) | 0 + this._b = (b + this._b) | 0 + this._c = (c + this._c) | 0 + this._d = (d + this._d) | 0 + this._e = (e + this._e) | 0 +} + +Sha.prototype._hash = function () { + var H = Buffer.allocUnsafe(20) + + H.writeInt32BE(this._a | 0, 0) + H.writeInt32BE(this._b | 0, 4) + H.writeInt32BE(this._c | 0, 8) + H.writeInt32BE(this._d | 0, 12) + H.writeInt32BE(this._e | 0, 16) + + return H +} + +module.exports = Sha + +},{"./hash":181,"inherits":143,"safe-buffer":179}],184:[function(require,module,exports){ +/* + * A JavaScript implementation of the Secure Hash Algorithm, SHA-1, as defined + * in FIPS PUB 180-1 + * Version 2.1a Copyright Paul Johnston 2000 - 2002. + * Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet + * Distributed under the BSD License + * See http://pajhome.org.uk/crypt/md5 for details. + */ + +var inherits = require('inherits') +var Hash = require('./hash') +var Buffer = require('safe-buffer').Buffer + +var K = [ + 0x5a827999, 0x6ed9eba1, 0x8f1bbcdc | 0, 0xca62c1d6 | 0 +] + +var W = new Array(80) + +function Sha1 () { + this.init() + this._w = W + + Hash.call(this, 64, 56) +} + +inherits(Sha1, Hash) + +Sha1.prototype.init = function () { + this._a = 0x67452301 + this._b = 0xefcdab89 + this._c = 0x98badcfe + this._d = 0x10325476 + this._e = 0xc3d2e1f0 + + return this +} + +function rotl1 (num) { + return (num << 1) | (num >>> 31) +} + +function rotl5 (num) { + return (num << 5) | (num >>> 27) +} + +function rotl30 (num) { + return (num << 30) | (num >>> 2) +} + +function ft (s, b, c, d) { + if (s === 0) return (b & c) | ((~b) & d) + if (s === 2) return (b & c) | (b & d) | (c & d) + return b ^ c ^ d +} + +Sha1.prototype._update = function (M) { + var W = this._w + + var a = this._a | 0 + var b = this._b | 0 + var c = this._c | 0 + var d = this._d | 0 + var e = this._e | 0 + + for (var i = 0; i < 16; ++i) W[i] = M.readInt32BE(i * 4) + for (; i < 80; ++i) W[i] = rotl1(W[i - 3] ^ W[i - 8] ^ W[i - 14] ^ W[i - 16]) + + for (var j = 0; j < 80; ++j) { + var s = ~~(j / 20) + var t = (rotl5(a) + ft(s, b, c, d) + e + W[j] + K[s]) | 0 + + e = d + d = c + c = rotl30(b) + b = a + a = t + } + + this._a = (a + this._a) | 0 + this._b = (b + this._b) | 0 + this._c = (c + this._c) | 0 + this._d = (d + this._d) | 0 + this._e = (e + this._e) | 0 +} + +Sha1.prototype._hash = function () { + var H = Buffer.allocUnsafe(20) + + H.writeInt32BE(this._a | 0, 0) + H.writeInt32BE(this._b | 0, 4) + H.writeInt32BE(this._c | 0, 8) + H.writeInt32BE(this._d | 0, 12) + H.writeInt32BE(this._e | 0, 16) + + return H +} + +module.exports = Sha1 + +},{"./hash":181,"inherits":143,"safe-buffer":179}],185:[function(require,module,exports){ +/** + * A JavaScript implementation of the Secure Hash Algorithm, SHA-256, as defined + * in FIPS 180-2 + * Version 2.2-beta Copyright Angel Marin, Paul Johnston 2000 - 2009. + * Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet + * + */ + +var inherits = require('inherits') +var Sha256 = require('./sha256') +var Hash = require('./hash') +var Buffer = require('safe-buffer').Buffer + +var W = new Array(64) + +function Sha224 () { + this.init() + + this._w = W // new Array(64) + + Hash.call(this, 64, 56) +} + +inherits(Sha224, Sha256) + +Sha224.prototype.init = function () { + this._a = 0xc1059ed8 + this._b = 0x367cd507 + this._c = 0x3070dd17 + this._d = 0xf70e5939 + this._e = 0xffc00b31 + this._f = 0x68581511 + this._g = 0x64f98fa7 + this._h = 0xbefa4fa4 + + return this +} + +Sha224.prototype._hash = function () { + var H = Buffer.allocUnsafe(28) + + H.writeInt32BE(this._a, 0) + H.writeInt32BE(this._b, 4) + H.writeInt32BE(this._c, 8) + H.writeInt32BE(this._d, 12) + H.writeInt32BE(this._e, 16) + H.writeInt32BE(this._f, 20) + H.writeInt32BE(this._g, 24) + + return H +} + +module.exports = Sha224 + +},{"./hash":181,"./sha256":186,"inherits":143,"safe-buffer":179}],186:[function(require,module,exports){ +/** + * A JavaScript implementation of the Secure Hash Algorithm, SHA-256, as defined + * in FIPS 180-2 + * Version 2.2-beta Copyright Angel Marin, Paul Johnston 2000 - 2009. + * Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet + * + */ + +var inherits = require('inherits') +var Hash = require('./hash') +var Buffer = require('safe-buffer').Buffer + +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 +] + +var W = new Array(64) + +function Sha256 () { + this.init() + + this._w = W // new Array(64) + + Hash.call(this, 64, 56) +} + +inherits(Sha256, Hash) + +Sha256.prototype.init = function () { + this._a = 0x6a09e667 + this._b = 0xbb67ae85 + this._c = 0x3c6ef372 + this._d = 0xa54ff53a + this._e = 0x510e527f + this._f = 0x9b05688c + this._g = 0x1f83d9ab + this._h = 0x5be0cd19 + + return this +} + +function ch (x, y, z) { + return z ^ (x & (y ^ z)) +} + +function maj (x, y, z) { + return (x & y) | (z & (x | y)) +} + +function sigma0 (x) { + return (x >>> 2 | x << 30) ^ (x >>> 13 | x << 19) ^ (x >>> 22 | x << 10) +} + +function sigma1 (x) { + return (x >>> 6 | x << 26) ^ (x >>> 11 | x << 21) ^ (x >>> 25 | x << 7) +} + +function gamma0 (x) { + return (x >>> 7 | x << 25) ^ (x >>> 18 | x << 14) ^ (x >>> 3) +} + +function gamma1 (x) { + return (x >>> 17 | x << 15) ^ (x >>> 19 | x << 13) ^ (x >>> 10) +} + +Sha256.prototype._update = function (M) { + var W = this._w + + var a = this._a | 0 + var b = this._b | 0 + var c = this._c | 0 + var d = this._d | 0 + var e = this._e | 0 + var f = this._f | 0 + var g = this._g | 0 + var h = this._h | 0 + + for (var i = 0; i < 16; ++i) W[i] = M.readInt32BE(i * 4) + for (; i < 64; ++i) W[i] = (gamma1(W[i - 2]) + W[i - 7] + gamma0(W[i - 15]) + W[i - 16]) | 0 + + for (var j = 0; j < 64; ++j) { + var T1 = (h + sigma1(e) + ch(e, f, g) + K[j] + W[j]) | 0 + var T2 = (sigma0(a) + maj(a, b, c)) | 0 + + h = g + g = f + f = e + e = (d + T1) | 0 + d = c + c = b + b = a + a = (T1 + T2) | 0 + } + + this._a = (a + this._a) | 0 + this._b = (b + this._b) | 0 + this._c = (c + this._c) | 0 + this._d = (d + this._d) | 0 + this._e = (e + this._e) | 0 + this._f = (f + this._f) | 0 + this._g = (g + this._g) | 0 + this._h = (h + this._h) | 0 +} + +Sha256.prototype._hash = function () { + var H = Buffer.allocUnsafe(32) + + H.writeInt32BE(this._a, 0) + H.writeInt32BE(this._b, 4) + H.writeInt32BE(this._c, 8) + H.writeInt32BE(this._d, 12) + H.writeInt32BE(this._e, 16) + H.writeInt32BE(this._f, 20) + H.writeInt32BE(this._g, 24) + H.writeInt32BE(this._h, 28) + + return H +} + +module.exports = Sha256 + +},{"./hash":181,"inherits":143,"safe-buffer":179}],187:[function(require,module,exports){ +var inherits = require('inherits') +var SHA512 = require('./sha512') +var Hash = require('./hash') +var Buffer = require('safe-buffer').Buffer + +var W = new Array(160) + +function Sha384 () { + this.init() + this._w = W + + Hash.call(this, 128, 112) +} + +inherits(Sha384, SHA512) + +Sha384.prototype.init = function () { + this._ah = 0xcbbb9d5d + this._bh = 0x629a292a + this._ch = 0x9159015a + this._dh = 0x152fecd8 + this._eh = 0x67332667 + this._fh = 0x8eb44a87 + this._gh = 0xdb0c2e0d + this._hh = 0x47b5481d + + this._al = 0xc1059ed8 + this._bl = 0x367cd507 + this._cl = 0x3070dd17 + this._dl = 0xf70e5939 + this._el = 0xffc00b31 + this._fl = 0x68581511 + this._gl = 0x64f98fa7 + this._hl = 0xbefa4fa4 + + return this +} + +Sha384.prototype._hash = function () { + var H = Buffer.allocUnsafe(48) + + function writeInt64BE (h, l, offset) { + H.writeInt32BE(h, offset) + H.writeInt32BE(l, offset + 4) + } + + writeInt64BE(this._ah, this._al, 0) + writeInt64BE(this._bh, this._bl, 8) + writeInt64BE(this._ch, this._cl, 16) + writeInt64BE(this._dh, this._dl, 24) + writeInt64BE(this._eh, this._el, 32) + writeInt64BE(this._fh, this._fl, 40) + + return H +} + +module.exports = Sha384 + +},{"./hash":181,"./sha512":188,"inherits":143,"safe-buffer":179}],188:[function(require,module,exports){ +var inherits = require('inherits') +var Hash = require('./hash') +var Buffer = require('safe-buffer').Buffer + +var K = [ + 0x428a2f98, 0xd728ae22, 0x71374491, 0x23ef65cd, + 0xb5c0fbcf, 0xec4d3b2f, 0xe9b5dba5, 0x8189dbbc, + 0x3956c25b, 0xf348b538, 0x59f111f1, 0xb605d019, + 0x923f82a4, 0xaf194f9b, 0xab1c5ed5, 0xda6d8118, + 0xd807aa98, 0xa3030242, 0x12835b01, 0x45706fbe, + 0x243185be, 0x4ee4b28c, 0x550c7dc3, 0xd5ffb4e2, + 0x72be5d74, 0xf27b896f, 0x80deb1fe, 0x3b1696b1, + 0x9bdc06a7, 0x25c71235, 0xc19bf174, 0xcf692694, + 0xe49b69c1, 0x9ef14ad2, 0xefbe4786, 0x384f25e3, + 0x0fc19dc6, 0x8b8cd5b5, 0x240ca1cc, 0x77ac9c65, + 0x2de92c6f, 0x592b0275, 0x4a7484aa, 0x6ea6e483, + 0x5cb0a9dc, 0xbd41fbd4, 0x76f988da, 0x831153b5, + 0x983e5152, 0xee66dfab, 0xa831c66d, 0x2db43210, + 0xb00327c8, 0x98fb213f, 0xbf597fc7, 0xbeef0ee4, + 0xc6e00bf3, 0x3da88fc2, 0xd5a79147, 0x930aa725, + 0x06ca6351, 0xe003826f, 0x14292967, 0x0a0e6e70, + 0x27b70a85, 0x46d22ffc, 0x2e1b2138, 0x5c26c926, + 0x4d2c6dfc, 0x5ac42aed, 0x53380d13, 0x9d95b3df, + 0x650a7354, 0x8baf63de, 0x766a0abb, 0x3c77b2a8, + 0x81c2c92e, 0x47edaee6, 0x92722c85, 0x1482353b, + 0xa2bfe8a1, 0x4cf10364, 0xa81a664b, 0xbc423001, + 0xc24b8b70, 0xd0f89791, 0xc76c51a3, 0x0654be30, + 0xd192e819, 0xd6ef5218, 0xd6990624, 0x5565a910, + 0xf40e3585, 0x5771202a, 0x106aa070, 0x32bbd1b8, + 0x19a4c116, 0xb8d2d0c8, 0x1e376c08, 0x5141ab53, + 0x2748774c, 0xdf8eeb99, 0x34b0bcb5, 0xe19b48a8, + 0x391c0cb3, 0xc5c95a63, 0x4ed8aa4a, 0xe3418acb, + 0x5b9cca4f, 0x7763e373, 0x682e6ff3, 0xd6b2b8a3, + 0x748f82ee, 0x5defb2fc, 0x78a5636f, 0x43172f60, + 0x84c87814, 0xa1f0ab72, 0x8cc70208, 0x1a6439ec, + 0x90befffa, 0x23631e28, 0xa4506ceb, 0xde82bde9, + 0xbef9a3f7, 0xb2c67915, 0xc67178f2, 0xe372532b, + 0xca273ece, 0xea26619c, 0xd186b8c7, 0x21c0c207, + 0xeada7dd6, 0xcde0eb1e, 0xf57d4f7f, 0xee6ed178, + 0x06f067aa, 0x72176fba, 0x0a637dc5, 0xa2c898a6, + 0x113f9804, 0xbef90dae, 0x1b710b35, 0x131c471b, + 0x28db77f5, 0x23047d84, 0x32caab7b, 0x40c72493, + 0x3c9ebe0a, 0x15c9bebc, 0x431d67c4, 0x9c100d4c, + 0x4cc5d4be, 0xcb3e42b6, 0x597f299c, 0xfc657e2a, + 0x5fcb6fab, 0x3ad6faec, 0x6c44198c, 0x4a475817 +] + +var W = new Array(160) + +function Sha512 () { + this.init() + this._w = W + + Hash.call(this, 128, 112) +} + +inherits(Sha512, Hash) + +Sha512.prototype.init = function () { + this._ah = 0x6a09e667 + this._bh = 0xbb67ae85 + this._ch = 0x3c6ef372 + this._dh = 0xa54ff53a + this._eh = 0x510e527f + this._fh = 0x9b05688c + this._gh = 0x1f83d9ab + this._hh = 0x5be0cd19 + + this._al = 0xf3bcc908 + this._bl = 0x84caa73b + this._cl = 0xfe94f82b + this._dl = 0x5f1d36f1 + this._el = 0xade682d1 + this._fl = 0x2b3e6c1f + this._gl = 0xfb41bd6b + this._hl = 0x137e2179 + + return this +} + +function Ch (x, y, z) { + return z ^ (x & (y ^ z)) +} + +function maj (x, y, z) { + return (x & y) | (z & (x | y)) +} + +function sigma0 (x, xl) { + return (x >>> 28 | xl << 4) ^ (xl >>> 2 | x << 30) ^ (xl >>> 7 | x << 25) +} + +function sigma1 (x, xl) { + return (x >>> 14 | xl << 18) ^ (x >>> 18 | xl << 14) ^ (xl >>> 9 | x << 23) +} + +function Gamma0 (x, xl) { + return (x >>> 1 | xl << 31) ^ (x >>> 8 | xl << 24) ^ (x >>> 7) +} + +function Gamma0l (x, xl) { + return (x >>> 1 | xl << 31) ^ (x >>> 8 | xl << 24) ^ (x >>> 7 | xl << 25) +} + +function Gamma1 (x, xl) { + return (x >>> 19 | xl << 13) ^ (xl >>> 29 | x << 3) ^ (x >>> 6) +} + +function Gamma1l (x, xl) { + return (x >>> 19 | xl << 13) ^ (xl >>> 29 | x << 3) ^ (x >>> 6 | xl << 26) +} + +function getCarry (a, b) { + return (a >>> 0) < (b >>> 0) ? 1 : 0 +} + +Sha512.prototype._update = function (M) { + var W = this._w + + var ah = this._ah | 0 + var bh = this._bh | 0 + var ch = this._ch | 0 + var dh = this._dh | 0 + var eh = this._eh | 0 + var fh = this._fh | 0 + var gh = this._gh | 0 + var hh = this._hh | 0 + + var al = this._al | 0 + var bl = this._bl | 0 + var cl = this._cl | 0 + var dl = this._dl | 0 + var el = this._el | 0 + var fl = this._fl | 0 + var gl = this._gl | 0 + var hl = this._hl | 0 + + for (var i = 0; i < 32; i += 2) { + W[i] = M.readInt32BE(i * 4) + W[i + 1] = M.readInt32BE(i * 4 + 4) + } + for (; i < 160; i += 2) { + var xh = W[i - 15 * 2] + var xl = W[i - 15 * 2 + 1] + var gamma0 = Gamma0(xh, xl) + var gamma0l = Gamma0l(xl, xh) + + xh = W[i - 2 * 2] + xl = W[i - 2 * 2 + 1] + var gamma1 = Gamma1(xh, xl) + var gamma1l = Gamma1l(xl, xh) + + // W[i] = gamma0 + W[i - 7] + gamma1 + W[i - 16] + var Wi7h = W[i - 7 * 2] + var Wi7l = W[i - 7 * 2 + 1] + + var Wi16h = W[i - 16 * 2] + var Wi16l = W[i - 16 * 2 + 1] + + var Wil = (gamma0l + Wi7l) | 0 + var Wih = (gamma0 + Wi7h + getCarry(Wil, gamma0l)) | 0 + Wil = (Wil + gamma1l) | 0 + Wih = (Wih + gamma1 + getCarry(Wil, gamma1l)) | 0 + Wil = (Wil + Wi16l) | 0 + Wih = (Wih + Wi16h + getCarry(Wil, Wi16l)) | 0 + + W[i] = Wih + W[i + 1] = Wil + } + + for (var j = 0; j < 160; j += 2) { + Wih = W[j] + Wil = W[j + 1] + + var majh = maj(ah, bh, ch) + var majl = maj(al, bl, cl) + + var sigma0h = sigma0(ah, al) + var sigma0l = sigma0(al, ah) + var sigma1h = sigma1(eh, el) + var sigma1l = sigma1(el, eh) + + // t1 = h + sigma1 + ch + K[j] + W[j] + var Kih = K[j] + var Kil = K[j + 1] + + var chh = Ch(eh, fh, gh) + var chl = Ch(el, fl, gl) + + var t1l = (hl + sigma1l) | 0 + var t1h = (hh + sigma1h + getCarry(t1l, hl)) | 0 + t1l = (t1l + chl) | 0 + t1h = (t1h + chh + getCarry(t1l, chl)) | 0 + t1l = (t1l + Kil) | 0 + t1h = (t1h + Kih + getCarry(t1l, Kil)) | 0 + t1l = (t1l + Wil) | 0 + t1h = (t1h + Wih + getCarry(t1l, Wil)) | 0 + + // t2 = sigma0 + maj + var t2l = (sigma0l + majl) | 0 + var t2h = (sigma0h + majh + getCarry(t2l, sigma0l)) | 0 + + hh = gh + hl = gl + gh = fh + gl = fl + fh = eh + fl = el + el = (dl + t1l) | 0 + eh = (dh + t1h + getCarry(el, dl)) | 0 + dh = ch + dl = cl + ch = bh + cl = bl + bh = ah + bl = al + al = (t1l + t2l) | 0 + ah = (t1h + t2h + getCarry(al, t1l)) | 0 + } + + this._al = (this._al + al) | 0 + this._bl = (this._bl + bl) | 0 + this._cl = (this._cl + cl) | 0 + this._dl = (this._dl + dl) | 0 + this._el = (this._el + el) | 0 + this._fl = (this._fl + fl) | 0 + this._gl = (this._gl + gl) | 0 + this._hl = (this._hl + hl) | 0 + + this._ah = (this._ah + ah + getCarry(this._al, al)) | 0 + this._bh = (this._bh + bh + getCarry(this._bl, bl)) | 0 + this._ch = (this._ch + ch + getCarry(this._cl, cl)) | 0 + this._dh = (this._dh + dh + getCarry(this._dl, dl)) | 0 + this._eh = (this._eh + eh + getCarry(this._el, el)) | 0 + this._fh = (this._fh + fh + getCarry(this._fl, fl)) | 0 + this._gh = (this._gh + gh + getCarry(this._gl, gl)) | 0 + this._hh = (this._hh + hh + getCarry(this._hl, hl)) | 0 +} + +Sha512.prototype._hash = function () { + var H = Buffer.allocUnsafe(64) + + function writeInt64BE (h, l, offset) { + H.writeInt32BE(h, offset) + H.writeInt32BE(l, offset + 4) + } + + writeInt64BE(this._ah, this._al, 0) + writeInt64BE(this._bh, this._bl, 8) + writeInt64BE(this._ch, this._cl, 16) + writeInt64BE(this._dh, this._dl, 24) + writeInt64BE(this._eh, this._el, 32) + writeInt64BE(this._fh, this._fl, 40) + writeInt64BE(this._gh, this._gl, 48) + writeInt64BE(this._hh, this._hl, 56) + + return H +} + +module.exports = Sha512 + +},{"./hash":181,"inherits":143,"safe-buffer":179}],189:[function(require,module,exports){ +// Copyright Joyent, Inc. and other Node contributors. +// +// 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. + +module.exports = Stream; + +var EE = require('events').EventEmitter; +var inherits = require('inherits'); + +inherits(Stream, EE); +Stream.Readable = require('readable-stream/lib/_stream_readable.js'); +Stream.Writable = require('readable-stream/lib/_stream_writable.js'); +Stream.Duplex = require('readable-stream/lib/_stream_duplex.js'); +Stream.Transform = require('readable-stream/lib/_stream_transform.js'); +Stream.PassThrough = require('readable-stream/lib/_stream_passthrough.js'); +Stream.finished = require('readable-stream/lib/internal/streams/end-of-stream.js') +Stream.pipeline = require('readable-stream/lib/internal/streams/pipeline.js') + +// Backwards-compat with node 0.4.x +Stream.Stream = Stream; + + + +// old-style streams. Note that the pipe method (the only relevant +// part of this class) is overridden in the Readable class. + +function Stream() { + EE.call(this); +} + +Stream.prototype.pipe = function(dest, options) { + var source = this; + + function ondata(chunk) { + if (dest.writable) { + if (false === dest.write(chunk) && source.pause) { + source.pause(); + } + } + } + + source.on('data', ondata); + + function ondrain() { + if (source.readable && source.resume) { + source.resume(); + } + } + + dest.on('drain', ondrain); + + // If the 'end' option is not supplied, dest.end() will be called when + // source gets the 'end' or 'close' events. Only dest.end() once. + if (!dest._isStdio && (!options || options.end !== false)) { + source.on('end', onend); + source.on('close', onclose); + } + + var didOnEnd = false; + function onend() { + if (didOnEnd) return; + didOnEnd = true; + + dest.end(); + } + + + function onclose() { + if (didOnEnd) return; + didOnEnd = true; + + if (typeof dest.destroy === 'function') dest.destroy(); + } + + // don't leave dangling pipes when there are errors. + function onerror(er) { + cleanup(); + if (EE.listenerCount(this, 'error') === 0) { + throw er; // Unhandled stream error in pipe. + } + } + + source.on('error', onerror); + dest.on('error', onerror); + + // remove all the event listeners that were added. + function cleanup() { + source.removeListener('data', ondata); + dest.removeListener('drain', ondrain); + + source.removeListener('end', onend); + source.removeListener('close', onclose); + + source.removeListener('error', onerror); + dest.removeListener('error', onerror); + + source.removeListener('end', cleanup); + source.removeListener('close', cleanup); + + dest.removeListener('close', cleanup); + } + + source.on('end', cleanup); + source.on('close', cleanup); + + dest.on('close', cleanup); + + dest.emit('pipe', source); + + // Allow for unix-like usage: A.pipe(B).pipe(C) + return dest; +}; + +},{"events":104,"inherits":143,"readable-stream/lib/_stream_duplex.js":191,"readable-stream/lib/_stream_passthrough.js":192,"readable-stream/lib/_stream_readable.js":193,"readable-stream/lib/_stream_transform.js":194,"readable-stream/lib/_stream_writable.js":195,"readable-stream/lib/internal/streams/end-of-stream.js":199,"readable-stream/lib/internal/streams/pipeline.js":201}],190:[function(require,module,exports){ +arguments[4][48][0].apply(exports,arguments) +},{"dup":48}],191:[function(require,module,exports){ +arguments[4][49][0].apply(exports,arguments) +},{"./_stream_readable":193,"./_stream_writable":195,"_process":164,"dup":49,"inherits":143}],192:[function(require,module,exports){ +arguments[4][50][0].apply(exports,arguments) +},{"./_stream_transform":194,"dup":50,"inherits":143}],193:[function(require,module,exports){ +arguments[4][51][0].apply(exports,arguments) +},{"../errors":190,"./_stream_duplex":191,"./internal/streams/async_iterator":196,"./internal/streams/buffer_list":197,"./internal/streams/destroy":198,"./internal/streams/from":200,"./internal/streams/state":202,"./internal/streams/stream":203,"_process":164,"buffer":64,"dup":51,"events":104,"inherits":143,"string_decoder/":204,"util":20}],194:[function(require,module,exports){ +arguments[4][52][0].apply(exports,arguments) +},{"../errors":190,"./_stream_duplex":191,"dup":52,"inherits":143}],195:[function(require,module,exports){ +arguments[4][53][0].apply(exports,arguments) +},{"../errors":190,"./_stream_duplex":191,"./internal/streams/destroy":198,"./internal/streams/state":202,"./internal/streams/stream":203,"_process":164,"buffer":64,"dup":53,"inherits":143,"util-deprecate":207}],196:[function(require,module,exports){ +arguments[4][54][0].apply(exports,arguments) +},{"./end-of-stream":199,"_process":164,"dup":54}],197:[function(require,module,exports){ +arguments[4][55][0].apply(exports,arguments) +},{"buffer":64,"dup":55,"util":20}],198:[function(require,module,exports){ +arguments[4][56][0].apply(exports,arguments) +},{"_process":164,"dup":56}],199:[function(require,module,exports){ +arguments[4][57][0].apply(exports,arguments) +},{"../../../errors":190,"dup":57}],200:[function(require,module,exports){ +arguments[4][58][0].apply(exports,arguments) +},{"dup":58}],201:[function(require,module,exports){ +arguments[4][59][0].apply(exports,arguments) +},{"../../../errors":190,"./end-of-stream":199,"dup":59}],202:[function(require,module,exports){ +arguments[4][60][0].apply(exports,arguments) +},{"../../../errors":190,"dup":60}],203:[function(require,module,exports){ +arguments[4][61][0].apply(exports,arguments) +},{"dup":61,"events":104}],204:[function(require,module,exports){ +// Copyright Joyent, Inc. and other Node contributors. +// +// 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. + +'use strict'; + +/**/ + +var Buffer = require('safe-buffer').Buffer; +/**/ + +var isEncoding = Buffer.isEncoding || function (encoding) { + encoding = '' + encoding; + switch (encoding && encoding.toLowerCase()) { + case 'hex':case 'utf8':case 'utf-8':case 'ascii':case 'binary':case 'base64':case 'ucs2':case 'ucs-2':case 'utf16le':case 'utf-16le':case 'raw': + return true; + default: + return false; + } +}; + +function _normalizeEncoding(enc) { + if (!enc) return 'utf8'; + var retried; + while (true) { + switch (enc) { + case 'utf8': + case 'utf-8': + return 'utf8'; + case 'ucs2': + case 'ucs-2': + case 'utf16le': + case 'utf-16le': + return 'utf16le'; + case 'latin1': + case 'binary': + return 'latin1'; + case 'base64': + case 'ascii': + case 'hex': + return enc; + default: + if (retried) return; // undefined + enc = ('' + enc).toLowerCase(); + retried = true; + } + } +}; + +// Do not cache `Buffer.isEncoding` when checking encoding names as some +// modules monkey-patch it to support additional encodings +function normalizeEncoding(enc) { + var nenc = _normalizeEncoding(enc); + if (typeof nenc !== 'string' && (Buffer.isEncoding === isEncoding || !isEncoding(enc))) throw new Error('Unknown encoding: ' + enc); + return nenc || enc; +} + +// StringDecoder provides an interface for efficiently splitting a series of +// buffers into a series of JS strings without breaking apart multi-byte +// characters. +exports.StringDecoder = StringDecoder; +function StringDecoder(encoding) { + this.encoding = normalizeEncoding(encoding); + var nb; + switch (this.encoding) { + case 'utf16le': + this.text = utf16Text; + this.end = utf16End; + nb = 4; + break; + case 'utf8': + this.fillLast = utf8FillLast; + nb = 4; + break; + case 'base64': + this.text = base64Text; + this.end = base64End; + nb = 3; + break; + default: + this.write = simpleWrite; + this.end = simpleEnd; + return; + } + this.lastNeed = 0; + this.lastTotal = 0; + this.lastChar = Buffer.allocUnsafe(nb); +} + +StringDecoder.prototype.write = function (buf) { + if (buf.length === 0) return ''; + var r; + var i; + if (this.lastNeed) { + r = this.fillLast(buf); + if (r === undefined) return ''; + i = this.lastNeed; + this.lastNeed = 0; + } else { + i = 0; + } + if (i < buf.length) return r ? r + this.text(buf, i) : this.text(buf, i); + return r || ''; +}; + +StringDecoder.prototype.end = utf8End; + +// Returns only complete characters in a Buffer +StringDecoder.prototype.text = utf8Text; + +// Attempts to complete a partial non-UTF-8 character using bytes from a Buffer +StringDecoder.prototype.fillLast = function (buf) { + if (this.lastNeed <= buf.length) { + buf.copy(this.lastChar, this.lastTotal - this.lastNeed, 0, this.lastNeed); + return this.lastChar.toString(this.encoding, 0, this.lastTotal); + } + buf.copy(this.lastChar, this.lastTotal - this.lastNeed, 0, buf.length); + this.lastNeed -= buf.length; +}; + +// Checks the type of a UTF-8 byte, whether it's ASCII, a leading byte, or a +// continuation byte. If an invalid byte is detected, -2 is returned. +function utf8CheckByte(byte) { + if (byte <= 0x7F) return 0;else if (byte >> 5 === 0x06) return 2;else if (byte >> 4 === 0x0E) return 3;else if (byte >> 3 === 0x1E) return 4; + return byte >> 6 === 0x02 ? -1 : -2; +} + +// Checks at most 3 bytes at the end of a Buffer in order to detect an +// incomplete multi-byte UTF-8 character. The total number of bytes (2, 3, or 4) +// needed to complete the UTF-8 character (if applicable) are returned. +function utf8CheckIncomplete(self, buf, i) { + var j = buf.length - 1; + if (j < i) return 0; + var nb = utf8CheckByte(buf[j]); + if (nb >= 0) { + if (nb > 0) self.lastNeed = nb - 1; + return nb; + } + if (--j < i || nb === -2) return 0; + nb = utf8CheckByte(buf[j]); + if (nb >= 0) { + if (nb > 0) self.lastNeed = nb - 2; + return nb; + } + if (--j < i || nb === -2) return 0; + nb = utf8CheckByte(buf[j]); + if (nb >= 0) { + if (nb > 0) { + if (nb === 2) nb = 0;else self.lastNeed = nb - 3; + } + return nb; + } + return 0; +} + +// Validates as many continuation bytes for a multi-byte UTF-8 character as +// needed or are available. If we see a non-continuation byte where we expect +// one, we "replace" the validated continuation bytes we've seen so far with +// a single UTF-8 replacement character ('\ufffd'), to match v8's UTF-8 decoding +// behavior. The continuation byte check is included three times in the case +// where all of the continuation bytes for a character exist in the same buffer. +// It is also done this way as a slight performance increase instead of using a +// loop. +function utf8CheckExtraBytes(self, buf, p) { + if ((buf[0] & 0xC0) !== 0x80) { + self.lastNeed = 0; + return '\ufffd'; + } + if (self.lastNeed > 1 && buf.length > 1) { + if ((buf[1] & 0xC0) !== 0x80) { + self.lastNeed = 1; + return '\ufffd'; + } + if (self.lastNeed > 2 && buf.length > 2) { + if ((buf[2] & 0xC0) !== 0x80) { + self.lastNeed = 2; + return '\ufffd'; + } + } + } +} + +// Attempts to complete a multi-byte UTF-8 character using bytes from a Buffer. +function utf8FillLast(buf) { + var p = this.lastTotal - this.lastNeed; + var r = utf8CheckExtraBytes(this, buf, p); + if (r !== undefined) return r; + if (this.lastNeed <= buf.length) { + buf.copy(this.lastChar, p, 0, this.lastNeed); + return this.lastChar.toString(this.encoding, 0, this.lastTotal); + } + buf.copy(this.lastChar, p, 0, buf.length); + this.lastNeed -= buf.length; +} + +// Returns all complete UTF-8 characters in a Buffer. If the Buffer ended on a +// partial character, the character's bytes are buffered until the required +// number of bytes are available. +function utf8Text(buf, i) { + var total = utf8CheckIncomplete(this, buf, i); + if (!this.lastNeed) return buf.toString('utf8', i); + this.lastTotal = total; + var end = buf.length - (total - this.lastNeed); + buf.copy(this.lastChar, 0, end); + return buf.toString('utf8', i, end); +} + +// For UTF-8, a replacement character is added when ending on a partial +// character. +function utf8End(buf) { + var r = buf && buf.length ? this.write(buf) : ''; + if (this.lastNeed) return r + '\ufffd'; + return r; +} + +// UTF-16LE typically needs two bytes per character, but even if we have an even +// number of bytes available, we need to check if we end on a leading/high +// surrogate. In that case, we need to wait for the next two bytes in order to +// decode the last character properly. +function utf16Text(buf, i) { + if ((buf.length - i) % 2 === 0) { + var r = buf.toString('utf16le', i); + if (r) { + var c = r.charCodeAt(r.length - 1); + if (c >= 0xD800 && c <= 0xDBFF) { + this.lastNeed = 2; + this.lastTotal = 4; + this.lastChar[0] = buf[buf.length - 2]; + this.lastChar[1] = buf[buf.length - 1]; + return r.slice(0, -1); + } + } + return r; + } + this.lastNeed = 1; + this.lastTotal = 2; + this.lastChar[0] = buf[buf.length - 1]; + return buf.toString('utf16le', i, buf.length - 1); +} + +// For UTF-16LE we do not explicitly append special replacement characters if we +// end on a partial character, we simply let v8 handle that. +function utf16End(buf) { + var r = buf && buf.length ? this.write(buf) : ''; + if (this.lastNeed) { + var end = this.lastTotal - this.lastNeed; + return r + this.lastChar.toString('utf16le', 0, end); + } + return r; +} + +function base64Text(buf, i) { + var n = (buf.length - i) % 3; + if (n === 0) return buf.toString('base64', i); + this.lastNeed = 3 - n; + this.lastTotal = 3; + if (n === 1) { + this.lastChar[0] = buf[buf.length - 1]; + } else { + this.lastChar[0] = buf[buf.length - 2]; + this.lastChar[1] = buf[buf.length - 1]; + } + return buf.toString('base64', i, buf.length - n); +} + +function base64End(buf) { + var r = buf && buf.length ? this.write(buf) : ''; + if (this.lastNeed) return r + this.lastChar.toString('base64', 0, 3 - this.lastNeed); + return r; +} + +// Pass bytes on through for single-byte encodings (e.g. ascii, latin1, hex) +function simpleWrite(buf) { + return buf.toString(this.encoding); +} + +function simpleEnd(buf) { + return buf && buf.length ? this.write(buf) : ''; +} +},{"safe-buffer":179}],205:[function(require,module,exports){ +// Copyright Joyent, Inc. and other Node contributors. +// +// 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. + +'use strict'; + +var punycode = require('punycode'); +var util = require('./util'); + +exports.parse = urlParse; +exports.resolve = urlResolve; +exports.resolveObject = urlResolveObject; +exports.format = urlFormat; + +exports.Url = Url; + +function Url() { + this.protocol = null; + this.slashes = null; + this.auth = null; + this.host = null; + this.port = null; + this.hostname = null; + this.hash = null; + this.search = null; + this.query = null; + this.pathname = null; + this.path = null; + this.href = null; +} + +// Reference: RFC 3986, RFC 1808, RFC 2396 + +// define these here so at least they only have to be +// compiled once on the first module load. +var protocolPattern = /^([a-z0-9.+-]+:)/i, + portPattern = /:[0-9]*$/, + + // Special case for a simple path URL + simplePathPattern = /^(\/\/?(?!\/)[^\?\s]*)(\?[^\s]*)?$/, + + // RFC 2396: characters reserved for delimiting URLs. + // We actually just auto-escape these. + delims = ['<', '>', '"', '`', ' ', '\r', '\n', '\t'], + + // RFC 2396: characters not allowed for various reasons. + unwise = ['{', '}', '|', '\\', '^', '`'].concat(delims), + + // Allowed by RFCs, but cause of XSS attacks. Always escape these. + autoEscape = ['\''].concat(unwise), + // Characters that are never ever allowed in a hostname. + // Note that any invalid chars are also handled, but these + // are the ones that are *expected* to be seen, so we fast-path + // them. + nonHostChars = ['%', '/', '?', ';', '#'].concat(autoEscape), + hostEndingChars = ['/', '?', '#'], + hostnameMaxLen = 255, + hostnamePartPattern = /^[+a-z0-9A-Z_-]{0,63}$/, + hostnamePartStart = /^([+a-z0-9A-Z_-]{0,63})(.*)$/, + // protocols that can allow "unsafe" and "unwise" chars. + unsafeProtocol = { + 'javascript': true, + 'javascript:': true + }, + // protocols that never have a hostname. + hostlessProtocol = { + 'javascript': true, + 'javascript:': true + }, + // protocols that always contain a // bit. + slashedProtocol = { + 'http': true, + 'https': true, + 'ftp': true, + 'gopher': true, + 'file': true, + 'http:': true, + 'https:': true, + 'ftp:': true, + 'gopher:': true, + 'file:': true + }, + querystring = require('querystring'); + +function urlParse(url, parseQueryString, slashesDenoteHost) { + if (url && util.isObject(url) && url instanceof Url) return url; + + var u = new Url; + u.parse(url, parseQueryString, slashesDenoteHost); + return u; +} + +Url.prototype.parse = function(url, parseQueryString, slashesDenoteHost) { + if (!util.isString(url)) { + throw new TypeError("Parameter 'url' must be a string, not " + typeof url); + } + + // Copy chrome, IE, opera backslash-handling behavior. + // Back slashes before the query string get converted to forward slashes + // See: https://code.google.com/p/chromium/issues/detail?id=25916 + var queryIndex = url.indexOf('?'), + splitter = + (queryIndex !== -1 && queryIndex < url.indexOf('#')) ? '?' : '#', + uSplit = url.split(splitter), + slashRegex = /\\/g; + uSplit[0] = uSplit[0].replace(slashRegex, '/'); + url = uSplit.join(splitter); + + var rest = url; + + // trim before proceeding. + // This is to support parse stuff like " http://foo.com \n" + rest = rest.trim(); + + if (!slashesDenoteHost && url.split('#').length === 1) { + // Try fast path regexp + var simplePath = simplePathPattern.exec(rest); + if (simplePath) { + this.path = rest; + this.href = rest; + this.pathname = simplePath[1]; + if (simplePath[2]) { + this.search = simplePath[2]; + if (parseQueryString) { + this.query = querystring.parse(this.search.substr(1)); + } else { + this.query = this.search.substr(1); + } + } else if (parseQueryString) { + this.search = ''; + this.query = {}; + } + return this; + } + } + + var proto = protocolPattern.exec(rest); + if (proto) { + proto = proto[0]; + var lowerProto = proto.toLowerCase(); + this.protocol = lowerProto; + rest = rest.substr(proto.length); + } + + // figure out if it's got a host + // user@server is *always* interpreted as a hostname, and url + // resolution will treat //foo/bar as host=foo,path=bar because that's + // how the browser resolves relative URLs. + if (slashesDenoteHost || proto || rest.match(/^\/\/[^@\/]+@[^@\/]+/)) { + var slashes = rest.substr(0, 2) === '//'; + if (slashes && !(proto && hostlessProtocol[proto])) { + rest = rest.substr(2); + this.slashes = true; + } + } + + if (!hostlessProtocol[proto] && + (slashes || (proto && !slashedProtocol[proto]))) { + + // there's a hostname. + // the first instance of /, ?, ;, or # ends the host. + // + // If there is an @ in the hostname, then non-host chars *are* allowed + // to the left of the last @ sign, unless some host-ending character + // comes *before* the @-sign. + // URLs are obnoxious. + // + // ex: + // http://a@b@c/ => user:a@b host:c + // http://a@b?@c => user:a host:c path:/?@c + + // v0.12 TODO(isaacs): This is not quite how Chrome does things. + // Review our test case against browsers more comprehensively. + + // find the first instance of any hostEndingChars + var hostEnd = -1; + for (var i = 0; i < hostEndingChars.length; i++) { + var hec = rest.indexOf(hostEndingChars[i]); + if (hec !== -1 && (hostEnd === -1 || hec < hostEnd)) + hostEnd = hec; + } + + // at this point, either we have an explicit point where the + // auth portion cannot go past, or the last @ char is the decider. + var auth, atSign; + if (hostEnd === -1) { + // atSign can be anywhere. + atSign = rest.lastIndexOf('@'); + } else { + // atSign must be in auth portion. + // http://a@b/c@d => host:b auth:a path:/c@d + atSign = rest.lastIndexOf('@', hostEnd); + } + + // Now we have a portion which is definitely the auth. + // Pull that off. + if (atSign !== -1) { + auth = rest.slice(0, atSign); + rest = rest.slice(atSign + 1); + this.auth = decodeURIComponent(auth); + } + + // the host is the remaining to the left of the first non-host char + hostEnd = -1; + for (var i = 0; i < nonHostChars.length; i++) { + var hec = rest.indexOf(nonHostChars[i]); + if (hec !== -1 && (hostEnd === -1 || hec < hostEnd)) + hostEnd = hec; + } + // if we still have not hit it, then the entire thing is a host. + if (hostEnd === -1) + hostEnd = rest.length; + + this.host = rest.slice(0, hostEnd); + rest = rest.slice(hostEnd); + + // pull out port. + this.parseHost(); + + // we've indicated that there is a hostname, + // so even if it's empty, it has to be present. + this.hostname = this.hostname || ''; + + // if hostname begins with [ and ends with ] + // assume that it's an IPv6 address. + var ipv6Hostname = this.hostname[0] === '[' && + this.hostname[this.hostname.length - 1] === ']'; + + // validate a little. + if (!ipv6Hostname) { + var hostparts = this.hostname.split(/\./); + for (var i = 0, l = hostparts.length; i < l; i++) { + var part = hostparts[i]; + if (!part) continue; + if (!part.match(hostnamePartPattern)) { + var newpart = ''; + for (var j = 0, k = part.length; j < k; j++) { + if (part.charCodeAt(j) > 127) { + // we replace non-ASCII char with a temporary placeholder + // we need this to make sure size of hostname is not + // broken by replacing non-ASCII by nothing + newpart += 'x'; + } else { + newpart += part[j]; + } + } + // we test again with ASCII char only + if (!newpart.match(hostnamePartPattern)) { + var validParts = hostparts.slice(0, i); + var notHost = hostparts.slice(i + 1); + var bit = part.match(hostnamePartStart); + if (bit) { + validParts.push(bit[1]); + notHost.unshift(bit[2]); + } + if (notHost.length) { + rest = '/' + notHost.join('.') + rest; + } + this.hostname = validParts.join('.'); + break; + } + } + } + } + + if (this.hostname.length > hostnameMaxLen) { + this.hostname = ''; + } else { + // hostnames are always lower case. + this.hostname = this.hostname.toLowerCase(); + } + + if (!ipv6Hostname) { + // IDNA Support: Returns a punycoded representation of "domain". + // It only converts parts of the domain name that + // have non-ASCII characters, i.e. it doesn't matter if + // you call it with a domain that already is ASCII-only. + this.hostname = punycode.toASCII(this.hostname); + } + + var p = this.port ? ':' + this.port : ''; + var h = this.hostname || ''; + this.host = h + p; + this.href += this.host; + + // strip [ and ] from the hostname + // the host field still retains them, though + if (ipv6Hostname) { + this.hostname = this.hostname.substr(1, this.hostname.length - 2); + if (rest[0] !== '/') { + rest = '/' + rest; + } + } + } + + // now rest is set to the post-host stuff. + // chop off any delim chars. + if (!unsafeProtocol[lowerProto]) { + + // First, make 100% sure that any "autoEscape" chars get + // escaped, even if encodeURIComponent doesn't think they + // need to be. + for (var i = 0, l = autoEscape.length; i < l; i++) { + var ae = autoEscape[i]; + if (rest.indexOf(ae) === -1) + continue; + var esc = encodeURIComponent(ae); + if (esc === ae) { + esc = escape(ae); + } + rest = rest.split(ae).join(esc); + } + } + + + // chop off from the tail first. + var hash = rest.indexOf('#'); + if (hash !== -1) { + // got a fragment string. + this.hash = rest.substr(hash); + rest = rest.slice(0, hash); + } + var qm = rest.indexOf('?'); + if (qm !== -1) { + this.search = rest.substr(qm); + this.query = rest.substr(qm + 1); + if (parseQueryString) { + this.query = querystring.parse(this.query); + } + rest = rest.slice(0, qm); + } else if (parseQueryString) { + // no query string, but parseQueryString still requested + this.search = ''; + this.query = {}; + } + if (rest) this.pathname = rest; + if (slashedProtocol[lowerProto] && + this.hostname && !this.pathname) { + this.pathname = '/'; + } + + //to support http.request + if (this.pathname || this.search) { + var p = this.pathname || ''; + var s = this.search || ''; + this.path = p + s; + } + + // finally, reconstruct the href based on what has been validated. + this.href = this.format(); + return this; +}; + +// format a parsed object into a url string +function urlFormat(obj) { + // ensure it's an object, and not a string url. + // If it's an obj, this is a no-op. + // this way, you can call url_format() on strings + // to clean up potentially wonky urls. + if (util.isString(obj)) obj = urlParse(obj); + if (!(obj instanceof Url)) return Url.prototype.format.call(obj); + return obj.format(); +} + +Url.prototype.format = function() { + var auth = this.auth || ''; + if (auth) { + auth = encodeURIComponent(auth); + auth = auth.replace(/%3A/i, ':'); + auth += '@'; + } + + var protocol = this.protocol || '', + pathname = this.pathname || '', + hash = this.hash || '', + host = false, + query = ''; + + if (this.host) { + host = auth + this.host; + } else if (this.hostname) { + host = auth + (this.hostname.indexOf(':') === -1 ? + this.hostname : + '[' + this.hostname + ']'); + if (this.port) { + host += ':' + this.port; + } + } + + if (this.query && + util.isObject(this.query) && + Object.keys(this.query).length) { + query = querystring.stringify(this.query); + } + + var search = this.search || (query && ('?' + query)) || ''; + + if (protocol && protocol.substr(-1) !== ':') protocol += ':'; + + // only the slashedProtocols get the //. Not mailto:, xmpp:, etc. + // unless they had them to begin with. + if (this.slashes || + (!protocol || slashedProtocol[protocol]) && host !== false) { + host = '//' + (host || ''); + if (pathname && pathname.charAt(0) !== '/') pathname = '/' + pathname; + } else if (!host) { + host = ''; + } + + if (hash && hash.charAt(0) !== '#') hash = '#' + hash; + if (search && search.charAt(0) !== '?') search = '?' + search; + + pathname = pathname.replace(/[?#]/g, function(match) { + return encodeURIComponent(match); + }); + search = search.replace('#', '%23'); + + return protocol + host + pathname + search + hash; +}; + +function urlResolve(source, relative) { + return urlParse(source, false, true).resolve(relative); +} + +Url.prototype.resolve = function(relative) { + return this.resolveObject(urlParse(relative, false, true)).format(); +}; + +function urlResolveObject(source, relative) { + if (!source) return relative; + return urlParse(source, false, true).resolveObject(relative); +} + +Url.prototype.resolveObject = function(relative) { + if (util.isString(relative)) { + var rel = new Url(); + rel.parse(relative, false, true); + relative = rel; + } + + var result = new Url(); + var tkeys = Object.keys(this); + for (var tk = 0; tk < tkeys.length; tk++) { + var tkey = tkeys[tk]; + result[tkey] = this[tkey]; + } + + // hash is always overridden, no matter what. + // even href="" will remove it. + result.hash = relative.hash; + + // if the relative url is empty, then there's nothing left to do here. + if (relative.href === '') { + result.href = result.format(); + return result; + } + + // hrefs like //foo/bar always cut to the protocol. + if (relative.slashes && !relative.protocol) { + // take everything except the protocol from relative + var rkeys = Object.keys(relative); + for (var rk = 0; rk < rkeys.length; rk++) { + var rkey = rkeys[rk]; + if (rkey !== 'protocol') + result[rkey] = relative[rkey]; + } + + //urlParse appends trailing / to urls like http://www.example.com + if (slashedProtocol[result.protocol] && + result.hostname && !result.pathname) { + result.path = result.pathname = '/'; + } + + result.href = result.format(); + return result; + } + + if (relative.protocol && relative.protocol !== result.protocol) { + // if it's a known url protocol, then changing + // the protocol does weird things + // first, if it's not file:, then we MUST have a host, + // and if there was a path + // to begin with, then we MUST have a path. + // if it is file:, then the host is dropped, + // because that's known to be hostless. + // anything else is assumed to be absolute. + if (!slashedProtocol[relative.protocol]) { + var keys = Object.keys(relative); + for (var v = 0; v < keys.length; v++) { + var k = keys[v]; + result[k] = relative[k]; + } + result.href = result.format(); + return result; + } + + result.protocol = relative.protocol; + if (!relative.host && !hostlessProtocol[relative.protocol]) { + var relPath = (relative.pathname || '').split('/'); + while (relPath.length && !(relative.host = relPath.shift())); + if (!relative.host) relative.host = ''; + if (!relative.hostname) relative.hostname = ''; + if (relPath[0] !== '') relPath.unshift(''); + if (relPath.length < 2) relPath.unshift(''); + result.pathname = relPath.join('/'); + } else { + result.pathname = relative.pathname; + } + result.search = relative.search; + result.query = relative.query; + result.host = relative.host || ''; + result.auth = relative.auth; + result.hostname = relative.hostname || relative.host; + result.port = relative.port; + // to support http.request + if (result.pathname || result.search) { + var p = result.pathname || ''; + var s = result.search || ''; + result.path = p + s; + } + result.slashes = result.slashes || relative.slashes; + result.href = result.format(); + return result; + } + + var isSourceAbs = (result.pathname && result.pathname.charAt(0) === '/'), + isRelAbs = ( + relative.host || + relative.pathname && relative.pathname.charAt(0) === '/' + ), + mustEndAbs = (isRelAbs || isSourceAbs || + (result.host && relative.pathname)), + removeAllDots = mustEndAbs, + srcPath = result.pathname && result.pathname.split('/') || [], + relPath = relative.pathname && relative.pathname.split('/') || [], + psychotic = result.protocol && !slashedProtocol[result.protocol]; + + // if the url is a non-slashed url, then relative + // links like ../.. should be able + // to crawl up to the hostname, as well. This is strange. + // result.protocol has already been set by now. + // Later on, put the first path part into the host field. + if (psychotic) { + result.hostname = ''; + result.port = null; + if (result.host) { + if (srcPath[0] === '') srcPath[0] = result.host; + else srcPath.unshift(result.host); + } + result.host = ''; + if (relative.protocol) { + relative.hostname = null; + relative.port = null; + if (relative.host) { + if (relPath[0] === '') relPath[0] = relative.host; + else relPath.unshift(relative.host); + } + relative.host = null; + } + mustEndAbs = mustEndAbs && (relPath[0] === '' || srcPath[0] === ''); + } + + if (isRelAbs) { + // it's absolute. + result.host = (relative.host || relative.host === '') ? + relative.host : result.host; + result.hostname = (relative.hostname || relative.hostname === '') ? + relative.hostname : result.hostname; + result.search = relative.search; + result.query = relative.query; + srcPath = relPath; + // fall through to the dot-handling below. + } else if (relPath.length) { + // it's relative + // throw away the existing file, and take the new path instead. + if (!srcPath) srcPath = []; + srcPath.pop(); + srcPath = srcPath.concat(relPath); + result.search = relative.search; + result.query = relative.query; + } else if (!util.isNullOrUndefined(relative.search)) { + // just pull out the search. + // like href='?foo'. + // Put this after the other two cases because it simplifies the booleans + if (psychotic) { + result.hostname = result.host = srcPath.shift(); + //occationaly the auth can get stuck only in host + //this especially happens in cases like + //url.resolveObject('mailto:local1@domain1', 'local2@domain2') + var authInHost = result.host && result.host.indexOf('@') > 0 ? + result.host.split('@') : false; + if (authInHost) { + result.auth = authInHost.shift(); + result.host = result.hostname = authInHost.shift(); + } + } + result.search = relative.search; + result.query = relative.query; + //to support http.request + if (!util.isNull(result.pathname) || !util.isNull(result.search)) { + result.path = (result.pathname ? result.pathname : '') + + (result.search ? result.search : ''); + } + result.href = result.format(); + return result; + } + + if (!srcPath.length) { + // no path at all. easy. + // we've already handled the other stuff above. + result.pathname = null; + //to support http.request + if (result.search) { + result.path = '/' + result.search; + } else { + result.path = null; + } + result.href = result.format(); + return result; + } + + // if a url ENDs in . or .., then it must get a trailing slash. + // however, if it ends in anything else non-slashy, + // then it must NOT get a trailing slash. + var last = srcPath.slice(-1)[0]; + var hasTrailingSlash = ( + (result.host || relative.host || srcPath.length > 1) && + (last === '.' || last === '..') || last === ''); + + // strip single dots, resolve double dots to parent dir + // if the path tries to go above the root, `up` ends up > 0 + var up = 0; + for (var i = srcPath.length; i >= 0; i--) { + last = srcPath[i]; + if (last === '.') { + srcPath.splice(i, 1); + } else if (last === '..') { + srcPath.splice(i, 1); + up++; + } else if (up) { + srcPath.splice(i, 1); + up--; + } + } + + // if the path is allowed to go above the root, restore leading ..s + if (!mustEndAbs && !removeAllDots) { + for (; up--; up) { + srcPath.unshift('..'); + } + } + + if (mustEndAbs && srcPath[0] !== '' && + (!srcPath[0] || srcPath[0].charAt(0) !== '/')) { + srcPath.unshift(''); + } + + if (hasTrailingSlash && (srcPath.join('/').substr(-1) !== '/')) { + srcPath.push(''); + } + + var isAbsolute = srcPath[0] === '' || + (srcPath[0] && srcPath[0].charAt(0) === '/'); + + // put the host back + if (psychotic) { + result.hostname = result.host = isAbsolute ? '' : + srcPath.length ? srcPath.shift() : ''; + //occationaly the auth can get stuck only in host + //this especially happens in cases like + //url.resolveObject('mailto:local1@domain1', 'local2@domain2') + var authInHost = result.host && result.host.indexOf('@') > 0 ? + result.host.split('@') : false; + if (authInHost) { + result.auth = authInHost.shift(); + result.host = result.hostname = authInHost.shift(); + } + } + + mustEndAbs = mustEndAbs || (result.host && srcPath.length); + + if (mustEndAbs && !isAbsolute) { + srcPath.unshift(''); + } + + if (!srcPath.length) { + result.pathname = null; + result.path = null; + } else { + result.pathname = srcPath.join('/'); + } + + //to support request.http + if (!util.isNull(result.pathname) || !util.isNull(result.search)) { + result.path = (result.pathname ? result.pathname : '') + + (result.search ? result.search : ''); + } + result.auth = relative.auth || result.auth; + result.slashes = result.slashes || relative.slashes; + result.href = result.format(); + return result; +}; + +Url.prototype.parseHost = function() { + var host = this.host; + var port = portPattern.exec(host); + if (port) { + port = port[0]; + if (port !== ':') { + this.port = port.substr(1); + } + host = host.substr(0, host.length - port.length); + } + if (host) this.hostname = host; +}; + +},{"./util":206,"punycode":172,"querystring":175}],206:[function(require,module,exports){ +'use strict'; + +module.exports = { + isString: function(arg) { + return typeof(arg) === 'string'; + }, + isObject: function(arg) { + return typeof(arg) === 'object' && arg !== null; + }, + isNull: function(arg) { + return arg === null; + }, + isNullOrUndefined: function(arg) { + return arg == null; + } +}; + +},{}],207:[function(require,module,exports){ +(function (global){(function (){ + +/** + * Module exports. + */ + +module.exports = deprecate; + +/** + * Mark that a method should not be used. + * Returns a modified function which warns once by default. + * + * If `localStorage.noDeprecation = true` is set, then it is a no-op. + * + * If `localStorage.throwDeprecation = true` is set, then deprecated functions + * will throw an Error when invoked. + * + * If `localStorage.traceDeprecation = true` is set, then deprecated functions + * will invoke `console.trace()` instead of `console.error()`. + * + * @param {Function} fn - the function to deprecate + * @param {String} msg - the string to print to the console when `fn` is invoked + * @returns {Function} a new "deprecated" version of `fn` + * @api public + */ + +function deprecate (fn, msg) { + if (config('noDeprecation')) { + return fn; + } + + var warned = false; + function deprecated() { + if (!warned) { + if (config('throwDeprecation')) { + throw new Error(msg); + } else if (config('traceDeprecation')) { + console.trace(msg); + } else { + console.warn(msg); + } + warned = true; + } + return fn.apply(this, arguments); + } + + return deprecated; +} + +/** + * Checks `localStorage` for boolean values for the given `name`. + * + * @param {String} name + * @returns {Boolean} + * @api private + */ + +function config (name) { + // accessing global.localStorage can trigger a DOMException in sandboxed iframes + try { + if (!global.localStorage) return false; + } catch (_) { + return false; + } + var val = global.localStorage[name]; + if (null == val) return false; + return String(val).toLowerCase() === 'true'; +} + +}).call(this)}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) +},{}],208:[function(require,module,exports){ +module.exports = function isBuffer(arg) { + return arg && typeof arg === 'object' + && typeof arg.copy === 'function' + && typeof arg.fill === 'function' + && typeof arg.readUInt8 === 'function'; +} +},{}],209:[function(require,module,exports){ +// Currently in sync with Node.js lib/internal/util/types.js +// https://github.com/nodejs/node/commit/112cc7c27551254aa2b17098fb774867f05ed0d9 + +'use strict'; + +var isArgumentsObject = require('is-arguments'); +var isGeneratorFunction = require('is-generator-function'); +var whichTypedArray = require('which-typed-array'); +var isTypedArray = require('is-typed-array'); + +function uncurryThis(f) { + return f.call.bind(f); +} + +var BigIntSupported = typeof BigInt !== 'undefined'; +var SymbolSupported = typeof Symbol !== 'undefined'; + +var ObjectToString = uncurryThis(Object.prototype.toString); + +var numberValue = uncurryThis(Number.prototype.valueOf); +var stringValue = uncurryThis(String.prototype.valueOf); +var booleanValue = uncurryThis(Boolean.prototype.valueOf); + +if (BigIntSupported) { + var bigIntValue = uncurryThis(BigInt.prototype.valueOf); +} + +if (SymbolSupported) { + var symbolValue = uncurryThis(Symbol.prototype.valueOf); +} + +function checkBoxedPrimitive(value, prototypeValueOf) { + if (typeof value !== 'object') { + return false; + } + try { + prototypeValueOf(value); + return true; + } catch(e) { + return false; + } +} + +exports.isArgumentsObject = isArgumentsObject; +exports.isGeneratorFunction = isGeneratorFunction; +exports.isTypedArray = isTypedArray; + +// Taken from here and modified for better browser support +// https://github.com/sindresorhus/p-is-promise/blob/cda35a513bda03f977ad5cde3a079d237e82d7ef/index.js +function isPromise(input) { + return ( + ( + typeof Promise !== 'undefined' && + input instanceof Promise + ) || + ( + input !== null && + typeof input === 'object' && + typeof input.then === 'function' && + typeof input.catch === 'function' + ) + ); +} +exports.isPromise = isPromise; + +function isArrayBufferView(value) { + if (typeof ArrayBuffer !== 'undefined' && ArrayBuffer.isView) { + return ArrayBuffer.isView(value); + } + + return ( + isTypedArray(value) || + isDataView(value) + ); +} +exports.isArrayBufferView = isArrayBufferView; + + +function isUint8Array(value) { + return whichTypedArray(value) === 'Uint8Array'; +} +exports.isUint8Array = isUint8Array; + +function isUint8ClampedArray(value) { + return whichTypedArray(value) === 'Uint8ClampedArray'; +} +exports.isUint8ClampedArray = isUint8ClampedArray; + +function isUint16Array(value) { + return whichTypedArray(value) === 'Uint16Array'; +} +exports.isUint16Array = isUint16Array; + +function isUint32Array(value) { + return whichTypedArray(value) === 'Uint32Array'; +} +exports.isUint32Array = isUint32Array; + +function isInt8Array(value) { + return whichTypedArray(value) === 'Int8Array'; +} +exports.isInt8Array = isInt8Array; + +function isInt16Array(value) { + return whichTypedArray(value) === 'Int16Array'; +} +exports.isInt16Array = isInt16Array; + +function isInt32Array(value) { + return whichTypedArray(value) === 'Int32Array'; +} +exports.isInt32Array = isInt32Array; + +function isFloat32Array(value) { + return whichTypedArray(value) === 'Float32Array'; +} +exports.isFloat32Array = isFloat32Array; + +function isFloat64Array(value) { + return whichTypedArray(value) === 'Float64Array'; +} +exports.isFloat64Array = isFloat64Array; + +function isBigInt64Array(value) { + return whichTypedArray(value) === 'BigInt64Array'; +} +exports.isBigInt64Array = isBigInt64Array; + +function isBigUint64Array(value) { + return whichTypedArray(value) === 'BigUint64Array'; +} +exports.isBigUint64Array = isBigUint64Array; + +function isMapToString(value) { + return ObjectToString(value) === '[object Map]'; +} +isMapToString.working = ( + typeof Map !== 'undefined' && + isMapToString(new Map()) +); + +function isMap(value) { + if (typeof Map === 'undefined') { + return false; + } + + return isMapToString.working + ? isMapToString(value) + : value instanceof Map; +} +exports.isMap = isMap; + +function isSetToString(value) { + return ObjectToString(value) === '[object Set]'; +} +isSetToString.working = ( + typeof Set !== 'undefined' && + isSetToString(new Set()) +); +function isSet(value) { + if (typeof Set === 'undefined') { + return false; + } + + return isSetToString.working + ? isSetToString(value) + : value instanceof Set; +} +exports.isSet = isSet; + +function isWeakMapToString(value) { + return ObjectToString(value) === '[object WeakMap]'; +} +isWeakMapToString.working = ( + typeof WeakMap !== 'undefined' && + isWeakMapToString(new WeakMap()) +); +function isWeakMap(value) { + if (typeof WeakMap === 'undefined') { + return false; + } + + return isWeakMapToString.working + ? isWeakMapToString(value) + : value instanceof WeakMap; +} +exports.isWeakMap = isWeakMap; + +function isWeakSetToString(value) { + return ObjectToString(value) === '[object WeakSet]'; +} +isWeakSetToString.working = ( + typeof WeakSet !== 'undefined' && + isWeakSetToString(new WeakSet()) +); +function isWeakSet(value) { + return isWeakSetToString(value); +} +exports.isWeakSet = isWeakSet; + +function isArrayBufferToString(value) { + return ObjectToString(value) === '[object ArrayBuffer]'; +} +isArrayBufferToString.working = ( + typeof ArrayBuffer !== 'undefined' && + isArrayBufferToString(new ArrayBuffer()) +); +function isArrayBuffer(value) { + if (typeof ArrayBuffer === 'undefined') { + return false; + } + + return isArrayBufferToString.working + ? isArrayBufferToString(value) + : value instanceof ArrayBuffer; +} +exports.isArrayBuffer = isArrayBuffer; + +function isDataViewToString(value) { + return ObjectToString(value) === '[object DataView]'; +} +isDataViewToString.working = ( + typeof ArrayBuffer !== 'undefined' && + typeof DataView !== 'undefined' && + isDataViewToString(new DataView(new ArrayBuffer(1), 0, 1)) +); +function isDataView(value) { + if (typeof DataView === 'undefined') { + return false; + } + + return isDataViewToString.working + ? isDataViewToString(value) + : value instanceof DataView; +} +exports.isDataView = isDataView; + +// Store a copy of SharedArrayBuffer in case it's deleted elsewhere +var SharedArrayBufferCopy = typeof SharedArrayBuffer !== 'undefined' ? SharedArrayBuffer : undefined; +function isSharedArrayBufferToString(value) { + return ObjectToString(value) === '[object SharedArrayBuffer]'; +} +function isSharedArrayBuffer(value) { + if (typeof SharedArrayBufferCopy === 'undefined') { + return false; + } + + if (typeof isSharedArrayBufferToString.working === 'undefined') { + isSharedArrayBufferToString.working = isSharedArrayBufferToString(new SharedArrayBufferCopy()); + } + + return isSharedArrayBufferToString.working + ? isSharedArrayBufferToString(value) + : value instanceof SharedArrayBufferCopy; +} +exports.isSharedArrayBuffer = isSharedArrayBuffer; + +function isAsyncFunction(value) { + return ObjectToString(value) === '[object AsyncFunction]'; +} +exports.isAsyncFunction = isAsyncFunction; + +function isMapIterator(value) { + return ObjectToString(value) === '[object Map Iterator]'; +} +exports.isMapIterator = isMapIterator; + +function isSetIterator(value) { + return ObjectToString(value) === '[object Set Iterator]'; +} +exports.isSetIterator = isSetIterator; + +function isGeneratorObject(value) { + return ObjectToString(value) === '[object Generator]'; +} +exports.isGeneratorObject = isGeneratorObject; + +function isWebAssemblyCompiledModule(value) { + return ObjectToString(value) === '[object WebAssembly.Module]'; +} +exports.isWebAssemblyCompiledModule = isWebAssemblyCompiledModule; + +function isNumberObject(value) { + return checkBoxedPrimitive(value, numberValue); +} +exports.isNumberObject = isNumberObject; + +function isStringObject(value) { + return checkBoxedPrimitive(value, stringValue); +} +exports.isStringObject = isStringObject; + +function isBooleanObject(value) { + return checkBoxedPrimitive(value, booleanValue); +} +exports.isBooleanObject = isBooleanObject; + +function isBigIntObject(value) { + return BigIntSupported && checkBoxedPrimitive(value, bigIntValue); +} +exports.isBigIntObject = isBigIntObject; + +function isSymbolObject(value) { + return SymbolSupported && checkBoxedPrimitive(value, symbolValue); +} +exports.isSymbolObject = isSymbolObject; + +function isBoxedPrimitive(value) { + return ( + isNumberObject(value) || + isStringObject(value) || + isBooleanObject(value) || + isBigIntObject(value) || + isSymbolObject(value) + ); +} +exports.isBoxedPrimitive = isBoxedPrimitive; + +function isAnyArrayBuffer(value) { + return typeof Uint8Array !== 'undefined' && ( + isArrayBuffer(value) || + isSharedArrayBuffer(value) + ); +} +exports.isAnyArrayBuffer = isAnyArrayBuffer; + +['isProxy', 'isExternal', 'isModuleNamespaceObject'].forEach(function(method) { + Object.defineProperty(exports, method, { + enumerable: false, + value: function() { + throw new Error(method + ' is not supported in userland'); + } + }); +}); + +},{"is-arguments":144,"is-generator-function":146,"is-typed-array":147,"which-typed-array":211}],210:[function(require,module,exports){ +(function (process){(function (){ +// Copyright Joyent, Inc. and other Node contributors. +// +// 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. + +var getOwnPropertyDescriptors = Object.getOwnPropertyDescriptors || + function getOwnPropertyDescriptors(obj) { + var keys = Object.keys(obj); + var descriptors = {}; + for (var i = 0; i < keys.length; i++) { + descriptors[keys[i]] = Object.getOwnPropertyDescriptor(obj, keys[i]); + } + return descriptors; + }; + +var formatRegExp = /%[sdj%]/g; +exports.format = function(f) { + if (!isString(f)) { + var objects = []; + for (var i = 0; i < arguments.length; i++) { + objects.push(inspect(arguments[i])); + } + return objects.join(' '); + } + + var i = 1; + var args = arguments; + var len = args.length; + var str = String(f).replace(formatRegExp, function(x) { + if (x === '%%') return '%'; + if (i >= len) return x; + switch (x) { + case '%s': return String(args[i++]); + case '%d': return Number(args[i++]); + case '%j': + try { + return JSON.stringify(args[i++]); + } catch (_) { + return '[Circular]'; + } + default: + return x; + } + }); + for (var x = args[i]; i < len; x = args[++i]) { + if (isNull(x) || !isObject(x)) { + str += ' ' + x; + } else { + str += ' ' + inspect(x); + } + } + return str; +}; + + +// Mark that a method should not be used. +// Returns a modified function which warns once by default. +// If --no-deprecation is set, then it is a no-op. +exports.deprecate = function(fn, msg) { + if (typeof process !== 'undefined' && process.noDeprecation === true) { + return fn; + } + + // Allow for deprecating things in the process of starting up. + if (typeof process === 'undefined') { + return function() { + return exports.deprecate(fn, msg).apply(this, arguments); + }; + } + + var warned = false; + function deprecated() { + if (!warned) { + if (process.throwDeprecation) { + throw new Error(msg); + } else if (process.traceDeprecation) { + console.trace(msg); + } else { + console.error(msg); + } + warned = true; + } + return fn.apply(this, arguments); + } + + return deprecated; +}; + + +var debugs = {}; +var debugEnvRegex = /^$/; + +if (process.env.NODE_DEBUG) { + var debugEnv = process.env.NODE_DEBUG; + debugEnv = debugEnv.replace(/[|\\{}()[\]^$+?.]/g, '\\$&') + .replace(/\*/g, '.*') + .replace(/,/g, '$|^') + .toUpperCase(); + debugEnvRegex = new RegExp('^' + debugEnv + '$', 'i'); +} +exports.debuglog = function(set) { + set = set.toUpperCase(); + if (!debugs[set]) { + if (debugEnvRegex.test(set)) { + var pid = process.pid; + debugs[set] = function() { + var msg = exports.format.apply(exports, arguments); + console.error('%s %d: %s', set, pid, msg); + }; + } else { + debugs[set] = function() {}; + } + } + return debugs[set]; +}; + + +/** + * Echos the value of a value. Trys to print the value out + * in the best way possible given the different types. + * + * @param {Object} obj The object to print out. + * @param {Object} opts Optional options object that alters the output. + */ +/* legacy: obj, showHidden, depth, colors*/ +function inspect(obj, opts) { + // default options + var ctx = { + seen: [], + stylize: stylizeNoColor + }; + // legacy... + if (arguments.length >= 3) ctx.depth = arguments[2]; + if (arguments.length >= 4) ctx.colors = arguments[3]; + if (isBoolean(opts)) { + // legacy... + ctx.showHidden = opts; + } else if (opts) { + // got an "options" object + exports._extend(ctx, opts); + } + // set default options + if (isUndefined(ctx.showHidden)) ctx.showHidden = false; + if (isUndefined(ctx.depth)) ctx.depth = 2; + if (isUndefined(ctx.colors)) ctx.colors = false; + if (isUndefined(ctx.customInspect)) ctx.customInspect = true; + if (ctx.colors) ctx.stylize = stylizeWithColor; + return formatValue(ctx, obj, ctx.depth); +} +exports.inspect = inspect; + + +// http://en.wikipedia.org/wiki/ANSI_escape_code#graphics +inspect.colors = { + 'bold' : [1, 22], + 'italic' : [3, 23], + 'underline' : [4, 24], + 'inverse' : [7, 27], + 'white' : [37, 39], + 'grey' : [90, 39], + 'black' : [30, 39], + 'blue' : [34, 39], + 'cyan' : [36, 39], + 'green' : [32, 39], + 'magenta' : [35, 39], + 'red' : [31, 39], + 'yellow' : [33, 39] +}; + +// Don't use 'blue' not visible on cmd.exe +inspect.styles = { + 'special': 'cyan', + 'number': 'yellow', + 'boolean': 'yellow', + 'undefined': 'grey', + 'null': 'bold', + 'string': 'green', + 'date': 'magenta', + // "name": intentionally not styling + 'regexp': 'red' +}; + + +function stylizeWithColor(str, styleType) { + var style = inspect.styles[styleType]; + + if (style) { + return '\u001b[' + inspect.colors[style][0] + 'm' + str + + '\u001b[' + inspect.colors[style][1] + 'm'; + } else { + return str; + } +} + + +function stylizeNoColor(str, styleType) { + return str; +} + + +function arrayToHash(array) { + var hash = {}; + + array.forEach(function(val, idx) { + hash[val] = true; + }); + + return hash; +} + + +function formatValue(ctx, value, recurseTimes) { + // Provide a hook for user-specified inspect functions. + // Check that value is an object with an inspect function on it + if (ctx.customInspect && + value && + isFunction(value.inspect) && + // Filter out the util module, it's inspect function is special + value.inspect !== exports.inspect && + // Also filter out any prototype objects using the circular check. + !(value.constructor && value.constructor.prototype === value)) { + var ret = value.inspect(recurseTimes, ctx); + if (!isString(ret)) { + ret = formatValue(ctx, ret, recurseTimes); + } + return ret; + } + + // Primitive types cannot have properties + var primitive = formatPrimitive(ctx, value); + if (primitive) { + return primitive; + } + + // Look up the keys of the object. + var keys = Object.keys(value); + var visibleKeys = arrayToHash(keys); + + if (ctx.showHidden) { + keys = Object.getOwnPropertyNames(value); + } + + // IE doesn't make error fields non-enumerable + // http://msdn.microsoft.com/en-us/library/ie/dww52sbt(v=vs.94).aspx + if (isError(value) + && (keys.indexOf('message') >= 0 || keys.indexOf('description') >= 0)) { + return formatError(value); + } + + // Some type of object without properties can be shortcutted. + if (keys.length === 0) { + if (isFunction(value)) { + var name = value.name ? ': ' + value.name : ''; + return ctx.stylize('[Function' + name + ']', 'special'); + } + if (isRegExp(value)) { + return ctx.stylize(RegExp.prototype.toString.call(value), 'regexp'); + } + if (isDate(value)) { + return ctx.stylize(Date.prototype.toString.call(value), 'date'); + } + if (isError(value)) { + return formatError(value); + } + } + + var base = '', array = false, braces = ['{', '}']; + + // Make Array say that they are Array + if (isArray(value)) { + array = true; + braces = ['[', ']']; + } + + // Make functions say that they are functions + if (isFunction(value)) { + var n = value.name ? ': ' + value.name : ''; + base = ' [Function' + n + ']'; + } + + // Make RegExps say that they are RegExps + if (isRegExp(value)) { + base = ' ' + RegExp.prototype.toString.call(value); + } + + // Make dates with properties first say the date + if (isDate(value)) { + base = ' ' + Date.prototype.toUTCString.call(value); + } + + // Make error with message first say the error + if (isError(value)) { + base = ' ' + formatError(value); + } + + if (keys.length === 0 && (!array || value.length == 0)) { + return braces[0] + base + braces[1]; + } + + if (recurseTimes < 0) { + if (isRegExp(value)) { + return ctx.stylize(RegExp.prototype.toString.call(value), 'regexp'); + } else { + return ctx.stylize('[Object]', 'special'); + } + } + + ctx.seen.push(value); + + var output; + if (array) { + output = formatArray(ctx, value, recurseTimes, visibleKeys, keys); + } else { + output = keys.map(function(key) { + return formatProperty(ctx, value, recurseTimes, visibleKeys, key, array); + }); + } + + ctx.seen.pop(); + + return reduceToSingleString(output, base, braces); +} + + +function formatPrimitive(ctx, value) { + if (isUndefined(value)) + return ctx.stylize('undefined', 'undefined'); + if (isString(value)) { + var simple = '\'' + JSON.stringify(value).replace(/^"|"$/g, '') + .replace(/'/g, "\\'") + .replace(/\\"/g, '"') + '\''; + return ctx.stylize(simple, 'string'); + } + if (isNumber(value)) + return ctx.stylize('' + value, 'number'); + if (isBoolean(value)) + return ctx.stylize('' + value, 'boolean'); + // For some reason typeof null is "object", so special case here. + if (isNull(value)) + return ctx.stylize('null', 'null'); +} + + +function formatError(value) { + return '[' + Error.prototype.toString.call(value) + ']'; +} + + +function formatArray(ctx, value, recurseTimes, visibleKeys, keys) { + var output = []; + for (var i = 0, l = value.length; i < l; ++i) { + if (hasOwnProperty(value, String(i))) { + output.push(formatProperty(ctx, value, recurseTimes, visibleKeys, + String(i), true)); + } else { + output.push(''); + } + } + keys.forEach(function(key) { + if (!key.match(/^\d+$/)) { + output.push(formatProperty(ctx, value, recurseTimes, visibleKeys, + key, true)); + } + }); + return output; +} + + +function formatProperty(ctx, value, recurseTimes, visibleKeys, key, array) { + var name, str, desc; + desc = Object.getOwnPropertyDescriptor(value, key) || { value: value[key] }; + if (desc.get) { + if (desc.set) { + str = ctx.stylize('[Getter/Setter]', 'special'); + } else { + str = ctx.stylize('[Getter]', 'special'); + } + } else { + if (desc.set) { + str = ctx.stylize('[Setter]', 'special'); + } + } + if (!hasOwnProperty(visibleKeys, key)) { + name = '[' + key + ']'; + } + if (!str) { + if (ctx.seen.indexOf(desc.value) < 0) { + if (isNull(recurseTimes)) { + str = formatValue(ctx, desc.value, null); + } else { + str = formatValue(ctx, desc.value, recurseTimes - 1); + } + if (str.indexOf('\n') > -1) { + if (array) { + str = str.split('\n').map(function(line) { + return ' ' + line; + }).join('\n').substr(2); + } else { + str = '\n' + str.split('\n').map(function(line) { + return ' ' + line; + }).join('\n'); + } + } + } else { + str = ctx.stylize('[Circular]', 'special'); + } + } + if (isUndefined(name)) { + if (array && key.match(/^\d+$/)) { + return str; + } + name = JSON.stringify('' + key); + if (name.match(/^"([a-zA-Z_][a-zA-Z_0-9]*)"$/)) { + name = name.substr(1, name.length - 2); + name = ctx.stylize(name, 'name'); + } else { + name = name.replace(/'/g, "\\'") + .replace(/\\"/g, '"') + .replace(/(^"|"$)/g, "'"); + name = ctx.stylize(name, 'string'); + } + } + + return name + ': ' + str; +} + + +function reduceToSingleString(output, base, braces) { + var numLinesEst = 0; + var length = output.reduce(function(prev, cur) { + numLinesEst++; + if (cur.indexOf('\n') >= 0) numLinesEst++; + return prev + cur.replace(/\u001b\[\d\d?m/g, '').length + 1; + }, 0); + + if (length > 60) { + return braces[0] + + (base === '' ? '' : base + '\n ') + + ' ' + + output.join(',\n ') + + ' ' + + braces[1]; + } + + return braces[0] + base + ' ' + output.join(', ') + ' ' + braces[1]; +} + + +// NOTE: These type checking functions intentionally don't use `instanceof` +// because it is fragile and can be easily faked with `Object.create()`. +exports.types = require('./support/types'); + +function isArray(ar) { + return Array.isArray(ar); +} +exports.isArray = isArray; + +function isBoolean(arg) { + return typeof arg === 'boolean'; +} +exports.isBoolean = isBoolean; + +function isNull(arg) { + return arg === null; +} +exports.isNull = isNull; + +function isNullOrUndefined(arg) { + return arg == null; +} +exports.isNullOrUndefined = isNullOrUndefined; + +function isNumber(arg) { + return typeof arg === 'number'; +} +exports.isNumber = isNumber; + +function isString(arg) { + return typeof arg === 'string'; +} +exports.isString = isString; + +function isSymbol(arg) { + return typeof arg === 'symbol'; +} +exports.isSymbol = isSymbol; + +function isUndefined(arg) { + return arg === void 0; +} +exports.isUndefined = isUndefined; + +function isRegExp(re) { + return isObject(re) && objectToString(re) === '[object RegExp]'; +} +exports.isRegExp = isRegExp; +exports.types.isRegExp = isRegExp; + +function isObject(arg) { + return typeof arg === 'object' && arg !== null; +} +exports.isObject = isObject; + +function isDate(d) { + return isObject(d) && objectToString(d) === '[object Date]'; +} +exports.isDate = isDate; +exports.types.isDate = isDate; + +function isError(e) { + return isObject(e) && + (objectToString(e) === '[object Error]' || e instanceof Error); +} +exports.isError = isError; +exports.types.isNativeError = isError; + +function isFunction(arg) { + return typeof arg === 'function'; +} +exports.isFunction = isFunction; + +function isPrimitive(arg) { + return arg === null || + typeof arg === 'boolean' || + typeof arg === 'number' || + typeof arg === 'string' || + typeof arg === 'symbol' || // ES6 symbol + typeof arg === 'undefined'; +} +exports.isPrimitive = isPrimitive; + +exports.isBuffer = require('./support/isBuffer'); + +function objectToString(o) { + return Object.prototype.toString.call(o); +} + + +function pad(n) { + return n < 10 ? '0' + n.toString(10) : n.toString(10); +} + + +var months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', + 'Oct', 'Nov', 'Dec']; + +// 26 Feb 16:19:34 +function timestamp() { + var d = new Date(); + var time = [pad(d.getHours()), + pad(d.getMinutes()), + pad(d.getSeconds())].join(':'); + return [d.getDate(), months[d.getMonth()], time].join(' '); +} + + +// log is just a thin wrapper to console.log that prepends a timestamp +exports.log = function() { + console.log('%s - %s', timestamp(), exports.format.apply(exports, arguments)); +}; + + +/** + * Inherit the prototype methods from one constructor into another. + * + * The Function.prototype.inherits from lang.js rewritten as a standalone + * function (not on Function.prototype). NOTE: If this file is to be loaded + * during bootstrapping this function needs to be rewritten using some native + * functions as prototype setup using normal JavaScript does not work as + * expected during bootstrapping (see mirror.js in r114903). + * + * @param {function} ctor Constructor function which needs to inherit the + * prototype. + * @param {function} superCtor Constructor function to inherit prototype from. + */ +exports.inherits = require('inherits'); + +exports._extend = function(origin, add) { + // Don't do anything if add isn't an object + if (!add || !isObject(add)) return origin; + + var keys = Object.keys(add); + var i = keys.length; + while (i--) { + origin[keys[i]] = add[keys[i]]; + } + return origin; +}; + +function hasOwnProperty(obj, prop) { + return Object.prototype.hasOwnProperty.call(obj, prop); +} + +var kCustomPromisifiedSymbol = typeof Symbol !== 'undefined' ? Symbol('util.promisify.custom') : undefined; + +exports.promisify = function promisify(original) { + if (typeof original !== 'function') + throw new TypeError('The "original" argument must be of type Function'); + + if (kCustomPromisifiedSymbol && original[kCustomPromisifiedSymbol]) { + var fn = original[kCustomPromisifiedSymbol]; + if (typeof fn !== 'function') { + throw new TypeError('The "util.promisify.custom" argument must be of type Function'); + } + Object.defineProperty(fn, kCustomPromisifiedSymbol, { + value: fn, enumerable: false, writable: false, configurable: true + }); + return fn; + } + + function fn() { + var promiseResolve, promiseReject; + var promise = new Promise(function (resolve, reject) { + promiseResolve = resolve; + promiseReject = reject; + }); + + var args = []; + for (var i = 0; i < arguments.length; i++) { + args.push(arguments[i]); + } + args.push(function (err, value) { + if (err) { + promiseReject(err); + } else { + promiseResolve(value); + } + }); + + try { + original.apply(this, args); + } catch (err) { + promiseReject(err); + } + + return promise; + } + + Object.setPrototypeOf(fn, Object.getPrototypeOf(original)); + + if (kCustomPromisifiedSymbol) Object.defineProperty(fn, kCustomPromisifiedSymbol, { + value: fn, enumerable: false, writable: false, configurable: true + }); + return Object.defineProperties( + fn, + getOwnPropertyDescriptors(original) + ); +} + +exports.promisify.custom = kCustomPromisifiedSymbol + +function callbackifyOnRejected(reason, cb) { + // `!reason` guard inspired by bluebird (Ref: https://goo.gl/t5IS6M). + // Because `null` is a special error value in callbacks which means "no error + // occurred", we error-wrap so the callback consumer can distinguish between + // "the promise rejected with null" or "the promise fulfilled with undefined". + if (!reason) { + var newReason = new Error('Promise was rejected with a falsy value'); + newReason.reason = reason; + reason = newReason; + } + return cb(reason); +} + +function callbackify(original) { + if (typeof original !== 'function') { + throw new TypeError('The "original" argument must be of type Function'); + } + + // We DO NOT return the promise as it gives the user a false sense that + // the promise is actually somehow related to the callback's execution + // and that the callback throwing will reject the promise. + function callbackified() { + var args = []; + for (var i = 0; i < arguments.length; i++) { + args.push(arguments[i]); + } + + var maybeCb = args.pop(); + if (typeof maybeCb !== 'function') { + throw new TypeError('The last argument must be of type Function'); + } + var self = this; + var cb = function() { + return maybeCb.apply(self, arguments); + }; + // In true node style we process the callback on `nextTick` with all the + // implications (stack, `uncaughtException`, `async_hooks`) + original.apply(this, args) + .then(function(ret) { process.nextTick(cb.bind(null, null, ret)) }, + function(rej) { process.nextTick(callbackifyOnRejected.bind(null, rej, cb)) }); + } + + Object.setPrototypeOf(callbackified, Object.getPrototypeOf(original)); + Object.defineProperties(callbackified, + getOwnPropertyDescriptors(original)); + return callbackified; +} +exports.callbackify = callbackify; + +}).call(this)}).call(this,require('_process')) +},{"./support/isBuffer":208,"./support/types":209,"_process":164,"inherits":143}],211:[function(require,module,exports){ +(function (global){(function (){ +'use strict'; + +var forEach = require('foreach'); +var availableTypedArrays = require('available-typed-arrays'); +var callBound = require('call-bind/callBound'); + +var $toString = callBound('Object.prototype.toString'); +var hasSymbols = require('has-symbols')(); +var hasToStringTag = hasSymbols && typeof Symbol.toStringTag === 'symbol'; + +var typedArrays = availableTypedArrays(); + +var $slice = callBound('String.prototype.slice'); +var toStrTags = {}; +var gOPD = require('es-abstract/helpers/getOwnPropertyDescriptor'); +var getPrototypeOf = Object.getPrototypeOf; // require('getprototypeof'); +if (hasToStringTag && gOPD && getPrototypeOf) { + forEach(typedArrays, function (typedArray) { + if (typeof global[typedArray] === 'function') { + var arr = new global[typedArray](); + if (!(Symbol.toStringTag in arr)) { + throw new EvalError('this engine has support for Symbol.toStringTag, but ' + typedArray + ' does not have the property! Please report this.'); + } + var proto = getPrototypeOf(arr); + var descriptor = gOPD(proto, Symbol.toStringTag); + if (!descriptor) { + var superProto = getPrototypeOf(proto); + descriptor = gOPD(superProto, Symbol.toStringTag); + } + toStrTags[typedArray] = descriptor.get; + } + }); +} + +var tryTypedArrays = function tryAllTypedArrays(value) { + var foundName = false; + forEach(toStrTags, function (getter, typedArray) { + if (!foundName) { + try { + var name = getter.call(value); + if (name === typedArray) { + foundName = name; + } + } catch (e) {} + } + }); + return foundName; +}; + +var isTypedArray = require('is-typed-array'); + +module.exports = function whichTypedArray(value) { + if (!isTypedArray(value)) { return false; } + if (!hasToStringTag) { return $slice($toString(value), 8, -1); } + return tryTypedArrays(value); +}; + +}).call(this)}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) +},{"available-typed-arrays":16,"call-bind/callBound":65,"es-abstract/helpers/getOwnPropertyDescriptor":103,"foreach":106,"has-symbols":110,"is-typed-array":147}],212:[function(require,module,exports){ +(function (Buffer){(function (){ +// this file serves as an input to +// browserify coseverify.js --standalone COSE > cose.js + +const cose = require('cose-js'); + +// x,y,doc is an ArrayBuffer +const verify = function (x, y, doc){ + const verifier = { + 'key': { + 'x': Buffer.from(x), + 'y': Buffer.from(y) + } + }; + + cose.sign.verify( + Buffer.from(doc), + verifier, + {defaultType: 18}) + .then((buf) => { + console.log("Verification successful") + //console.log('Verified message: ' + buf.toString('utf8')); + }).catch((error) => { + console.log(error); + }); +} + +if (typeof module !== 'undefined'){ //we are in node.js environment + module.exports={ + verify + } +} +}).call(this)}).call(this,require("buffer").Buffer) +},{"buffer":64,"cose-js":232}],213:[function(require,module,exports){ +(function (Buffer){(function (){ +/* jshint esversion: 6 */ +/* jslint node: true */ +'use strict'; + +const crypto = require('crypto'); + +const toAlg = { + 16: 'aes-128-cbc', + 32: 'aes-256-cbc' +}; + +const supportedLen = { + 8: true, + 16: true +}; + +const iv = Buffer.alloc(16, 0); // Initialization vector. + +exports.create = function (key, msg, len) { + if (!Buffer.isBuffer(key)) { + throw new Error('Key must be of type Buffer'); + } + if (!Buffer.isBuffer(msg)) { + throw new Error('Msg must be of type Buffer'); + } + if (!supportedLen[len]) { + throw new Error('Len must be 8 or 16'); + } + + const algorithm = toAlg[key.length]; + + if (!algorithm) { + throw new Error('Unsupported key length ' + key.length); + } + + const msgLen = msg.length; + const padLen = 16 - (msgLen % 16); + const padding = (padLen === 16) ? Buffer.alloc(0, 0) : Buffer.alloc(padLen, 0); + const paddedMsg = Buffer.concat([msg, padding]); + + const cipher = crypto.createCipheriv(algorithm, key, iv); + const enc = cipher.update(paddedMsg); + const tagStart = enc.length - 16; + const tag = enc.slice(tagStart, tagStart + len); + + return tag; +}; + +}).call(this)}).call(this,require("buffer").Buffer) +},{"buffer":64,"crypto":74}],214:[function(require,module,exports){ +module.exports = require('./register')().Promise + +},{"./register":216}],215:[function(require,module,exports){ +"use strict" + // global key for user preferred registration +var REGISTRATION_KEY = '@@any-promise/REGISTRATION', + // Prior registration (preferred or detected) + registered = null + +/** + * Registers the given implementation. An implementation must + * be registered prior to any call to `require("any-promise")`, + * typically on application load. + * + * If called with no arguments, will return registration in + * following priority: + * + * For Node.js: + * + * 1. Previous registration + * 2. global.Promise if node.js version >= 0.12 + * 3. Auto detected promise based on first sucessful require of + * known promise libraries. Note this is a last resort, as the + * loaded library is non-deterministic. node.js >= 0.12 will + * always use global.Promise over this priority list. + * 4. Throws error. + * + * For Browser: + * + * 1. Previous registration + * 2. window.Promise + * 3. Throws error. + * + * Options: + * + * Promise: Desired Promise constructor + * global: Boolean - Should the registration be cached in a global variable to + * allow cross dependency/bundle registration? (default true) + */ +module.exports = function(root, loadImplementation){ + return function register(implementation, opts){ + implementation = implementation || null + opts = opts || {} + // global registration unless explicitly {global: false} in options (default true) + var registerGlobal = opts.global !== false; + + // load any previous global registration + if(registered === null && registerGlobal){ + registered = root[REGISTRATION_KEY] || null + } + + if(registered !== null + && implementation !== null + && registered.implementation !== implementation){ + // Throw error if attempting to redefine implementation + throw new Error('any-promise already defined as "'+registered.implementation+ + '". You can only register an implementation before the first '+ + ' call to require("any-promise") and an implementation cannot be changed') + } + + if(registered === null){ + // use provided implementation + if(implementation !== null && typeof opts.Promise !== 'undefined'){ + registered = { + Promise: opts.Promise, + implementation: implementation + } + } else { + // require implementation if implementation is specified but not provided + registered = loadImplementation(implementation) + } + + if(registerGlobal){ + // register preference globally in case multiple installations + root[REGISTRATION_KEY] = registered + } + } + + return registered + } +} + +},{}],216:[function(require,module,exports){ +"use strict"; +module.exports = require('./loader')(window, loadImplementation) + +/** + * Browser specific loadImplementation. Always uses `window.Promise` + * + * To register a custom implementation, must register with `Promise` option. + */ +function loadImplementation(){ + if(typeof window.Promise === 'undefined'){ + throw new Error("any-promise browser requires a polyfill or explicit registration"+ + " e.g: require('any-promise/register/bluebird')") + } + return { + Promise: window.Promise, + implementation: 'window.Promise' + } +} + +},{"./loader":215}],217:[function(require,module,exports){ +/*! bignumber.js v4.1.0 https://github.com/MikeMcl/bignumber.js/LICENCE */ + +;(function (globalObj) { + 'use strict'; + + /* + bignumber.js v4.1.0 + A JavaScript library for arbitrary-precision arithmetic. + https://github.com/MikeMcl/bignumber.js + Copyright (c) 2017 Michael Mclaughlin + MIT Expat Licence + */ + + + var BigNumber, + isNumeric = /^-?(\d+(\.\d*)?|\.\d+)(e[+-]?\d+)?$/i, + mathceil = Math.ceil, + mathfloor = Math.floor, + notBool = ' not a boolean or binary digit', + roundingMode = 'rounding mode', + tooManyDigits = 'number type has more than 15 significant digits', + ALPHABET = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ$_', + BASE = 1e14, + LOG_BASE = 14, + MAX_SAFE_INTEGER = 0x1fffffffffffff, // 2^53 - 1 + // MAX_INT32 = 0x7fffffff, // 2^31 - 1 + POWS_TEN = [1, 10, 100, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9, 1e10, 1e11, 1e12, 1e13], + SQRT_BASE = 1e7, + + /* + * The limit on the value of DECIMAL_PLACES, TO_EXP_NEG, TO_EXP_POS, MIN_EXP, MAX_EXP, and + * the arguments to toExponential, toFixed, toFormat, and toPrecision, beyond which an + * exception is thrown (if ERRORS is true). + */ + MAX = 1E9; // 0 to MAX_INT32 + + + /* + * Create and return a BigNumber constructor. + */ + function constructorFactory(config) { + var div, parseNumeric, + + // id tracks the caller function, so its name can be included in error messages. + id = 0, + P = BigNumber.prototype, + ONE = new BigNumber(1), + + + /********************************* EDITABLE DEFAULTS **********************************/ + + + /* + * The default values below must be integers within the inclusive ranges stated. + * The values can also be changed at run-time using BigNumber.config. + */ + + // The maximum number of decimal places for operations involving division. + DECIMAL_PLACES = 20, // 0 to MAX + + /* + * The rounding mode used when rounding to the above decimal places, and when using + * toExponential, toFixed, toFormat and toPrecision, and round (default value). + * UP 0 Away from zero. + * DOWN 1 Towards zero. + * CEIL 2 Towards +Infinity. + * FLOOR 3 Towards -Infinity. + * HALF_UP 4 Towards nearest neighbour. If equidistant, up. + * HALF_DOWN 5 Towards nearest neighbour. If equidistant, down. + * HALF_EVEN 6 Towards nearest neighbour. If equidistant, towards even neighbour. + * HALF_CEIL 7 Towards nearest neighbour. If equidistant, towards +Infinity. + * HALF_FLOOR 8 Towards nearest neighbour. If equidistant, towards -Infinity. + */ + ROUNDING_MODE = 4, // 0 to 8 + + // EXPONENTIAL_AT : [TO_EXP_NEG , TO_EXP_POS] + + // The exponent value at and beneath which toString returns exponential notation. + // Number type: -7 + TO_EXP_NEG = -7, // 0 to -MAX + + // The exponent value at and above which toString returns exponential notation. + // Number type: 21 + TO_EXP_POS = 21, // 0 to MAX + + // RANGE : [MIN_EXP, MAX_EXP] + + // The minimum exponent value, beneath which underflow to zero occurs. + // Number type: -324 (5e-324) + MIN_EXP = -1e7, // -1 to -MAX + + // The maximum exponent value, above which overflow to Infinity occurs. + // Number type: 308 (1.7976931348623157e+308) + // For MAX_EXP > 1e7, e.g. new BigNumber('1e100000000').plus(1) may be slow. + MAX_EXP = 1e7, // 1 to MAX + + // Whether BigNumber Errors are ever thrown. + ERRORS = true, // true or false + + // Change to intValidatorNoErrors if ERRORS is false. + isValidInt = intValidatorWithErrors, // intValidatorWithErrors/intValidatorNoErrors + + // Whether to use cryptographically-secure random number generation, if available. + CRYPTO = false, // true or false + + /* + * The modulo mode used when calculating the modulus: a mod n. + * The quotient (q = a / n) is calculated according to the corresponding rounding mode. + * The remainder (r) is calculated as: r = a - n * q. + * + * UP 0 The remainder is positive if the dividend is negative, else is negative. + * DOWN 1 The remainder has the same sign as the dividend. + * This modulo mode is commonly known as 'truncated division' and is + * equivalent to (a % n) in JavaScript. + * FLOOR 3 The remainder has the same sign as the divisor (Python %). + * HALF_EVEN 6 This modulo mode implements the IEEE 754 remainder function. + * EUCLID 9 Euclidian division. q = sign(n) * floor(a / abs(n)). + * The remainder is always positive. + * + * The truncated division, floored division, Euclidian division and IEEE 754 remainder + * modes are commonly used for the modulus operation. + * Although the other rounding modes can also be used, they may not give useful results. + */ + MODULO_MODE = 1, // 0 to 9 + + // The maximum number of significant digits of the result of the toPower operation. + // If POW_PRECISION is 0, there will be unlimited significant digits. + POW_PRECISION = 0, // 0 to MAX + + // The format specification used by the BigNumber.prototype.toFormat method. + FORMAT = { + decimalSeparator: '.', + groupSeparator: ',', + groupSize: 3, + secondaryGroupSize: 0, + fractionGroupSeparator: '\xA0', // non-breaking space + fractionGroupSize: 0 + }; + + + /******************************************************************************************/ + + + // CONSTRUCTOR + + + /* + * The BigNumber constructor and exported function. + * Create and return a new instance of a BigNumber object. + * + * n {number|string|BigNumber} A numeric value. + * [b] {number} The base of n. Integer, 2 to 64 inclusive. + */ + function BigNumber( n, b ) { + var c, e, i, num, len, str, + x = this; + + // Enable constructor usage without new. + if ( !( x instanceof BigNumber ) ) { + + // 'BigNumber() constructor call without new: {n}' + if (ERRORS) raise( 26, 'constructor call without new', n ); + return new BigNumber( n, b ); + } + + // 'new BigNumber() base not an integer: {b}' + // 'new BigNumber() base out of range: {b}' + if ( b == null || !isValidInt( b, 2, 64, id, 'base' ) ) { + + // Duplicate. + if ( n instanceof BigNumber ) { + x.s = n.s; + x.e = n.e; + x.c = ( n = n.c ) ? n.slice() : n; + id = 0; + return; + } + + if ( ( num = typeof n == 'number' ) && n * 0 == 0 ) { + x.s = 1 / n < 0 ? ( n = -n, -1 ) : 1; + + // Fast path for integers. + if ( n === ~~n ) { + for ( e = 0, i = n; i >= 10; i /= 10, e++ ); + x.e = e; + x.c = [n]; + id = 0; + return; + } + + str = n + ''; + } else { + if ( !isNumeric.test( str = n + '' ) ) return parseNumeric( x, str, num ); + x.s = str.charCodeAt(0) === 45 ? ( str = str.slice(1), -1 ) : 1; + } + } else { + b = b | 0; + str = n + ''; + + // Ensure return value is rounded to DECIMAL_PLACES as with other bases. + // Allow exponential notation to be used with base 10 argument. + if ( b == 10 ) { + x = new BigNumber( n instanceof BigNumber ? n : str ); + return round( x, DECIMAL_PLACES + x.e + 1, ROUNDING_MODE ); + } + + // Avoid potential interpretation of Infinity and NaN as base 44+ values. + // Any number in exponential form will fail due to the [Ee][+-]. + if ( ( num = typeof n == 'number' ) && n * 0 != 0 || + !( new RegExp( '^-?' + ( c = '[' + ALPHABET.slice( 0, b ) + ']+' ) + + '(?:\\.' + c + ')?$',b < 37 ? 'i' : '' ) ).test(str) ) { + return parseNumeric( x, str, num, b ); + } + + if (num) { + x.s = 1 / n < 0 ? ( str = str.slice(1), -1 ) : 1; + + if ( ERRORS && str.replace( /^0\.0*|\./, '' ).length > 15 ) { + + // 'new BigNumber() number type has more than 15 significant digits: {n}' + raise( id, tooManyDigits, n ); + } + + // Prevent later check for length on converted number. + num = false; + } else { + x.s = str.charCodeAt(0) === 45 ? ( str = str.slice(1), -1 ) : 1; + } + + str = convertBase( str, 10, b, x.s ); + } + + // Decimal point? + if ( ( e = str.indexOf('.') ) > -1 ) str = str.replace( '.', '' ); + + // Exponential form? + if ( ( i = str.search( /e/i ) ) > 0 ) { + + // Determine exponent. + if ( e < 0 ) e = i; + e += +str.slice( i + 1 ); + str = str.substring( 0, i ); + } else if ( e < 0 ) { + + // Integer. + e = str.length; + } + + // Determine leading zeros. + for ( i = 0; str.charCodeAt(i) === 48; i++ ); + + // Determine trailing zeros. + for ( len = str.length; str.charCodeAt(--len) === 48; ); + str = str.slice( i, len + 1 ); + + if (str) { + len = str.length; + + // Disallow numbers with over 15 significant digits if number type. + // 'new BigNumber() number type has more than 15 significant digits: {n}' + if ( num && ERRORS && len > 15 && ( n > MAX_SAFE_INTEGER || n !== mathfloor(n) ) ) { + raise( id, tooManyDigits, x.s * n ); + } + + e = e - i - 1; + + // Overflow? + if ( e > MAX_EXP ) { + + // Infinity. + x.c = x.e = null; + + // Underflow? + } else if ( e < MIN_EXP ) { + + // Zero. + x.c = [ x.e = 0 ]; + } else { + x.e = e; + x.c = []; + + // Transform base + + // e is the base 10 exponent. + // i is where to slice str to get the first element of the coefficient array. + i = ( e + 1 ) % LOG_BASE; + if ( e < 0 ) i += LOG_BASE; + + if ( i < len ) { + if (i) x.c.push( +str.slice( 0, i ) ); + + for ( len -= LOG_BASE; i < len; ) { + x.c.push( +str.slice( i, i += LOG_BASE ) ); + } + + str = str.slice(i); + i = LOG_BASE - str.length; + } else { + i -= len; + } + + for ( ; i--; str += '0' ); + x.c.push( +str ); + } + } else { + + // Zero. + x.c = [ x.e = 0 ]; + } + + id = 0; + } + + + // CONSTRUCTOR PROPERTIES + + + BigNumber.another = constructorFactory; + + BigNumber.ROUND_UP = 0; + BigNumber.ROUND_DOWN = 1; + BigNumber.ROUND_CEIL = 2; + BigNumber.ROUND_FLOOR = 3; + BigNumber.ROUND_HALF_UP = 4; + BigNumber.ROUND_HALF_DOWN = 5; + BigNumber.ROUND_HALF_EVEN = 6; + BigNumber.ROUND_HALF_CEIL = 7; + BigNumber.ROUND_HALF_FLOOR = 8; + BigNumber.EUCLID = 9; + + + /* + * Configure infrequently-changing library-wide settings. + * + * Accept an object or an argument list, with one or many of the following properties or + * parameters respectively: + * + * DECIMAL_PLACES {number} Integer, 0 to MAX inclusive + * ROUNDING_MODE {number} Integer, 0 to 8 inclusive + * EXPONENTIAL_AT {number|number[]} Integer, -MAX to MAX inclusive or + * [integer -MAX to 0 incl., 0 to MAX incl.] + * RANGE {number|number[]} Non-zero integer, -MAX to MAX inclusive or + * [integer -MAX to -1 incl., integer 1 to MAX incl.] + * ERRORS {boolean|number} true, false, 1 or 0 + * CRYPTO {boolean|number} true, false, 1 or 0 + * MODULO_MODE {number} 0 to 9 inclusive + * POW_PRECISION {number} 0 to MAX inclusive + * FORMAT {object} See BigNumber.prototype.toFormat + * decimalSeparator {string} + * groupSeparator {string} + * groupSize {number} + * secondaryGroupSize {number} + * fractionGroupSeparator {string} + * fractionGroupSize {number} + * + * (The values assigned to the above FORMAT object properties are not checked for validity.) + * + * E.g. + * BigNumber.config(20, 4) is equivalent to + * BigNumber.config({ DECIMAL_PLACES : 20, ROUNDING_MODE : 4 }) + * + * Ignore properties/parameters set to null or undefined. + * Return an object with the properties current values. + */ + BigNumber.config = BigNumber.set = function () { + var v, p, + i = 0, + r = {}, + a = arguments, + o = a[0], + has = o && typeof o == 'object' + ? function () { if ( o.hasOwnProperty(p) ) return ( v = o[p] ) != null; } + : function () { if ( a.length > i ) return ( v = a[i++] ) != null; }; + + // DECIMAL_PLACES {number} Integer, 0 to MAX inclusive. + // 'config() DECIMAL_PLACES not an integer: {v}' + // 'config() DECIMAL_PLACES out of range: {v}' + if ( has( p = 'DECIMAL_PLACES' ) && isValidInt( v, 0, MAX, 2, p ) ) { + DECIMAL_PLACES = v | 0; + } + r[p] = DECIMAL_PLACES; + + // ROUNDING_MODE {number} Integer, 0 to 8 inclusive. + // 'config() ROUNDING_MODE not an integer: {v}' + // 'config() ROUNDING_MODE out of range: {v}' + if ( has( p = 'ROUNDING_MODE' ) && isValidInt( v, 0, 8, 2, p ) ) { + ROUNDING_MODE = v | 0; + } + r[p] = ROUNDING_MODE; + + // EXPONENTIAL_AT {number|number[]} + // Integer, -MAX to MAX inclusive or [integer -MAX to 0 inclusive, 0 to MAX inclusive]. + // 'config() EXPONENTIAL_AT not an integer: {v}' + // 'config() EXPONENTIAL_AT out of range: {v}' + if ( has( p = 'EXPONENTIAL_AT' ) ) { + + if ( isArray(v) ) { + if ( isValidInt( v[0], -MAX, 0, 2, p ) && isValidInt( v[1], 0, MAX, 2, p ) ) { + TO_EXP_NEG = v[0] | 0; + TO_EXP_POS = v[1] | 0; + } + } else if ( isValidInt( v, -MAX, MAX, 2, p ) ) { + TO_EXP_NEG = -( TO_EXP_POS = ( v < 0 ? -v : v ) | 0 ); + } + } + r[p] = [ TO_EXP_NEG, TO_EXP_POS ]; + + // RANGE {number|number[]} Non-zero integer, -MAX to MAX inclusive or + // [integer -MAX to -1 inclusive, integer 1 to MAX inclusive]. + // 'config() RANGE not an integer: {v}' + // 'config() RANGE cannot be zero: {v}' + // 'config() RANGE out of range: {v}' + if ( has( p = 'RANGE' ) ) { + + if ( isArray(v) ) { + if ( isValidInt( v[0], -MAX, -1, 2, p ) && isValidInt( v[1], 1, MAX, 2, p ) ) { + MIN_EXP = v[0] | 0; + MAX_EXP = v[1] | 0; + } + } else if ( isValidInt( v, -MAX, MAX, 2, p ) ) { + if ( v | 0 ) MIN_EXP = -( MAX_EXP = ( v < 0 ? -v : v ) | 0 ); + else if (ERRORS) raise( 2, p + ' cannot be zero', v ); + } + } + r[p] = [ MIN_EXP, MAX_EXP ]; + + // ERRORS {boolean|number} true, false, 1 or 0. + // 'config() ERRORS not a boolean or binary digit: {v}' + if ( has( p = 'ERRORS' ) ) { + + if ( v === !!v || v === 1 || v === 0 ) { + id = 0; + isValidInt = ( ERRORS = !!v ) ? intValidatorWithErrors : intValidatorNoErrors; + } else if (ERRORS) { + raise( 2, p + notBool, v ); + } + } + r[p] = ERRORS; + + // CRYPTO {boolean|number} true, false, 1 or 0. + // 'config() CRYPTO not a boolean or binary digit: {v}' + // 'config() crypto unavailable: {crypto}' + if ( has( p = 'CRYPTO' ) ) { + + if ( v === true || v === false || v === 1 || v === 0 ) { + if (v) { + v = typeof crypto == 'undefined'; + if ( !v && crypto && (crypto.getRandomValues || crypto.randomBytes)) { + CRYPTO = true; + } else if (ERRORS) { + raise( 2, 'crypto unavailable', v ? void 0 : crypto ); + } else { + CRYPTO = false; + } + } else { + CRYPTO = false; + } + } else if (ERRORS) { + raise( 2, p + notBool, v ); + } + } + r[p] = CRYPTO; + + // MODULO_MODE {number} Integer, 0 to 9 inclusive. + // 'config() MODULO_MODE not an integer: {v}' + // 'config() MODULO_MODE out of range: {v}' + if ( has( p = 'MODULO_MODE' ) && isValidInt( v, 0, 9, 2, p ) ) { + MODULO_MODE = v | 0; + } + r[p] = MODULO_MODE; + + // POW_PRECISION {number} Integer, 0 to MAX inclusive. + // 'config() POW_PRECISION not an integer: {v}' + // 'config() POW_PRECISION out of range: {v}' + if ( has( p = 'POW_PRECISION' ) && isValidInt( v, 0, MAX, 2, p ) ) { + POW_PRECISION = v | 0; + } + r[p] = POW_PRECISION; + + // FORMAT {object} + // 'config() FORMAT not an object: {v}' + if ( has( p = 'FORMAT' ) ) { + + if ( typeof v == 'object' ) { + FORMAT = v; + } else if (ERRORS) { + raise( 2, p + ' not an object', v ); + } + } + r[p] = FORMAT; + + return r; + }; + + + /* + * Return a new BigNumber whose value is the maximum of the arguments. + * + * arguments {number|string|BigNumber} + */ + BigNumber.max = function () { return maxOrMin( arguments, P.lt ); }; + + + /* + * Return a new BigNumber whose value is the minimum of the arguments. + * + * arguments {number|string|BigNumber} + */ + BigNumber.min = function () { return maxOrMin( arguments, P.gt ); }; + + + /* + * Return a new BigNumber with a random value equal to or greater than 0 and less than 1, + * and with dp, or DECIMAL_PLACES if dp is omitted, decimal places (or less if trailing + * zeros are produced). + * + * [dp] {number} Decimal places. Integer, 0 to MAX inclusive. + * + * 'random() decimal places not an integer: {dp}' + * 'random() decimal places out of range: {dp}' + * 'random() crypto unavailable: {crypto}' + */ + BigNumber.random = (function () { + var pow2_53 = 0x20000000000000; + + // Return a 53 bit integer n, where 0 <= n < 9007199254740992. + // Check if Math.random() produces more than 32 bits of randomness. + // If it does, assume at least 53 bits are produced, otherwise assume at least 30 bits. + // 0x40000000 is 2^30, 0x800000 is 2^23, 0x1fffff is 2^21 - 1. + var random53bitInt = (Math.random() * pow2_53) & 0x1fffff + ? function () { return mathfloor( Math.random() * pow2_53 ); } + : function () { return ((Math.random() * 0x40000000 | 0) * 0x800000) + + (Math.random() * 0x800000 | 0); }; + + return function (dp) { + var a, b, e, k, v, + i = 0, + c = [], + rand = new BigNumber(ONE); + + dp = dp == null || !isValidInt( dp, 0, MAX, 14 ) ? DECIMAL_PLACES : dp | 0; + k = mathceil( dp / LOG_BASE ); + + if (CRYPTO) { + + // Browsers supporting crypto.getRandomValues. + if (crypto.getRandomValues) { + + a = crypto.getRandomValues( new Uint32Array( k *= 2 ) ); + + for ( ; i < k; ) { + + // 53 bits: + // ((Math.pow(2, 32) - 1) * Math.pow(2, 21)).toString(2) + // 11111 11111111 11111111 11111111 11100000 00000000 00000000 + // ((Math.pow(2, 32) - 1) >>> 11).toString(2) + // 11111 11111111 11111111 + // 0x20000 is 2^21. + v = a[i] * 0x20000 + (a[i + 1] >>> 11); + + // Rejection sampling: + // 0 <= v < 9007199254740992 + // Probability that v >= 9e15, is + // 7199254740992 / 9007199254740992 ~= 0.0008, i.e. 1 in 1251 + if ( v >= 9e15 ) { + b = crypto.getRandomValues( new Uint32Array(2) ); + a[i] = b[0]; + a[i + 1] = b[1]; + } else { + + // 0 <= v <= 8999999999999999 + // 0 <= (v % 1e14) <= 99999999999999 + c.push( v % 1e14 ); + i += 2; + } + } + i = k / 2; + + // Node.js supporting crypto.randomBytes. + } else if (crypto.randomBytes) { + + // buffer + a = crypto.randomBytes( k *= 7 ); + + for ( ; i < k; ) { + + // 0x1000000000000 is 2^48, 0x10000000000 is 2^40 + // 0x100000000 is 2^32, 0x1000000 is 2^24 + // 11111 11111111 11111111 11111111 11111111 11111111 11111111 + // 0 <= v < 9007199254740992 + v = ( ( a[i] & 31 ) * 0x1000000000000 ) + ( a[i + 1] * 0x10000000000 ) + + ( a[i + 2] * 0x100000000 ) + ( a[i + 3] * 0x1000000 ) + + ( a[i + 4] << 16 ) + ( a[i + 5] << 8 ) + a[i + 6]; + + if ( v >= 9e15 ) { + crypto.randomBytes(7).copy( a, i ); + } else { + + // 0 <= (v % 1e14) <= 99999999999999 + c.push( v % 1e14 ); + i += 7; + } + } + i = k / 7; + } else { + CRYPTO = false; + if (ERRORS) raise( 14, 'crypto unavailable', crypto ); + } + } + + // Use Math.random. + if (!CRYPTO) { + + for ( ; i < k; ) { + v = random53bitInt(); + if ( v < 9e15 ) c[i++] = v % 1e14; + } + } + + k = c[--i]; + dp %= LOG_BASE; + + // Convert trailing digits to zeros according to dp. + if ( k && dp ) { + v = POWS_TEN[LOG_BASE - dp]; + c[i] = mathfloor( k / v ) * v; + } + + // Remove trailing elements which are zero. + for ( ; c[i] === 0; c.pop(), i-- ); + + // Zero? + if ( i < 0 ) { + c = [ e = 0 ]; + } else { + + // Remove leading elements which are zero and adjust exponent accordingly. + for ( e = -1 ; c[0] === 0; c.splice(0, 1), e -= LOG_BASE); + + // Count the digits of the first element of c to determine leading zeros, and... + for ( i = 1, v = c[0]; v >= 10; v /= 10, i++); + + // adjust the exponent accordingly. + if ( i < LOG_BASE ) e -= LOG_BASE - i; + } + + rand.e = e; + rand.c = c; + return rand; + }; + })(); + + + // PRIVATE FUNCTIONS + + + // Convert a numeric string of baseIn to a numeric string of baseOut. + function convertBase( str, baseOut, baseIn, sign ) { + var d, e, k, r, x, xc, y, + i = str.indexOf( '.' ), + dp = DECIMAL_PLACES, + rm = ROUNDING_MODE; + + if ( baseIn < 37 ) str = str.toLowerCase(); + + // Non-integer. + if ( i >= 0 ) { + k = POW_PRECISION; + + // Unlimited precision. + POW_PRECISION = 0; + str = str.replace( '.', '' ); + y = new BigNumber(baseIn); + x = y.pow( str.length - i ); + POW_PRECISION = k; + + // Convert str as if an integer, then restore the fraction part by dividing the + // result by its base raised to a power. + y.c = toBaseOut( toFixedPoint( coeffToString( x.c ), x.e ), 10, baseOut ); + y.e = y.c.length; + } + + // Convert the number as integer. + xc = toBaseOut( str, baseIn, baseOut ); + e = k = xc.length; + + // Remove trailing zeros. + for ( ; xc[--k] == 0; xc.pop() ); + if ( !xc[0] ) return '0'; + + if ( i < 0 ) { + --e; + } else { + x.c = xc; + x.e = e; + + // sign is needed for correct rounding. + x.s = sign; + x = div( x, y, dp, rm, baseOut ); + xc = x.c; + r = x.r; + e = x.e; + } + + d = e + dp + 1; + + // The rounding digit, i.e. the digit to the right of the digit that may be rounded up. + i = xc[d]; + k = baseOut / 2; + r = r || d < 0 || xc[d + 1] != null; + + r = rm < 4 ? ( i != null || r ) && ( rm == 0 || rm == ( x.s < 0 ? 3 : 2 ) ) + : i > k || i == k &&( rm == 4 || r || rm == 6 && xc[d - 1] & 1 || + rm == ( x.s < 0 ? 8 : 7 ) ); + + if ( d < 1 || !xc[0] ) { + + // 1^-dp or 0. + str = r ? toFixedPoint( '1', -dp ) : '0'; + } else { + xc.length = d; + + if (r) { + + // Rounding up may mean the previous digit has to be rounded up and so on. + for ( --baseOut; ++xc[--d] > baseOut; ) { + xc[d] = 0; + + if ( !d ) { + ++e; + xc = [1].concat(xc); + } + } + } + + // Determine trailing zeros. + for ( k = xc.length; !xc[--k]; ); + + // E.g. [4, 11, 15] becomes 4bf. + for ( i = 0, str = ''; i <= k; str += ALPHABET.charAt( xc[i++] ) ); + str = toFixedPoint( str, e ); + } + + // The caller will add the sign. + return str; + } + + + // Perform division in the specified base. Called by div and convertBase. + div = (function () { + + // Assume non-zero x and k. + function multiply( x, k, base ) { + var m, temp, xlo, xhi, + carry = 0, + i = x.length, + klo = k % SQRT_BASE, + khi = k / SQRT_BASE | 0; + + for ( x = x.slice(); i--; ) { + xlo = x[i] % SQRT_BASE; + xhi = x[i] / SQRT_BASE | 0; + m = khi * xlo + xhi * klo; + temp = klo * xlo + ( ( m % SQRT_BASE ) * SQRT_BASE ) + carry; + carry = ( temp / base | 0 ) + ( m / SQRT_BASE | 0 ) + khi * xhi; + x[i] = temp % base; + } + + if (carry) x = [carry].concat(x); + + return x; + } + + function compare( a, b, aL, bL ) { + var i, cmp; + + if ( aL != bL ) { + cmp = aL > bL ? 1 : -1; + } else { + + for ( i = cmp = 0; i < aL; i++ ) { + + if ( a[i] != b[i] ) { + cmp = a[i] > b[i] ? 1 : -1; + break; + } + } + } + return cmp; + } + + function subtract( a, b, aL, base ) { + var i = 0; + + // Subtract b from a. + for ( ; aL--; ) { + a[aL] -= i; + i = a[aL] < b[aL] ? 1 : 0; + a[aL] = i * base + a[aL] - b[aL]; + } + + // Remove leading zeros. + for ( ; !a[0] && a.length > 1; a.splice(0, 1) ); + } + + // x: dividend, y: divisor. + return function ( x, y, dp, rm, base ) { + var cmp, e, i, more, n, prod, prodL, q, qc, rem, remL, rem0, xi, xL, yc0, + yL, yz, + s = x.s == y.s ? 1 : -1, + xc = x.c, + yc = y.c; + + // Either NaN, Infinity or 0? + if ( !xc || !xc[0] || !yc || !yc[0] ) { + + return new BigNumber( + + // Return NaN if either NaN, or both Infinity or 0. + !x.s || !y.s || ( xc ? yc && xc[0] == yc[0] : !yc ) ? NaN : + + // Return ±0 if x is ±0 or y is ±Infinity, or return ±Infinity as y is ±0. + xc && xc[0] == 0 || !yc ? s * 0 : s / 0 + ); + } + + q = new BigNumber(s); + qc = q.c = []; + e = x.e - y.e; + s = dp + e + 1; + + if ( !base ) { + base = BASE; + e = bitFloor( x.e / LOG_BASE ) - bitFloor( y.e / LOG_BASE ); + s = s / LOG_BASE | 0; + } + + // Result exponent may be one less then the current value of e. + // The coefficients of the BigNumbers from convertBase may have trailing zeros. + for ( i = 0; yc[i] == ( xc[i] || 0 ); i++ ); + if ( yc[i] > ( xc[i] || 0 ) ) e--; + + if ( s < 0 ) { + qc.push(1); + more = true; + } else { + xL = xc.length; + yL = yc.length; + i = 0; + s += 2; + + // Normalise xc and yc so highest order digit of yc is >= base / 2. + + n = mathfloor( base / ( yc[0] + 1 ) ); + + // Not necessary, but to handle odd bases where yc[0] == ( base / 2 ) - 1. + // if ( n > 1 || n++ == 1 && yc[0] < base / 2 ) { + if ( n > 1 ) { + yc = multiply( yc, n, base ); + xc = multiply( xc, n, base ); + yL = yc.length; + xL = xc.length; + } + + xi = yL; + rem = xc.slice( 0, yL ); + remL = rem.length; + + // Add zeros to make remainder as long as divisor. + for ( ; remL < yL; rem[remL++] = 0 ); + yz = yc.slice(); + yz = [0].concat(yz); + yc0 = yc[0]; + if ( yc[1] >= base / 2 ) yc0++; + // Not necessary, but to prevent trial digit n > base, when using base 3. + // else if ( base == 3 && yc0 == 1 ) yc0 = 1 + 1e-15; + + do { + n = 0; + + // Compare divisor and remainder. + cmp = compare( yc, rem, yL, remL ); + + // If divisor < remainder. + if ( cmp < 0 ) { + + // Calculate trial digit, n. + + rem0 = rem[0]; + if ( yL != remL ) rem0 = rem0 * base + ( rem[1] || 0 ); + + // n is how many times the divisor goes into the current remainder. + n = mathfloor( rem0 / yc0 ); + + // Algorithm: + // 1. product = divisor * trial digit (n) + // 2. if product > remainder: product -= divisor, n-- + // 3. remainder -= product + // 4. if product was < remainder at 2: + // 5. compare new remainder and divisor + // 6. If remainder > divisor: remainder -= divisor, n++ + + if ( n > 1 ) { + + // n may be > base only when base is 3. + if (n >= base) n = base - 1; + + // product = divisor * trial digit. + prod = multiply( yc, n, base ); + prodL = prod.length; + remL = rem.length; + + // Compare product and remainder. + // If product > remainder. + // Trial digit n too high. + // n is 1 too high about 5% of the time, and is not known to have + // ever been more than 1 too high. + while ( compare( prod, rem, prodL, remL ) == 1 ) { + n--; + + // Subtract divisor from product. + subtract( prod, yL < prodL ? yz : yc, prodL, base ); + prodL = prod.length; + cmp = 1; + } + } else { + + // n is 0 or 1, cmp is -1. + // If n is 0, there is no need to compare yc and rem again below, + // so change cmp to 1 to avoid it. + // If n is 1, leave cmp as -1, so yc and rem are compared again. + if ( n == 0 ) { + + // divisor < remainder, so n must be at least 1. + cmp = n = 1; + } + + // product = divisor + prod = yc.slice(); + prodL = prod.length; + } + + if ( prodL < remL ) prod = [0].concat(prod); + + // Subtract product from remainder. + subtract( rem, prod, remL, base ); + remL = rem.length; + + // If product was < remainder. + if ( cmp == -1 ) { + + // Compare divisor and new remainder. + // If divisor < new remainder, subtract divisor from remainder. + // Trial digit n too low. + // n is 1 too low about 5% of the time, and very rarely 2 too low. + while ( compare( yc, rem, yL, remL ) < 1 ) { + n++; + + // Subtract divisor from remainder. + subtract( rem, yL < remL ? yz : yc, remL, base ); + remL = rem.length; + } + } + } else if ( cmp === 0 ) { + n++; + rem = [0]; + } // else cmp === 1 and n will be 0 + + // Add the next digit, n, to the result array. + qc[i++] = n; + + // Update the remainder. + if ( rem[0] ) { + rem[remL++] = xc[xi] || 0; + } else { + rem = [ xc[xi] ]; + remL = 1; + } + } while ( ( xi++ < xL || rem[0] != null ) && s-- ); + + more = rem[0] != null; + + // Leading zero? + if ( !qc[0] ) qc.splice(0, 1); + } + + if ( base == BASE ) { + + // To calculate q.e, first get the number of digits of qc[0]. + for ( i = 1, s = qc[0]; s >= 10; s /= 10, i++ ); + round( q, dp + ( q.e = i + e * LOG_BASE - 1 ) + 1, rm, more ); + + // Caller is convertBase. + } else { + q.e = e; + q.r = +more; + } + + return q; + }; + })(); + + + /* + * Return a string representing the value of BigNumber n in fixed-point or exponential + * notation rounded to the specified decimal places or significant digits. + * + * n is a BigNumber. + * i is the index of the last digit required (i.e. the digit that may be rounded up). + * rm is the rounding mode. + * caller is caller id: toExponential 19, toFixed 20, toFormat 21, toPrecision 24. + */ + function format( n, i, rm, caller ) { + var c0, e, ne, len, str; + + rm = rm != null && isValidInt( rm, 0, 8, caller, roundingMode ) + ? rm | 0 : ROUNDING_MODE; + + if ( !n.c ) return n.toString(); + c0 = n.c[0]; + ne = n.e; + + if ( i == null ) { + str = coeffToString( n.c ); + str = caller == 19 || caller == 24 && ne <= TO_EXP_NEG + ? toExponential( str, ne ) + : toFixedPoint( str, ne ); + } else { + n = round( new BigNumber(n), i, rm ); + + // n.e may have changed if the value was rounded up. + e = n.e; + + str = coeffToString( n.c ); + len = str.length; + + // toPrecision returns exponential notation if the number of significant digits + // specified is less than the number of digits necessary to represent the integer + // part of the value in fixed-point notation. + + // Exponential notation. + if ( caller == 19 || caller == 24 && ( i <= e || e <= TO_EXP_NEG ) ) { + + // Append zeros? + for ( ; len < i; str += '0', len++ ); + str = toExponential( str, e ); + + // Fixed-point notation. + } else { + i -= ne; + str = toFixedPoint( str, e ); + + // Append zeros? + if ( e + 1 > len ) { + if ( --i > 0 ) for ( str += '.'; i--; str += '0' ); + } else { + i += e - len; + if ( i > 0 ) { + if ( e + 1 == len ) str += '.'; + for ( ; i--; str += '0' ); + } + } + } + } + + return n.s < 0 && c0 ? '-' + str : str; + } + + + // Handle BigNumber.max and BigNumber.min. + function maxOrMin( args, method ) { + var m, n, + i = 0; + + if ( isArray( args[0] ) ) args = args[0]; + m = new BigNumber( args[0] ); + + for ( ; ++i < args.length; ) { + n = new BigNumber( args[i] ); + + // If any number is NaN, return NaN. + if ( !n.s ) { + m = n; + break; + } else if ( method.call( m, n ) ) { + m = n; + } + } + + return m; + } + + + /* + * Return true if n is an integer in range, otherwise throw. + * Use for argument validation when ERRORS is true. + */ + function intValidatorWithErrors( n, min, max, caller, name ) { + if ( n < min || n > max || n != truncate(n) ) { + raise( caller, ( name || 'decimal places' ) + + ( n < min || n > max ? ' out of range' : ' not an integer' ), n ); + } + + return true; + } + + + /* + * Strip trailing zeros, calculate base 10 exponent and check against MIN_EXP and MAX_EXP. + * Called by minus, plus and times. + */ + function normalise( n, c, e ) { + var i = 1, + j = c.length; + + // Remove trailing zeros. + for ( ; !c[--j]; c.pop() ); + + // Calculate the base 10 exponent. First get the number of digits of c[0]. + for ( j = c[0]; j >= 10; j /= 10, i++ ); + + // Overflow? + if ( ( e = i + e * LOG_BASE - 1 ) > MAX_EXP ) { + + // Infinity. + n.c = n.e = null; + + // Underflow? + } else if ( e < MIN_EXP ) { + + // Zero. + n.c = [ n.e = 0 ]; + } else { + n.e = e; + n.c = c; + } + + return n; + } + + + // Handle values that fail the validity test in BigNumber. + parseNumeric = (function () { + var basePrefix = /^(-?)0([xbo])(?=\w[\w.]*$)/i, + dotAfter = /^([^.]+)\.$/, + dotBefore = /^\.([^.]+)$/, + isInfinityOrNaN = /^-?(Infinity|NaN)$/, + whitespaceOrPlus = /^\s*\+(?=[\w.])|^\s+|\s+$/g; + + return function ( x, str, num, b ) { + var base, + s = num ? str : str.replace( whitespaceOrPlus, '' ); + + // No exception on ±Infinity or NaN. + if ( isInfinityOrNaN.test(s) ) { + x.s = isNaN(s) ? null : s < 0 ? -1 : 1; + } else { + if ( !num ) { + + // basePrefix = /^(-?)0([xbo])(?=\w[\w.]*$)/i + s = s.replace( basePrefix, function ( m, p1, p2 ) { + base = ( p2 = p2.toLowerCase() ) == 'x' ? 16 : p2 == 'b' ? 2 : 8; + return !b || b == base ? p1 : m; + }); + + if (b) { + base = b; + + // E.g. '1.' to '1', '.1' to '0.1' + s = s.replace( dotAfter, '$1' ).replace( dotBefore, '0.$1' ); + } + + if ( str != s ) return new BigNumber( s, base ); + } + + // 'new BigNumber() not a number: {n}' + // 'new BigNumber() not a base {b} number: {n}' + if (ERRORS) raise( id, 'not a' + ( b ? ' base ' + b : '' ) + ' number', str ); + x.s = null; + } + + x.c = x.e = null; + id = 0; + } + })(); + + + // Throw a BigNumber Error. + function raise( caller, msg, val ) { + var error = new Error( [ + 'new BigNumber', // 0 + 'cmp', // 1 + 'config', // 2 + 'div', // 3 + 'divToInt', // 4 + 'eq', // 5 + 'gt', // 6 + 'gte', // 7 + 'lt', // 8 + 'lte', // 9 + 'minus', // 10 + 'mod', // 11 + 'plus', // 12 + 'precision', // 13 + 'random', // 14 + 'round', // 15 + 'shift', // 16 + 'times', // 17 + 'toDigits', // 18 + 'toExponential', // 19 + 'toFixed', // 20 + 'toFormat', // 21 + 'toFraction', // 22 + 'pow', // 23 + 'toPrecision', // 24 + 'toString', // 25 + 'BigNumber' // 26 + ][caller] + '() ' + msg + ': ' + val ); + + error.name = 'BigNumber Error'; + id = 0; + throw error; + } + + + /* + * Round x to sd significant digits using rounding mode rm. Check for over/under-flow. + * If r is truthy, it is known that there are more digits after the rounding digit. + */ + function round( x, sd, rm, r ) { + var d, i, j, k, n, ni, rd, + xc = x.c, + pows10 = POWS_TEN; + + // if x is not Infinity or NaN... + if (xc) { + + // rd is the rounding digit, i.e. the digit after the digit that may be rounded up. + // n is a base 1e14 number, the value of the element of array x.c containing rd. + // ni is the index of n within x.c. + // d is the number of digits of n. + // i is the index of rd within n including leading zeros. + // j is the actual index of rd within n (if < 0, rd is a leading zero). + out: { + + // Get the number of digits of the first element of xc. + for ( d = 1, k = xc[0]; k >= 10; k /= 10, d++ ); + i = sd - d; + + // If the rounding digit is in the first element of xc... + if ( i < 0 ) { + i += LOG_BASE; + j = sd; + n = xc[ ni = 0 ]; + + // Get the rounding digit at index j of n. + rd = n / pows10[ d - j - 1 ] % 10 | 0; + } else { + ni = mathceil( ( i + 1 ) / LOG_BASE ); + + if ( ni >= xc.length ) { + + if (r) { + + // Needed by sqrt. + for ( ; xc.length <= ni; xc.push(0) ); + n = rd = 0; + d = 1; + i %= LOG_BASE; + j = i - LOG_BASE + 1; + } else { + break out; + } + } else { + n = k = xc[ni]; + + // Get the number of digits of n. + for ( d = 1; k >= 10; k /= 10, d++ ); + + // Get the index of rd within n. + i %= LOG_BASE; + + // Get the index of rd within n, adjusted for leading zeros. + // The number of leading zeros of n is given by LOG_BASE - d. + j = i - LOG_BASE + d; + + // Get the rounding digit at index j of n. + rd = j < 0 ? 0 : n / pows10[ d - j - 1 ] % 10 | 0; + } + } + + r = r || sd < 0 || + + // Are there any non-zero digits after the rounding digit? + // The expression n % pows10[ d - j - 1 ] returns all digits of n to the right + // of the digit at j, e.g. if n is 908714 and j is 2, the expression gives 714. + xc[ni + 1] != null || ( j < 0 ? n : n % pows10[ d - j - 1 ] ); + + r = rm < 4 + ? ( rd || r ) && ( rm == 0 || rm == ( x.s < 0 ? 3 : 2 ) ) + : rd > 5 || rd == 5 && ( rm == 4 || r || rm == 6 && + + // Check whether the digit to the left of the rounding digit is odd. + ( ( i > 0 ? j > 0 ? n / pows10[ d - j ] : 0 : xc[ni - 1] ) % 10 ) & 1 || + rm == ( x.s < 0 ? 8 : 7 ) ); + + if ( sd < 1 || !xc[0] ) { + xc.length = 0; + + if (r) { + + // Convert sd to decimal places. + sd -= x.e + 1; + + // 1, 0.1, 0.01, 0.001, 0.0001 etc. + xc[0] = pows10[ ( LOG_BASE - sd % LOG_BASE ) % LOG_BASE ]; + x.e = -sd || 0; + } else { + + // Zero. + xc[0] = x.e = 0; + } + + return x; + } + + // Remove excess digits. + if ( i == 0 ) { + xc.length = ni; + k = 1; + ni--; + } else { + xc.length = ni + 1; + k = pows10[ LOG_BASE - i ]; + + // E.g. 56700 becomes 56000 if 7 is the rounding digit. + // j > 0 means i > number of leading zeros of n. + xc[ni] = j > 0 ? mathfloor( n / pows10[ d - j ] % pows10[j] ) * k : 0; + } + + // Round up? + if (r) { + + for ( ; ; ) { + + // If the digit to be rounded up is in the first element of xc... + if ( ni == 0 ) { + + // i will be the length of xc[0] before k is added. + for ( i = 1, j = xc[0]; j >= 10; j /= 10, i++ ); + j = xc[0] += k; + for ( k = 1; j >= 10; j /= 10, k++ ); + + // if i != k the length has increased. + if ( i != k ) { + x.e++; + if ( xc[0] == BASE ) xc[0] = 1; + } + + break; + } else { + xc[ni] += k; + if ( xc[ni] != BASE ) break; + xc[ni--] = 0; + k = 1; + } + } + } + + // Remove trailing zeros. + for ( i = xc.length; xc[--i] === 0; xc.pop() ); + } + + // Overflow? Infinity. + if ( x.e > MAX_EXP ) { + x.c = x.e = null; + + // Underflow? Zero. + } else if ( x.e < MIN_EXP ) { + x.c = [ x.e = 0 ]; + } + } + + return x; + } + + + // PROTOTYPE/INSTANCE METHODS + + + /* + * Return a new BigNumber whose value is the absolute value of this BigNumber. + */ + P.absoluteValue = P.abs = function () { + var x = new BigNumber(this); + if ( x.s < 0 ) x.s = 1; + return x; + }; + + + /* + * Return a new BigNumber whose value is the value of this BigNumber rounded to a whole + * number in the direction of Infinity. + */ + P.ceil = function () { + return round( new BigNumber(this), this.e + 1, 2 ); + }; + + + /* + * Return + * 1 if the value of this BigNumber is greater than the value of BigNumber(y, b), + * -1 if the value of this BigNumber is less than the value of BigNumber(y, b), + * 0 if they have the same value, + * or null if the value of either is NaN. + */ + P.comparedTo = P.cmp = function ( y, b ) { + id = 1; + return compare( this, new BigNumber( y, b ) ); + }; + + + /* + * Return the number of decimal places of the value of this BigNumber, or null if the value + * of this BigNumber is ±Infinity or NaN. + */ + P.decimalPlaces = P.dp = function () { + var n, v, + c = this.c; + + if ( !c ) return null; + n = ( ( v = c.length - 1 ) - bitFloor( this.e / LOG_BASE ) ) * LOG_BASE; + + // Subtract the number of trailing zeros of the last number. + if ( v = c[v] ) for ( ; v % 10 == 0; v /= 10, n-- ); + if ( n < 0 ) n = 0; + + return n; + }; + + + /* + * n / 0 = I + * n / N = N + * n / I = 0 + * 0 / n = 0 + * 0 / 0 = N + * 0 / N = N + * 0 / I = 0 + * N / n = N + * N / 0 = N + * N / N = N + * N / I = N + * I / n = I + * I / 0 = I + * I / N = N + * I / I = N + * + * Return a new BigNumber whose value is the value of this BigNumber divided by the value of + * BigNumber(y, b), rounded according to DECIMAL_PLACES and ROUNDING_MODE. + */ + P.dividedBy = P.div = function ( y, b ) { + id = 3; + return div( this, new BigNumber( y, b ), DECIMAL_PLACES, ROUNDING_MODE ); + }; + + + /* + * Return a new BigNumber whose value is the integer part of dividing the value of this + * BigNumber by the value of BigNumber(y, b). + */ + P.dividedToIntegerBy = P.divToInt = function ( y, b ) { + id = 4; + return div( this, new BigNumber( y, b ), 0, 1 ); + }; + + + /* + * Return true if the value of this BigNumber is equal to the value of BigNumber(y, b), + * otherwise returns false. + */ + P.equals = P.eq = function ( y, b ) { + id = 5; + return compare( this, new BigNumber( y, b ) ) === 0; + }; + + + /* + * Return a new BigNumber whose value is the value of this BigNumber rounded to a whole + * number in the direction of -Infinity. + */ + P.floor = function () { + return round( new BigNumber(this), this.e + 1, 3 ); + }; + + + /* + * Return true if the value of this BigNumber is greater than the value of BigNumber(y, b), + * otherwise returns false. + */ + P.greaterThan = P.gt = function ( y, b ) { + id = 6; + return compare( this, new BigNumber( y, b ) ) > 0; + }; + + + /* + * Return true if the value of this BigNumber is greater than or equal to the value of + * BigNumber(y, b), otherwise returns false. + */ + P.greaterThanOrEqualTo = P.gte = function ( y, b ) { + id = 7; + return ( b = compare( this, new BigNumber( y, b ) ) ) === 1 || b === 0; + + }; + + + /* + * Return true if the value of this BigNumber is a finite number, otherwise returns false. + */ + P.isFinite = function () { + return !!this.c; + }; + + + /* + * Return true if the value of this BigNumber is an integer, otherwise return false. + */ + P.isInteger = P.isInt = function () { + return !!this.c && bitFloor( this.e / LOG_BASE ) > this.c.length - 2; + }; + + + /* + * Return true if the value of this BigNumber is NaN, otherwise returns false. + */ + P.isNaN = function () { + return !this.s; + }; + + + /* + * Return true if the value of this BigNumber is negative, otherwise returns false. + */ + P.isNegative = P.isNeg = function () { + return this.s < 0; + }; + + + /* + * Return true if the value of this BigNumber is 0 or -0, otherwise returns false. + */ + P.isZero = function () { + return !!this.c && this.c[0] == 0; + }; + + + /* + * Return true if the value of this BigNumber is less than the value of BigNumber(y, b), + * otherwise returns false. + */ + P.lessThan = P.lt = function ( y, b ) { + id = 8; + return compare( this, new BigNumber( y, b ) ) < 0; + }; + + + /* + * Return true if the value of this BigNumber is less than or equal to the value of + * BigNumber(y, b), otherwise returns false. + */ + P.lessThanOrEqualTo = P.lte = function ( y, b ) { + id = 9; + return ( b = compare( this, new BigNumber( y, b ) ) ) === -1 || b === 0; + }; + + + /* + * n - 0 = n + * n - N = N + * n - I = -I + * 0 - n = -n + * 0 - 0 = 0 + * 0 - N = N + * 0 - I = -I + * N - n = N + * N - 0 = N + * N - N = N + * N - I = N + * I - n = I + * I - 0 = I + * I - N = N + * I - I = N + * + * Return a new BigNumber whose value is the value of this BigNumber minus the value of + * BigNumber(y, b). + */ + P.minus = P.sub = function ( y, b ) { + var i, j, t, xLTy, + x = this, + a = x.s; + + id = 10; + y = new BigNumber( y, b ); + b = y.s; + + // Either NaN? + if ( !a || !b ) return new BigNumber(NaN); + + // Signs differ? + if ( a != b ) { + y.s = -b; + return x.plus(y); + } + + var xe = x.e / LOG_BASE, + ye = y.e / LOG_BASE, + xc = x.c, + yc = y.c; + + if ( !xe || !ye ) { + + // Either Infinity? + if ( !xc || !yc ) return xc ? ( y.s = -b, y ) : new BigNumber( yc ? x : NaN ); + + // Either zero? + if ( !xc[0] || !yc[0] ) { + + // Return y if y is non-zero, x if x is non-zero, or zero if both are zero. + return yc[0] ? ( y.s = -b, y ) : new BigNumber( xc[0] ? x : + + // IEEE 754 (2008) 6.3: n - n = -0 when rounding to -Infinity + ROUNDING_MODE == 3 ? -0 : 0 ); + } + } + + xe = bitFloor(xe); + ye = bitFloor(ye); + xc = xc.slice(); + + // Determine which is the bigger number. + if ( a = xe - ye ) { + + if ( xLTy = a < 0 ) { + a = -a; + t = xc; + } else { + ye = xe; + t = yc; + } + + t.reverse(); + + // Prepend zeros to equalise exponents. + for ( b = a; b--; t.push(0) ); + t.reverse(); + } else { + + // Exponents equal. Check digit by digit. + j = ( xLTy = ( a = xc.length ) < ( b = yc.length ) ) ? a : b; + + for ( a = b = 0; b < j; b++ ) { + + if ( xc[b] != yc[b] ) { + xLTy = xc[b] < yc[b]; + break; + } + } + } + + // x < y? Point xc to the array of the bigger number. + if (xLTy) t = xc, xc = yc, yc = t, y.s = -y.s; + + b = ( j = yc.length ) - ( i = xc.length ); + + // Append zeros to xc if shorter. + // No need to add zeros to yc if shorter as subtract only needs to start at yc.length. + if ( b > 0 ) for ( ; b--; xc[i++] = 0 ); + b = BASE - 1; + + // Subtract yc from xc. + for ( ; j > a; ) { + + if ( xc[--j] < yc[j] ) { + for ( i = j; i && !xc[--i]; xc[i] = b ); + --xc[i]; + xc[j] += BASE; + } + + xc[j] -= yc[j]; + } + + // Remove leading zeros and adjust exponent accordingly. + for ( ; xc[0] == 0; xc.splice(0, 1), --ye ); + + // Zero? + if ( !xc[0] ) { + + // Following IEEE 754 (2008) 6.3, + // n - n = +0 but n - n = -0 when rounding towards -Infinity. + y.s = ROUNDING_MODE == 3 ? -1 : 1; + y.c = [ y.e = 0 ]; + return y; + } + + // No need to check for Infinity as +x - +y != Infinity && -x - -y != Infinity + // for finite x and y. + return normalise( y, xc, ye ); + }; + + + /* + * n % 0 = N + * n % N = N + * n % I = n + * 0 % n = 0 + * -0 % n = -0 + * 0 % 0 = N + * 0 % N = N + * 0 % I = 0 + * N % n = N + * N % 0 = N + * N % N = N + * N % I = N + * I % n = N + * I % 0 = N + * I % N = N + * I % I = N + * + * Return a new BigNumber whose value is the value of this BigNumber modulo the value of + * BigNumber(y, b). The result depends on the value of MODULO_MODE. + */ + P.modulo = P.mod = function ( y, b ) { + var q, s, + x = this; + + id = 11; + y = new BigNumber( y, b ); + + // Return NaN if x is Infinity or NaN, or y is NaN or zero. + if ( !x.c || !y.s || y.c && !y.c[0] ) { + return new BigNumber(NaN); + + // Return x if y is Infinity or x is zero. + } else if ( !y.c || x.c && !x.c[0] ) { + return new BigNumber(x); + } + + if ( MODULO_MODE == 9 ) { + + // Euclidian division: q = sign(y) * floor(x / abs(y)) + // r = x - qy where 0 <= r < abs(y) + s = y.s; + y.s = 1; + q = div( x, y, 0, 3 ); + y.s = s; + q.s *= s; + } else { + q = div( x, y, 0, MODULO_MODE ); + } + + return x.minus( q.times(y) ); + }; + + + /* + * Return a new BigNumber whose value is the value of this BigNumber negated, + * i.e. multiplied by -1. + */ + P.negated = P.neg = function () { + var x = new BigNumber(this); + x.s = -x.s || null; + return x; + }; + + + /* + * n + 0 = n + * n + N = N + * n + I = I + * 0 + n = n + * 0 + 0 = 0 + * 0 + N = N + * 0 + I = I + * N + n = N + * N + 0 = N + * N + N = N + * N + I = N + * I + n = I + * I + 0 = I + * I + N = N + * I + I = I + * + * Return a new BigNumber whose value is the value of this BigNumber plus the value of + * BigNumber(y, b). + */ + P.plus = P.add = function ( y, b ) { + var t, + x = this, + a = x.s; + + id = 12; + y = new BigNumber( y, b ); + b = y.s; + + // Either NaN? + if ( !a || !b ) return new BigNumber(NaN); + + // Signs differ? + if ( a != b ) { + y.s = -b; + return x.minus(y); + } + + var xe = x.e / LOG_BASE, + ye = y.e / LOG_BASE, + xc = x.c, + yc = y.c; + + if ( !xe || !ye ) { + + // Return ±Infinity if either ±Infinity. + if ( !xc || !yc ) return new BigNumber( a / 0 ); + + // Either zero? + // Return y if y is non-zero, x if x is non-zero, or zero if both are zero. + if ( !xc[0] || !yc[0] ) return yc[0] ? y : new BigNumber( xc[0] ? x : a * 0 ); + } + + xe = bitFloor(xe); + ye = bitFloor(ye); + xc = xc.slice(); + + // Prepend zeros to equalise exponents. Faster to use reverse then do unshifts. + if ( a = xe - ye ) { + if ( a > 0 ) { + ye = xe; + t = yc; + } else { + a = -a; + t = xc; + } + + t.reverse(); + for ( ; a--; t.push(0) ); + t.reverse(); + } + + a = xc.length; + b = yc.length; + + // Point xc to the longer array, and b to the shorter length. + if ( a - b < 0 ) t = yc, yc = xc, xc = t, b = a; + + // Only start adding at yc.length - 1 as the further digits of xc can be ignored. + for ( a = 0; b; ) { + a = ( xc[--b] = xc[b] + yc[b] + a ) / BASE | 0; + xc[b] = BASE === xc[b] ? 0 : xc[b] % BASE; + } + + if (a) { + xc = [a].concat(xc); + ++ye; + } + + // No need to check for zero, as +x + +y != 0 && -x + -y != 0 + // ye = MAX_EXP + 1 possible + return normalise( y, xc, ye ); + }; + + + /* + * Return the number of significant digits of the value of this BigNumber. + * + * [z] {boolean|number} Whether to count integer-part trailing zeros: true, false, 1 or 0. + */ + P.precision = P.sd = function (z) { + var n, v, + x = this, + c = x.c; + + // 'precision() argument not a boolean or binary digit: {z}' + if ( z != null && z !== !!z && z !== 1 && z !== 0 ) { + if (ERRORS) raise( 13, 'argument' + notBool, z ); + if ( z != !!z ) z = null; + } + + if ( !c ) return null; + v = c.length - 1; + n = v * LOG_BASE + 1; + + if ( v = c[v] ) { + + // Subtract the number of trailing zeros of the last element. + for ( ; v % 10 == 0; v /= 10, n-- ); + + // Add the number of digits of the first element. + for ( v = c[0]; v >= 10; v /= 10, n++ ); + } + + if ( z && x.e + 1 > n ) n = x.e + 1; + + return n; + }; + + + /* + * Return a new BigNumber whose value is the value of this BigNumber rounded to a maximum of + * dp decimal places using rounding mode rm, or to 0 and ROUNDING_MODE respectively if + * omitted. + * + * [dp] {number} Decimal places. Integer, 0 to MAX inclusive. + * [rm] {number} Rounding mode. Integer, 0 to 8 inclusive. + * + * 'round() decimal places out of range: {dp}' + * 'round() decimal places not an integer: {dp}' + * 'round() rounding mode not an integer: {rm}' + * 'round() rounding mode out of range: {rm}' + */ + P.round = function ( dp, rm ) { + var n = new BigNumber(this); + + if ( dp == null || isValidInt( dp, 0, MAX, 15 ) ) { + round( n, ~~dp + this.e + 1, rm == null || + !isValidInt( rm, 0, 8, 15, roundingMode ) ? ROUNDING_MODE : rm | 0 ); + } + + return n; + }; + + + /* + * Return a new BigNumber whose value is the value of this BigNumber shifted by k places + * (powers of 10). Shift to the right if n > 0, and to the left if n < 0. + * + * k {number} Integer, -MAX_SAFE_INTEGER to MAX_SAFE_INTEGER inclusive. + * + * If k is out of range and ERRORS is false, the result will be ±0 if k < 0, or ±Infinity + * otherwise. + * + * 'shift() argument not an integer: {k}' + * 'shift() argument out of range: {k}' + */ + P.shift = function (k) { + var n = this; + return isValidInt( k, -MAX_SAFE_INTEGER, MAX_SAFE_INTEGER, 16, 'argument' ) + + // k < 1e+21, or truncate(k) will produce exponential notation. + ? n.times( '1e' + truncate(k) ) + : new BigNumber( n.c && n.c[0] && ( k < -MAX_SAFE_INTEGER || k > MAX_SAFE_INTEGER ) + ? n.s * ( k < 0 ? 0 : 1 / 0 ) + : n ); + }; + + + /* + * sqrt(-n) = N + * sqrt( N) = N + * sqrt(-I) = N + * sqrt( I) = I + * sqrt( 0) = 0 + * sqrt(-0) = -0 + * + * Return a new BigNumber whose value is the square root of the value of this BigNumber, + * rounded according to DECIMAL_PLACES and ROUNDING_MODE. + */ + P.squareRoot = P.sqrt = function () { + var m, n, r, rep, t, + x = this, + c = x.c, + s = x.s, + e = x.e, + dp = DECIMAL_PLACES + 4, + half = new BigNumber('0.5'); + + // Negative/NaN/Infinity/zero? + if ( s !== 1 || !c || !c[0] ) { + return new BigNumber( !s || s < 0 && ( !c || c[0] ) ? NaN : c ? x : 1 / 0 ); + } + + // Initial estimate. + s = Math.sqrt( +x ); + + // Math.sqrt underflow/overflow? + // Pass x to Math.sqrt as integer, then adjust the exponent of the result. + if ( s == 0 || s == 1 / 0 ) { + n = coeffToString(c); + if ( ( n.length + e ) % 2 == 0 ) n += '0'; + s = Math.sqrt(n); + e = bitFloor( ( e + 1 ) / 2 ) - ( e < 0 || e % 2 ); + + if ( s == 1 / 0 ) { + n = '1e' + e; + } else { + n = s.toExponential(); + n = n.slice( 0, n.indexOf('e') + 1 ) + e; + } + + r = new BigNumber(n); + } else { + r = new BigNumber( s + '' ); + } + + // Check for zero. + // r could be zero if MIN_EXP is changed after the this value was created. + // This would cause a division by zero (x/t) and hence Infinity below, which would cause + // coeffToString to throw. + if ( r.c[0] ) { + e = r.e; + s = e + dp; + if ( s < 3 ) s = 0; + + // Newton-Raphson iteration. + for ( ; ; ) { + t = r; + r = half.times( t.plus( div( x, t, dp, 1 ) ) ); + + if ( coeffToString( t.c ).slice( 0, s ) === ( n = + coeffToString( r.c ) ).slice( 0, s ) ) { + + // The exponent of r may here be one less than the final result exponent, + // e.g 0.0009999 (e-4) --> 0.001 (e-3), so adjust s so the rounding digits + // are indexed correctly. + if ( r.e < e ) --s; + n = n.slice( s - 3, s + 1 ); + + // The 4th rounding digit may be in error by -1 so if the 4 rounding digits + // are 9999 or 4999 (i.e. approaching a rounding boundary) continue the + // iteration. + if ( n == '9999' || !rep && n == '4999' ) { + + // On the first iteration only, check to see if rounding up gives the + // exact result as the nines may infinitely repeat. + if ( !rep ) { + round( t, t.e + DECIMAL_PLACES + 2, 0 ); + + if ( t.times(t).eq(x) ) { + r = t; + break; + } + } + + dp += 4; + s += 4; + rep = 1; + } else { + + // If rounding digits are null, 0{0,4} or 50{0,3}, check for exact + // result. If not, then there are further digits and m will be truthy. + if ( !+n || !+n.slice(1) && n.charAt(0) == '5' ) { + + // Truncate to the first rounding digit. + round( r, r.e + DECIMAL_PLACES + 2, 1 ); + m = !r.times(r).eq(x); + } + + break; + } + } + } + } + + return round( r, r.e + DECIMAL_PLACES + 1, ROUNDING_MODE, m ); + }; + + + /* + * n * 0 = 0 + * n * N = N + * n * I = I + * 0 * n = 0 + * 0 * 0 = 0 + * 0 * N = N + * 0 * I = N + * N * n = N + * N * 0 = N + * N * N = N + * N * I = N + * I * n = I + * I * 0 = N + * I * N = N + * I * I = I + * + * Return a new BigNumber whose value is the value of this BigNumber times the value of + * BigNumber(y, b). + */ + P.times = P.mul = function ( y, b ) { + var c, e, i, j, k, m, xcL, xlo, xhi, ycL, ylo, yhi, zc, + base, sqrtBase, + x = this, + xc = x.c, + yc = ( id = 17, y = new BigNumber( y, b ) ).c; + + // Either NaN, ±Infinity or ±0? + if ( !xc || !yc || !xc[0] || !yc[0] ) { + + // Return NaN if either is NaN, or one is 0 and the other is Infinity. + if ( !x.s || !y.s || xc && !xc[0] && !yc || yc && !yc[0] && !xc ) { + y.c = y.e = y.s = null; + } else { + y.s *= x.s; + + // Return ±Infinity if either is ±Infinity. + if ( !xc || !yc ) { + y.c = y.e = null; + + // Return ±0 if either is ±0. + } else { + y.c = [0]; + y.e = 0; + } + } + + return y; + } + + e = bitFloor( x.e / LOG_BASE ) + bitFloor( y.e / LOG_BASE ); + y.s *= x.s; + xcL = xc.length; + ycL = yc.length; + + // Ensure xc points to longer array and xcL to its length. + if ( xcL < ycL ) zc = xc, xc = yc, yc = zc, i = xcL, xcL = ycL, ycL = i; + + // Initialise the result array with zeros. + for ( i = xcL + ycL, zc = []; i--; zc.push(0) ); + + base = BASE; + sqrtBase = SQRT_BASE; + + for ( i = ycL; --i >= 0; ) { + c = 0; + ylo = yc[i] % sqrtBase; + yhi = yc[i] / sqrtBase | 0; + + for ( k = xcL, j = i + k; j > i; ) { + xlo = xc[--k] % sqrtBase; + xhi = xc[k] / sqrtBase | 0; + m = yhi * xlo + xhi * ylo; + xlo = ylo * xlo + ( ( m % sqrtBase ) * sqrtBase ) + zc[j] + c; + c = ( xlo / base | 0 ) + ( m / sqrtBase | 0 ) + yhi * xhi; + zc[j--] = xlo % base; + } + + zc[j] = c; + } + + if (c) { + ++e; + } else { + zc.splice(0, 1); + } + + return normalise( y, zc, e ); + }; + + + /* + * Return a new BigNumber whose value is the value of this BigNumber rounded to a maximum of + * sd significant digits using rounding mode rm, or ROUNDING_MODE if rm is omitted. + * + * [sd] {number} Significant digits. Integer, 1 to MAX inclusive. + * [rm] {number} Rounding mode. Integer, 0 to 8 inclusive. + * + * 'toDigits() precision out of range: {sd}' + * 'toDigits() precision not an integer: {sd}' + * 'toDigits() rounding mode not an integer: {rm}' + * 'toDigits() rounding mode out of range: {rm}' + */ + P.toDigits = function ( sd, rm ) { + var n = new BigNumber(this); + sd = sd == null || !isValidInt( sd, 1, MAX, 18, 'precision' ) ? null : sd | 0; + rm = rm == null || !isValidInt( rm, 0, 8, 18, roundingMode ) ? ROUNDING_MODE : rm | 0; + return sd ? round( n, sd, rm ) : n; + }; + + + /* + * Return a string representing the value of this BigNumber in exponential notation and + * rounded using ROUNDING_MODE to dp fixed decimal places. + * + * [dp] {number} Decimal places. Integer, 0 to MAX inclusive. + * [rm] {number} Rounding mode. Integer, 0 to 8 inclusive. + * + * 'toExponential() decimal places not an integer: {dp}' + * 'toExponential() decimal places out of range: {dp}' + * 'toExponential() rounding mode not an integer: {rm}' + * 'toExponential() rounding mode out of range: {rm}' + */ + P.toExponential = function ( dp, rm ) { + return format( this, + dp != null && isValidInt( dp, 0, MAX, 19 ) ? ~~dp + 1 : null, rm, 19 ); + }; + + + /* + * Return a string representing the value of this BigNumber in fixed-point notation rounding + * to dp fixed decimal places using rounding mode rm, or ROUNDING_MODE if rm is omitted. + * + * Note: as with JavaScript's number type, (-0).toFixed(0) is '0', + * but e.g. (-0.00001).toFixed(0) is '-0'. + * + * [dp] {number} Decimal places. Integer, 0 to MAX inclusive. + * [rm] {number} Rounding mode. Integer, 0 to 8 inclusive. + * + * 'toFixed() decimal places not an integer: {dp}' + * 'toFixed() decimal places out of range: {dp}' + * 'toFixed() rounding mode not an integer: {rm}' + * 'toFixed() rounding mode out of range: {rm}' + */ + P.toFixed = function ( dp, rm ) { + return format( this, dp != null && isValidInt( dp, 0, MAX, 20 ) + ? ~~dp + this.e + 1 : null, rm, 20 ); + }; + + + /* + * Return a string representing the value of this BigNumber in fixed-point notation rounded + * using rm or ROUNDING_MODE to dp decimal places, and formatted according to the properties + * of the FORMAT object (see BigNumber.config). + * + * FORMAT = { + * decimalSeparator : '.', + * groupSeparator : ',', + * groupSize : 3, + * secondaryGroupSize : 0, + * fractionGroupSeparator : '\xA0', // non-breaking space + * fractionGroupSize : 0 + * }; + * + * [dp] {number} Decimal places. Integer, 0 to MAX inclusive. + * [rm] {number} Rounding mode. Integer, 0 to 8 inclusive. + * + * 'toFormat() decimal places not an integer: {dp}' + * 'toFormat() decimal places out of range: {dp}' + * 'toFormat() rounding mode not an integer: {rm}' + * 'toFormat() rounding mode out of range: {rm}' + */ + P.toFormat = function ( dp, rm ) { + var str = format( this, dp != null && isValidInt( dp, 0, MAX, 21 ) + ? ~~dp + this.e + 1 : null, rm, 21 ); + + if ( this.c ) { + var i, + arr = str.split('.'), + g1 = +FORMAT.groupSize, + g2 = +FORMAT.secondaryGroupSize, + groupSeparator = FORMAT.groupSeparator, + intPart = arr[0], + fractionPart = arr[1], + isNeg = this.s < 0, + intDigits = isNeg ? intPart.slice(1) : intPart, + len = intDigits.length; + + if (g2) i = g1, g1 = g2, g2 = i, len -= i; + + if ( g1 > 0 && len > 0 ) { + i = len % g1 || g1; + intPart = intDigits.substr( 0, i ); + + for ( ; i < len; i += g1 ) { + intPart += groupSeparator + intDigits.substr( i, g1 ); + } + + if ( g2 > 0 ) intPart += groupSeparator + intDigits.slice(i); + if (isNeg) intPart = '-' + intPart; + } + + str = fractionPart + ? intPart + FORMAT.decimalSeparator + ( ( g2 = +FORMAT.fractionGroupSize ) + ? fractionPart.replace( new RegExp( '\\d{' + g2 + '}\\B', 'g' ), + '$&' + FORMAT.fractionGroupSeparator ) + : fractionPart ) + : intPart; + } + + return str; + }; + + + /* + * Return a string array representing the value of this BigNumber as a simple fraction with + * an integer numerator and an integer denominator. The denominator will be a positive + * non-zero value less than or equal to the specified maximum denominator. If a maximum + * denominator is not specified, the denominator will be the lowest value necessary to + * represent the number exactly. + * + * [md] {number|string|BigNumber} Integer >= 1 and < Infinity. The maximum denominator. + * + * 'toFraction() max denominator not an integer: {md}' + * 'toFraction() max denominator out of range: {md}' + */ + P.toFraction = function (md) { + var arr, d0, d2, e, exp, n, n0, q, s, + k = ERRORS, + x = this, + xc = x.c, + d = new BigNumber(ONE), + n1 = d0 = new BigNumber(ONE), + d1 = n0 = new BigNumber(ONE); + + if ( md != null ) { + ERRORS = false; + n = new BigNumber(md); + ERRORS = k; + + if ( !( k = n.isInt() ) || n.lt(ONE) ) { + + if (ERRORS) { + raise( 22, + 'max denominator ' + ( k ? 'out of range' : 'not an integer' ), md ); + } + + // ERRORS is false: + // If md is a finite non-integer >= 1, round it to an integer and use it. + md = !k && n.c && round( n, n.e + 1, 1 ).gte(ONE) ? n : null; + } + } + + if ( !xc ) return x.toString(); + s = coeffToString(xc); + + // Determine initial denominator. + // d is a power of 10 and the minimum max denominator that specifies the value exactly. + e = d.e = s.length - x.e - 1; + d.c[0] = POWS_TEN[ ( exp = e % LOG_BASE ) < 0 ? LOG_BASE + exp : exp ]; + md = !md || n.cmp(d) > 0 ? ( e > 0 ? d : n1 ) : n; + + exp = MAX_EXP; + MAX_EXP = 1 / 0; + n = new BigNumber(s); + + // n0 = d1 = 0 + n0.c[0] = 0; + + for ( ; ; ) { + q = div( n, d, 0, 1 ); + d2 = d0.plus( q.times(d1) ); + if ( d2.cmp(md) == 1 ) break; + d0 = d1; + d1 = d2; + n1 = n0.plus( q.times( d2 = n1 ) ); + n0 = d2; + d = n.minus( q.times( d2 = d ) ); + n = d2; + } + + d2 = div( md.minus(d0), d1, 0, 1 ); + n0 = n0.plus( d2.times(n1) ); + d0 = d0.plus( d2.times(d1) ); + n0.s = n1.s = x.s; + e *= 2; + + // Determine which fraction is closer to x, n0/d0 or n1/d1 + arr = div( n1, d1, e, ROUNDING_MODE ).minus(x).abs().cmp( + div( n0, d0, e, ROUNDING_MODE ).minus(x).abs() ) < 1 + ? [ n1.toString(), d1.toString() ] + : [ n0.toString(), d0.toString() ]; + + MAX_EXP = exp; + return arr; + }; + + + /* + * Return the value of this BigNumber converted to a number primitive. + */ + P.toNumber = function () { + return +this; + }; + + + /* + * Return a BigNumber whose value is the value of this BigNumber raised to the power n. + * If m is present, return the result modulo m. + * If n is negative round according to DECIMAL_PLACES and ROUNDING_MODE. + * If POW_PRECISION is non-zero and m is not present, round to POW_PRECISION using + * ROUNDING_MODE. + * + * The modular power operation works efficiently when x, n, and m are positive integers, + * otherwise it is equivalent to calculating x.toPower(n).modulo(m) (with POW_PRECISION 0). + * + * n {number} Integer, -MAX_SAFE_INTEGER to MAX_SAFE_INTEGER inclusive. + * [m] {number|string|BigNumber} The modulus. + * + * 'pow() exponent not an integer: {n}' + * 'pow() exponent out of range: {n}' + * + * Performs 54 loop iterations for n of 9007199254740991. + */ + P.toPower = P.pow = function ( n, m ) { + var k, y, z, + i = mathfloor( n < 0 ? -n : +n ), + x = this; + + if ( m != null ) { + id = 23; + m = new BigNumber(m); + } + + // Pass ±Infinity to Math.pow if exponent is out of range. + if ( !isValidInt( n, -MAX_SAFE_INTEGER, MAX_SAFE_INTEGER, 23, 'exponent' ) && + ( !isFinite(n) || i > MAX_SAFE_INTEGER && ( n /= 0 ) || + parseFloat(n) != n && !( n = NaN ) ) || n == 0 ) { + k = Math.pow( +x, n ); + return new BigNumber( m ? k % m : k ); + } + + if (m) { + if ( n > 1 && x.gt(ONE) && x.isInt() && m.gt(ONE) && m.isInt() ) { + x = x.mod(m); + } else { + z = m; + + // Nullify m so only a single mod operation is performed at the end. + m = null; + } + } else if (POW_PRECISION) { + + // Truncating each coefficient array to a length of k after each multiplication + // equates to truncating significant digits to POW_PRECISION + [28, 41], + // i.e. there will be a minimum of 28 guard digits retained. + // (Using + 1.5 would give [9, 21] guard digits.) + k = mathceil( POW_PRECISION / LOG_BASE + 2 ); + } + + y = new BigNumber(ONE); + + for ( ; ; ) { + if ( i % 2 ) { + y = y.times(x); + if ( !y.c ) break; + if (k) { + if ( y.c.length > k ) y.c.length = k; + } else if (m) { + y = y.mod(m); + } + } + + i = mathfloor( i / 2 ); + if ( !i ) break; + x = x.times(x); + if (k) { + if ( x.c && x.c.length > k ) x.c.length = k; + } else if (m) { + x = x.mod(m); + } + } + + if (m) return y; + if ( n < 0 ) y = ONE.div(y); + + return z ? y.mod(z) : k ? round( y, POW_PRECISION, ROUNDING_MODE ) : y; + }; + + + /* + * Return a string representing the value of this BigNumber rounded to sd significant digits + * using rounding mode rm or ROUNDING_MODE. If sd is less than the number of digits + * necessary to represent the integer part of the value in fixed-point notation, then use + * exponential notation. + * + * [sd] {number} Significant digits. Integer, 1 to MAX inclusive. + * [rm] {number} Rounding mode. Integer, 0 to 8 inclusive. + * + * 'toPrecision() precision not an integer: {sd}' + * 'toPrecision() precision out of range: {sd}' + * 'toPrecision() rounding mode not an integer: {rm}' + * 'toPrecision() rounding mode out of range: {rm}' + */ + P.toPrecision = function ( sd, rm ) { + return format( this, sd != null && isValidInt( sd, 1, MAX, 24, 'precision' ) + ? sd | 0 : null, rm, 24 ); + }; + + + /* + * Return a string representing the value of this BigNumber in base b, or base 10 if b is + * omitted. If a base is specified, including base 10, round according to DECIMAL_PLACES and + * ROUNDING_MODE. If a base is not specified, and this BigNumber has a positive exponent + * that is equal to or greater than TO_EXP_POS, or a negative exponent equal to or less than + * TO_EXP_NEG, return exponential notation. + * + * [b] {number} Integer, 2 to 64 inclusive. + * + * 'toString() base not an integer: {b}' + * 'toString() base out of range: {b}' + */ + P.toString = function (b) { + var str, + n = this, + s = n.s, + e = n.e; + + // Infinity or NaN? + if ( e === null ) { + + if (s) { + str = 'Infinity'; + if ( s < 0 ) str = '-' + str; + } else { + str = 'NaN'; + } + } else { + str = coeffToString( n.c ); + + if ( b == null || !isValidInt( b, 2, 64, 25, 'base' ) ) { + str = e <= TO_EXP_NEG || e >= TO_EXP_POS + ? toExponential( str, e ) + : toFixedPoint( str, e ); + } else { + str = convertBase( toFixedPoint( str, e ), b | 0, 10, s ); + } + + if ( s < 0 && n.c[0] ) str = '-' + str; + } + + return str; + }; + + + /* + * Return a new BigNumber whose value is the value of this BigNumber truncated to a whole + * number. + */ + P.truncated = P.trunc = function () { + return round( new BigNumber(this), this.e + 1, 1 ); + }; + + + /* + * Return as toString, but do not accept a base argument, and include the minus sign for + * negative zero. + */ + P.valueOf = P.toJSON = function () { + var str, + n = this, + e = n.e; + + if ( e === null ) return n.toString(); + + str = coeffToString( n.c ); + + str = e <= TO_EXP_NEG || e >= TO_EXP_POS + ? toExponential( str, e ) + : toFixedPoint( str, e ); + + return n.s < 0 ? '-' + str : str; + }; + + + P.isBigNumber = true; + + if ( config != null ) BigNumber.config(config); + + return BigNumber; + } + + + // PRIVATE HELPER FUNCTIONS + + + function bitFloor(n) { + var i = n | 0; + return n > 0 || n === i ? i : i - 1; + } + + + // Return a coefficient array as a string of base 10 digits. + function coeffToString(a) { + var s, z, + i = 1, + j = a.length, + r = a[0] + ''; + + for ( ; i < j; ) { + s = a[i++] + ''; + z = LOG_BASE - s.length; + for ( ; z--; s = '0' + s ); + r += s; + } + + // Determine trailing zeros. + for ( j = r.length; r.charCodeAt(--j) === 48; ); + return r.slice( 0, j + 1 || 1 ); + } + + + // Compare the value of BigNumbers x and y. + function compare( x, y ) { + var a, b, + xc = x.c, + yc = y.c, + i = x.s, + j = y.s, + k = x.e, + l = y.e; + + // Either NaN? + if ( !i || !j ) return null; + + a = xc && !xc[0]; + b = yc && !yc[0]; + + // Either zero? + if ( a || b ) return a ? b ? 0 : -j : i; + + // Signs differ? + if ( i != j ) return i; + + a = i < 0; + b = k == l; + + // Either Infinity? + if ( !xc || !yc ) return b ? 0 : !xc ^ a ? 1 : -1; + + // Compare exponents. + if ( !b ) return k > l ^ a ? 1 : -1; + + j = ( k = xc.length ) < ( l = yc.length ) ? k : l; + + // Compare digit by digit. + for ( i = 0; i < j; i++ ) if ( xc[i] != yc[i] ) return xc[i] > yc[i] ^ a ? 1 : -1; + + // Compare lengths. + return k == l ? 0 : k > l ^ a ? 1 : -1; + } + + + /* + * Return true if n is a valid number in range, otherwise false. + * Use for argument validation when ERRORS is false. + * Note: parseInt('1e+1') == 1 but parseFloat('1e+1') == 10. + */ + function intValidatorNoErrors( n, min, max ) { + return ( n = truncate(n) ) >= min && n <= max; + } + + + function isArray(obj) { + return Object.prototype.toString.call(obj) == '[object Array]'; + } + + + /* + * Convert string of baseIn to an array of numbers of baseOut. + * Eg. convertBase('255', 10, 16) returns [15, 15]. + * Eg. convertBase('ff', 16, 10) returns [2, 5, 5]. + */ + function toBaseOut( str, baseIn, baseOut ) { + var j, + arr = [0], + arrL, + i = 0, + len = str.length; + + for ( ; i < len; ) { + for ( arrL = arr.length; arrL--; arr[arrL] *= baseIn ); + arr[ j = 0 ] += ALPHABET.indexOf( str.charAt( i++ ) ); + + for ( ; j < arr.length; j++ ) { + + if ( arr[j] > baseOut - 1 ) { + if ( arr[j + 1] == null ) arr[j + 1] = 0; + arr[j + 1] += arr[j] / baseOut | 0; + arr[j] %= baseOut; + } + } + } + + return arr.reverse(); + } + + + function toExponential( str, e ) { + return ( str.length > 1 ? str.charAt(0) + '.' + str.slice(1) : str ) + + ( e < 0 ? 'e' : 'e+' ) + e; + } + + + function toFixedPoint( str, e ) { + var len, z; + + // Negative exponent? + if ( e < 0 ) { + + // Prepend zeros. + for ( z = '0.'; ++e; z += '0' ); + str = z + str; + + // Positive exponent + } else { + len = str.length; + + // Append zeros. + if ( ++e > len ) { + for ( z = '0', e -= len; --e; z += '0' ); + str += z; + } else if ( e < len ) { + str = str.slice( 0, e ) + '.' + str.slice(e); + } + } + + return str; + } + + + function truncate(n) { + n = parseFloat(n); + return n < 0 ? mathceil(n) : mathfloor(n); + } + + + // EXPORT + + + BigNumber = constructorFactory(); + BigNumber['default'] = BigNumber.BigNumber = BigNumber; + + + // AMD. + if ( typeof define == 'function' && define.amd ) { + define( function () { return BigNumber; } ); + + // Node.js and other environments that support module.exports. + } else if ( typeof module != 'undefined' && module.exports ) { + module.exports = BigNumber; + + // Browser. + } else { + if ( !globalObj ) globalObj = typeof self != 'undefined' ? self : Function('return this')(); + globalObj.BigNumber = BigNumber; + } +})(this); + +},{}],218:[function(require,module,exports){ +arguments[4][15][0].apply(exports,arguments) +},{"buffer":20,"dup":15}],219:[function(require,module,exports){ +arguments[4][19][0].apply(exports,arguments) +},{"crypto":20,"dup":19}],220:[function(require,module,exports){ +'use strict' + +exports.Commented = require('./commented') +exports.Diagnose = require('./diagnose') +exports.Decoder = require('./decoder') +exports.Encoder = require('./encoder') +exports.Simple = require('./simple') +exports.Tagged = require('./tagged') + +exports.comment = exports.Commented.comment +exports.decodeAll = exports.Decoder.decodeAll +exports.decodeFirst = exports.Decoder.decodeFirst +exports.decodeAllSync = exports.Decoder.decodeAllSync +exports.decodeFirstSync = exports.Decoder.decodeFirstSync +exports.diagnose = exports.Diagnose.diagnose +exports.encode = exports.Encoder.encode +exports.encodeCanonical = exports.Encoder.encodeCanonical +exports.decode = exports.Decoder.decodeFirstSync + +exports.leveldb = { + decode: exports.Decoder.decodeAllSync, + encode: exports.Encoder.encode, + buffer: true, + name: 'cbor' +} + +},{"./commented":221,"./decoder":223,"./diagnose":224,"./encoder":225,"./simple":226,"./tagged":227}],221:[function(require,module,exports){ +(function (Buffer){(function (){ +'use strict' + +const stream = require('stream') +const util = require('util') +const utils = require('./utils') +const Simple = require('./simple') +const Decoder = require('./decoder') +const constants = require('./constants') +const bignumber = require('bignumber.js') +const NoFilter = require('nofilter') + +const MT = constants.MT +const NUMBYTES = constants.NUMBYTES +const SYMS = constants.SYMS + +function plural(c) { + if (c > 1) { + return 's' + } else { + return '' + } +} + +/** + * Generate the expanded format of RFC 7049, section 2.2.1 + * + * @extends {stream.Transform} + */ +class Commented extends stream.Transform { + /** + * Create a CBOR commenter. + * + * @param {any} [options={}] - Stream options + * @param {bool} [options.max_depth=10] - how many times to indent the dashes + */ + constructor(options) { + options = options || {} + options.readableObjectMode = false + options.writableObjectMode = false + const max_depth = (options.max_depth != null) ? options.max_depth : 10 + delete options.max_depth + super(options) + + this.depth = 1 + this.max_depth = max_depth + this.all = new NoFilter + this.parser = new Decoder(options) + this.parser.on('value', this._on_value.bind(this)) + this.parser.on('start', this._on_start.bind(this)) + this.parser.on('start-string', this._on_start_string.bind(this)) + this.parser.on('stop', this._on_stop.bind(this)) + this.parser.on('more-bytes', this._on_more.bind(this)) + this.parser.on('error', this._on_error.bind(this)) + this.parser.on('data', this._on_data.bind(this)) + this.parser.bs.on('read', this._on_read.bind(this)) + } + + /** + * @private + */ + _transform(fresh, encoding, cb) { + this.parser.write(fresh, encoding, cb) + } + + /** + * @private + */ + _flush(cb) { + // TODO: find the test that covers this, and look at the return value + return this.parser._flush(cb) + } + + /** + * @callback commentCallback + * @param {Error} error - if one was generated + * @param {string} commented - the comment string + */ + + /** + * Comment on an input Buffer or string, creating a string passed to the + * callback. If callback not specified, a promise is returned. + * + * @static + * @param {(string|Buffer|NoFilter)} input + * @param {(string|object|function)} options + * @param {number} [options.max_depth=10] how many times to indent the dashes + * @param {commentCallback=} cb + * @returns {Promise} if cb not specified + */ + static comment(input, options, cb) { + if (input == null) { + throw new Error('input required') + } + let encoding = (typeof input === 'string') ? 'hex' : void 0 + let max_depth = 10 + switch (typeof options) { + case 'function': + cb = options + break + case 'string': + encoding = options + break + case 'number': + max_depth = options + break + case 'object': + const ref1 = options.encoding + const ref2 = options.max_depth + encoding = (ref1 != null) ? ref1 : encoding + max_depth = (ref2 != null) ? ref2 : max_depth + break + case 'undefined': + break + default: + throw new Error('Unknown option type') + } + const bs = new NoFilter + const d = new Commented({ + max_depth: max_depth + }) + let p = null + if (typeof cb === 'function') { + d.on('end', () => { + cb(null, bs.toString('utf8')) + }) + d.on('error', cb) + } else { + p = new Promise((resolve, reject) => { + d.on('end', () => { + resolve(bs.toString('utf8')) + }) + return d.on('error', reject) + }) + } + d.pipe(bs) + d.end(input, encoding) + return p + } + + /** + * @private + */ + _on_error(er) { + return this.push('ERROR: ') && + this.push(er.toString()) && + this.push('\n') + } + + /** + * @private + */ + _on_read(buf) { + this.all.write(buf) + const hex = buf.toString('hex') + this.push(new Array(this.depth + 1).join(' ')) + this.push(hex) + let ind = (this.max_depth - this.depth) * 2 + ind -= hex.length + if (ind < 1) { + ind = 1 + } + this.push(new Array(ind + 1).join(' ')) + return this.push('-- ') + } + + /** + * @private + */ + _on_more(mt, len, parent_mt, pos) { + this.depth++ + let desc = '' + switch (mt) { + case MT.POS_INT: + desc = 'Positive number,' + break + case MT.NEG_INT: + desc = 'Negative number,' + break + case MT.ARRAY: + desc = 'Array, length' + break + case MT.MAP: + desc = 'Map, count' + break + case MT.BYTE_STRING: + desc = 'Bytes, length' + break + case MT.UTF8_STRING: + desc = 'String, length' + break + case MT.SIMPLE_FLOAT: + if (len === 1) { + desc = 'Simple value,' + } else { + desc = 'Float,' + } + break + } + return this.push(desc + ' next ' + len + ' byte' + (plural(len)) + '\n') + } + + /** + * @private + */ + _on_start_string(mt, tag, parent_mt, pos) { + this.depth++ + let desc = '' + switch (mt) { + case MT.BYTE_STRING: + desc = 'Bytes, length: ' + tag + break + case MT.UTF8_STRING: + desc = 'String, length: ' + (tag.toString()) + break + } + return this.push(desc + '\n') + } + + /** + * @private + */ + _on_start(mt, tag, parent_mt, pos) { + this.depth++ + if (tag !== SYMS.BREAK) { + this.push((() => { + switch (parent_mt) { + case MT.ARRAY: + return '[' + pos + '], ' + case MT.MAP: + if (pos % 2) { + return '{Val:' + (Math.floor(pos / 2)) + '}, ' + } else { + return '{Key:' + (Math.floor(pos / 2)) + '}, ' + } + } + })()) + } + this.push((() => { + switch (mt) { + case MT.TAG: + return 'Tag #' + tag + case MT.ARRAY: + if (tag === SYMS.STREAM) { + return 'Array (streaming)' + } else { + return 'Array, ' + tag + ' item' + (plural(tag)) + } + case MT.MAP: + if (tag === SYMS.STREAM) { + return 'Map (streaming)' + } else { + return 'Map, ' + tag + ' pair' + (plural(tag)) + } + case MT.BYTE_STRING: + return 'Bytes (streaming)' + case MT.UTF8_STRING: + return 'String (streaming)' + } + })()) + return this.push('\n') + } + + /** + * @private + */ + _on_stop(mt) { + return this.depth-- + } + + /** + * @private + */ + _on_value(val, parent_mt, pos, ai) { + if (val !== SYMS.BREAK) { + this.push((() => { + switch (parent_mt) { + case MT.ARRAY: + return '[' + pos + '], ' + case MT.MAP: + if (pos % 2) { + return '{Val:' + (Math.floor(pos / 2)) + '}, ' + } else { + return '{Key:' + (Math.floor(pos / 2)) + '}, ' + } + } + })()) + } + + if (val === SYMS.BREAK) { + this.push('BREAK\n') + } else if (val === SYMS.NULL) { + this.push('null\n') + } else if (val === SYMS.UNDEFINED) { + this.push('undefined\n') + } else if (typeof val === 'string') { + this.depth-- + if (val.length > 0 ) { + this.push(JSON.stringify(val)) + this.push('\n') + } + } else if (Buffer.isBuffer(val)) { + this.depth-- + if (val.length > 0) { + this.push(val.toString('hex')) + this.push('\n') + } + } else if (val instanceof bignumber) { + this.push(val.toString()) + this.push('\n') + } else { + this.push(util.inspect(val)) + this.push('\n') + } + + switch (ai) { + case NUMBYTES.ONE: + case NUMBYTES.TWO: + case NUMBYTES.FOUR: + case NUMBYTES.EIGHT: + this.depth-- + } + } + + /** + * @private + */ + _on_data() { + this.push('0x') + this.push(this.all.read().toString('hex')) + return this.push('\n') + } +} + +module.exports = Commented + +}).call(this)}).call(this,{"isBuffer":require("../../../../../.nvm/versions/node/v14.16.1/lib/node_modules/browserify/node_modules/is-buffer/index.js")}) +},{"../../../../../.nvm/versions/node/v14.16.1/lib/node_modules/browserify/node_modules/is-buffer/index.js":145,"./constants":222,"./decoder":223,"./simple":226,"./utils":228,"bignumber.js":217,"nofilter":269,"stream":189,"util":210}],222:[function(require,module,exports){ +'use strict' + +exports.MT = { + POS_INT: 0, + NEG_INT: 1, + BYTE_STRING: 2, + UTF8_STRING: 3, + ARRAY: 4, + MAP: 5, + TAG: 6, + SIMPLE_FLOAT: 7 +} + +exports.TAG = { + DATE_STRING: 0, + DATE_EPOCH: 1, + POS_BIGINT: 2, + NEG_BIGINT: 3, + DECIMAL_FRAC: 4, + BIGFLOAT: 5, + BASE64URL_EXPECTED: 21, + BASE64_EXPECTED: 22, + BASE16_EXPECTED: 23, + CBOR: 24, + URI: 32, + BASE64URL: 33, + BASE64: 34, + REGEXP: 35, + MIME: 36 +} + +exports.NUMBYTES = { + ZERO: 0, + ONE: 24, + TWO: 25, + FOUR: 26, + EIGHT: 27, + INDEFINITE: 31 +} + +exports.SIMPLE = { + FALSE: 20, + TRUE: 21, + NULL: 22, + UNDEFINED: 23 +} + +exports.SYMS = { + NULL: Symbol('null'), + UNDEFINED: Symbol('undef'), + PARENT: Symbol('parent'), + BREAK: Symbol('break'), + STREAM: Symbol('stream') +} + +exports.SHIFT32 = Math.pow(2, 32) + +},{}],223:[function(require,module,exports){ +(function (Buffer){(function (){ +'use strict' + +const BinaryParseStream = require('../vendor/binary-parse-stream') +const Tagged = require('./tagged') +const Simple = require('./simple') +const utils = require('./utils') +const bignumber = require('bignumber.js') +const NoFilter = require('nofilter') +const constants = require('./constants') +// Do not fix this if you want to support node v4 +const MT = constants.MT +const NUMBYTES = constants.NUMBYTES +const SIMPLE = constants.SIMPLE +const SYMS = constants.SYMS + +const NEG_ONE = new bignumber(-1) +const NEG_MAX = NEG_ONE.sub( + new bignumber(Number.MAX_SAFE_INTEGER.toString(16), 16)) +const COUNT = Symbol('count') +const PENDING_KEY = Symbol('pending_key') +const MAJOR = Symbol('major type') +const ERROR = Symbol('error') +const NOT_FOUND = Symbol('not found') + +function parentArray(parent, typ, count) { + const a = [] + a[COUNT] = count + a[SYMS.PARENT] = parent + a[MAJOR] = typ + return a +} + +function parentBufferStream(parent, typ) { + const b = new NoFilter + b[SYMS.PARENT] = parent + b[MAJOR] = typ + return b +} + +/** + * Decode a stream of CBOR bytes by transforming them into equivalent + * JavaScript data. Because of the limitations of Node object streams, + * special symbols are emitted instead of NULL or UNDEFINED. Fix those + * up by calling {@link Decoder.nullcheck}. + * + * @extends {BinaryParseStream} + */ +class Decoder extends BinaryParseStream { + + /** + * Create a parsing stream. + * + * @param {object} [options={}] + * @param {number} [options.max_depth=-1] - the maximum depth to parse. + * Use -1 for "until you run out of memory". Set this to a finite + * positive number for un-trusted inputs. Most standard inputs won't nest + * more than 100 or so levels; I've tested into the millions before + * running out of memory. + * @param {object=} options.tags - mapping from tag number to function(v), + * where v is the decoded value that comes after the tag, and where the + * function returns the correctly-created value for that tag. + */ + constructor(options) { + options = options || {} + const tags = options.tags + delete options.tags + const max_depth = (options.max_depth != null) ? options.max_depth : -1 + delete options.max_depth + super(options) + + this.running = true + this.max_depth = max_depth + this.tags = tags + } + + /** + * Check the given value for a symbol encoding a NULL or UNDEFINED value in + * the CBOR stream. + * + * @static + * @param {any} val - the value to check + * @returns {any} the corrected value + * + * @example + * myDecoder.on('data', function(val) { + * val = Decoder.nullcheck(val); + * ... + * }); + */ + static nullcheck(val) { + switch (val) { + case SYMS.NULL: + return null + case SYMS.UNDEFINED: + return undefined + case NOT_FOUND: + throw new Error('Value not found') + default: + return val + } + } + + /** + * Decode the first CBOR item in the input, synchronously. This will throw an + * exception if the input is not valid CBOR. + * + * @static + * @param {(string|Buffer)} input + * @param {object} [options={encoding: 'hex'}] + * @param {string} [options.encoding: 'hex'] - The encoding of the input. + * Ignored if input is a Buffer. + * @returns {any} - the decoded value + */ + static decodeFirstSync(input, options) { + options = options || { encoding: 'hex' } + let opts = {} + let encod + switch (typeof options) { + case 'string': + encod = options + break + case 'object': + opts = utils.extend({}, options) + encod = opts.encoding + delete opts.encoding + break + } + const c = new Decoder(opts) + const s = new NoFilter( + input, + encod != null ? encod : utils.guessEncoding(input)) + const parser = c._parse() + let state = parser.next() + while (!state.done) { + const b = s.read(state.value) + if ((b == null) || (b.length !== state.value)) { + throw new Error('Insufficient data') + } + state = parser.next(b) + } + return Decoder.nullcheck(state.value) + } + + /** + * Decode all of the CBOR items in the input into an array. This will throw + * an exception if the input is not valid CBOR; a zero-length input will + * return an empty array. + * + * @static + * @param {(string|Buffer)} input + * @param {(string|Object)} [options={encoding: 'hex'}] + * @param {string} [options.encoding: 'hex'] - The encoding of the input. + * Ignored if input is a Buffer. + * @returns {Array} - Array of all found items + */ + static decodeAllSync(input, options) { + options = options || { encoding: 'hex' } + let opts = {} + let encod + switch (typeof options) { + case 'string': + encod = options + break + case 'object': + opts = utils.extend({}, options) + encod = opts.encoding + delete opts.encoding + } + const c = new Decoder(opts) + const s = new NoFilter( + input, + encod != null ? encod : utils.guessEncoding(input)) + const res = [] + while (s.length > 0) { + const parser = c._parse() + let state = parser.next() + while (!state.done) { + const b = s.read(state.value) + if ((b == null) || (b.length !== state.value)) { + throw new Error('Insufficient data') + } + state = parser.next(b) + } + res.push(Decoder.nullcheck(state.value)) + } + return res + } + + /** + * @callback decodeCallback + * @param {Error} error - if one was generated + * @param {any} value - the decoded value + */ + + /** + * Decode the first CBOR item in the input. This will error if there are more + * bytes left over at the end, and optionally if there were no valid CBOR + * bytes in the input. Emits the {Decoder.NOT_FOUND} Symbol in the callback + * if no data was found and the `required` option is false. + * + * @static + * @param {(string|Buffer)} input - the input to parse + * @param {(function|string|Object)} options + * @param {string} [options.encoding: 'hex'] - The encoding of the input. + * Ignored if input is a Buffer. + * @param {decodeCallback} cb + * @returns {Promise} if no cb specified + */ + static decodeFirst(input, options, cb) { + let opts = {} + let required = false + let encod = 'hex' + switch (typeof options) { + case 'function': + cb = options + encod = utils.guessEncoding(input) + break + case 'string': + encod = options + break + case 'object': + opts = utils.extend({}, options) + encod = (opts.encoding != null) ? + opts.encoding : utils.guessEncoding(input) + delete opts.encoding + required = (opts.required != null) ? opts.required : false + delete opts.required + } + const c = new Decoder(opts) + let p + let v = NOT_FOUND + c.on('data', (val) => { + v = Decoder.nullcheck(val) + c.close() + }) + if (typeof cb === 'function') { + c.once('error', (er) => { + const u = v + v = ERROR + c.close() + return cb(er, u) + }) + c.once('end', () => { + switch (v) { + case NOT_FOUND: + if (required) { + return cb(new Error('No CBOR found')) + } else { + return cb(null, v) + } + case ERROR: + return void 0 + default: + return cb(null, v) + } + }) + } else { + p = new Promise((resolve, reject) => { + c.once('error', (er) => { + v = ERROR + c.close() + return reject(er) + }) + return c.once('end', () => { + switch (v) { + case NOT_FOUND: + if (required) { + return reject(new Error('No CBOR found')) + } else { + return resolve(v) + } + case ERROR: + return void 0 + default: + return resolve(v) + } + }) + }) + } + c.end(input, encod) + return p + } + + /** + * @callback decodeAllCallback + * @param {Error} error - if one was generated + * @param {Array} value - all of the decoded values, wrapped in an Array + */ + + /** + * Decode all of the CBOR items in the input. This will error if there are + * more bytes left over at the end. + * + * @static + * @param {(string|Buffer)} input - the input to parse + * @param {(string|Object)} options - Decoding options. + * If string, the input encoding. + * @param {decodeAllCallback} cb + * @returns {Promise} if no callback + */ + static decodeAll(input, options, cb) { + let opts = {} + let encod = 'hex' + switch (typeof options) { + case 'function': + cb = options + encod = utils.guessEncoding(input) + break + case 'string': + encod = options + break + case 'object': + opts = utils.extend({}, options) + encod = (opts.encoding != null) ? + opts.encoding : utils.guessEncoding(input) + delete opts.encoding + } + const c = new Decoder(opts) + let p + const vals = [] + c.on('data', (val) => { + return vals.push(Decoder.nullcheck(val)) + }) + if (typeof cb === 'function') { + c.on('error', cb) + c.on('end', () => cb(null, vals)) + } else { + p = new Promise((resolve, reject) => { + c.on('error', reject) + c.on('end', () => resolve(vals)) + }) + } + c.end(input, encod) + return p + } + + /** + * Stop processing + */ + close() { + this.running = false + this.__fresh = true + } + + *_parse() { + let parent = null + let depth = 0 + let val = null + while (true) { + if ((this.max_depth >= 0) && (depth > this.max_depth)) { + throw new Error('Maximum depth ' + this.max_depth + ' exceeded') + } + const octet = (yield 1)[0] + if (!this.running) { + throw new Error('Unexpected data: 0x' + (octet.toString(16))) + } + const mt = octet >> 5 + const ai = octet & 0x1f + const parent_major = (parent != null) ? parent[MAJOR] : undefined + const parent_length = (parent != null) ? parent.length : undefined + switch (ai) { + case NUMBYTES.ONE: + this.emit('more-bytes', mt, 1, parent_major, parent_length) + val = (yield 1)[0] + break + case NUMBYTES.TWO: + case NUMBYTES.FOUR: + case NUMBYTES.EIGHT: + const numbytes = 1 << (ai - 24) + this.emit('more-bytes', mt, numbytes, parent_major, parent_length) + const buf = yield numbytes + val = (mt === MT.SIMPLE_FLOAT) ? buf : utils.parseCBORint(ai, buf) + break + case 28: + case 29: + case 30: + this.running = false + throw new Error('Additional info not implemented: ' + ai) + case NUMBYTES.INDEFINITE: + val = -1 + break + default: + val = ai + } + switch (mt) { + case MT.POS_INT: + // val already decoded + break + case MT.NEG_INT: + if (val === Number.MAX_SAFE_INTEGER) { + val = NEG_MAX + } else if (val instanceof bignumber) { + val = NEG_ONE.sub(val) + } else { + val = -1 - val + } + break + case MT.BYTE_STRING: + case MT.UTF8_STRING: + switch (val) { + case 0: + this.emit('start-string', mt, val, parent_major, parent_length) + val = (mt === MT.BYTE_STRING) ? new Buffer(0) : '' + break + case -1: + this.emit('start', mt, SYMS.STREAM, parent_major, parent_length) + parent = parentBufferStream(parent, mt) + depth++ + continue + default: + this.emit('start-string', mt, val, parent_major, parent_length) + val = yield val + if (mt === MT.UTF8_STRING) { + val = val.toString('utf-8') + } + } + break + case MT.ARRAY: + case MT.MAP: + switch (val) { + case 0: + val = (mt === MT.MAP) ? {} : [] + break + case -1: + this.emit('start', mt, SYMS.STREAM, parent_major, parent_length) + parent = parentArray(parent, mt, -1) + depth++ + continue + default: + this.emit('start', mt, val, parent_major, parent_length) + parent = parentArray(parent, mt, val * (mt - 3)) + depth++ + continue + } + break + case MT.TAG: + this.emit('start', mt, val, parent_major, parent_length) + parent = parentArray(parent, mt, 1) + parent.push(val) + depth++ + continue + case MT.SIMPLE_FLOAT: + if (typeof val === 'number') { + val = Simple.decode(val, parent != null) + } else { + val = utils.parseCBORfloat(val) + } + } + this.emit('value', val, parent_major, parent_length, ai) + let again = false + while (parent != null) { + switch (false) { + case val !== SYMS.BREAK: + parent[COUNT] = 1 + break + case !Array.isArray(parent): + parent.push(val) + break + case !(parent instanceof NoFilter): + const pm = parent[MAJOR] + if ((pm != null) && (pm !== mt)) { + this.running = false + throw new Error('Invalid major type in indefinite encoding') + } + parent.write(val) + } + if ((--parent[COUNT]) !== 0) { + again = true + break + } + --depth + delete parent[COUNT] + this.emit('stop', parent[MAJOR]) + + if (Array.isArray(parent)) { + switch (parent[MAJOR]) { + case MT.ARRAY: + val = parent + break + case MT.MAP: + let allstrings = true + if ((parent.length % 2) !== 0) { + throw new Error('Invalid map length: ' + parent.length) + } + for (let i = 0, len = parent.length; i < len; i += 2) { + if (typeof parent[i] !== 'string') { + allstrings = false + break + } + } + if (allstrings) { + val = {} + for (let i = 0, len = parent.length; i < len; i += 2) { + val[parent[i]] = parent[i + 1] + } + } else { + val = new Map + for (let i = 0, len = parent.length; i < len; i += 2) { + val.set(parent[i], parent[i + 1]) + } + } + break + case MT.TAG: + const t = new Tagged(parent[0], parent[1]) + val = t.convert(this.tags) + break + } + } else if (parent instanceof NoFilter) { + switch (parent[MAJOR]) { + case MT.BYTE_STRING: + val = parent.slice() + break + case MT.UTF8_STRING: + val = parent.toString('utf-8') + break + } + } + + const old = parent + parent = parent[SYMS.PARENT] + delete old[SYMS.PARENT] + delete old[MAJOR] + } + if (!again) { + return val + } + } + } +} + +Decoder.NOT_FOUND = NOT_FOUND +module.exports = Decoder + +}).call(this)}).call(this,require("buffer").Buffer) +},{"../vendor/binary-parse-stream":229,"./constants":222,"./simple":226,"./tagged":227,"./utils":228,"bignumber.js":217,"buffer":64,"nofilter":269}],224:[function(require,module,exports){ +(function (Buffer){(function (){ +'use strict' + +const stream = require('stream') +const util = require('util') +const Decoder = require('./decoder') +const Simple = require('./simple') +const utils = require('./utils') +const constants = require('./constants') +const bignumber = require('bignumber.js') +const NoFilter = require('nofilter') + +const MT = constants.MT, SYMS = constants.SYMS + +/** + * Output the diagnostic format from a stream of CBOR bytes. + * + * @extends {stream.Transform} + */ +class Diagnose extends stream.Transform { + + /** + * Creates an instance of Diagnose. + * + * @param {Object} [options={}] - options for creation + * @param {string} [options.separator='\n'] - output between detected objects + * @param {bool} [options.stream_errors=false] - put error info into the + * output stream + * @param {number} [options.max_depth=-1] - -1 for "until you run out of + * memory". Set this to a finite positive number for un-trusted inputs. Most + * standard inputs won't nest more than 100 or so levels; I've tested into the + * millions before running out of memory. + */ + constructor (options) { + options = options || {} + const separator = (options.separator != null) ? options.separator : '\n' + delete options.separator + const stream_errors = (options.stream_errors != null) ? options.stream_errors : false + delete options.stream_errors + options.readableObjectMode = false + options.writableObjectMode = false + super(options) + + this.float_bytes = -1 + this.separator = separator + this.stream_errors = stream_errors + this.parser = new Decoder(options) + this.parser.on('more-bytes', this._on_more.bind(this)) + this.parser.on('value', this._on_value.bind(this)) + this.parser.on('start', this._on_start.bind(this)) + this.parser.on('stop', this._on_stop.bind(this)) + this.parser.on('data', this._on_data.bind(this)) + this.parser.on('error', this._on_error.bind(this)) + } + + _transform (fresh, encoding, cb) { + return this.parser.write(fresh, encoding, cb) + } + + _flush (cb) { + return this.parser._flush((er) => { + if (this.stream_errors) { + this._on_error(er) + return cb() + } else { + return cb(er) + } + }) + } + + /** + * Convenience function to return a string in diagnostic format. + * + * @param {(Buffer|string)} input - the CBOR bytes to format + * @param {string} [encoding='hex'] - the encoding of input, ignored if input is Buffer + * @param {commentCallback} cb - callback + * @returns {Promise} if callback not specified + */ + static diagnose (input, encoding, cb) { + if (input == null) { + throw new Error('input required') + } + let opts = {} + let encod = 'hex' + switch (typeof encoding) { + case 'function': + cb = encoding + encod = utils.guessEncoding(input) + break + case 'object': + opts = utils.extend({}, encoding) + encod = (opts.encoding != null) ? opts.encoding : utils.guessEncoding(input) + delete opts.encoding + break + default: + encod = (encoding != null) ? encoding : 'hex' + } + const bs = new NoFilter + const d = new Diagnose(opts) + let p = null + if (typeof cb === 'function') { + d.on('end', function () { + return cb(null, bs.toString('utf8')) + }) + d.on('error', cb) + } else { + p = new Promise(function (resolve, reject) { + d.on('end', function () { + return resolve(bs.toString('utf8')) + }) + return d.on('error', reject) + }) + } + d.pipe(bs) + d.end(input, encod) + return p + } + + _on_error (er) { + if (this.stream_errors) { + return this.push(er.toString()) + } else { + return this.emit('error', er) + } + } + + _on_more (mt, len, parent_mt, pos) { + if (mt === MT.SIMPLE_FLOAT) { + return this.float_bytes = (function () { + switch (len) { + case 2: + return 1 + case 4: + return 2 + case 8: + return 3 + } + })() + } + } + + _fore (parent_mt, pos) { + switch (parent_mt) { + case MT.BYTE_STRING: + case MT.UTF8_STRING: + case MT.ARRAY: + if (pos > 0) { + return this.push(', ') + } + break + case MT.MAP: + if (pos > 0) { + if (pos % 2) { + return this.push(': ') + } else { + return this.push(', ') + } + } + } + } + + _on_value (val, parent_mt, pos) { + if (val === SYMS.BREAK) { + return + } + this._fore(parent_mt, pos) + return this.push((function () { + switch (false) { + case val !== SYMS.NULL: + return 'null' + case val !== SYMS.UNDEFINED: + return 'undefined' + case typeof val !== 'string': + return JSON.stringify(val) + case !(this.float_bytes > 0): + const fb = this.float_bytes + this.float_bytes = -1 + return (util.inspect(val)) + '_' + fb + case !Buffer.isBuffer(val): + return "h'" + (val.toString('hex')) + "'" + case !(val instanceof bignumber): + return val.toString() + default: + return util.inspect(val) + } + }).call(this)) + } + + _on_start (mt, tag, parent_mt, pos) { + this._fore(parent_mt, pos) + this.push((function () { + switch (mt) { + case MT.TAG: + return tag + '(' + case MT.ARRAY: + return '[' + case MT.MAP: + return '{' + case MT.BYTE_STRING: + case MT.UTF8_STRING: + return '(' + default: + // istanbul ignore next + throw new Error('Unknown diagnostic type: ' + mt) + } + })()) + if (tag === SYMS.STREAM) { + return this.push('_ ') + } + } + + _on_stop (mt) { + return this.push((function () { + switch (mt) { + case MT.TAG: + return ')' + case MT.ARRAY: + return ']' + case MT.MAP: + return '}' + case MT.BYTE_STRING: + case MT.UTF8_STRING: + return ')' + default: + // istanbul ignore next + throw new Error('Unknown diagnostic type: ' + mt) + } + })()) + } + + _on_data () { + return this.push(this.separator) + } +} + +module.exports = Diagnose + +}).call(this)}).call(this,{"isBuffer":require("../../../../../.nvm/versions/node/v14.16.1/lib/node_modules/browserify/node_modules/is-buffer/index.js")}) +},{"../../../../../.nvm/versions/node/v14.16.1/lib/node_modules/browserify/node_modules/is-buffer/index.js":145,"./constants":222,"./decoder":223,"./simple":226,"./utils":228,"bignumber.js":217,"nofilter":269,"stream":189,"util":210}],225:[function(require,module,exports){ +(function (Buffer){(function (){ +'use strict' + +const stream = require('stream') +const url = require('url') +const bignumber = require('bignumber.js') +const NoFilter = require('nofilter') +const Tagged = require('./tagged') +const Simple = require('./simple') +const utils = require('./utils') + +const constants = require('./constants') +const MT = constants.MT, NUMBYTES = constants.NUMBYTES, SHIFT32 = constants.SHIFT32, SYMS = constants.SYMS, TAG = constants.TAG +const HALF = (constants.MT.SIMPLE_FLOAT << 5) | constants.NUMBYTES.TWO +const FLOAT = (constants.MT.SIMPLE_FLOAT << 5) | constants.NUMBYTES.FOUR +const DOUBLE = (constants.MT.SIMPLE_FLOAT << 5) | constants.NUMBYTES.EIGHT +const TRUE = (constants.MT.SIMPLE_FLOAT << 5) | constants.SIMPLE.TRUE +const FALSE = (constants.MT.SIMPLE_FLOAT << 5) | constants.SIMPLE.FALSE +const UNDEFINED = (constants.MT.SIMPLE_FLOAT << 5) | constants.SIMPLE.UNDEFINED +const NULL = (constants.MT.SIMPLE_FLOAT << 5) | constants.SIMPLE.NULL + +const MAXINT_BN = new bignumber('0x20000000000000') +const BUF_NAN = new Buffer('f97e00', 'hex') +const BUF_INF_NEG = new Buffer('f9fc00', 'hex') +const BUF_INF_POS = new Buffer('f97c00', 'hex') + +/** + * Transform JavaScript values into CBOR bytes. The `Writable` side of + * the stream is in object mode. + * + * @extends {stream.Transform} + */ +class Encoder extends stream.Transform { + + /** + * Creates an instance of Encoder. + * + * @param {Object} [options={}] - options for the encoder + * @param {any[]} [options.genTypes=[]] - array of pairs of `type`, + * `function(Encoder)` for semantic types to be encoded. Not needed + * for Array, Date, Buffer, Map, RegExp, Set, Url, or bignumber. + * @param {boolean} [options.canonical=false] - should the output be + * canonicalized + */ + constructor (options) { + options = options || {} + options.readableObjectMode = false + options.writableObjectMode = true + super(options) + + this.canonical = options.canonical + this.semanticTypes = [ + Array, this._pushArray, + Date, this._pushDate, + Buffer, this._pushBuffer, + Map, this._pushMap, + NoFilter, this._pushNoFilter, + RegExp, this._pushRegexp, + Set, this._pushSet, + url.Url, this._pushUrl, + bignumber, this._pushBigNumber + ] + + const addTypes = options.genTypes || [] + for (let i = 0, len = addTypes.length; i < len; i += 2) { + this.addSemanticType(addTypes[i], addTypes[i + 1]) + } + } + + _transform (fresh, encoding, cb) { + const ret = this.pushAny(fresh) + // Old transformers might not return bool. undefined !== false + return cb((ret === false) ? new Error('Push Error') : undefined) + } + + _flush (cb) { + return cb() + } + + /** + * @callback encodeFunction + * @param {Encoder} encoder - the encoder to serialize into. Call "write" + * on the encoder as needed. + * @return {bool} - true on success, else false + */ + + /** + * Add an encoding function to the list of supported semantic types. This is + * useful for objects for which you can't add an encodeCBOR method + * + * @param {any} type + * @param {any} fun + * @returns {encodeFunction} + */ + addSemanticType (type, fun) { + for (let i = 0, len = this.semanticTypes.length; i < len; i += 2) { + const typ = this.semanticTypes[i] + if (typ === type) { + const old = this.semanticTypes[i + 1] + this.semanticTypes[i + 1] = fun + return old + } + } + this.semanticTypes.push(type, fun) + return null + } + + _pushUInt8 (val) { + const b = new Buffer(1) + b.writeUInt8(val) + return this.push(b) + } + + _pushUInt16BE (val) { + const b = new Buffer(2) + b.writeUInt16BE(val) + return this.push(b) + } + + _pushUInt32BE (val) { + const b = new Buffer(4) + b.writeUInt32BE(val) + return this.push(b) + } + + _pushDoubleBE (val) { + const b = new Buffer(8) + b.writeDoubleBE(val) + return this.push(b) + } + + _pushNaN () { + return this.push(BUF_NAN) + } + + _pushInfinity (obj) { + const half = (obj < 0) ? BUF_INF_NEG : BUF_INF_POS + return this.push(half) + } + + _pushFloat (obj) { + if (this.canonical) { + // TODO: is this enough slower to hide behind canonical? + // It's certainly enough of a hack (see utils.parseHalf) + + // From section 3.9: + // If a protocol allows for IEEE floats, then additional canonicalization + // rules might need to be added. One example rule might be to have all + // floats start as a 64-bit float, then do a test conversion to a 32-bit + // float; if the result is the same numeric value, use the shorter value + // and repeat the process with a test conversion to a 16-bit float. (This + // rule selects 16-bit float for positive and negative Infinity as well.) + + // which seems pretty much backwards to me. + const b2 = new Buffer(2) + if (utils.writeHalf(b2, obj)) { + if (utils.parseHalf(b2) === obj) { + return this._pushUInt8(HALF) && this.push(b2) + } + } + const b4 = new Buffer(4) + b4.writeFloatBE(obj) + if (b4.readFloatBE() === obj) { + return this._pushUInt8(FLOAT) && this.push(b4) + } + } + + return this._pushUInt8(DOUBLE) && this._pushDoubleBE(obj) + } + + _pushInt (obj, mt, orig) { + const m = mt << 5 + switch (false) { + case !(obj < 24): + return this._pushUInt8(m | obj) + case !(obj <= 0xff): + return this._pushUInt8(m | NUMBYTES.ONE) && this._pushUInt8(obj) + case !(obj <= 0xffff): + return this._pushUInt8(m | NUMBYTES.TWO) && this._pushUInt16BE(obj) + case !(obj <= 0xffffffff): + return this._pushUInt8(m | NUMBYTES.FOUR) && this._pushUInt32BE(obj) + case !(obj <= Number.MAX_SAFE_INTEGER): + return this._pushUInt8(m | NUMBYTES.EIGHT) && + this._pushUInt32BE(Math.floor(obj / SHIFT32)) && + this._pushUInt32BE(obj % SHIFT32) + default: + if (mt === MT.NEG_INT) { + return this._pushFloat(orig) + } else { + return this._pushFloat(obj) + } + } + } + + _pushIntNum (obj) { + if (obj < 0) { + return this._pushInt(-obj - 1, MT.NEG_INT, obj) + } else { + return this._pushInt(obj, MT.POS_INT) + } + } + + _pushNumber (obj) { + switch (false) { + case !isNaN(obj): + return this._pushNaN(obj) + case isFinite(obj): + return this._pushInfinity(obj) + case Math.round(obj) !== obj: + return this._pushIntNum(obj) + default: + return this._pushFloat(obj) + } + } + + _pushString (obj) { + const len = Buffer.byteLength(obj, 'utf8') + return this._pushInt(len, MT.UTF8_STRING) && this.push(obj, 'utf8') + } + + _pushBoolean (obj) { + return this._pushUInt8(obj ? TRUE : FALSE) + } + + _pushUndefined (obj) { + return this._pushUInt8(UNDEFINED) + } + + _pushNull (obj) { + return this._pushUInt8(NULL) + } + + _pushArray (gen, obj) { + const len = obj.length + if (!gen._pushInt(len, MT.ARRAY)) { + return false + } + for (let j = 0; j < len; j++) { + if (!gen.pushAny(obj[j])) { + return false + } + } + return true + } + + _pushTag (tag) { + return this._pushInt(tag, MT.TAG) + } + + _pushDate (gen, obj) { + return gen._pushTag(TAG.DATE_EPOCH) && gen.pushAny(obj / 1000) + } + + _pushBuffer (gen, obj) { + return gen._pushInt(obj.length, MT.BYTE_STRING) && gen.push(obj) + } + + _pushNoFilter (gen, obj) { + return gen._pushBuffer(gen, obj.slice()) + } + + _pushRegexp (gen, obj) { + return gen._pushTag(TAG.REGEXP) && gen.pushAny(obj.source) + } + + _pushSet (gen, obj) { + if (!gen._pushInt(obj.size, MT.ARRAY)) { + return false + } + for (let x of obj) { + if (!gen.pushAny(x)) { + return false + } + } + return true + } + + _pushUrl (gen, obj) { + return gen._pushTag(TAG.URI) && gen.pushAny(obj.format()) + } + + _pushBigint (obj) { + let tag = TAG.POS_BIGINT + if (obj.isNegative()) { + obj = obj.negated().minus(1) + tag = TAG.NEG_BIGINT + } + let str = obj.toString(16) + if (str.length % 2) { + str = '0' + str + } + const buf = new Buffer(str, 'hex') + return this._pushTag(tag) && this._pushBuffer(this, buf) + } + + _pushBigNumber (gen, obj) { + if (obj.isNaN()) { + return gen._pushNaN() + } + if (!obj.isFinite()) { + return gen._pushInfinity(obj.isNegative() ? -Infinity : Infinity) + } + if (obj.isInteger()) { + return gen._pushBigint(obj) + } + if (!(gen._pushTag(TAG.DECIMAL_FRAC) && + gen._pushInt(2, MT.ARRAY))) { + return false + } + + const dec = obj.decimalPlaces() + const slide = obj.mul(new bignumber(10).pow(dec)) + if (!gen._pushIntNum(-dec)) { + return false + } + if (slide.abs().lessThan(MAXINT_BN)) { + return gen._pushIntNum(slide.toNumber()) + } else { + return gen._pushBigint(slide) + } + } + + _pushMap (gen, obj) { + if (!gen._pushInt(obj.size, MT.MAP)) { + return false + } + // memoizing the cbor only helps in certain cases, and hurts in most + // others. Just avoid it. + if (gen.canonical) { + // keep the key/value pairs together, so we don't have to do odd + // gets with object keys later + const entries = [] + // iterator. If we drop support for node4, use ... + for (const e of obj.entries()) { + entries.push(e) + } + entries.sort((a,b) => { + // a, b are both entries of [key, value] + const a_cbor = Encoder.encode(a[0]) + const b_cbor = Encoder.encode(b[0]) + return a_cbor.compare(b_cbor) + }) + for (const kv of entries) { + if (!(gen.pushAny(kv[0]) && gen.pushAny(kv[1]))) { + return false + } + } + } else { + for (const kv of obj) { + if (!(gen.pushAny(kv[0]) && gen.pushAny(kv[1]))) { + return false + } + } + } + return true + } + + _pushObject (obj) { + if (!obj) { + return this._pushNull(obj) + } + for (let i = 0, len1 = this.semanticTypes.length; i < len1; i += 2) { + const typ = this.semanticTypes[i] + if (obj instanceof typ) { + return this.semanticTypes[i + 1].call(obj, this, obj) + } + } + const f = obj.encodeCBOR + if (typeof f === 'function') { + return f.call(obj, this) + } + const keys = Object.keys(obj) + const cbor_keys = {} + if (this.canonical) { + // note: this can't be a normal sort, because 'b' needs to sort before + // 'aa' + keys.sort((a, b) => { + // Always strings, so don't bother to pass options. + // hold on to the cbor versions, since there's no need + // to encode more than once + const a_cbor = cbor_keys[a] || (cbor_keys[a] = Encoder.encode(a)) + const b_cbor = cbor_keys[b] || (cbor_keys[b] = Encoder.encode(b)) + + return a_cbor.compare(b_cbor) + }) + } + if (!this._pushInt(keys.length, MT.MAP)) { + return false + } + let ck + for (let j = 0, len2 = keys.length; j < len2; j++) { + const k = keys[j] + if (this.canonical && ((ck = cbor_keys[k]))) { + if (!this.push(ck)) { // already a Buffer + return false + } + } else { + if (!this._pushString(k)) { + return false + } + } + if (!this.pushAny(obj[k])) { + return false + } + } + + return true + } + + /** + * Push any supported type onto the encoded stream + * + * @param {any} obj + * @returns {boolean} true on success + */ + pushAny (obj) { + switch (typeof obj) { + case 'number': + return this._pushNumber(obj) + case 'string': + return this._pushString(obj) + case 'boolean': + return this._pushBoolean(obj) + case 'undefined': + return this._pushUndefined(obj) + case 'object': + return this._pushObject(obj) + case 'symbol': + switch (obj) { + case SYMS.NULL: + return this._pushNull(null) + case SYMS.UNDEFINED: + return this._pushUndefined(void 0) + // TODO: Add pluggable support for other symbols + default: + throw new Error('Unknown symbol: ' + obj.toString()) + } + default: + throw new Error('Unknown type: ' + typeof obj + ', ' + (!!obj ? obj.toString() : '')) + } + } + + /* backwards-compat wrapper */ + _pushAny (obj) { + // TODO: write deprecation warning + return this.pushAny(obj) + } + + _encodeAll (objs) { + const bs = new NoFilter() + this.pipe(bs) + for (let o of objs) { + if (typeof o === 'undefined') { + this._pushUndefined() + } else if (o === null) { + this._pushNull(null) + } else { + this.write(o) + } + } + this.end() + return bs.read() + } + + /** + * Encode one or more JavaScript objects, and return a Buffer containing the + * CBOR bytes. + * + * @param {...any} objs - the objects to encode + * @returns {Buffer} - the encoded objects + */ + static encode () { + const objs = Array.prototype.slice.apply(arguments) + return new Encoder()._encodeAll(objs) + } + + /** + * Encode one or more JavaScript objects canonically (slower!), and return + * a Buffer containing the CBOR bytes. + * + * @param {...any} objs - the objects to encode + * @returns {Buffer} - the encoded objects + */ + static encodeCanonical () { + const objs = Array.prototype.slice.apply(arguments) + return new Encoder({canonical: true})._encodeAll(objs) + } +} + +module.exports = Encoder + +}).call(this)}).call(this,require("buffer").Buffer) +},{"./constants":222,"./simple":226,"./tagged":227,"./utils":228,"bignumber.js":217,"buffer":64,"nofilter":269,"stream":189,"url":205}],226:[function(require,module,exports){ +'use strict' + +const constants = require('./constants') +const MT = constants.MT, SIMPLE = constants.SIMPLE, SYMS = constants.SYMS + +/** + * A CBOR Simple Value that does not map onto a known constant. + */ +class Simple { + /** + * Creates an instance of Simple. + * + * @param {integer} value - the simple value's integer value + */ + constructor (value) { + if (typeof value !== 'number') { + throw new Error('Invalid Simple type: ' + (typeof value)) + } + if ((value < 0) || (value > 255) || ((value|0) !== value)) { + throw new Error('value must be a small positive integer: ' + value) + } + this.value = value + } + + /** + * Debug string for simple value + * + * @returns {string} simple(value) + */ + toString () { + return 'simple(' + this.value + ')' + } + + /** + * Debug string for simple value + * + * @returns {string} simple(value) + */ + inspect (depth, opts) { + return 'simple(' + this.value + ')' + } + + /** + * Push the simple value onto the CBOR stream + * + * @param {cbor.Encoder} gen The generator to push onto + */ + encodeCBOR (gen) { + return gen._pushInt(this.value, MT.SIMPLE_FLOAT) + } + + /** + * Is the given object a Simple? + * + * @param {any} obj - object to test + * @returns {bool} - is it Simple? + */ + static isSimple (obj) { + return obj instanceof Simple + } + + /** + * Decode from the CBOR additional information into a JavaScript value. + * If the CBOR item has no parent, return a "safe" symbol instead of + * `null` or `undefined`, so that the value can be passed through a + * stream in object mode. + * + * @param {Number} val - the CBOR additional info to convert + * @param {bool} has_parent - Does the CBOR item have a parent? + * @returns {(null|undefined|Boolean|Symbol)} - the decoded value + */ + static decode (val, has_parent) { + if (has_parent == null) { + has_parent = true + } + switch (val) { + case SIMPLE.FALSE: + return false + case SIMPLE.TRUE: + return true + case SIMPLE.NULL: + if (has_parent) { + return null + } else { + return SYMS.NULL + } + case SIMPLE.UNDEFINED: + if (has_parent) { + return void 0 + } else { + return SYMS.UNDEFINED + } + case -1: + if (!has_parent) { + throw new Error('Invalid BREAK') + } + return SYMS.BREAK + default: + return new Simple(val) + } + } +} + +module.exports = Simple + +},{"./constants":222}],227:[function(require,module,exports){ +'use strict' + +const bignumber = require('bignumber.js') +const utils = require('./utils') +const url = require('url') + +const MINUS_ONE = new bignumber(-1) +const TEN = new bignumber(10) +const TWO = new bignumber(2) + + +/** + * A CBOR tagged item, where the tag does not have semantics specified at the + * moment, or those semantics threw an error during parsing. Typically this will + * be an extension point you're not yet expecting. + */ +class Tagged { + + /** + * Creates an instance of Tagged. + * + * @param {Number} tag - the number of the tag + * @param {any} value - the value inside the tag + * @param {Error} err - the error that was thrown parsing the tag, or null + */ + constructor (tag, value, err) { + this.tag = tag + this.value = value + this.err = err + if (typeof this.tag !== 'number') { + throw new Error('Invalid tag type (' + (typeof this.tag) + ')') + } + if ((this.tag < 0) || ((this.tag | 0) !== this.tag)) { + throw new Error('Tag must be a positive integer: ' + this.tag) + } + } + + /** + * Convert to a String + * + * @returns {String} string of the form '1(2)' + */ + toString () { + return `${this.tag}(${JSON.stringify(this.value)})` + } + + /** + * Push the simple value onto the CBOR stream + * + * @param {cbor.Encoder} gen The generator to push onto + */ + encodeCBOR (gen) { + gen._pushTag(this.tag) + return gen.pushAny(this.value) + } + + /** + * If we have a converter for this type, do the conversion. Some converters + * are built-in. Additional ones can be passed in. If you want to remove + * a built-in converter, pass a converter in whose value is 'null' instead + * of a function. + * + * @param {Object} converters - keys in the object are a tag number, the value + * is a function that takes the decoded CBOR and returns a JavaScript value + * of the appropriate type. Throw an exception in the function on errors. + * @returns {any} - the converted item + */ + convert (converters) { + var er, f + f = converters != null ? converters[this.tag] : void 0 + if (typeof f !== 'function') { + f = Tagged['_tag_' + this.tag] + if (typeof f !== 'function') { + return this + } + } + try { + return f.call(Tagged, this.value) + } catch (error) { + er = error + this.err = er + return this + } + } + + static _tag_0 (v) { + return new Date(v) + } + + static _tag_1 (v) { + return new Date(v * 1000) + } + + static _tag_2 (v) { + return utils.bufferToBignumber(v) + } + + static _tag_3 (v) { + return MINUS_ONE.minus(utils.bufferToBignumber(v)) + } + + static _tag_4 (v) { + return TEN.pow(v[0]).times(v[1]) + } + + static _tag_5 (v) { + return TWO.pow(v[0]).times(v[1]) + } + + static _tag_32 (v) { + return url.parse(v) + } + + static _tag_35 (v) { + return new RegExp(v) + } +} + +module.exports = Tagged + +},{"./utils":228,"bignumber.js":217,"url":205}],228:[function(require,module,exports){ +(function (process,Buffer){(function (){ +'use strict' + +const fs = require('fs') +const stream = require('stream') +const bignumber = require('bignumber.js') + +const constants = require('./constants') +const NUMBYTES = constants.NUMBYTES +const SHIFT32 = constants.SHIFT32 +const MAX_SAFE_HIGH = 0x1fffff + +exports.parseCBORint = function(ai, buf) { + switch (ai) { + case NUMBYTES.ONE: + return buf.readUInt8(0, true) + case NUMBYTES.TWO: + return buf.readUInt16BE(0, true) + case NUMBYTES.FOUR: + return buf.readUInt32BE(0, true) + case NUMBYTES.EIGHT: + const f = buf.readUInt32BE(0) + const g = buf.readUInt32BE(4) + if (f > MAX_SAFE_HIGH) { + return new bignumber(f).times(SHIFT32).plus(g) + } else { + return (f * SHIFT32) + g + } + default: + throw new Error('Invalid additional info for int: ' + ai) + } +} + +exports.writeHalf = function writeHalf(buf, half) { + // assume 0, -0, NaN, Infinity, and -Infinity have already been caught + + // HACK: everyone settle in. This isn't going to be pretty. + // Translate cn-cbor's C code (from Carsten Borman): + + // uint32_t be32; + // uint16_t be16, u16; + // union { + // float f; + // uint32_t u; + // } u32; + // u32.f = float_val; + + const u32 = new Buffer(4) + u32.writeFloatBE(half) + const u = u32.readUInt32BE() + + // if ((u32.u & 0x1FFF) == 0) { /* worth trying half */ + + // hildjj: If the lower 13 bits are 0, + // we won't lose anything in the conversion + if ((u & 0x1FFF) !== 0) { + return false + } + + // int s16 = (u32.u >> 16) & 0x8000; + // int exp = (u32.u >> 23) & 0xff; + // int mant = u32.u & 0x7fffff; + + let s16 = (u >> 16) & 0x8000 // top bit is sign + const exp = (u >> 23) & 0xff // then 5 bits of exponent + const mant = u & 0x7fffff + + // if (exp == 0 && mant == 0) + // ; /* 0.0, -0.0 */ + + // hildjj: zeros already handled. Assert if you don't believe me. + + // else if (exp >= 113 && exp <= 142) /* normalized */ + // s16 += ((exp - 112) << 10) + (mant >> 13); + + if ((exp >= 113) && (exp <= 142)) { + s16 += ((exp - 112) << 10) + (mant >> 13) + } else if ((exp >= 103) && (exp < 113)) { + // else if (exp >= 103 && exp < 113) { /* denorm, exp16 = 0 */ + // if (mant & ((1 << (126 - exp)) - 1)) + // goto float32; /* loss of precision */ + // s16 += ((mant + 0x800000) >> (126 - exp)); + + if (mant & ((1 << (126 - exp)) - 1)) { + return false + } + s16 += ((mant + 0x800000) >> (126 - exp)) + } else { + // } else if (exp == 255 && mant == 0) { /* Inf */ + // s16 += 0x7c00; + + // hildjj: Infinity already handled + + // } else + // goto float32; /* loss of range */ + + return false + } + + // ensure_writable(3); + // u16 = s16; + // be16 = hton16p((const uint8_t*)&u16); + buf.writeUInt16BE(s16) + return true +} + +exports.parseHalf = function parseHalf(buf) { + const sign = buf[0] & 0x80 ? -1 : 1 + const exp = (buf[0] & 0x7C) >> 2 + const mant = ((buf[0] & 0x03) << 8) | buf[1] + if (!exp) { + return sign * 5.9604644775390625e-8 * mant + } else if (exp === 0x1f) { + return sign * (mant ? 0 / 0 : 2e308) + } else { + return sign * Math.pow(2, exp - 25) * (1024 + mant) + } +} + +exports.parseCBORfloat = function parseCBORfloat(buf) { + switch (buf.length) { + case 2: + return exports.parseHalf(buf) + case 4: + return buf.readFloatBE(0, true) + case 8: + return buf.readDoubleBE(0, true) + default: + throw new Error('Invalid float size: ' + buf.length) + } +} + +exports.hex = function hex(s) { + return new Buffer(s.replace(/^0x/, ''), 'hex') +} + +exports.bin = function bin(s) { + s = s.replace(/\s/g, '') + let start = 0 + let end = (s.length % 8) || 8 + const chunks = [] + while (end <= s.length) { + chunks.push(parseInt(s.slice(start, end), 2)) + start = end + end += 8 + } + return new Buffer(chunks) +} + +exports.extend = function extend() { + let old = arguments[0] + const adds = (2 <= arguments.length) ? + Array.prototype.slice.call(arguments, 1) : [] + const len = adds.length + if (old == null) { + old = {} + } + for (let j = 0; j < len; j++) { + const a = adds[j] + for (const k in a) { + const v = a[k] + old[k] = v + } + } + return old +} + +exports.arrayEqual = function arrayEqual(a, b) { + if ((a == null) && (b == null)) { + return true + } + if ((a == null) || (b == null)) { + return false + } + return (a.length === b.length) && a.every((elem, i) => elem === b[i]) +} + +exports.bufferEqual = function bufferEqual(a, b) { + if ((a == null) && (b == null)) { + return true + } + if ((a == null) || (b == null)) { + return false + } + if (!(Buffer.isBuffer(a) && Buffer.isBuffer(b) && (a.length === b.length))) { + return false + } + const len = a.length + let ret = true + let i + let j + for (i = j = 0; j < len; i = ++j) { + const byte = a[i] + ret &= b[i] === byte + } + return !!ret +} + +exports.bufferToBignumber = function bufferToBignumber(buf) { + return new bignumber(buf.toString('hex'), 16) +} + +exports.DeHexStream = class DeHexStream extends stream.Readable { + constructor(hex) { + super() + hex = hex.replace(/^0x/, '') + if (hex) { + this.push(new Buffer(hex, 'hex')) + } + this.push(null) + } +} + +exports.HexStream = class HexStream extends stream.Transform { + constructor(options) { + super(options) + } + + _transform(fresh, encoding, cb) { + this.push(fresh.toString('hex')) + return cb() + } +} + +function printError(er) { + if (er != null) { + return console.log(er) + } +} + +exports.streamFiles = function streamFiles(files, streamFunc, cb) { + if (cb == null) { + cb = printError + } + const f = files.shift() + if (!f) { + return cb() + } + const sf = streamFunc() + sf.on('end', () => exports.streamFiles(files, streamFunc, cb)) + sf.on('error', cb) + const s = (f === '-') ? + process.stdin : (f instanceof stream.Stream) ? f : fs.createReadStream(f) + s.on('error', cb) + return s.pipe(sf) +} + +exports.guessEncoding = function guessEncoding(input) { + switch (false) { + case typeof input !== 'string': + return 'hex' + case !Buffer.isBuffer(input): + return undefined + default: + throw new Error('Unknown input type') + } +} + +}).call(this)}).call(this,require('_process'),require("buffer").Buffer) +},{"./constants":222,"_process":164,"bignumber.js":217,"buffer":64,"fs":20,"stream":189}],229:[function(require,module,exports){ +// Tweaked version of nathan7's binary-parse-stream +// (see https://github.com/nathan7/binary-parse-stream) +// Uses NoFilter instead of the readable in the original. Removes +// the ability to read -1, which was odd and un-needed. +// License for binary-parse-stream: MIT + +'use strict'; +exports = module.exports = BinaryParseStream +var Stream = require('stream') + , TransformStream = Stream.Transform + , inherits = require('util').inherits + , NoFilter = require('nofilter') + +exports.One = -1 + +inherits(BinaryParseStream, TransformStream) +function BinaryParseStream(options) { + TransformStream.call(this, options) + this._writableState.objectMode = false + this._readableState.objectMode = true + + this.bs = new NoFilter() + this.__restart() +} + +BinaryParseStream.prototype._transform = function(fresh, encoding, cb) { var self = this + this.bs.write(fresh) + + while (this.bs.length >= this.__needed) { + var ret + , chunk = this.__needed === null + ? undefined + : this.bs.read(this.__needed) + + try { ret = this.__parser.next(chunk) } + catch (e) { + return cb(e) } + + if (this.__needed) + this.__fresh = false + + if (!ret.done) + this.__needed = ret.value | 0 + else { + this.push(ret.value) + this.__restart() + } + } + + return cb() +} + +BinaryParseStream.prototype.__restart = function() { + this.__needed = null + this.__parser = this._parse() + this.__fresh = true +} + +BinaryParseStream.prototype._flush = function(cb) { + cb(this.__fresh + ? null + : new Error('unexpected end of input')) +} + +},{"nofilter":269,"stream":189,"util":210}],230:[function(require,module,exports){ +(function (global,Buffer){(function (){ +/* jshint esversion: 6 */ +/* jslint node: true */ +'use strict'; + +const AlgToTags = { + 'RS512': -259, + 'RS384': -258, + 'RS256': -257, + 'ECDH-SS-512': -28, + 'ECDH-SS': -27, + 'ECDH-ES-512': -26, + 'ECDH-ES': -25, + 'ES256': -7, + 'ES512': -36, + 'direct': -6, + 'A128GCM': 1, + 'A192GCM': 2, + 'A256GCM': 3, + 'SHA-256_64': 4, + 'SHA-256-64': 4, + 'HS256/64': 4, + 'SHA-256': 5, + 'HS256': 5, + 'SHA-384': 6, + 'HS384': 6, + 'SHA-512': 7, + 'HS512': 7, + 'AES-CCM-16-64-128': 10, + 'AES-CCM-16-128/64': 10, + 'AES-CCM-16-64-256': 11, + 'AES-CCM-16-256/64': 11, + 'AES-CCM-64-64-128': 12, + 'AES-CCM-64-128/64': 12, + 'AES-CCM-64-64-256': 13, + 'AES-CCM-64-256/64': 13, + 'AES-MAC-128/64': 14, + 'AES-MAC-256/64': 15, + 'AES-MAC-128/128': 25, + 'AES-MAC-256/128': 26, + 'AES-CCM-16-128-128': 30, + 'AES-CCM-16-128/128': 30, + 'AES-CCM-16-128-256': 31, + 'AES-CCM-16-256/128': 31, + 'AES-CCM-64-128-128': 32, + 'AES-CCM-64-128/128': 32, + 'AES-CCM-64-128-256': 33, + 'AES-CCM-64-256/128': 33 +}; + +const Translators = { + 'kid': (value) => { + return Buffer.from(value, 'utf8'); + }, + 'alg': (value) => { + if (!(AlgToTags[value])) { + throw new Error('Unknown \'alg\' parameter, ' + value); + } + return AlgToTags[value]; + } +}; + +const HeaderParameters = { + 'partyUNonce': -22, + 'static_key_id': -3, + 'static_key': -2, + 'ephemeral_key': -1, + 'alg': 1, + 'crit': 2, + 'content_type': 3, + 'ctyp': 3, // one could question this but it makes testing easier + 'kid': 4, + 'IV': 5, + 'Partial_IV': 6, + 'counter_signature': 7 +}; + +exports.EMPTY_BUFFER = Buffer.alloc(0); + +exports.TranslateHeaders = function (header) { + const result = new Map(); + for (const param in header) { + if (!HeaderParameters[param]) { + throw new Error('Unknown parameter, \'' + param + '\''); + } + let value = header[param]; + if (Translators[param]) { + value = Translators[param](header[param]); + } + if (value !== undefined && value !== null) { + result.set(HeaderParameters[param], value); + } + } + return result; +}; + +const KeyParameters = { + 'crv': -1, + 'k': -1, + 'x': -2, + 'y': -3, + 'd': -4, + 'kty': 1 +}; + +const KeyTypes = { + 'OKP': 1, + 'EC2': 2, + 'RSA': 3, + 'Symmetric': 4 +}; + +const KeyCrv = { + 'P-256': 1, + 'P-384': 2, + 'P-521': 3, + 'X25519': 4, + 'X448': 5, + 'Ed25519': 6, + 'Ed448': 7 +}; + +const KeyTranslators = { + 'kty': (value) => { + if (!(KeyTypes[value])) { + throw new Error('Unknown \'kty\' parameter, ' + value); + } + return KeyTypes[value]; + }, + 'crv': (value) => { + if (!(KeyCrv[value])) { + throw new Error('Unknown \'crv\' parameter, ' + value); + } + return KeyCrv[value]; + } +}; + +exports.TranslateKey = function (key) { + const result = new Map(); + for (const param in key) { + if (!KeyParameters[param]) { + throw new Error('Unknown parameter, \'' + param + '\''); + } + let value = key[param]; + if (KeyTranslators[param]) { + value = KeyTranslators[param](value); + } + result.set(KeyParameters[param], value); + } + return result; +}; + +module.exports.xor = function (a, b) { + const buffer = Buffer.alloc(Math.max(a.length, b.length)); + for (let i = 1; i <= buffer.length; ++i) { + const av = (a.length - i) < 0 ? 0 : a[a.length - i]; + const bv = (b.length - i) < 0 ? 0 : b[b.length - i]; + buffer[buffer.length - i] = av ^ bv; + } + return buffer; +}; + +exports.HeaderParameters = HeaderParameters; + +exports.runningInNode = function () { + return Object.prototype.toString.call(global.process) === '[object process]'; +}; + +}).call(this)}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {},require("buffer").Buffer) +},{"buffer":64}],231:[function(require,module,exports){ +(function (Buffer){(function (){ +/* jshint esversion: 6 */ +/* jslint node: true */ +'use strict'; + +const cbor = require('cbor'); +const crypto = require('crypto'); +const Promise = require('any-promise'); +const common = require('./common'); +const HKDF = require('node-hkdf-sync'); + +const Tagged = cbor.Tagged; + +const EMPTY_BUFFER = common.EMPTY_BUFFER; +const EncryptTag = exports.EncryptTag = 96; +const Encrypt0Tag = exports.Encrypt0Tag = 16; + +const runningInNode = common.runningInNode; + +const TagToAlg = { + 1: 'A128GCM', + 2: 'A192GCM', + 3: 'A256GCM', + 10: 'AES-CCM-16-64-128', + 11: 'AES-CCM-16-64-256', + 12: 'AES-CCM-64-64-128', + 13: 'AES-CCM-64-64-256', + 30: 'AES-CCM-16-128-128', + 31: 'AES-CCM-16-128-256', + 32: 'AES-CCM-64-128-128', + 33: 'AES-CCM-64-128-256' +}; + +const COSEAlgToNodeAlg = { + 'A128GCM': 'aes-128-gcm', + 'A192GCM': 'aes-192-gcm', + 'A256GCM': 'aes-256-gcm', + + 'AES-CCM-16-64-128': 'aes-128-ccm', + 'AES-CCM-16-64-256': 'aes-256-ccm', + 'AES-CCM-64-64-128': 'aes-128-ccm', + 'AES-CCM-64-64-256': 'aes-256-ccm', + 'AES-CCM-16-128-128': 'aes-128-ccm', + 'AES-CCM-16-128-256': 'aes-256-ccm', + 'AES-CCM-64-128-128': 'aes-128-ccm', + 'AES-CCM-64-128-256': 'aes-256-ccm' +}; + +const isNodeAlg = { + 1: true, // A128GCM + 2: true, // A192GCM + 3: true // A256GCM +}; + +const isCCMAlg = { + 10: true, // AES-CCM-16-64-128 + 11: true, // AES-CCM-16-64-256 + 12: true, // AES-CCM-64-64-128 + 13: true, // AES-CCM-64-64-256 + 30: true, // AES-CCM-16-128-128 + 31: true, // AES-CCM-16-128-256 + 32: true, // AES-CCM-64-128-128 + 33: true // AES-CCM-64-128-256 +}; + +const authTagLength = { + 1: 16, + 2: 16, + 3: 16, + 10: 8, // AES-CCM-16-64-128 + 11: 8, // AES-CCM-16-64-256 + 12: 8, // AES-CCM-64-64-128 + 13: 8, // AES-CCM-64-64-256 + 30: 16, // AES-CCM-16-128-128 + 31: 16, // AES-CCM-16-128-256 + 32: 16, // AES-CCM-64-128-128 + 33: 16 // AES-CCM-64-128-256 +}; + +const ivLenght = { + 1: 12, // A128GCM + 2: 12, // A192GCM + 3: 12, // A256GCM + 10: 13, // AES-CCM-16-64-128 + 11: 13, // AES-CCM-16-64-256 + 12: 7, // AES-CCM-64-64-128 + 13: 7, // AES-CCM-64-64-256 + 30: 13, // AES-CCM-16-128-128 + 31: 13, // AES-CCM-16-128-256 + 32: 7, // AES-CCM-64-128-128 + 33: 7 // AES-CCM-64-128-256 +}; + +const keyLength = { + 1: 16, // A128GCM + 2: 24, // A192GCM + 3: 32, // A256GCM + 10: 16, // AES-CCM-16-64-128 + 11: 32, // AES-CCM-16-64-256 + 12: 16, // AES-CCM-64-64-128 + 13: 32, // AES-CCM-64-64-256 + 30: 16, // AES-CCM-16-128-128 + 31: 32, // AES-CCM-16-128-256 + 32: 16, // AES-CCM-64-128-128 + 33: 32, // AES-CCM-64-128-256 + 'P-521': 66, + 'P-256': 32 +}; + +const HKDFAlg = { + 'ECDH-ES': 'sha256', + 'ECDH-ES-512': 'sha512', + 'ECDH-SS': 'sha256', + 'ECDH-SS-512': 'sha512' +}; + +const nodeCRV = { + 'P-521': 'secp521r1', + 'P-256': 'prime256v1' +}; + +function createAAD (p, context, externalAAD) { + p = (!p.size) ? EMPTY_BUFFER : cbor.encode(p); + const encStructure = [ + context, + p, + externalAAD + ]; + return cbor.encode(encStructure); +} + +function _randomSource (bytes) { + return crypto.randomBytes(bytes); +} + +function nodeEncrypt (payload, key, alg, iv, aad, ccm = false) { + const nodeAlg = COSEAlgToNodeAlg[TagToAlg[alg]]; + const chiperOptions = ccm ? { authTagLength: authTagLength[alg] } : null; + const aadOptions = ccm ? { plaintextLength: Buffer.byteLength(payload) } : null; + const cipher = crypto.createCipheriv(nodeAlg, key, iv, chiperOptions); + cipher.setAAD(aad, aadOptions); + return Buffer.concat([ + cipher.update(payload), + cipher.final(), + cipher.getAuthTag() + ]); +} + +function createContext (rp, alg, partyUNonce) { + return cbor.encode([ + alg, // AlgorithmID + [ // PartyUInfo + null, // identity + (partyUNonce || null), // nonce + null // other + ], + [ // PartyVInfo + null, // identity + null, // nonce + null // other + ], + [ + keyLength[alg] * 8, // keyDataLength + rp // protected + ] + ]); +} + +exports.create = function (headers, payload, recipients, options) { + return new Promise((resolve, reject) => { + options = options || {}; + const externalAAD = options.externalAAD || EMPTY_BUFFER; + const randomSource = options.randomSource || _randomSource; + let u = headers.u || {}; + let p = headers.p || {}; + + p = common.TranslateHeaders(p); + u = common.TranslateHeaders(u); + + const alg = p.get(common.HeaderParameters.alg) || u.get(common.HeaderParameters.alg); + + if (!alg) { + throw new Error('Missing mandatory parameter \'alg\''); + } + + if (Array.isArray(recipients)) { + if (recipients.length === 0) { + throw new Error('There has to be at least one recipent'); + } + if (recipients.length > 1) { + throw new Error('Encrypting with multiple recipents is not implemented'); + } + + let iv; + if (options.contextIv) { + let partialIv = randomSource(2); + iv = common.xor(partialIv, options.contextIv); + u.set(common.HeaderParameters.Partial_IV, partialIv); + } else { + iv = randomSource(ivLenght[alg]); + u.set(common.HeaderParameters.IV, iv); + } + + const aad = createAAD(p, 'Encrypt', externalAAD); + + let key; + let recipientStruct; + // TODO do a more accurate check + if (recipients[0] && recipients[0].p && + (recipients[0].p.alg === 'ECDH-ES' || + recipients[0].p.alg === 'ECDH-ES-512' || + recipients[0].p.alg === 'ECDH-SS' || + recipients[0].p.alg === 'ECDH-SS-512')) { + const recipient = crypto.createECDH(nodeCRV[recipients[0].key.crv]); + const generated = crypto.createECDH(nodeCRV[recipients[0].key.crv]); + recipient.setPrivateKey(recipients[0].key.d); + let pk = randomSource(keyLength[recipients[0].key.crv]); + if (recipients[0].p.alg === 'ECDH-ES' || + recipients[0].p.alg === 'ECDH-ES-512') { + pk = randomSource(keyLength[recipients[0].key.crv]); + pk[0] = (recipients[0].key.crv !== 'P-521' || pk[0] === 1) ? pk[0] : 0; + } else { + pk = recipients[0].sender.d; + } + + generated.setPrivateKey(pk); + const senderPublicKey = generated.getPublicKey(); + const recipientPublicKey = Buffer.concat([ + Buffer.from('04', 'hex'), + recipients[0].key.x, + recipients[0].key.y + ]); + + const generatedKey = common.TranslateKey({ + 'crv': recipients[0].key.crv, + 'x': senderPublicKey.slice(1, keyLength[recipients[0].key.crv] + 1), // TODO slice based on key length + 'y': senderPublicKey.slice(keyLength[recipients[0].key.crv] + 1), + 'kty': 'EC2' // TODO use real value + }); + const rp = cbor.encode(common.TranslateHeaders(recipients[0].p)); + const ikm = generated.computeSecret(recipientPublicKey); + let partyUNonce = null; + if (recipients[0].p.alg === 'ECDH-SS' || recipients[0].p.alg === 'ECDH-SS-512') { + partyUNonce = randomSource(64); // TODO use real value + } + const context = createContext(rp, alg, partyUNonce); + const nrBytes = keyLength[alg]; + const hkdf = new HKDF(HKDFAlg[recipients[0].p.alg], undefined, ikm); + key = hkdf.derive(context, nrBytes); + let ru = recipients[0].u; + + if (recipients[0].p.alg === 'ECDH-ES' || + recipients[0].p.alg === 'ECDH-ES-512') { + ru.ephemeral_key = generatedKey; + } else { + ru.static_key = generatedKey; + } + + ru.partyUNonce = partyUNonce; + ru = common.TranslateHeaders(ru); + + recipientStruct = [[rp, ru, EMPTY_BUFFER]]; + } else { + key = recipients[0].key; + const ru = common.TranslateHeaders(recipients[0].u); + recipientStruct = [[EMPTY_BUFFER, ru, EMPTY_BUFFER]]; + } + + let ciphertext; + if (isNodeAlg[alg]) { + ciphertext = nodeEncrypt(payload, key, alg, iv, aad); + } else if (isCCMAlg[alg] && runningInNode()) { + ciphertext = nodeEncrypt(payload, key, alg, iv, aad, true); + } else { + throw new Error('No implementation for algorithm, ' + alg); + } + + if (p.size === 0 && options.encodep === 'empty') { + p = EMPTY_BUFFER; + } else { + p = cbor.encode(p); + } + + const encrypted = [p, u, ciphertext, recipientStruct]; + resolve(cbor.encode(options.excludetag ? encrypted : new Tagged(EncryptTag, encrypted))); + } else { + let iv; + if (options.contextIv) { + let partialIv = randomSource(2); + iv = common.xor(partialIv, options.contextIv); + u.set(common.HeaderParameters.Partial_IV, partialIv); + } else { + iv = randomSource(ivLenght[alg]); + u.set(common.HeaderParameters.IV, iv); + } + + let key; + if (recipients && recipients.p && recipients.p.alg === 'ECDH-ES') { + // TODO use curve from parameters + const recipient = crypto.createECDH('prime256v1'); + const generated = crypto.createECDH('prime256v1'); + recipient.setPrivateKey(recipients.key.d); + generated.setPrivateKey(randomSource(32)); // TODO use real alg value + const recipientPublicKey = Buffer.concat([ + Buffer.from('04', 'hex'), + recipients.key.x, + recipients.key.y + ]); + const ikm = generated.computeSecret(recipientPublicKey); + const context = createContext(p); + const nrBytes = 16; // TODO use real number based on alg + const hkdf = new HKDF('sha256', undefined, ikm); // TODO use real alg + key = hkdf.derive(context, nrBytes); + } else { + key = recipients.key; + } + + const aad = createAAD(p, 'Encrypt0', externalAAD); + let ciphertext; + if (isNodeAlg[alg]) { + ciphertext = nodeEncrypt(payload, key, alg, iv, aad); + } else if (isCCMAlg[alg] && runningInNode()) { + ciphertext = nodeEncrypt(payload, key, alg, iv, aad, true); + } else { + throw new Error('No implementation for algorithm, ' + alg); + } + + if (p.size === 0 && options.encodep === 'empty') { + p = EMPTY_BUFFER; + } else { + p = cbor.encode(p); + } + const encrypted = [p, u, ciphertext]; + resolve(cbor.encode(options.excludetag ? encrypted : new Tagged(Encrypt0Tag, encrypted))); + } + }); +}; + +function nodeDecrypt (ciphertext, key, alg, iv, tag, aad, ccm = false) { + const nodeAlg = COSEAlgToNodeAlg[TagToAlg[alg]]; + const chiperOptions = ccm ? { authTagLength: authTagLength[alg] } : null; + const aadOptions = ccm ? { plaintextLength: Buffer.byteLength(ciphertext) } : null; + const decipher = crypto.createDecipheriv(nodeAlg, key, iv, chiperOptions); + decipher.setAuthTag(tag); + decipher.setAAD(aad, aadOptions); + return Buffer.concat([decipher.update(ciphertext), decipher.final()]); +} + +exports.read = function (data, key, options) { + options = options || {}; + const externalAAD = options.externalAAD || EMPTY_BUFFER; + return cbor.decodeFirst(data) + .then((obj) => { + let msgTag = options.defaultType ? options.defaultType : EncryptTag; + if (obj instanceof Tagged) { + if (obj.tag !== EncryptTag && obj.tag !== Encrypt0Tag) { + throw new Error('Unknown tag, ' + obj.tag); + } + msgTag = obj.tag; + obj = obj.value; + } + + if (!Array.isArray(obj)) { + throw new Error('Expecting Array'); + } + + if (msgTag === EncryptTag && obj.length !== 4) { + throw new Error('Expecting Array of lenght 4 for COSE Encrypt message'); + } + + if (msgTag === Encrypt0Tag && obj.length !== 3) { + throw new Error('Expecting Array of lenght 4 for COSE Encrypt0 message'); + } + + let [p, u, ciphertext] = obj; + + p = (p.length === 0) ? EMPTY_BUFFER : cbor.decodeFirstSync(p); + p = (!p.size) ? EMPTY_BUFFER : p; + u = (!u.size) ? EMPTY_BUFFER : u; + + const alg = (p !== EMPTY_BUFFER) ? p.get(common.HeaderParameters.alg) : (u !== EMPTY_BUFFER) ? u.get(common.HeaderParameters.alg) : undefined; + if (!TagToAlg[alg]) { + throw new Error('Unknown or unsupported algorithm ' + alg); + } + + let iv = u.get(common.HeaderParameters.IV); + const partialIv = u.get(common.HeaderParameters.Partial_IV); + if (iv && partialIv) { + throw new Error('IV and Partial IV parameters MUST NOT both be present in the same security layer'); + } + if (partialIv && !options.contextIv) { + throw new Error('Context IV must be provided when Partial IV is used'); + } + if (partialIv && options.contextIv) { + iv = common.xor(partialIv, options.contextIv); + } + + const tagLength = authTagLength[alg]; + const tag = ciphertext.slice(ciphertext.length - tagLength, ciphertext.length); + ciphertext = ciphertext.slice(0, ciphertext.length - tagLength); + + const aad = createAAD(p, (msgTag === EncryptTag ? 'Encrypt' : 'Encrypt0'), externalAAD); + if (isNodeAlg[alg]) { + return nodeDecrypt(ciphertext, key, alg, iv, tag, aad); + } else if (isCCMAlg[alg] && runningInNode()) { + return nodeDecrypt(ciphertext, key, alg, iv, tag, aad, true); + } else { + throw new Error('No implementation for algorithm, ' + alg); + } + }); +}; + +}).call(this)}).call(this,require("buffer").Buffer) +},{"./common":230,"any-promise":214,"buffer":64,"cbor":220,"crypto":74,"node-hkdf-sync":267}],232:[function(require,module,exports){ +/* jshint esversion: 6 */ +/* jslint node: true */ +'use strict'; + +exports.common = require('./common'); +exports.mac = require('./mac'); +exports.sign = require('./sign'); +exports.encrypt = require('./encrypt'); + +},{"./common":230,"./encrypt":231,"./mac":233,"./sign":234}],233:[function(require,module,exports){ +/* jshint esversion: 6 */ +/* jslint node: true */ +'use strict'; + +const cbor = require('cbor'); +const aesCbcMac = require('aes-cbc-mac'); +const crypto = require('crypto'); +const Promise = require('any-promise'); +const common = require('./common'); +const Tagged = cbor.Tagged; +const EMPTY_BUFFER = common.EMPTY_BUFFER; + +const MAC0Tag = exports.MAC0Tag = 17; +const MACTag = exports.MACTag = 97; + +const AlgFromTags = { + 4: 'SHA-256_64', + 5: 'SHA-256', + 6: 'SHA-384', + 7: 'SHA-512', + 14: 'AES-MAC-128/64', + 15: 'AES-MAC-256/64', + 25: 'AES-MAC-128/128', + 26: 'AES-MAC-256/128' +}; + +const COSEAlgToNodeAlg = { + 'SHA-256_64': 'sha256', + 'SHA-256': 'sha256', + 'HS256': 'sha256', + 'SHA-384': 'sha384', + 'SHA-512': 'sha512', + 'AES-MAC-128/64': 'aes-cbc-mac-64', + 'AES-MAC-128/128': 'aes-cbc-mac-128', + 'AES-MAC-256/64': 'aes-cbc-mac-64', + 'AES-MAC-256/128': 'aes-cbc-mac-128' +}; + +const CutTo = { + 4: 8, + 5: 32, + 6: 48, + 7: 64 +}; + +const context = {}; +context[MAC0Tag] = 'MAC0'; +context[MACTag] = 'MAC'; + +function doMac (context, p, externalAAD, payload, alg, key) { + return new Promise((resolve, reject) => { + const MACstructure = [ + context, // 'MAC0' or 'MAC1', // context + p, // protected + externalAAD, // bstr, + payload // bstr + ]; + + const toBeMACed = cbor.encode(MACstructure); + if (alg === 'aes-cbc-mac-64') { + const mac = aesCbcMac.create(key, toBeMACed, 8); + resolve(mac); + } else if (alg === 'aes-cbc-mac-128') { + const mac = aesCbcMac.create(key, toBeMACed, 16); + resolve(mac); + } else { + const hmac = crypto.createHmac(alg, key); + hmac.end(toBeMACed, function () { + resolve(hmac.read()); + }); + } + }); +} + +exports.create = function (headers, payload, recipents, externalAAD, options) { + options = options || {}; + externalAAD = externalAAD || EMPTY_BUFFER; + let u = headers.u || {}; + let p = headers.p || {}; + + p = common.TranslateHeaders(p); + u = common.TranslateHeaders(u); + + const alg = p.get(common.HeaderParameters.alg) || u.get(common.HeaderParameters.alg); + + if (!alg) { + throw new Error('Missing mandatory parameter \'alg\''); + } + + if (recipents.length === 0) { + throw new Error('There has to be at least one recipent'); + } + + const predictableP = (!p.size) ? EMPTY_BUFFER : cbor.encode(p); + if (p.size === 0 && options.encodep === 'empty') { + p = EMPTY_BUFFER; + } else { + p = cbor.encode(p); + } + // TODO check crit headers + if (Array.isArray(recipents)) { + if (recipents.length > 1) { + throw new Error('MACing with multiple recipents is not implemented'); + } + const recipent = recipents[0]; + return doMac('MAC', + predictableP, + externalAAD, + payload, + COSEAlgToNodeAlg[AlgFromTags[alg]], + recipent.key) + .then((tag) => { + tag = tag.slice(0, CutTo[alg]); + const ru = common.TranslateHeaders(recipent.u); + const rp = EMPTY_BUFFER; + const maced = [p, u, payload, tag, [[rp, ru, EMPTY_BUFFER]]]; + return cbor.encode(options.excludetag ? maced : new Tagged(MACTag, maced)); + }); + } else { + return doMac('MAC0', + predictableP, + externalAAD, + payload, + COSEAlgToNodeAlg[AlgFromTags[alg]], + recipents.key) + .then((tag) => { + tag = tag.slice(0, CutTo[alg]); + const maced = [p, u, payload, tag]; + return cbor.encode(options.excludetag ? maced : new Tagged(MAC0Tag, maced)); + }); + } +}; + +exports.read = function (data, key, externalAAD, options) { + options = options || {}; + externalAAD = externalAAD || EMPTY_BUFFER; + + return cbor.decodeFirst(data) + .then((obj) => { + let type = options.defaultType ? options.defaultType : MAC0Tag; + if (obj instanceof Tagged) { + if (obj.tag !== MAC0Tag && obj.tag !== MACTag) { + throw new Error('Unexpected cbor tag, \'' + obj.tag + '\''); + } + type = obj.tag; + obj = obj.value; + } + + if (!Array.isArray(obj)) { + throw new Error('Expecting Array'); + } + + if (type === MAC0Tag && obj.length !== 4) { + throw new Error('Expecting Array of lenght 4'); + } + if (type === MACTag && obj.length !== 5) { + throw new Error('Expecting Array of lenght 5'); + } + + let [p, u, payload, tag] = obj; + p = (!p.length) ? EMPTY_BUFFER : cbor.decode(p); + p = (!p.size) ? EMPTY_BUFFER : p; + u = (!u.size) ? EMPTY_BUFFER : u; + + // TODO validate protected header + const alg = (p !== EMPTY_BUFFER) ? p.get(common.HeaderParameters.alg) : (u !== EMPTY_BUFFER) ? u.get(common.HeaderParameters.alg) : undefined; + p = (!p.size) ? EMPTY_BUFFER : cbor.encode(p); + if (!AlgFromTags[alg]) { + throw new Error('Unknown algorithm, ' + alg); + } + if (!COSEAlgToNodeAlg[AlgFromTags[alg]]) { + throw new Error('Unsupported algorithm, ' + AlgFromTags[alg]); + } + + return doMac(context[type], p, externalAAD, payload, COSEAlgToNodeAlg[AlgFromTags[alg]], key) + .then((calcTag) => { + calcTag = calcTag.slice(0, CutTo[alg]); + + if (tag.toString('hex') !== calcTag.toString('hex')) { + throw new Error('Tag mismatch'); + } + + return payload; + }); + }); +}; + +},{"./common":230,"aes-cbc-mac":213,"any-promise":214,"cbor":220,"crypto":74}],234:[function(require,module,exports){ +(function (Buffer){(function (){ +/* jshint esversion: 6 */ +/* jslint node: true */ +'use strict'; + +const cbor = require('cbor'); +const EC = require('elliptic').ec; +const crypto = require('crypto'); +const common = require('./common'); +const Promise = require('any-promise'); +const EMPTY_BUFFER = common.EMPTY_BUFFER; +const Tagged = cbor.Tagged; + +const SignTag = exports.SignTag = 98; +const Sign1Tag = exports.Sign1Tag = 18; + +const AlgFromTags = {}; +AlgFromTags[-7] = { 'sign': 'ES256', 'digest': 'SHA-256' }; +AlgFromTags[-35] = { 'sign': 'ES384', 'digest': 'SHA-384' }; +AlgFromTags[-36] = { 'sign': 'ES512', 'digest': 'SHA-512' }; +AlgFromTags[-257] = { 'sign': 'RS256', 'digest': 'SHA-256' }; +AlgFromTags[-258] = { 'sign': 'RS384', 'digest': 'SHA-384' }; +AlgFromTags[-259] = { 'sign': 'RS512', 'digest': 'SHA-512' }; + +const COSEAlgToNodeAlg = { + 'ES256': { 'sign': 'p256', 'digest': 'sha256' }, + 'ES384': { 'sign': 'p384', 'digest': 'sha384' }, + 'ES512': { 'sign': 'p521', 'digest': 'sha512' }, + 'RS256': { 'sign': 'RSA-SHA256' }, + 'RS384': { 'sign': 'RSA-SHA384' }, + 'RS512': { 'sign': 'RSA-SHA512' } +}; + +function doSign (SigStructure, signer, alg) { + return new Promise((resolve, reject) => { + if (!AlgFromTags[alg]) { + throw new Error('Unknown algorithm, ' + alg); + } + if (!COSEAlgToNodeAlg[AlgFromTags[alg].sign]) { + throw new Error('Unsupported algorithm, ' + AlgFromTags[alg].sign); + } + + let ToBeSigned = cbor.encode(SigStructure); + + let sig; + if (AlgFromTags[alg].sign.startsWith('ES')) { + const hash = crypto.createHash(COSEAlgToNodeAlg[AlgFromTags[alg].sign].digest); + hash.update(ToBeSigned); + ToBeSigned = hash.digest(); + const ec = new EC(COSEAlgToNodeAlg[AlgFromTags[alg].sign].sign); + const key = ec.keyFromPrivate(signer.key.d); + const signature = key.sign(ToBeSigned); + const bitLength = Math.ceil(ec.curve._bitLength / 8); + sig = Buffer.concat([signature.r.toArrayLike(Buffer, undefined, bitLength), signature.s.toArrayLike(Buffer, undefined, bitLength)]); + } else { + const sign = crypto.createSign(COSEAlgToNodeAlg[AlgFromTags[alg].sign].sign); + sign.update(ToBeSigned); + sign.end(); + sig = sign.sign(signer.key); + } + + resolve(sig); + }); +} + +exports.create = function (headers, payload, signers, options) { + options = options || {}; + let u = headers.u || {}; + let p = headers.p || {}; + + p = common.TranslateHeaders(p); + u = common.TranslateHeaders(u); + let bodyP = p || {}; + bodyP = (bodyP.size === 0) ? EMPTY_BUFFER : cbor.encode(bodyP); + if (Array.isArray(signers)) { + if (signers.length === 0) { + throw new Error('There has to be at least one signer'); + } + if (signers.length > 1) { + throw new Error('Only one signer is supported'); + } + // TODO handle multiple signers + const signer = signers[0]; + const externalAAD = signer.externalAAD || EMPTY_BUFFER; + let signerP = signer.p || {}; + let signerU = signer.u || {}; + + signerP = common.TranslateHeaders(signerP); + signerU = common.TranslateHeaders(signerU); + const alg = signerP.get(common.HeaderParameters.alg); + signerP = (signerP.size === 0) ? EMPTY_BUFFER : cbor.encode(signerP); + + const SigStructure = [ + 'Signature', + bodyP, + signerP, + externalAAD, + payload + ]; + + console.log('') + + return doSign(SigStructure, signer, alg).then((sig) => { + if (p.size === 0 && options.encodep === 'empty') { + p = EMPTY_BUFFER; + } else { + p = cbor.encode(p); + } + const signed = [p, u, payload, [[signerP, signerU, sig]]]; + return cbor.encode(options.excludetag ? signed : new Tagged(SignTag, signed)); + }); + } else { + const signer = signers; + const externalAAD = signer.externalAAD || EMPTY_BUFFER; + const alg = p.get(common.HeaderParameters.alg) || u.get(common.HeaderParameters.alg); + const SigStructure = [ + 'Signature1', + bodyP, + externalAAD, + payload + ]; + return doSign(SigStructure, signer, alg).then((sig) => { + if (p.size === 0 && options.encodep === 'empty') { + p = EMPTY_BUFFER; + } else { + p = cbor.encode(p); + } + const signed = [p, u, payload, sig]; + return cbor.encodeCanonical(options.excludetag ? signed : new Tagged(Sign1Tag, signed)); + }); + } +}; + +function doVerify (SigStructure, verifier, alg, sig) { + return new Promise((resolve, reject) => { + if (!AlgFromTags[alg]) { + throw new Error('Unknown algorithm, ' + alg); + } + if (!COSEAlgToNodeAlg[AlgFromTags[alg].sign]) { + throw new Error('Unsupported algorithm, ' + AlgFromTags[alg].sign); + } + const ToBeSigned = cbor.encode(SigStructure); + + if (AlgFromTags[alg].sign.startsWith('ES')) { + const hash = crypto.createHash(COSEAlgToNodeAlg[AlgFromTags[alg].sign].digest); + hash.update(ToBeSigned); + const msgHash = hash.digest(); + + const pub = { 'x': verifier.key.x, 'y': verifier.key.y }; + const ec = new EC(COSEAlgToNodeAlg[AlgFromTags[alg].sign].sign); + const key = ec.keyFromPublic(pub); + sig = { 'r': sig.slice(0, sig.length / 2), 's': sig.slice(sig.length / 2) }; + if (key.verify(msgHash, sig)) { + resolve(); + } else { + throw new Error('Signature missmatch'); + } + } else { + const verify = crypto.createVerify(COSEAlgToNodeAlg[AlgFromTags[alg].sign].sign); + verify.update(ToBeSigned); + if (verify.verify(verifier.key, sig)) { + resolve(); + } else { + throw new Error('Signature missmatch'); + } + } + }); +} + +function getSigner (signers, verifier) { + for (let i = 0; i < signers.length; i++) { + const kid = signers[i][1].get(common.HeaderParameters.kid); // TODO create constant for header locations + if (kid.equals(Buffer.from(verifier.key.kid, 'utf8'))) { + return signers[i]; + } + } +} + +function getCommonParameter (first, second, parameter) { + let result; + if (first.get) { + result = first.get(parameter); + } + if (!result && second.get) { + result = second.get(parameter); + } + return result; +} + +exports.verify = function (payload, verifier, options) { + options = options || {}; + return cbor.decodeFirst(payload) + .then((obj) => { + let type = options.defaultType ? options.defaultType : SignTag; + if (obj instanceof Tagged) { + if (obj.tag !== SignTag && obj.tag !== Sign1Tag) { + throw new Error('Unexpected cbor tag, \'' + obj.tag + '\''); + } + type = obj.tag; + obj = obj.value; + } + + if (!Array.isArray(obj)) { + throw new Error('Expecting Array'); + } + + if (obj.length !== 4) { + throw new Error('Expecting Array of lenght 4'); + } + + let [p, u, plaintext, signers] = obj; + + if (type === SignTag && !Array.isArray(signers)) { + throw new Error('Expecting signature Array'); + } + + p = (!p.length) ? EMPTY_BUFFER : cbor.decodeFirstSync(p); + u = (!u.size) ? EMPTY_BUFFER : u; + + let signer = (type === SignTag ? getSigner(signers, verifier) : signers); + + if (!signer) { + throw new Error('Failed to find signer with kid' + verifier.key.kid); + } + + if (type === SignTag) { + const externalAAD = verifier.externalAAD || EMPTY_BUFFER; + let [signerP, , sig] = signer; + signerP = (!signerP.length) ? EMPTY_BUFFER : signerP; + p = (!p.size) ? EMPTY_BUFFER : cbor.encode(p); + const signerPMap = cbor.decode(signerP); + const alg = signerPMap.get(common.HeaderParameters.alg); + const SigStructure = [ + 'Signature', + p, + signerP, + externalAAD, + plaintext + ]; + return doVerify(SigStructure, verifier, alg, sig) + .then(() => { + return plaintext; + }); + } else { + const externalAAD = verifier.externalAAD || EMPTY_BUFFER; + + const alg = getCommonParameter(p, u, common.HeaderParameters.alg); + p = (!p.size) ? EMPTY_BUFFER : cbor.encode(p); + const SigStructure = [ + 'Signature1', + p, + externalAAD, + plaintext + ]; + return doVerify(SigStructure, verifier, alg, signer) + .then(() => { + return plaintext; + }); + } + }); +}; + +}).call(this)}).call(this,require("buffer").Buffer) +},{"./common":230,"any-promise":214,"buffer":64,"cbor":220,"crypto":74,"elliptic":235}],235:[function(require,module,exports){ +arguments[4][86][0].apply(exports,arguments) +},{"../package.json":250,"./elliptic/curve":238,"./elliptic/curves":241,"./elliptic/ec":242,"./elliptic/eddsa":245,"./elliptic/utils":249,"brorand":219,"dup":86}],236:[function(require,module,exports){ +arguments[4][87][0].apply(exports,arguments) +},{"../utils":249,"bn.js":218,"dup":87}],237:[function(require,module,exports){ +arguments[4][88][0].apply(exports,arguments) +},{"../utils":249,"./base":236,"bn.js":218,"dup":88,"inherits":264}],238:[function(require,module,exports){ +arguments[4][89][0].apply(exports,arguments) +},{"./base":236,"./edwards":237,"./mont":239,"./short":240,"dup":89}],239:[function(require,module,exports){ +arguments[4][90][0].apply(exports,arguments) +},{"../utils":249,"./base":236,"bn.js":218,"dup":90,"inherits":264}],240:[function(require,module,exports){ +arguments[4][91][0].apply(exports,arguments) +},{"../utils":249,"./base":236,"bn.js":218,"dup":91,"inherits":264}],241:[function(require,module,exports){ +arguments[4][92][0].apply(exports,arguments) +},{"./curve":238,"./precomputed/secp256k1":248,"./utils":249,"dup":92,"hash.js":251}],242:[function(require,module,exports){ +arguments[4][93][0].apply(exports,arguments) +},{"../curves":241,"../utils":249,"./key":243,"./signature":244,"bn.js":218,"brorand":219,"dup":93,"hmac-drbg":263}],243:[function(require,module,exports){ +arguments[4][94][0].apply(exports,arguments) +},{"../utils":249,"bn.js":218,"dup":94}],244:[function(require,module,exports){ +arguments[4][95][0].apply(exports,arguments) +},{"../utils":249,"bn.js":218,"dup":95}],245:[function(require,module,exports){ +arguments[4][96][0].apply(exports,arguments) +},{"../curves":241,"../utils":249,"./key":246,"./signature":247,"dup":96,"hash.js":251}],246:[function(require,module,exports){ +arguments[4][97][0].apply(exports,arguments) +},{"../utils":249,"dup":97}],247:[function(require,module,exports){ +arguments[4][98][0].apply(exports,arguments) +},{"../utils":249,"bn.js":218,"dup":98}],248:[function(require,module,exports){ +arguments[4][99][0].apply(exports,arguments) +},{"dup":99}],249:[function(require,module,exports){ +arguments[4][100][0].apply(exports,arguments) +},{"bn.js":218,"dup":100,"minimalistic-assert":265,"minimalistic-crypto-utils":266}],250:[function(require,module,exports){ +module.exports={ + "_from": "elliptic@^6.4.0", + "_id": "elliptic@6.5.4", + "_inBundle": false, + "_integrity": "sha512-iLhC6ULemrljPZb+QutR5TQGB+pdW6KGD5RSegS+8sorOZT+rdQFbsQFJgvN3eRqNALqJer4oQ16YvJHlU8hzQ==", + "_location": "/elliptic", + "_phantomChildren": {}, + "_requested": { + "type": "range", + "registry": true, + "raw": "elliptic@^6.4.0", + "name": "elliptic", + "escapedName": "elliptic", + "rawSpec": "^6.4.0", + "saveSpec": null, + "fetchSpec": "^6.4.0" + }, + "_requiredBy": [ + "/cose-js" + ], + "_resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.5.4.tgz", + "_shasum": "da37cebd31e79a1367e941b592ed1fbebd58abbb", + "_spec": "elliptic@^6.4.0", + "_where": "/home/default2/Desktop/o1labs/node_modules/cose-js", + "author": { + "name": "Fedor Indutny", + "email": "fedor@indutny.com" + }, + "bugs": { + "url": "https://github.com/indutny/elliptic/issues" + }, + "bundleDependencies": false, + "dependencies": { + "bn.js": "^4.11.9", + "brorand": "^1.1.0", + "hash.js": "^1.0.0", + "hmac-drbg": "^1.0.1", + "inherits": "^2.0.4", + "minimalistic-assert": "^1.0.1", + "minimalistic-crypto-utils": "^1.0.1" + }, + "deprecated": false, + "description": "EC cryptography", + "devDependencies": { + "brfs": "^2.0.2", + "coveralls": "^3.1.0", + "eslint": "^7.6.0", + "grunt": "^1.2.1", + "grunt-browserify": "^5.3.0", + "grunt-cli": "^1.3.2", + "grunt-contrib-connect": "^3.0.0", + "grunt-contrib-copy": "^1.0.0", + "grunt-contrib-uglify": "^5.0.0", + "grunt-mocha-istanbul": "^5.0.2", + "grunt-saucelabs": "^9.0.1", + "istanbul": "^0.4.5", + "mocha": "^8.0.1" + }, + "files": [ + "lib" + ], + "homepage": "https://github.com/indutny/elliptic", + "keywords": [ + "EC", + "Elliptic", + "curve", + "Cryptography" + ], + "license": "MIT", + "main": "lib/elliptic.js", + "name": "elliptic", + "repository": { + "type": "git", + "url": "git+ssh://git@github.com/indutny/elliptic.git" + }, + "scripts": { + "lint": "eslint lib test", + "lint:fix": "npm run lint -- --fix", + "test": "npm run lint && npm run unit", + "unit": "istanbul test _mocha --reporter=spec test/index.js", + "version": "grunt dist && git add dist/" + }, + "version": "6.5.4" +} + +},{}],251:[function(require,module,exports){ +arguments[4][129][0].apply(exports,arguments) +},{"./hash/common":252,"./hash/hmac":253,"./hash/ripemd":254,"./hash/sha":255,"./hash/utils":262,"dup":129}],252:[function(require,module,exports){ +arguments[4][130][0].apply(exports,arguments) +},{"./utils":262,"dup":130,"minimalistic-assert":265}],253:[function(require,module,exports){ +arguments[4][131][0].apply(exports,arguments) +},{"./utils":262,"dup":131,"minimalistic-assert":265}],254:[function(require,module,exports){ +arguments[4][132][0].apply(exports,arguments) +},{"./common":252,"./utils":262,"dup":132}],255:[function(require,module,exports){ +arguments[4][133][0].apply(exports,arguments) +},{"./sha/1":256,"./sha/224":257,"./sha/256":258,"./sha/384":259,"./sha/512":260,"dup":133}],256:[function(require,module,exports){ +arguments[4][134][0].apply(exports,arguments) +},{"../common":252,"../utils":262,"./common":261,"dup":134}],257:[function(require,module,exports){ +arguments[4][135][0].apply(exports,arguments) +},{"../utils":262,"./256":258,"dup":135}],258:[function(require,module,exports){ +arguments[4][136][0].apply(exports,arguments) +},{"../common":252,"../utils":262,"./common":261,"dup":136,"minimalistic-assert":265}],259:[function(require,module,exports){ +arguments[4][137][0].apply(exports,arguments) +},{"../utils":262,"./512":260,"dup":137}],260:[function(require,module,exports){ +arguments[4][138][0].apply(exports,arguments) +},{"../common":252,"../utils":262,"dup":138,"minimalistic-assert":265}],261:[function(require,module,exports){ +arguments[4][139][0].apply(exports,arguments) +},{"../utils":262,"dup":139}],262:[function(require,module,exports){ +arguments[4][140][0].apply(exports,arguments) +},{"dup":140,"inherits":264,"minimalistic-assert":265}],263:[function(require,module,exports){ +arguments[4][141][0].apply(exports,arguments) +},{"dup":141,"hash.js":251,"minimalistic-assert":265,"minimalistic-crypto-utils":266}],264:[function(require,module,exports){ +arguments[4][143][0].apply(exports,arguments) +},{"dup":143}],265:[function(require,module,exports){ +arguments[4][151][0].apply(exports,arguments) +},{"dup":151}],266:[function(require,module,exports){ +arguments[4][152][0].apply(exports,arguments) +},{"dup":152}],267:[function(require,module,exports){ +module.exports = require("./lib/hkdf"); +},{"./lib/hkdf":268}],268:[function(require,module,exports){ +(function (Buffer){(function (){ +// +// a straightforward implementation of HKDF +// +// https://tools.ietf.org/html/rfc5869 +// + +var crypto = require("crypto"); + +function zeros(length) { + var buf = new Buffer(length); + + buf.fill(0); + + return buf.toString(); +} +// imk is initial keying material +function HKDF(hashAlg, salt, ikm) { + this.hashAlg = hashAlg; + + // create the hash alg to see if it exists and get its length + var hash = crypto.createHash(this.hashAlg); + this.hashLength = hash.digest().length; + + this.salt = salt || zeros(this.hashLength); + this.ikm = ikm; + + // now we compute the PRK + var hmac = crypto.createHmac(this.hashAlg, this.salt); + hmac.update(this.ikm); + this.prk = hmac.digest(); +} + +HKDF.prototype = { + derive: function(info, size) { + var prev = new Buffer(0); + var output; + var buffers = []; + var num_blocks = Math.ceil(size / this.hashLength); + info = new Buffer(info); + + for (var i=0; i 0) && (om !== _this._readableState.objectMode)) { + throw new Error('Do not switch objectMode in the middle of the stream'); + } + _this._readableState.objectMode = om; + return _this._writableState.objectMode = om; + }; + })(this)); + } + if (inp != null) { + this.end(inp, inpE); + } + } + + NoFilter.isNoFilter = function(obj) { + return obj instanceof this; + }; + + NoFilter.compare = function(nf1, nf2) { + if (!(nf1 instanceof this)) { + throw new TypeError('Arguments must be NoFilters'); + } + if (nf1 === nf2) { + return 0; + } else { + return nf1.compare(nf2); + } + }; + + NoFilter.concat = function(list, length) { + var bufs; + if (!Array.isArray(list)) { + throw new TypeError('list argument must be an Array of NoFilters'); + } + if ((list.length === 0) || (length === 0)) { + return new Buffer(0); + } + if (length == null) { + length = list.reduce(function(tot, nf) { + if (!(nf instanceof NoFilter)) { + throw new TypeError('list argument must be an Array of NoFilters'); + } + return tot + nf.length; + }, 0); + } + bufs = list.map(function(nf) { + if (!(nf instanceof NoFilter)) { + throw new TypeError('list argument must be an Array of NoFilters'); + } + if (nf._readableState.objectMode) { + throw new Error('NoFilter may not be in object mode for concat'); + } + return nf.slice(); + }); + return Buffer.concat(bufs, length); + }; + + NoFilter.prototype._transform = function(chunk, encoding, callback) { + if (!this._readableState.objectMode && !Buffer.isBuffer(chunk)) { + chunk = new Buffer(chunk, encoding); + } + this.push(chunk); + return callback(); + }; + + NoFilter.prototype._bufArray = function() { + var b, bufs; + bufs = this._readableState.buffer; + if (!Array.isArray(bufs)) { + b = bufs.head; + bufs = []; + while (b != null) { + bufs.push(b.data); + b = b.next; + } + } + return bufs; + }; + + NoFilter.prototype.read = function(size) { + var buf; + buf = NoFilter.__super__.read.call(this, size); + if (buf != null) { + this.emit('read', buf); + } + return buf; + }; + + NoFilter.prototype.promise = function(cb) { + var done; + done = false; + return new Promise((function(_this) { + return function(resolve, reject) { + _this.on('finish', function() { + var data; + data = _this.read(); + if ((cb != null) && !done) { + done = true; + cb(null, data); + } + return resolve(data); + }); + return _this.on('error', function(er) { + if ((cb != null) && !done) { + done = true; + cb(er); + } + return reject(er); + }); + }; + })(this)); + }; + + NoFilter.prototype.compare = function(other) { + if (!(other instanceof NoFilter)) { + throw new TypeError('Arguments must be NoFilters'); + } + if (this._readableState.objectMode || other._readableState.objectMode) { + throw new Error('Must not be in object mode to compare'); + } + if (this === other) { + return 0; + } else { + return this.slice().compare(other.slice()); + } + }; + + NoFilter.prototype.equals = function(other) { + return this.compare(other) === 0; + }; + + NoFilter.prototype.slice = function(start, end) { + var b, bufs; + if (this._readableState.objectMode) { + return this._bufArray().slice(start, end); + } else { + bufs = this._bufArray(); + switch (bufs.length) { + case 0: + return new Buffer(0); + case 1: + return bufs[0].slice(start, end); + default: + b = Buffer.concat(bufs); + return b.slice(start, end); + } + } + }; + + NoFilter.prototype.get = function(index) { + return this.slice()[index]; + }; + + NoFilter.prototype.toJSON = function() { + var b; + b = this.slice(); + if (Buffer.isBuffer(b)) { + return b.toJSON(); + } else { + return b; + } + }; + + NoFilter.prototype.toString = function(encoding, start, end) { + return this.slice().toString(encoding, start, end); + }; + + NoFilter.prototype.inspect = function(depth, options) { + var bufs, hex; + bufs = this._bufArray(); + hex = bufs.map(function(b) { + if (Buffer.isBuffer(b)) { + if (options != null ? options.stylize : void 0) { + return options.stylize(b.toString('hex'), 'string'); + } else { + return b.toString('hex'); + } + } else { + return util.inspect(b, options); + } + }).join(', '); + return this.constructor.name + " [" + hex + "]"; + }; + + _read_gen = function(meth, len) { + return function(val) { + var b; + b = this.read(len); + if (!Buffer.isBuffer(b)) { + return null; + } + return b[meth].call(b, 0, true); + }; + }; + + _write_gen = function(meth, len) { + return function(val) { + var b; + b = new Buffer(len); + b[meth].call(b, val, 0, true); + return this.push(b); + }; + }; + + NoFilter.prototype.writeUInt8 = _write_gen('writeUInt8', 1); + + NoFilter.prototype.writeUInt16LE = _write_gen('writeUInt16LE', 2); + + NoFilter.prototype.writeUInt16BE = _write_gen('writeUInt16BE', 2); + + NoFilter.prototype.writeUInt32LE = _write_gen('writeUInt32LE', 4); + + NoFilter.prototype.writeUInt32BE = _write_gen('writeUInt32BE', 4); + + NoFilter.prototype.writeInt8 = _write_gen('writeInt8', 1); + + NoFilter.prototype.writeInt16LE = _write_gen('writeInt16LE', 2); + + NoFilter.prototype.writeInt16BE = _write_gen('writeInt16BE', 2); + + NoFilter.prototype.writeInt32LE = _write_gen('writeInt32LE', 4); + + NoFilter.prototype.writeInt32BE = _write_gen('writeInt32BE', 4); + + NoFilter.prototype.writeFloatLE = _write_gen('writeFloatLE', 4); + + NoFilter.prototype.writeFloatBE = _write_gen('writeFloatBE', 4); + + NoFilter.prototype.writeDoubleLE = _write_gen('writeDoubleLE', 8); + + NoFilter.prototype.writeDoubleBE = _write_gen('writeDoubleBE', 8); + + NoFilter.prototype.readUInt8 = _read_gen('readUInt8', 1); + + NoFilter.prototype.readUInt16LE = _read_gen('readUInt16LE', 2); + + NoFilter.prototype.readUInt16BE = _read_gen('readUInt16BE', 2); + + NoFilter.prototype.readUInt32LE = _read_gen('readUInt32LE', 4); + + NoFilter.prototype.readUInt32BE = _read_gen('readUInt32BE', 4); + + NoFilter.prototype.readInt8 = _read_gen('readInt8', 1); + + NoFilter.prototype.readInt16LE = _read_gen('readInt16LE', 2); + + NoFilter.prototype.readInt16BE = _read_gen('readInt16BE', 2); + + NoFilter.prototype.readInt32LE = _read_gen('readInt32LE', 4); + + NoFilter.prototype.readInt32BE = _read_gen('readInt32BE', 4); + + NoFilter.prototype.readFloatLE = _read_gen('readFloatLE', 4); + + NoFilter.prototype.readFloatBE = _read_gen('readFloatBE', 4); + + NoFilter.prototype.readDoubleLE = _read_gen('readDoubleLE', 8); + + NoFilter.prototype.readDoubleBE = _read_gen('readDoubleBE', 8); + + get = function(props) { + var getter, name, results; + results = []; + for (name in props) { + getter = props[name]; + results.push(NoFilter.prototype.__defineGetter__(name, getter)); + } + return results; + }; + + get({ + length: function() { + return this._readableState.length; + } + }); + + return NoFilter; + + })(stream.Transform); + +}).call(this); + + + +}).call(this)}).call(this,require("buffer").Buffer) +},{"buffer":64,"stream":189,"util":210}]},{},[212])(212) +}); diff --git a/core/third-party/coseverify.js b/core/third-party/coseverify.js new file mode 100644 index 0000000..4ac8ecc --- /dev/null +++ b/core/third-party/coseverify.js @@ -0,0 +1,31 @@ +// this file is not used by the extension, it serves as an input to to create cose.js with: +// browserify coseverify.js --standalone COSE > cose.js + +const cose = require('cose-js'); + +// x,y,doc is an ArrayBuffer +const verify = function (x, y, doc){ + const verifier = { + 'key': { + 'x': Buffer.from(x), + 'y': Buffer.from(y) + } + }; + + cose.sign.verify( + Buffer.from(doc), + verifier, + {defaultType: 18}) + .then((buf) => { + console.log("Verification successful") + //console.log('Verified message: ' + buf.toString('utf8')); + }).catch((error) => { + console.log(error); + }); +} + +if (typeof module !== 'undefined'){ //we are in node.js environment + module.exports={ + verify + } +} \ No newline at end of file diff --git a/core/third-party/fastsha256.js b/core/third-party/fastsha256.js new file mode 100644 index 0000000..2808184 --- /dev/null +++ b/core/third-party/fastsha256.js @@ -0,0 +1,427 @@ +(function (root, factory) { + // Hack to make all exports of this module sha256 function object properties. + var exports = {}; + factory(exports); + var fastsha256 = exports["default"]; + for (var k in exports) { + fastsha256[k] = exports[k]; + } + + if (typeof module === 'object' && typeof module.exports === 'object') { + module.exports = fastsha256; + } else if (typeof define === 'function' && define.amd) { + define(function() { return fastsha256; }); + } else { + root.fastsha256 = fastsha256; + } +})(this, function(exports) { +"use strict"; +exports.__esModule = true; +// SHA-256 (+ HMAC and PBKDF2) for JavaScript. +// +// Written in 2014-2016 by Dmitry Chestnykh. +// Public domain, no warranty. +// +// Functions (accept and return Uint8Arrays): +// +// sha256(message) -> hash +// sha256.hmac(key, message) -> mac +// sha256.pbkdf2(password, salt, rounds, dkLen) -> dk +// +// Classes: +// +// new sha256.Hash() +// new sha256.HMAC(key) +// +exports.digestLength = 32; +exports.blockSize = 64; +// SHA-256 constants +var K = new Uint32Array([ + 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 +]); +function hashBlocks(w, v, p, pos, len) { + var a, b, c, d, e, f, g, h, u, i, j, t1, t2; + while (len >= 64) { + a = v[0]; + b = v[1]; + c = v[2]; + d = v[3]; + e = v[4]; + f = v[5]; + g = v[6]; + h = v[7]; + for (i = 0; i < 16; i++) { + j = pos + i * 4; + w[i] = (((p[j] & 0xff) << 24) | ((p[j + 1] & 0xff) << 16) | + ((p[j + 2] & 0xff) << 8) | (p[j + 3] & 0xff)); + } + for (i = 16; i < 64; i++) { + u = w[i - 2]; + t1 = (u >>> 17 | u << (32 - 17)) ^ (u >>> 19 | u << (32 - 19)) ^ (u >>> 10); + u = w[i - 15]; + t2 = (u >>> 7 | u << (32 - 7)) ^ (u >>> 18 | u << (32 - 18)) ^ (u >>> 3); + w[i] = (t1 + w[i - 7] | 0) + (t2 + w[i - 16] | 0); + } + for (i = 0; i < 64; i++) { + t1 = (((((e >>> 6 | e << (32 - 6)) ^ (e >>> 11 | e << (32 - 11)) ^ + (e >>> 25 | e << (32 - 25))) + ((e & f) ^ (~e & g))) | 0) + + ((h + ((K[i] + w[i]) | 0)) | 0)) | 0; + t2 = (((a >>> 2 | a << (32 - 2)) ^ (a >>> 13 | a << (32 - 13)) ^ + (a >>> 22 | a << (32 - 22))) + ((a & b) ^ (a & c) ^ (b & c))) | 0; + h = g; + g = f; + f = e; + e = (d + t1) | 0; + d = c; + c = b; + b = a; + a = (t1 + t2) | 0; + } + v[0] += a; + v[1] += b; + v[2] += c; + v[3] += d; + v[4] += e; + v[5] += f; + v[6] += g; + v[7] += h; + pos += 64; + len -= 64; + } + return pos; +} +// Hash implements SHA256 hash algorithm. +var Hash = /** @class */ (function () { + function Hash() { + this.digestLength = exports.digestLength; + this.blockSize = exports.blockSize; + // Note: Int32Array is used instead of Uint32Array for performance reasons. + this.state = new Int32Array(8); // hash state + this.temp = new Int32Array(64); // temporary state + this.buffer = new Uint8Array(128); // buffer for data to hash + this.bufferLength = 0; // number of bytes in buffer + this.bytesHashed = 0; // number of total bytes hashed + this.finished = false; // indicates whether the hash was finalized + this.reset(); + } + // Resets hash state making it possible + // to re-use this instance to hash other data. + Hash.prototype.reset = function () { + this.state[0] = 0x6a09e667; + this.state[1] = 0xbb67ae85; + this.state[2] = 0x3c6ef372; + this.state[3] = 0xa54ff53a; + this.state[4] = 0x510e527f; + this.state[5] = 0x9b05688c; + this.state[6] = 0x1f83d9ab; + this.state[7] = 0x5be0cd19; + this.bufferLength = 0; + this.bytesHashed = 0; + this.finished = false; + return this; + }; + // Cleans internal buffers and re-initializes hash state. + Hash.prototype.clean = function () { + for (var i = 0; i < this.buffer.length; i++) { + this.buffer[i] = 0; + } + for (var i = 0; i < this.temp.length; i++) { + this.temp[i] = 0; + } + this.reset(); + }; + // Updates hash state with the given data. + // + // Optionally, length of the data can be specified to hash + // fewer bytes than data.length. + // + // Throws error when trying to update already finalized hash: + // instance must be reset to use it again. + Hash.prototype.update = function (data, dataLength) { + if (dataLength === void 0) { dataLength = data.length; } + if (this.finished) { + throw new Error("SHA256: can't update because hash was finished."); + } + var dataPos = 0; + this.bytesHashed += dataLength; + if (this.bufferLength > 0) { + while (this.bufferLength < 64 && dataLength > 0) { + this.buffer[this.bufferLength++] = data[dataPos++]; + dataLength--; + } + if (this.bufferLength === 64) { + hashBlocks(this.temp, this.state, this.buffer, 0, 64); + this.bufferLength = 0; + } + } + if (dataLength >= 64) { + dataPos = hashBlocks(this.temp, this.state, data, dataPos, dataLength); + dataLength %= 64; + } + while (dataLength > 0) { + this.buffer[this.bufferLength++] = data[dataPos++]; + dataLength--; + } + return this; + }; + // Finalizes hash state and puts hash into out. + // + // If hash was already finalized, puts the same value. + Hash.prototype.finish = function (out) { + if (!this.finished) { + var bytesHashed = this.bytesHashed; + var left = this.bufferLength; + var bitLenHi = (bytesHashed / 0x20000000) | 0; + var bitLenLo = bytesHashed << 3; + var padLength = (bytesHashed % 64 < 56) ? 64 : 128; + this.buffer[left] = 0x80; + for (var i = left + 1; i < padLength - 8; i++) { + this.buffer[i] = 0; + } + this.buffer[padLength - 8] = (bitLenHi >>> 24) & 0xff; + this.buffer[padLength - 7] = (bitLenHi >>> 16) & 0xff; + this.buffer[padLength - 6] = (bitLenHi >>> 8) & 0xff; + this.buffer[padLength - 5] = (bitLenHi >>> 0) & 0xff; + this.buffer[padLength - 4] = (bitLenLo >>> 24) & 0xff; + this.buffer[padLength - 3] = (bitLenLo >>> 16) & 0xff; + this.buffer[padLength - 2] = (bitLenLo >>> 8) & 0xff; + this.buffer[padLength - 1] = (bitLenLo >>> 0) & 0xff; + hashBlocks(this.temp, this.state, this.buffer, 0, padLength); + this.finished = true; + } + for (var i = 0; i < 8; i++) { + out[i * 4 + 0] = (this.state[i] >>> 24) & 0xff; + out[i * 4 + 1] = (this.state[i] >>> 16) & 0xff; + out[i * 4 + 2] = (this.state[i] >>> 8) & 0xff; + out[i * 4 + 3] = (this.state[i] >>> 0) & 0xff; + } + return this; + }; + // Returns the final hash digest. + Hash.prototype.digest = function () { + var out = new Uint8Array(this.digestLength); + this.finish(out); + return out; + }; + // Internal function for use in HMAC for optimization. + Hash.prototype._saveState = function (out) { + for (var i = 0; i < this.state.length; i++) { + out[i] = this.state[i]; + } + }; + // Internal function for use in HMAC for optimization. + Hash.prototype._restoreState = function (from, bytesHashed) { + for (var i = 0; i < this.state.length; i++) { + this.state[i] = from[i]; + } + this.bytesHashed = bytesHashed; + this.finished = false; + this.bufferLength = 0; + }; + return Hash; +}()); +exports.Hash = Hash; +// HMAC implements HMAC-SHA256 message authentication algorithm. +var HMAC = /** @class */ (function () { + function HMAC(key) { + this.inner = new Hash(); + this.outer = new Hash(); + this.blockSize = this.inner.blockSize; + this.digestLength = this.inner.digestLength; + var pad = new Uint8Array(this.blockSize); + if (key.length > this.blockSize) { + (new Hash()).update(key).finish(pad).clean(); + } + else { + for (var i = 0; i < key.length; i++) { + pad[i] = key[i]; + } + } + for (var i = 0; i < pad.length; i++) { + pad[i] ^= 0x36; + } + this.inner.update(pad); + for (var i = 0; i < pad.length; i++) { + pad[i] ^= 0x36 ^ 0x5c; + } + this.outer.update(pad); + this.istate = new Uint32Array(8); + this.ostate = new Uint32Array(8); + this.inner._saveState(this.istate); + this.outer._saveState(this.ostate); + for (var i = 0; i < pad.length; i++) { + pad[i] = 0; + } + } + // Returns HMAC state to the state initialized with key + // to make it possible to run HMAC over the other data with the same + // key without creating a new instance. + HMAC.prototype.reset = function () { + this.inner._restoreState(this.istate, this.inner.blockSize); + this.outer._restoreState(this.ostate, this.outer.blockSize); + return this; + }; + // Cleans HMAC state. + HMAC.prototype.clean = function () { + for (var i = 0; i < this.istate.length; i++) { + this.ostate[i] = this.istate[i] = 0; + } + this.inner.clean(); + this.outer.clean(); + }; + // Updates state with provided data. + HMAC.prototype.update = function (data) { + this.inner.update(data); + return this; + }; + // Finalizes HMAC and puts the result in out. + HMAC.prototype.finish = function (out) { + if (this.outer.finished) { + this.outer.finish(out); + } + else { + this.inner.finish(out); + this.outer.update(out, this.digestLength).finish(out); + } + return this; + }; + // Returns message authentication code. + HMAC.prototype.digest = function () { + var out = new Uint8Array(this.digestLength); + this.finish(out); + return out; + }; + return HMAC; +}()); +exports.HMAC = HMAC; +// Returns SHA256 hash of data. +function hash(data) { + var h = (new Hash()).update(data); + var digest = h.digest(); + h.clean(); + return digest; +} +exports.hash = hash; +// Function hash is both available as module.hash and as default export. +exports["default"] = hash; +// Returns HMAC-SHA256 of data under the key. +function hmac(key, data) { + var h = (new HMAC(key)).update(data); + var digest = h.digest(); + h.clean(); + return digest; +} +exports.hmac = hmac; +// Fills hkdf buffer like this: +// T(1) = HMAC-Hash(PRK, T(0) | info | 0x01) +function fillBuffer(buffer, hmac, info, counter) { + // Counter is a byte value: check if it overflowed. + var num = counter[0]; + if (num === 0) { + throw new Error("hkdf: cannot expand more"); + } + // Prepare HMAC instance for new data with old key. + hmac.reset(); + // Hash in previous output if it was generated + // (i.e. counter is greater than 1). + if (num > 1) { + hmac.update(buffer); + } + // Hash in info if it exists. + if (info) { + hmac.update(info); + } + // Hash in the counter. + hmac.update(counter); + // Output result to buffer and clean HMAC instance. + hmac.finish(buffer); + // Increment counter inside typed array, this works properly. + counter[0]++; +} +var hkdfSalt = new Uint8Array(exports.digestLength); // Filled with zeroes. +function hkdf(key, salt, info, length) { + if (salt === void 0) { salt = hkdfSalt; } + if (length === void 0) { length = 32; } + var counter = new Uint8Array([1]); + // HKDF-Extract uses salt as HMAC key, and key as data. + var okm = hmac(salt, key); + // Initialize HMAC for expanding with extracted key. + // Ensure no collisions with `hmac` function. + var hmac_ = new HMAC(okm); + // Allocate buffer. + var buffer = new Uint8Array(hmac_.digestLength); + var bufpos = buffer.length; + var out = new Uint8Array(length); + for (var i = 0; i < length; i++) { + if (bufpos === buffer.length) { + fillBuffer(buffer, hmac_, info, counter); + bufpos = 0; + } + out[i] = buffer[bufpos++]; + } + hmac_.clean(); + buffer.fill(0); + counter.fill(0); + return out; +} +exports.hkdf = hkdf; +// Derives a key from password and salt using PBKDF2-HMAC-SHA256 +// with the given number of iterations. +// +// The number of bytes returned is equal to dkLen. +// +// (For better security, avoid dkLen greater than hash length - 32 bytes). +function pbkdf2(password, salt, iterations, dkLen) { + var prf = new HMAC(password); + var len = prf.digestLength; + var ctr = new Uint8Array(4); + var t = new Uint8Array(len); + var u = new Uint8Array(len); + var dk = new Uint8Array(dkLen); + for (var i = 0; i * len < dkLen; i++) { + var c = i + 1; + ctr[0] = (c >>> 24) & 0xff; + ctr[1] = (c >>> 16) & 0xff; + ctr[2] = (c >>> 8) & 0xff; + ctr[3] = (c >>> 0) & 0xff; + prf.reset(); + prf.update(salt); + prf.update(ctr); + prf.finish(u); + for (var j = 0; j < len; j++) { + t[j] = u[j]; + } + for (var j = 2; j <= iterations; j++) { + prf.reset(); + prf.update(u).finish(u); + for (var k = 0; k < len; k++) { + t[k] ^= u[k]; + } + } + for (var j = 0; j < len && i * len + j < dkLen; j++) { + dk[i * len + j] = t[j]; + } + } + for (var i = 0; i < len; i++) { + t[i] = u[i] = 0; + } + for (var i = 0; i < 4; i++) { + ctr[i] = 0; + } + prf.clean(); + return dk; +} +exports.pbkdf2 = pbkdf2; +}); diff --git a/core/third-party/math.js b/core/third-party/math.js new file mode 100644 index 0000000..4ee0174 --- /dev/null +++ b/core/third-party/math.js @@ -0,0 +1,852 @@ +/** + * Absolute value. abs(a)==a if a>=0. abs(a)==-a if a<0 + * + * @param a + * + * @returns The absolute value of a + */ +function abs(a) { + return (a >= 0) ? a : -a; +} + +/** + * Returns the bitlength of a number + * + * @param a + * @returns The bit length + */ +function bitLength(a) { + if (typeof a === 'number') + a = BigInt(a); + if (a === 1n) { + return 1; + } + let bits = 1; + do { + bits++; + } while ((a >>= 1n) > 1n); + return bits; +} + +/** + * An iterative implementation of the extended euclidean algorithm or extended greatest common divisor algorithm. + * Take positive integers a, b as input, and return a triple (g, x, y), such that ax + by = g = gcd(a, b). + * + * @param a + * @param b + * + * @throws {RangeError} + * This excepction is thrown if a or b are less than 0 + * + * @returns A triple (g, x, y), such that ax + by = g = gcd(a, b). + */ +function eGcd(a, b) { + if (typeof a === 'number') + a = BigInt(a); + if (typeof b === 'number') + b = BigInt(b); + if (a <= 0n || b <= 0n) + throw new RangeError('a and b MUST be > 0'); // a and b MUST be positive + let x = 0n; + let y = 1n; + let u = 1n; + let v = 0n; + while (a !== 0n) { + const q = b / a; + const r = b % a; + const m = x - (u * q); + const n = y - (v * q); + b = a; + a = r; + x = u; + y = v; + u = m; + v = n; + } + return { + g: b, + x: x, + y: y + }; +} + +/** + * Greatest-common divisor of two integers based on the iterative binary algorithm. + * + * @param a + * @param b + * + * @returns The greatest common divisor of a and b + */ +function gcd(a, b) { + let aAbs = (typeof a === 'number') ? BigInt(abs(a)) : abs(a); + let bAbs = (typeof b === 'number') ? BigInt(abs(b)) : abs(b); + if (aAbs === 0n) { + return bAbs; + } + else if (bAbs === 0n) { + return aAbs; + } + let shift = 0n; + while (((aAbs | bAbs) & 1n) === 0n) { + aAbs >>= 1n; + bAbs >>= 1n; + shift++; + } + while ((aAbs & 1n) === 0n) + aAbs >>= 1n; + do { + while ((bAbs & 1n) === 0n) + bAbs >>= 1n; + if (aAbs > bAbs) { + const x = aAbs; + aAbs = bAbs; + bAbs = x; + } + bAbs -= aAbs; + } while (bAbs !== 0n); + // rescale + return aAbs << shift; +} + +/** + * The least common multiple computed as abs(a*b)/gcd(a,b) + * @param a + * @param b + * + * @returns The least common multiple of a and b + */ +function lcm(a, b) { + if (typeof a === 'number') + a = BigInt(a); + if (typeof b === 'number') + b = BigInt(b); + if (a === 0n && b === 0n) + return BigInt(0); + return abs(a * b) / gcd(a, b); +} + +/** + * Maximum. max(a,b)==a if a>=b. max(a,b)==b if a<=b + * + * @param a + * @param b + * + * @returns Maximum of numbers a and b + */ +function max(a, b) { + return (a >= b) ? a : b; +} + +/** + * Minimum. min(a,b)==b if a>=b. min(a,b)==a if a<=b + * + * @param a + * @param b + * + * @returns Minimum of numbers a and b + */ +function min(a, b) { + return (a >= b) ? b : a; +} + +/** + * Finds the smallest positive element that is congruent to a in modulo n + * + * @remarks + * a and b must be the same type, either number or bigint + * + * @param a - An integer + * @param n - The modulo + * + * @throws {RangeError} + * Excpeption thrown when n is not > 0 + * + * @returns A bigint with the smallest positive representation of a modulo n + */ +function toZn(a, n) { + if (typeof a === 'number') + a = BigInt(a); + if (typeof n === 'number') + n = BigInt(n); + if (n <= 0n) { + throw new RangeError('n must be > 0'); + } + const aZn = a % n; + return (aZn < 0n) ? aZn + n : aZn; +} + +/** + * Modular inverse. + * + * @param a The number to find an inverse for + * @param n The modulo + * + * @throws {RangeError} + * Excpeption thorwn when a does not have inverse modulo n + * + * @returns The inverse modulo n + */ +function modInv(a, n) { + const egcd = eGcd(toZn(a, n), n); + if (egcd.g !== 1n) { + throw new RangeError(`${a.toString()} does not have inverse modulo ${n.toString()}`); // modular inverse does not exist + } + else { + return toZn(egcd.x, n); + } +} + +/** + * Modular exponentiation b**e mod n. Currently using the right-to-left binary method + * + * @param b base + * @param e exponent + * @param n modulo + * + * @throws {RangeError} + * Excpeption thrown when n is not > 0 + * + * @returns b**e mod n + */ +function modPow(b, e, n) { + if (typeof b === 'number') + b = BigInt(b); + if (typeof e === 'number') + e = BigInt(e); + if (typeof n === 'number') + n = BigInt(n); + if (n <= 0n) { + throw new RangeError('n must be > 0'); + } + else if (n === 1n) { + return 0n; + } + b = toZn(b, n); + if (e < 0n) { + return modInv(modPow(b, abs(e), n), n); + } + let r = 1n; + while (e > 0) { + if ((e % 2n) === 1n) { + r = r * b % n; + } + e = e / 2n; + b = b ** 2n % n; + } + return r; +} + +function fromBuffer(buf) { + let ret = 0n; + for (const i of buf.values()) { + const bi = BigInt(i); + ret = (ret << 8n) + bi; + } + return ret; +} + +/** + * Secure random bytes for both node and browsers. Node version uses crypto.randomBytes() and browser one self.crypto.getRandomValues() + * + * @param byteLength - The desired number of random bytes + * @param forceLength - If we want to force the output to have a bit length of 8*byteLength. It basically forces the msb to be 1 + * + * @throws {RangeError} + * byteLength MUST be > 0 + * + * @returns A promise that resolves to a UInt8Array/Buffer (Browser/Node.js) filled with cryptographically secure random bytes + */ +function randBytes(byteLength, forceLength = false) { + if (byteLength < 1) + throw new RangeError('byteLength MUST be > 0'); + return new Promise(function (resolve, reject) { + { // browser + const buf = new Uint8Array(byteLength); + self.crypto.getRandomValues(buf); + // If fixed length is required we put the first bit to 1 -> to get the necessary bitLength + if (forceLength) + buf[0] = buf[0] | 128; + resolve(buf); + } + }); +} +/** + * Secure random bytes for both node and browsers. Node version uses crypto.randomFill() and browser one self.crypto.getRandomValues() + * + * @param byteLength - The desired number of random bytes + * @param forceLength - If we want to force the output to have a bit length of 8*byteLength. It basically forces the msb to be 1 + * + * @throws {RangeError} + * byteLength MUST be > 0 + * + * @returns A UInt8Array/Buffer (Browser/Node.js) filled with cryptographically secure random bytes + */ +function randBytesSync(byteLength, forceLength = false) { + if (byteLength < 1) + throw new RangeError('byteLength MUST be > 0'); + /* eslint-disable no-lone-blocks */ + { // browser + const buf = new Uint8Array(byteLength); + self.crypto.getRandomValues(buf); + // If fixed length is required we put the first bit to 1 -> to get the necessary bitLength + if (forceLength) + buf[0] = buf[0] | 128; + return buf; + } + /* eslint-enable no-lone-blocks */ +} + +/** + * Secure random bits for both node and browsers. Node version uses crypto.randomFill() and browser one self.crypto.getRandomValues() + * + * @param bitLength - The desired number of random bits + * @param forceLength - If we want to force the output to have a specific bit length. It basically forces the msb to be 1 + * + * @throws {RangeError} + * bitLength MUST be > 0 + * + * @returns A Promise that resolves to a UInt8Array/Buffer (Browser/Node.js) filled with cryptographically secure random bits + */ +function randBits(bitLength, forceLength = false) { + if (bitLength < 1) + throw new RangeError('bitLength MUST be > 0'); + const byteLength = Math.ceil(bitLength / 8); + const bitLengthMod8 = bitLength % 8; + return new Promise((resolve, reject) => { + randBytes(byteLength, false).then(function (rndBytes) { + if (bitLengthMod8 !== 0) { + // Fill with 0's the extra bits + rndBytes[0] = rndBytes[0] & (2 ** bitLengthMod8 - 1); + } + if (forceLength) { + const mask = (bitLengthMod8 !== 0) ? 2 ** (bitLengthMod8 - 1) : 128; + rndBytes[0] = rndBytes[0] | mask; + } + resolve(rndBytes); + }); + }); +} +/** + * Secure random bits for both node and browsers. Node version uses crypto.randomFill() and browser one self.crypto.getRandomValues() + * @param bitLength - The desired number of random bits + * @param forceLength - If we want to force the output to have a specific bit length. It basically forces the msb to be 1 + * + * @throws {RangeError} + * bitLength MUST be > 0 + * + * @returns A Uint8Array/Buffer (Browser/Node.js) filled with cryptographically secure random bits + */ +function randBitsSync(bitLength, forceLength = false) { + if (bitLength < 1) + throw new RangeError('bitLength MUST be > 0'); + const byteLength = Math.ceil(bitLength / 8); + const rndBytes = randBytesSync(byteLength, false); + const bitLengthMod8 = bitLength % 8; + if (bitLengthMod8 !== 0) { + // Fill with 0's the extra bits + rndBytes[0] = rndBytes[0] & (2 ** bitLengthMod8 - 1); + } + if (forceLength) { + const mask = (bitLengthMod8 !== 0) ? 2 ** (bitLengthMod8 - 1) : 128; + rndBytes[0] = rndBytes[0] | mask; + } + return rndBytes; +} + +/** + * Returns a cryptographically secure random integer between [min,max]. Both numbers must be >=0 + * @param max Returned value will be <= max + * @param min Returned value will be >= min + * + * @throws {RangeError} + * Arguments MUST be: max > 0 && min >=0 && max > min + * + * @returns A cryptographically secure random bigint between [min,max] + */ +function randBetween(max, min = 1n) { + if (max <= 0n || min < 0n || max <= min) + throw new RangeError('Arguments MUST be: max > 0 && min >=0 && max > min'); + const interval = max - min; + const bitLen = bitLength(interval); + let rnd; + do { + const buf = randBitsSync(bitLen); + rnd = fromBuffer(buf); + } while (rnd > interval); + return rnd + min; +} + +function _workerUrl(workerCode) { + workerCode = `(() => {${workerCode}})()`; // encapsulate IIFE + const _blob = new Blob([workerCode], { type: 'text/javascript' }); + return window.URL.createObjectURL(_blob); +} +let _useWorkers = false; // The following is just to check whether we can use workers +/* eslint-disable no-lone-blocks */ +{ // Native JS + if (self.Worker !== undefined) + _useWorkers = true; +} + +/** + * The test first tries if any of the first 250 small primes are a factor of the input number and then passes several + * iterations of Miller-Rabin Probabilistic Primality Test (FIPS 186-4 C.3.1) + * + * @param w - A positive integer to be tested for primality + * @param iterations - The number of iterations for the primality test. The value shall be consistent with Table C.1, C.2 or C.3 + * @param disableWorkers - Disable the use of workers for the primality test + * + * @throws {RangeError} + * w MUST be >= 0 + * + * @returns A promise that resolves to a boolean that is either true (a probably prime number) or false (definitely composite) + */ +function isProbablyPrime(w, iterations = 16, disableWorkers = false) { + if (typeof w === 'number') { + w = BigInt(w); + } + if (w < 0n) + throw RangeError('w MUST be >= 0'); + { // browser + return new Promise((resolve, reject) => { + const worker = new Worker(_isProbablyPrimeWorkerUrl()); + worker.onmessage = (event) => { + worker.terminate(); + resolve(event.data.isPrime); + }; + worker.onmessageerror = (event) => { + reject(event); + }; + const msg = { + rnd: w, + iterations: iterations, + id: 0 + }; + worker.postMessage(msg); + }); + } +} +function _isProbablyPrime(w, iterations) { + /* + PREFILTERING. Even values but 2 are not primes, so don't test. + 1 is not a prime and the M-R algorithm needs w>1. + */ + if (w === 2n) + return true; + else if ((w & 1n) === 0n || w === 1n) + return false; + /* + Test if any of the first 250 small primes are a factor of w. 2 is not tested because it was already tested above. + */ + const firstPrimes = [ + 3n, + 5n, + 7n, + 11n, + 13n, + 17n, + 19n, + 23n, + 29n, + 31n, + 37n, + 41n, + 43n, + 47n, + 53n, + 59n, + 61n, + 67n, + 71n, + 73n, + 79n, + 83n, + 89n, + 97n, + 101n, + 103n, + 107n, + 109n, + 113n, + 127n, + 131n, + 137n, + 139n, + 149n, + 151n, + 157n, + 163n, + 167n, + 173n, + 179n, + 181n, + 191n, + 193n, + 197n, + 199n, + 211n, + 223n, + 227n, + 229n, + 233n, + 239n, + 241n, + 251n, + 257n, + 263n, + 269n, + 271n, + 277n, + 281n, + 283n, + 293n, + 307n, + 311n, + 313n, + 317n, + 331n, + 337n, + 347n, + 349n, + 353n, + 359n, + 367n, + 373n, + 379n, + 383n, + 389n, + 397n, + 401n, + 409n, + 419n, + 421n, + 431n, + 433n, + 439n, + 443n, + 449n, + 457n, + 461n, + 463n, + 467n, + 479n, + 487n, + 491n, + 499n, + 503n, + 509n, + 521n, + 523n, + 541n, + 547n, + 557n, + 563n, + 569n, + 571n, + 577n, + 587n, + 593n, + 599n, + 601n, + 607n, + 613n, + 617n, + 619n, + 631n, + 641n, + 643n, + 647n, + 653n, + 659n, + 661n, + 673n, + 677n, + 683n, + 691n, + 701n, + 709n, + 719n, + 727n, + 733n, + 739n, + 743n, + 751n, + 757n, + 761n, + 769n, + 773n, + 787n, + 797n, + 809n, + 811n, + 821n, + 823n, + 827n, + 829n, + 839n, + 853n, + 857n, + 859n, + 863n, + 877n, + 881n, + 883n, + 887n, + 907n, + 911n, + 919n, + 929n, + 937n, + 941n, + 947n, + 953n, + 967n, + 971n, + 977n, + 983n, + 991n, + 997n, + 1009n, + 1013n, + 1019n, + 1021n, + 1031n, + 1033n, + 1039n, + 1049n, + 1051n, + 1061n, + 1063n, + 1069n, + 1087n, + 1091n, + 1093n, + 1097n, + 1103n, + 1109n, + 1117n, + 1123n, + 1129n, + 1151n, + 1153n, + 1163n, + 1171n, + 1181n, + 1187n, + 1193n, + 1201n, + 1213n, + 1217n, + 1223n, + 1229n, + 1231n, + 1237n, + 1249n, + 1259n, + 1277n, + 1279n, + 1283n, + 1289n, + 1291n, + 1297n, + 1301n, + 1303n, + 1307n, + 1319n, + 1321n, + 1327n, + 1361n, + 1367n, + 1373n, + 1381n, + 1399n, + 1409n, + 1423n, + 1427n, + 1429n, + 1433n, + 1439n, + 1447n, + 1451n, + 1453n, + 1459n, + 1471n, + 1481n, + 1483n, + 1487n, + 1489n, + 1493n, + 1499n, + 1511n, + 1523n, + 1531n, + 1543n, + 1549n, + 1553n, + 1559n, + 1567n, + 1571n, + 1579n, + 1583n, + 1597n + ]; + for (let i = 0; i < firstPrimes.length && (firstPrimes[i] <= w); i++) { + const p = firstPrimes[i]; + if (w === p) + return true; + else if (w % p === 0n) + return false; + } + /* + 1. Let a be the largest integer such that 2**a divides w−1. + 2. m = (w−1) / 2**a. + 3. wlen = len (w). + 4. For i = 1 to iterations do + 4.1 Obtain a string b of wlen bits from an RBG. + Comment: Ensure that 1 < b < w−1. + 4.2 If ((b ≤ 1) or (b ≥ w−1)), then go to step 4.1. + 4.3 z = b**m mod w. + 4.4 If ((z = 1) or (z = w − 1)), then go to step 4.7. + 4.5 For j = 1 to a − 1 do. + 4.5.1 z = z**2 mod w. + 4.5.2 If (z = w−1), then go to step 4.7. + 4.5.3 If (z = 1), then go to step 4.6. + 4.6 Return COMPOSITE. + 4.7 Continue. + Comment: Increment i for the do-loop in step 4. + 5. Return PROBABLY PRIME. + */ + let a = 0n; + const d = w - 1n; + let aux = d; + while (aux % 2n === 0n) { + aux /= 2n; + ++a; + } + const m = d / (2n ** a); + do { + const b = randBetween(d, 2n); + let z = modPow(b, m, w); + if (z === 1n || z === d) + continue; + let j = 1; + while (j < a) { + z = modPow(z, 2n, w); + if (z === d) + break; + if (z === 1n) + return false; + j++; + } + if (z !== d) + return false; + } while (--iterations !== 0); + return true; +} +function _isProbablyPrimeWorkerUrl() { + // Let's us first add all the required functions + let workerCode = `'use strict';const ${eGcd.name}=${eGcd.toString()};const ${modInv.name}=${modInv.toString()};const ${modPow.name}=${modPow.toString()};const ${toZn.name}=${toZn.toString()};const ${randBitsSync.name}=${randBitsSync.toString()};const ${randBytesSync.name}=${randBytesSync.toString()};const ${randBetween.name}=${randBetween.toString()};const ${isProbablyPrime.name}=${_isProbablyPrime.toString()};${bitLength.toString()};${fromBuffer.toString()};`; + workerCode += `onmessage=async function(e){const m={isPrime:await ${isProbablyPrime.name}(e.data.rnd,e.data.iterations),value:e.data.rnd,id:e.data.id};postMessage(m);}`; + return _workerUrl(workerCode); +} + +/** + * A probably-prime (Miller-Rabin), cryptographically-secure, random-number generator. + * The browser version uses web workers to parallelise prime look up. Therefore, it does not lock the UI + * main process, and it can be much faster (if several cores or cpu are available). + * The node version can also use worker_threads if they are available (enabled by default with Node 11 and + * and can be enabled at runtime executing node --experimental-worker with node >=10.5.0). + * + * @param bitLength - The required bit length for the generated prime + * @param iterations - The number of iterations for the Miller-Rabin Probabilistic Primality Test + * + * @throws {RangeError} + * bitLength MUST be > 0 + * + * @returns A promise that resolves to a bigint probable prime of bitLength bits. + */ +function prime(bitLength, iterations = 16) { + if (bitLength < 1) + throw new RangeError('bitLength MUST be > 0'); + /* istanbul ignore if */ + if (!_useWorkers) { // If there is no support for workers + let rnd = 0n; + do { + rnd = fromBuffer(randBitsSync(bitLength, true)); + } while (!_isProbablyPrime(rnd, iterations)); + return new Promise((resolve) => { resolve(rnd); }); + } + return new Promise((resolve, reject) => { + const workerList = []; + const _onmessage = (msg, newWorker) => { + if (msg.isPrime) { + // if a prime number has been found, stop all the workers, and return it + for (let j = 0; j < workerList.length; j++) { + workerList[j].terminate(); + } + while (workerList.length > 0) { + workerList.pop(); + } + resolve(msg.value); + } + else { // if a composite is found, make the worker test another random number + const buf = randBitsSync(bitLength, true); + const rnd = fromBuffer(buf); + try { + const msgToWorker = { + rnd: rnd, + iterations: iterations, + id: msg.id + }; + newWorker.postMessage(msgToWorker); + } + catch (error) { + // The worker has already terminated. There is nothing to handle here + } + } + }; + { // browser + const workerURL = _isProbablyPrimeWorkerUrl(); + for (let i = 0; i < self.navigator.hardwareConcurrency - 1; i++) { + const newWorker = new Worker(workerURL); + newWorker.onmessage = (event) => _onmessage(event.data, newWorker); + workerList.push(newWorker); + } + } + for (let i = 0; i < workerList.length; i++) { + randBits(bitLength, true).then(function (buf) { + const rnd = fromBuffer(buf); + workerList[i].postMessage({ + rnd: rnd, + iterations: iterations, + id: i + }); + }).catch(reject); + } + }); +} +/** + * A probably-prime (Miller-Rabin), cryptographically-secure, random-number generator. + * The sync version is NOT RECOMMENDED since it won't use workers and thus it'll be slower and may freeze thw window in browser's javascript. Please consider using prime() instead. + * + * @param bitLength - The required bit length for the generated prime + * @param iterations - The number of iterations for the Miller-Rabin Probabilistic Primality Test + * + * @throws {RangeError} + * bitLength MUST be > 0 + * + * @returns A bigint probable prime of bitLength bits. + */ +function primeSync(bitLength, iterations = 16) { + if (bitLength < 1) + throw new RangeError('bitLength MUST be > 0'); + let rnd = 0n; + do { + rnd = fromBuffer(randBitsSync(bitLength, true)); + } while (!_isProbablyPrime(rnd, iterations)); + return rnd; +} + +export { abs, bitLength, eGcd, gcd, isProbablyPrime, lcm, max, min, modInv, modPow, prime, primeSync, randBetween, randBits, randBitsSync, randBytes, randBytesSync, toZn }; +//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguYnJvd3Nlci5qcyIsInNvdXJjZXMiOlsiLi4vLi4vbm9kZV9tb2R1bGVzL2JpZ2ludC1tb2QtYXJpdGgvZGlzdC9lc20vaW5kZXguYnJvd3Nlci5qcyIsIi4uLy4uL3NyYy90cy9mcm9tQnVmZmVyLnRzIiwiLi4vLi4vc3JjL3RzL3JhbmRCeXRlcy50cyIsIi4uLy4uL3NyYy90cy9yYW5kQml0cy50cyIsIi4uLy4uL3NyYy90cy9yYW5kQmV0d2Vlbi50cyIsIi4uLy4uL3NyYy90cy93b3JrZXJVdGlscy50cyIsIi4uLy4uL3NyYy90cy9pc1Byb2JhYmx5UHJpbWUudHMiLCIuLi8uLi9zcmMvdHMvcHJpbWUudHMiXSwic291cmNlc0NvbnRlbnQiOm51bGwsIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsU0FBUyxHQUFHLENBQUMsQ0FBQyxFQUFFO0FBQ2hCLElBQUksT0FBTyxDQUFDLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDO0FBQzdCLENBQUM7QUFDRDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLFNBQVMsU0FBUyxDQUFDLENBQUMsRUFBRTtBQUN0QixJQUFJLElBQUksT0FBTyxDQUFDLEtBQUssUUFBUTtBQUM3QixRQUFRLENBQUMsR0FBRyxNQUFNLENBQUMsQ0FBQyxDQUFDLENBQUM7QUFDdEIsSUFBSSxJQUFJLENBQUMsS0FBSyxFQUFFLEVBQUU7QUFDbEIsUUFBUSxPQUFPLENBQUMsQ0FBQztBQUNqQixLQUFLO0FBQ0wsSUFBSSxJQUFJLElBQUksR0FBRyxDQUFDLENBQUM7QUFDakIsSUFBSSxHQUFHO0FBQ1AsUUFBUSxJQUFJLEVBQUUsQ0FBQztBQUNmLEtBQUssUUFBUSxDQUFDLENBQUMsS0FBSyxFQUFFLElBQUksRUFBRSxFQUFFO0FBQzlCLElBQUksT0FBTyxJQUFJLENBQUM7QUFDaEIsQ0FBQztBQUNEO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsU0FBUyxJQUFJLENBQUMsQ0FBQyxFQUFFLENBQUMsRUFBRTtBQUNwQixJQUFJLElBQUksT0FBTyxDQUFDLEtBQUssUUFBUTtBQUM3QixRQUFRLENBQUMsR0FBRyxNQUFNLENBQUMsQ0FBQyxDQUFDLENBQUM7QUFDdEIsSUFBSSxJQUFJLE9BQU8sQ0FBQyxLQUFLLFFBQVE7QUFDN0IsUUFBUSxDQUFDLEdBQUcsTUFBTSxDQUFDLENBQUMsQ0FBQyxDQUFDO0FBQ3RCLElBQUksSUFBSSxDQUFDLElBQUksRUFBRSxJQUFJLENBQUMsSUFBSSxFQUFFO0FBQzFCLFFBQVEsTUFBTSxJQUFJLFVBQVUsQ0FBQyxxQkFBcUIsQ0FBQyxDQUFDO0FBQ3BELElBQUksSUFBSSxDQUFDLEdBQUcsRUFBRSxDQUFDO0FBQ2YsSUFBSSxJQUFJLENBQUMsR0FBRyxFQUFFLENBQUM7QUFDZixJQUFJLElBQUksQ0FBQyxHQUFHLEVBQUUsQ0FBQztBQUNmLElBQUksSUFBSSxDQUFDLEdBQUcsRUFBRSxDQUFDO0FBQ2YsSUFBSSxPQUFPLENBQUMsS0FBSyxFQUFFLEVBQUU7QUFDckIsUUFBUSxNQUFNLENBQUMsR0FBRyxDQUFDLEdBQUcsQ0FBQyxDQUFDO0FBQ3hCLFFBQVEsTUFBTSxDQUFDLEdBQUcsQ0FBQyxHQUFHLENBQUMsQ0FBQztBQUN4QixRQUFRLE1BQU0sQ0FBQyxHQUFHLENBQUMsSUFBSSxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUM7QUFDOUIsUUFBUSxNQUFNLENBQUMsR0FBRyxDQUFDLElBQUksQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDO0FBQzlCLFFBQVEsQ0FBQyxHQUFHLENBQUMsQ0FBQztBQUNkLFFBQVEsQ0FBQyxHQUFHLENBQUMsQ0FBQztBQUNkLFFBQVEsQ0FBQyxHQUFHLENBQUMsQ0FBQztBQUNkLFFBQVEsQ0FBQyxHQUFHLENBQUMsQ0FBQztBQUNkLFFBQVEsQ0FBQyxHQUFHLENBQUMsQ0FBQztBQUNkLFFBQVEsQ0FBQyxHQUFHLENBQUMsQ0FBQztBQUNkLEtBQUs7QUFDTCxJQUFJLE9BQU87QUFDWCxRQUFRLENBQUMsRUFBRSxDQUFDO0FBQ1osUUFBUSxDQUFDLEVBQUUsQ0FBQztBQUNaLFFBQVEsQ0FBQyxFQUFFLENBQUM7QUFDWixLQUFLLENBQUM7QUFDTixDQUFDO0FBQ0Q7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsU0FBUyxHQUFHLENBQUMsQ0FBQyxFQUFFLENBQUMsRUFBRTtBQUNuQixJQUFJLElBQUksSUFBSSxHQUFHLENBQUMsT0FBTyxDQUFDLEtBQUssUUFBUSxJQUFJLE1BQU0sQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDLENBQUMsR0FBRyxHQUFHLENBQUMsQ0FBQyxDQUFDLENBQUM7QUFDakUsSUFBSSxJQUFJLElBQUksR0FBRyxDQUFDLE9BQU8sQ0FBQyxLQUFLLFFBQVEsSUFBSSxNQUFNLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxDQUFDLEdBQUcsR0FBRyxDQUFDLENBQUMsQ0FBQyxDQUFDO0FBQ2pFLElBQUksSUFBSSxJQUFJLEtBQUssRUFBRSxFQUFFO0FBQ3JCLFFBQVEsT0FBTyxJQUFJLENBQUM7QUFDcEIsS0FBSztBQUNMLFNBQVMsSUFBSSxJQUFJLEtBQUssRUFBRSxFQUFFO0FBQzFCLFFBQVEsT0FBTyxJQUFJLENBQUM7QUFDcEIsS0FBSztBQUNMLElBQUksSUFBSSxLQUFLLEdBQUcsRUFBRSxDQUFDO0FBQ25CLElBQUksT0FBTyxDQUFDLENBQUMsSUFBSSxHQUFHLElBQUksSUFBSSxFQUFFLE1BQU0sRUFBRSxFQUFFO0FBQ3hDLFFBQVEsSUFBSSxLQUFLLEVBQUUsQ0FBQztBQUNwQixRQUFRLElBQUksS0FBSyxFQUFFLENBQUM7QUFDcEIsUUFBUSxLQUFLLEVBQUUsQ0FBQztBQUNoQixLQUFLO0FBQ0wsSUFBSSxPQUFPLENBQUMsSUFBSSxHQUFHLEVBQUUsTUFBTSxFQUFFO0FBQzdCLFFBQVEsSUFBSSxLQUFLLEVBQUUsQ0FBQztBQUNwQixJQUFJLEdBQUc7QUFDUCxRQUFRLE9BQU8sQ0FBQyxJQUFJLEdBQUcsRUFBRSxNQUFNLEVBQUU7QUFDakMsWUFBWSxJQUFJLEtBQUssRUFBRSxDQUFDO0FBQ3hCLFFBQVEsSUFBSSxJQUFJLEdBQUcsSUFBSSxFQUFFO0FBQ3pCLFlBQVksTUFBTSxDQUFDLEdBQUcsSUFBSSxDQUFDO0FBQzNCLFlBQVksSUFBSSxHQUFHLElBQUksQ0FBQztBQUN4QixZQUFZLElBQUksR0FBRyxDQUFDLENBQUM7QUFDckIsU0FBUztBQUNULFFBQVEsSUFBSSxJQUFJLElBQUksQ0FBQztBQUNyQixLQUFLLFFBQVEsSUFBSSxLQUFLLEVBQUUsRUFBRTtBQUMxQjtBQUNBLElBQUksT0FBTyxJQUFJLElBQUksS0FBSyxDQUFDO0FBQ3pCLENBQUM7QUFDRDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsU0FBUyxHQUFHLENBQUMsQ0FBQyxFQUFFLENBQUMsRUFBRTtBQUNuQixJQUFJLElBQUksT0FBTyxDQUFDLEtBQUssUUFBUTtBQUM3QixRQUFRLENBQUMsR0FBRyxNQUFNLENBQUMsQ0FBQyxDQUFDLENBQUM7QUFDdEIsSUFBSSxJQUFJLE9BQU8sQ0FBQyxLQUFLLFFBQVE7QUFDN0IsUUFBUSxDQUFDLEdBQUcsTUFBTSxDQUFDLENBQUMsQ0FBQyxDQUFDO0FBQ3RCLElBQUksSUFBSSxDQUFDLEtBQUssRUFBRSxJQUFJLENBQUMsS0FBSyxFQUFFO0FBQzVCLFFBQVEsT0FBTyxNQUFNLENBQUMsQ0FBQyxDQUFDLENBQUM7QUFDekIsSUFBSSxPQUFPLEdBQUcsQ0FBQyxDQUFDLEdBQUcsQ0FBQyxDQUFDLEdBQUcsR0FBRyxDQUFDLENBQUMsRUFBRSxDQUFDLENBQUMsQ0FBQztBQUNsQyxDQUFDO0FBQ0Q7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsU0FBUyxHQUFHLENBQUMsQ0FBQyxFQUFFLENBQUMsRUFBRTtBQUNuQixJQUFJLE9BQU8sQ0FBQyxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsR0FBRyxDQUFDLENBQUM7QUFDNUIsQ0FBQztBQUNEO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLFNBQVMsR0FBRyxDQUFDLENBQUMsRUFBRSxDQUFDLEVBQUU7QUFDbkIsSUFBSSxPQUFPLENBQUMsQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLEdBQUcsQ0FBQyxDQUFDO0FBQzVCLENBQUM7QUFDRDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxTQUFTLElBQUksQ0FBQyxDQUFDLEVBQUUsQ0FBQyxFQUFFO0FBQ3BCLElBQUksSUFBSSxPQUFPLENBQUMsS0FBSyxRQUFRO0FBQzdCLFFBQVEsQ0FBQyxHQUFHLE1BQU0sQ0FBQyxDQUFDLENBQUMsQ0FBQztBQUN0QixJQUFJLElBQUksT0FBTyxDQUFDLEtBQUssUUFBUTtBQUM3QixRQUFRLENBQUMsR0FBRyxNQUFNLENBQUMsQ0FBQyxDQUFDLENBQUM7QUFDdEIsSUFBSSxJQUFJLENBQUMsSUFBSSxFQUFFLEVBQUU7QUFDakIsUUFBUSxNQUFNLElBQUksVUFBVSxDQUFDLGVBQWUsQ0FBQyxDQUFDO0FBQzlDLEtBQUs7QUFDTCxJQUFJLE1BQU0sR0FBRyxHQUFHLENBQUMsR0FBRyxDQUFDLENBQUM7QUFDdEIsSUFBSSxPQUFPLENBQUMsR0FBRyxHQUFHLEVBQUUsSUFBSSxHQUFHLEdBQUcsQ0FBQyxHQUFHLEdBQUcsQ0FBQztBQUN0QyxDQUFDO0FBQ0Q7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsU0FBUyxNQUFNLENBQUMsQ0FBQyxFQUFFLENBQUMsRUFBRTtBQUN0QixJQUFJLE1BQU0sSUFBSSxHQUFHLElBQUksQ0FBQyxJQUFJLENBQUMsQ0FBQyxFQUFFLENBQUMsQ0FBQyxFQUFFLENBQUMsQ0FBQyxDQUFDO0FBQ3JDLElBQUksSUFBSSxJQUFJLENBQUMsQ0FBQyxLQUFLLEVBQUUsRUFBRTtBQUN2QixRQUFRLE1BQU0sSUFBSSxVQUFVLENBQUMsQ0FBQyxFQUFFLENBQUMsQ0FBQyxRQUFRLEVBQUUsQ0FBQyw4QkFBOEIsRUFBRSxDQUFDLENBQUMsUUFBUSxFQUFFLENBQUMsQ0FBQyxDQUFDLENBQUM7QUFDN0YsS0FBSztBQUNMLFNBQVM7QUFDVCxRQUFRLE9BQU8sSUFBSSxDQUFDLElBQUksQ0FBQyxDQUFDLEVBQUUsQ0FBQyxDQUFDLENBQUM7QUFDL0IsS0FBSztBQUNMLENBQUM7QUFDRDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLFNBQVMsTUFBTSxDQUFDLENBQUMsRUFBRSxDQUFDLEVBQUUsQ0FBQyxFQUFFO0FBQ3pCLElBQUksSUFBSSxPQUFPLENBQUMsS0FBSyxRQUFRO0FBQzdCLFFBQVEsQ0FBQyxHQUFHLE1BQU0sQ0FBQyxDQUFDLENBQUMsQ0FBQztBQUN0QixJQUFJLElBQUksT0FBTyxDQUFDLEtBQUssUUFBUTtBQUM3QixRQUFRLENBQUMsR0FBRyxNQUFNLENBQUMsQ0FBQyxDQUFDLENBQUM7QUFDdEIsSUFBSSxJQUFJLE9BQU8sQ0FBQyxLQUFLLFFBQVE7QUFDN0IsUUFBUSxDQUFDLEdBQUcsTUFBTSxDQUFDLENBQUMsQ0FBQyxDQUFDO0FBQ3RCLElBQUksSUFBSSxDQUFDLElBQUksRUFBRSxFQUFFO0FBQ2pCLFFBQVEsTUFBTSxJQUFJLFVBQVUsQ0FBQyxlQUFlLENBQUMsQ0FBQztBQUM5QyxLQUFLO0FBQ0wsU0FBUyxJQUFJLENBQUMsS0FBSyxFQUFFLEVBQUU7QUFDdkIsUUFBUSxPQUFPLEVBQUUsQ0FBQztBQUNsQixLQUFLO0FBQ0wsSUFBSSxDQUFDLEdBQUcsSUFBSSxDQUFDLENBQUMsRUFBRSxDQUFDLENBQUMsQ0FBQztBQUNuQixJQUFJLElBQUksQ0FBQyxHQUFHLEVBQUUsRUFBRTtBQUNoQixRQUFRLE9BQU8sTUFBTSxDQUFDLE1BQU0sQ0FBQyxDQUFDLEVBQUUsR0FBRyxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUMsQ0FBQyxFQUFFLENBQUMsQ0FBQyxDQUFDO0FBQy9DLEtBQUs7QUFDTCxJQUFJLElBQUksQ0FBQyxHQUFHLEVBQUUsQ0FBQztBQUNmLElBQUksT0FBTyxDQUFDLEdBQUcsQ0FBQyxFQUFFO0FBQ2xCLFFBQVEsSUFBSSxDQUFDLENBQUMsR0FBRyxFQUFFLE1BQU0sRUFBRSxFQUFFO0FBQzdCLFlBQVksQ0FBQyxHQUFHLENBQUMsR0FBRyxDQUFDLEdBQUcsQ0FBQyxDQUFDO0FBQzFCLFNBQVM7QUFDVCxRQUFRLENBQUMsR0FBRyxDQUFDLEdBQUcsRUFBRSxDQUFDO0FBQ25CLFFBQVEsQ0FBQyxHQUFHLENBQUMsSUFBSSxFQUFFLEdBQUcsQ0FBQyxDQUFDO0FBQ3hCLEtBQUs7QUFDTCxJQUFJLE9BQU8sQ0FBQyxDQUFDO0FBQ2I7O1NDN09nQixVQUFVLENBQUUsR0FBc0I7SUFDaEQsSUFBSSxHQUFHLEdBQUcsRUFBRSxDQUFBO0lBQ1osS0FBSyxNQUFNLENBQUMsSUFBSSxHQUFHLENBQUMsTUFBTSxFQUFFLEVBQUU7UUFDNUIsTUFBTSxFQUFFLEdBQUcsTUFBTSxDQUFDLENBQUMsQ0FBQyxDQUFBO1FBQ3BCLEdBQUcsR0FBRyxDQUFDLEdBQUcsSUFBSSxFQUFFLElBQUksRUFBRSxDQUFBO0tBQ3ZCO0lBQ0QsT0FBTyxHQUFHLENBQUE7QUFDWjs7QUNQQTs7Ozs7Ozs7Ozs7U0FXZ0IsU0FBUyxDQUFFLFVBQWtCLEVBQUUsV0FBVyxHQUFHLEtBQUs7SUFDaEUsSUFBSSxVQUFVLEdBQUcsQ0FBQztRQUFFLE1BQU0sSUFBSSxVQUFVLENBQUMsd0JBQXdCLENBQUMsQ0FBQTtJQUVsRSxPQUFPLElBQUksT0FBTyxDQUFDLFVBQVUsT0FBTyxFQUFFLE1BQU07UUFVbkM7WUFDTCxNQUFNLEdBQUcsR0FBRyxJQUFJLFVBQVUsQ0FBQyxVQUFVLENBQUMsQ0FBQTtZQUN0QyxJQUFJLENBQUMsTUFBTSxDQUFDLGVBQWUsQ0FBQyxHQUFHLENBQUMsQ0FBQTs7WUFFaEMsSUFBSSxXQUFXO2dCQUFFLEdBQUcsQ0FBQyxDQUFDLENBQUMsR0FBRyxHQUFHLENBQUMsQ0FBQyxDQUFDLEdBQUcsR0FBRyxDQUFBO1lBQ3RDLE9BQU8sQ0FBQyxHQUFHLENBQUMsQ0FBQTtTQUNiO0tBQ0YsQ0FBQyxDQUFBO0FBQ0osQ0FBQztBQUVEOzs7Ozs7Ozs7OztTQVdnQixhQUFhLENBQUUsVUFBa0IsRUFBRSxjQUF1QixLQUFLO0lBQzdFLElBQUksVUFBVSxHQUFHLENBQUM7UUFBRSxNQUFNLElBQUksVUFBVSxDQUFDLHdCQUF3QixDQUFDLENBQUE7O0lBUzNEO1FBQ0wsTUFBTSxHQUFHLEdBQUcsSUFBSSxVQUFVLENBQUMsVUFBVSxDQUFDLENBQUE7UUFDdEMsSUFBSSxDQUFDLE1BQU0sQ0FBQyxlQUFlLENBQUMsR0FBRyxDQUFDLENBQUE7O1FBRWhDLElBQUksV0FBVztZQUFFLEdBQUcsQ0FBQyxDQUFDLENBQUMsR0FBRyxHQUFHLENBQUMsQ0FBQyxDQUFDLEdBQUcsR0FBRyxDQUFBO1FBQ3RDLE9BQU8sR0FBRyxDQUFBO0tBQ1g7O0FBRUg7O0FDN0RBOzs7Ozs7Ozs7OztTQVdnQixRQUFRLENBQUUsU0FBaUIsRUFBRSxjQUF1QixLQUFLO0lBQ3ZFLElBQUksU0FBUyxHQUFHLENBQUM7UUFBRSxNQUFNLElBQUksVUFBVSxDQUFDLHVCQUF1QixDQUFDLENBQUE7SUFFaEUsTUFBTSxVQUFVLEdBQUcsSUFBSSxDQUFDLElBQUksQ0FBQyxTQUFTLEdBQUcsQ0FBQyxDQUFDLENBQUE7SUFDM0MsTUFBTSxhQUFhLEdBQUcsU0FBUyxHQUFHLENBQUMsQ0FBQTtJQUVuQyxPQUFPLElBQUksT0FBTyxDQUFDLENBQUMsT0FBTyxFQUFFLE1BQU07UUFDakMsU0FBUyxDQUFDLFVBQVUsRUFBRSxLQUFLLENBQUMsQ0FBQyxJQUFJLENBQUMsVUFBVSxRQUFRO1lBQ2xELElBQUksYUFBYSxLQUFLLENBQUMsRUFBRTs7Z0JBRXZCLFFBQVEsQ0FBQyxDQUFDLENBQUMsR0FBRyxRQUFRLENBQUMsQ0FBQyxDQUFDLElBQUksQ0FBQyxJQUFJLGFBQWEsR0FBRyxDQUFDLENBQUMsQ0FBQTthQUNyRDtZQUNELElBQUksV0FBVyxFQUFFO2dCQUNmLE1BQU0sSUFBSSxHQUFHLENBQUMsYUFBYSxLQUFLLENBQUMsSUFBSSxDQUFDLEtBQUssYUFBYSxHQUFHLENBQUMsQ0FBQyxHQUFHLEdBQUcsQ0FBQTtnQkFDbkUsUUFBUSxDQUFDLENBQUMsQ0FBQyxHQUFHLFFBQVEsQ0FBQyxDQUFDLENBQUMsR0FBRyxJQUFJLENBQUE7YUFDakM7WUFDRCxPQUFPLENBQUMsUUFBUSxDQUFDLENBQUE7U0FDbEIsQ0FBQyxDQUFBO0tBQ0gsQ0FBQyxDQUFBO0FBQ0osQ0FBQztBQUVEOzs7Ozs7Ozs7O1NBVWdCLFlBQVksQ0FBRSxTQUFpQixFQUFFLGNBQXVCLEtBQUs7SUFDM0UsSUFBSSxTQUFTLEdBQUcsQ0FBQztRQUFFLE1BQU0sSUFBSSxVQUFVLENBQUMsdUJBQXVCLENBQUMsQ0FBQTtJQUVoRSxNQUFNLFVBQVUsR0FBRyxJQUFJLENBQUMsSUFBSSxDQUFDLFNBQVMsR0FBRyxDQUFDLENBQUMsQ0FBQTtJQUMzQyxNQUFNLFFBQVEsR0FBRyxhQUFhLENBQUMsVUFBVSxFQUFFLEtBQUssQ0FBQyxDQUFBO0lBQ2pELE1BQU0sYUFBYSxHQUFHLFNBQVMsR0FBRyxDQUFDLENBQUE7SUFDbkMsSUFBSSxhQUFhLEtBQUssQ0FBQyxFQUFFOztRQUV2QixRQUFRLENBQUMsQ0FBQyxDQUFDLEdBQUcsUUFBUSxDQUFDLENBQUMsQ0FBQyxJQUFJLENBQUMsSUFBSSxhQUFhLEdBQUcsQ0FBQyxDQUFDLENBQUE7S0FDckQ7SUFDRCxJQUFJLFdBQVcsRUFBRTtRQUNmLE1BQU0sSUFBSSxHQUFHLENBQUMsYUFBYSxLQUFLLENBQUMsSUFBSSxDQUFDLEtBQUssYUFBYSxHQUFHLENBQUMsQ0FBQyxHQUFHLEdBQUcsQ0FBQTtRQUNuRSxRQUFRLENBQUMsQ0FBQyxDQUFDLEdBQUcsUUFBUSxDQUFDLENBQUMsQ0FBQyxHQUFHLElBQUksQ0FBQTtLQUNqQztJQUNELE9BQU8sUUFBUSxDQUFBO0FBQ2pCOztBQ3ZEQTs7Ozs7Ozs7OztTQVVnQixXQUFXLENBQUUsR0FBVyxFQUFFLE1BQWMsRUFBRTtJQUN4RCxJQUFJLEdBQUcsSUFBSSxFQUFFLElBQUksR0FBRyxHQUFHLEVBQUUsSUFBSSxHQUFHLElBQUksR0FBRztRQUFFLE1BQU0sSUFBSSxVQUFVLENBQUMsb0RBQW9ELENBQUMsQ0FBQTtJQUNuSCxNQUFNLFFBQVEsR0FBRyxHQUFHLEdBQUcsR0FBRyxDQUFBO0lBQzFCLE1BQU0sTUFBTSxHQUFHLFNBQVMsQ0FBQyxRQUFRLENBQUMsQ0FBQTtJQUNsQyxJQUFJLEdBQUcsQ0FBQTtJQUNQLEdBQUc7UUFDRCxNQUFNLEdBQUcsR0FBRyxZQUFZLENBQUMsTUFBTSxDQUFDLENBQUE7UUFDaEMsR0FBRyxHQUFHLFVBQVUsQ0FBQyxHQUFHLENBQUMsQ0FBQTtLQUN0QixRQUFRLEdBQUcsR0FBRyxRQUFRLEVBQUM7SUFDeEIsT0FBTyxHQUFHLEdBQUcsR0FBRyxDQUFBO0FBQ2xCOztTQ3hCZ0IsVUFBVSxDQUFFLFVBQWtCO0lBQzVDLFVBQVUsR0FBRyxXQUFXLFVBQVUsTUFBTSxDQUFBO0lBQ3hDLE1BQU0sS0FBSyxHQUFHLElBQUksSUFBSSxDQUFDLENBQUMsVUFBVSxDQUFDLEVBQUUsRUFBRSxJQUFJLEVBQUUsaUJBQWlCLEVBQUUsQ0FBQyxDQUFBO0lBQ2pFLE9BQU8sTUFBTSxDQUFDLEdBQUcsQ0FBQyxlQUFlLENBQUMsS0FBSyxDQUFDLENBQUE7QUFDMUMsQ0FBQztBQUVELElBQUksV0FBVyxHQUFHLEtBQUssQ0FBQTtBQUN2QjtBQVlPO0lBQ0wsSUFBSSxJQUFJLENBQUMsTUFBTSxLQUFLLFNBQVM7UUFBRSxXQUFXLEdBQUcsSUFBSSxDQUFBOzs7QUNibkQ7Ozs7Ozs7Ozs7Ozs7U0FhZ0IsZUFBZSxDQUFFLENBQWdCLEVBQUUsYUFBcUIsRUFBRSxFQUFFLGlCQUEwQixLQUFLO0lBQ3pHLElBQUksT0FBTyxDQUFDLEtBQUssUUFBUSxFQUFFO1FBQ3pCLENBQUMsR0FBRyxNQUFNLENBQUMsQ0FBQyxDQUFDLENBQUE7S0FDZDtJQUNELElBQUksQ0FBQyxHQUFHLEVBQUU7UUFBRSxNQUFNLFVBQVUsQ0FBQyxnQkFBZ0IsQ0FBQyxDQUFBO0lBNEJ2QztRQUNMLE9BQU8sSUFBSSxPQUFPLENBQUMsQ0FBQyxPQUFPLEVBQUUsTUFBTTtZQUNqQyxNQUFNLE1BQU0sR0FBRyxJQUFJLE1BQU0sQ0FBQyx5QkFBeUIsRUFBRSxDQUFDLENBQUE7WUFFdEQsTUFBTSxDQUFDLFNBQVMsR0FBRyxDQUFDLEtBQUs7Z0JBQ3ZCLE1BQU0sQ0FBQyxTQUFTLEVBQUUsQ0FBQTtnQkFDbEIsT0FBTyxDQUFDLEtBQUssQ0FBQyxJQUFJLENBQUMsT0FBTyxDQUFDLENBQUE7YUFDNUIsQ0FBQTtZQUVELE1BQU0sQ0FBQyxjQUFjLEdBQUcsQ0FBQyxLQUFLO2dCQUM1QixNQUFNLENBQUMsS0FBSyxDQUFDLENBQUE7YUFDZCxDQUFBO1lBRUQsTUFBTSxHQUFHLEdBQW9CO2dCQUMzQixHQUFHLEVBQUUsQ0FBVztnQkFDaEIsVUFBVSxFQUFFLFVBQVU7Z0JBQ3RCLEVBQUUsRUFBRSxDQUFDO2FBQ04sQ0FBQTtZQUNELE1BQU0sQ0FBQyxXQUFXLENBQUMsR0FBRyxDQUFDLENBQUE7U0FDeEIsQ0FBQyxDQUFBO0tBQ0g7QUFDSCxDQUFDO1NBRWUsZ0JBQWdCLENBQUUsQ0FBUyxFQUFFLFVBQWtCOzs7OztJQUs3RCxJQUFJLENBQUMsS0FBSyxFQUFFO1FBQUUsT0FBTyxJQUFJLENBQUE7U0FDcEIsSUFBSSxDQUFDLENBQUMsR0FBRyxFQUFFLE1BQU0sRUFBRSxJQUFJLENBQUMsS0FBSyxFQUFFO1FBQUUsT0FBTyxLQUFLLENBQUE7Ozs7SUFLbEQsTUFBTSxXQUFXLEdBQUc7UUFDbEIsRUFBRTtRQUNGLEVBQUU7UUFDRixFQUFFO1FBQ0YsR0FBRztRQUNILEdBQUc7UUFDSCxHQUFHO1FBQ0gsR0FBRztRQUNILEdBQUc7UUFDSCxHQUFHO1FBQ0gsR0FBRztRQUNILEdBQUc7UUFDSCxHQUFHO1FBQ0gsR0FBRztRQUNILEdBQUc7UUFDSCxHQUFHO1FBQ0gsR0FBRztRQUNILEdBQUc7UUFDSCxHQUFHO1FBQ0gsR0FBRztRQUNILEdBQUc7UUFDSCxHQUFHO1FBQ0gsR0FBRztRQUNILEdBQUc7UUFDSCxHQUFHO1FBQ0gsSUFBSTtRQUNKLElBQUk7UUFDSixJQUFJO1FBQ0osSUFBSTtRQUNKLElBQUk7UUFDSixJQUFJO1FBQ0osSUFBSTtRQUNKLElBQUk7UUFDSixJQUFJO1FBQ0osSUFBSTtRQUNKLElBQUk7UUFDSixJQUFJO1FBQ0osSUFBSTtRQUNKLElBQUk7UUFDSixJQUFJO1FBQ0osSUFBSTtRQUNKLElBQUk7UUFDSixJQUFJO1FBQ0osSUFBSTtRQUNKLElBQUk7UUFDSixJQUFJO1FBQ0osSUFBSTtRQUNKLElBQUk7UUFDSixJQUFJO1FBQ0osSUFBSTtRQUNKLElBQUk7UUFDSixJQUFJO1FBQ0osSUFBSTtRQUNKLElBQUk7UUFDSixJQUFJO1FBQ0osSUFBSTtRQUNKLElBQUk7UUFDSixJQUFJO1FBQ0osSUFBSTtRQUNKLElBQUk7UUFDSixJQUFJO1FBQ0osSUFBSTtRQUNKLElBQUk7UUFDSixJQUFJO1FBQ0osSUFBSTtRQUNKLElBQUk7UUFDSixJQUFJO1FBQ0osSUFBSTtRQUNKLElBQUk7UUFDSixJQUFJO1FBQ0osSUFBSTtRQUNKLElBQUk7UUFDSixJQUFJO1FBQ0osSUFBSTtRQUNKLElBQUk7UUFDSixJQUFJO1FBQ0osSUFBSTtRQUNKLElBQUk7UUFDSixJQUFJO1FBQ0osSUFBSTtRQUNKLElBQUk7UUFDSixJQUFJO1FBQ0osSUFBSTtRQUNKLElBQUk7UUFDSixJQUFJO1FBQ0osSUFBSTtRQUNKLElBQUk7UUFDSixJQUFJO1FBQ0osSUFBSTtRQUNKLElBQUk7UUFDSixJQUFJO1FBQ0osSUFBSTtRQUNKLElBQUk7UUFDSixJQUFJO1FBQ0osSUFBSTtRQUNKLElBQUk7UUFDSixJQUFJO1FBQ0osSUFBSTtRQUNKLElBQUk7UUFDSixJQUFJO1FBQ0osSUFBSTtRQUNKLElBQUk7UUFDSixJQUFJO1FBQ0osSUFBSTtRQUNKLElBQUk7UUFDSixJQUFJO1FBQ0osSUFBSTtRQUNKLElBQUk7UUFDSixJQUFJO1FBQ0osSUFBSTtRQUNKLElBQUk7UUFDSixJQUFJO1FBQ0osSUFBSTtRQUNKLElBQUk7UUFDSixJQUFJO1FBQ0osSUFBSTtRQUNKLElBQUk7UUFDSixJQUFJO1FBQ0osSUFBSTtRQUNKLElBQUk7UUFDSixJQUFJO1FBQ0osSUFBSTtRQUNKLElBQUk7UUFDSixJQUFJO1FBQ0osSUFBSTtRQUNKLElBQUk7UUFDSixJQUFJO1FBQ0osSUFBSTtRQUNKLElBQUk7UUFDSixJQUFJO1FBQ0osSUFBSTtRQUNKLElBQUk7UUFDSixJQUFJO1FBQ0osSUFBSTtRQUNKLElBQUk7UUFDSixJQUFJO1FBQ0osSUFBSTtRQUNKLElBQUk7UUFDSixJQUFJO1FBQ0osSUFBSTtRQUNKLElBQUk7UUFDSixJQUFJO1FBQ0osSUFBSTtRQUNKLElBQUk7UUFDSixJQUFJO1FBQ0osSUFBSTtRQUNKLElBQUk7UUFDSixJQUFJO1FBQ0osSUFBSTtRQUNKLElBQUk7UUFDSixJQUFJO1FBQ0osSUFBSTtRQUNKLElBQUk7UUFDSixJQUFJO1FBQ0osSUFBSTtRQUNKLElBQUk7UUFDSixJQUFJO1FBQ0osSUFBSTtRQUNKLElBQUk7UUFDSixJQUFJO1FBQ0osSUFBSTtRQUNKLElBQUk7UUFDSixJQUFJO1FBQ0osSUFBSTtRQUNKLElBQUk7UUFDSixJQUFJO1FBQ0osSUFBSTtRQUNKLElBQUk7UUFDSixLQUFLO1FBQ0wsS0FBSztRQUNMLEtBQUs7UUFDTCxLQUFLO1FBQ0wsS0FBSztRQUNMLEtBQUs7UUFDTCxLQUFLO1FBQ0wsS0FBSztRQUNMLEtBQUs7UUFDTCxLQUFLO1FBQ0wsS0FBSztRQUNMLEtBQUs7UUFDTCxLQUFLO1FBQ0wsS0FBSztRQUNMLEtBQUs7UUFDTCxLQUFLO1FBQ0wsS0FBSztRQUNMLEtBQUs7UUFDTCxLQUFLO1FBQ0wsS0FBSztRQUNMLEtBQUs7UUFDTCxLQUFLO1FBQ0wsS0FBSztRQUNMLEtBQUs7UUFDTCxLQUFLO1FBQ0wsS0FBSztRQUNMLEtBQUs7UUFDTCxLQUFLO1FBQ0wsS0FBSztRQUNMLEtBQUs7UUFDTCxLQUFLO1FBQ0wsS0FBSztRQUNMLEtBQUs7UUFDTCxLQUFLO1FBQ0wsS0FBSztRQUNMLEtBQUs7UUFDTCxLQUFLO1FBQ0wsS0FBSztRQUNMLEtBQUs7UUFDTCxLQUFLO1FBQ0wsS0FBSztRQUNMLEtBQUs7UUFDTCxLQUFLO1FBQ0wsS0FBSztRQUNMLEtBQUs7UUFDTCxLQUFLO1FBQ0wsS0FBSztRQUNMLEtBQUs7UUFDTCxLQUFLO1FBQ0wsS0FBSztRQUNMLEtBQUs7UUFDTCxLQUFLO1FBQ0wsS0FBSztRQUNMLEtBQUs7UUFDTCxLQUFLO1FBQ0wsS0FBSztRQUNMLEtBQUs7UUFDTCxLQUFLO1FBQ0wsS0FBSztRQUNMLEtBQUs7UUFDTCxLQUFLO1FBQ0wsS0FBSztRQUNMLEtBQUs7UUFDTCxLQUFLO1FBQ0wsS0FBSztRQUNMLEtBQUs7UUFDTCxLQUFLO1FBQ0wsS0FBSztRQUNMLEtBQUs7UUFDTCxLQUFLO1FBQ0wsS0FBSztRQUNMLEtBQUs7UUFDTCxLQUFLO1FBQ0wsS0FBSztRQUNMLEtBQUs7UUFDTCxLQUFLO1FBQ0wsS0FBSztRQUNMLEtBQUs7UUFDTCxLQUFLO1FBQ0wsS0FBSztRQUNMLEtBQUs7UUFDTCxLQUFLO1FBQ0wsS0FBSztLQUNOLENBQUE7SUFFRCxLQUFLLElBQUksQ0FBQyxHQUFHLENBQUMsRUFBRSxDQUFDLEdBQUcsV0FBVyxDQUFDLE1BQU0sS0FBSyxXQUFXLENBQUMsQ0FBQyxDQUFDLElBQUksQ0FBQyxDQUFDLEVBQUUsQ0FBQyxFQUFFLEVBQUU7UUFDcEUsTUFBTSxDQUFDLEdBQUcsV0FBVyxDQUFDLENBQUMsQ0FBQyxDQUFBO1FBQ3hCLElBQUksQ0FBQyxLQUFLLENBQUM7WUFBRSxPQUFPLElBQUksQ0FBQTthQUNuQixJQUFJLENBQUMsR0FBRyxDQUFDLEtBQUssRUFBRTtZQUFFLE9BQU8sS0FBSyxDQUFBO0tBQ3BDOzs7Ozs7Ozs7Ozs7Ozs7Ozs7OztJQXFCRCxJQUFJLENBQUMsR0FBRyxFQUFFLENBQUE7SUFDVixNQUFNLENBQUMsR0FBRyxDQUFDLEdBQUcsRUFBRSxDQUFBO0lBQ2hCLElBQUksR0FBRyxHQUFHLENBQUMsQ0FBQTtJQUNYLE9BQU8sR0FBRyxHQUFHLEVBQUUsS0FBSyxFQUFFLEVBQUU7UUFDdEIsR0FBRyxJQUFJLEVBQUUsQ0FBQTtRQUNULEVBQUUsQ0FBQyxDQUFBO0tBQ0o7SUFFRCxNQUFNLENBQUMsR0FBRyxDQUFDLElBQUksRUFBRSxJQUFJLENBQUMsQ0FBQyxDQUFBO0lBRXZCLEdBQUc7UUFDRCxNQUFNLENBQUMsR0FBRyxXQUFXLENBQUMsQ0FBQyxFQUFFLEVBQUUsQ0FBQyxDQUFBO1FBQzVCLElBQUksQ0FBQyxHQUFHLE1BQU0sQ0FBQyxDQUFDLEVBQUUsQ0FBQyxFQUFFLENBQUMsQ0FBQyxDQUFBO1FBQ3ZCLElBQUksQ0FBQyxLQUFLLEVBQUUsSUFBSSxDQUFDLEtBQUssQ0FBQztZQUFFLFNBQVE7UUFDakMsSUFBSSxDQUFDLEdBQUcsQ0FBQyxDQUFBO1FBQ1QsT0FBTyxDQUFDLEdBQUcsQ0FBQyxFQUFFO1lBQ1osQ0FBQyxHQUFHLE1BQU0sQ0FBQyxDQUFDLEVBQUUsRUFBRSxFQUFFLENBQUMsQ0FBQyxDQUFBO1lBQ3BCLElBQUksQ0FBQyxLQUFLLENBQUM7Z0JBQUUsTUFBSztZQUNsQixJQUFJLENBQUMsS0FBSyxFQUFFO2dCQUFFLE9BQU8sS0FBSyxDQUFBO1lBQzFCLENBQUMsRUFBRSxDQUFBO1NBQ0o7UUFDRCxJQUFJLENBQUMsS0FBSyxDQUFDO1lBQUUsT0FBTyxLQUFLLENBQUE7S0FDMUIsUUFBUSxFQUFFLFVBQVUsS0FBSyxDQUFDLEVBQUM7SUFFNUIsT0FBTyxJQUFJLENBQUE7QUFDYixDQUFDO1NBRWUseUJBQXlCOztJQUV2QyxJQUFJLFVBQVUsR0FBRyxzQkFBc0IsSUFBSSxDQUFDLElBQUksSUFBSSxJQUFJLENBQUMsUUFBUSxFQUFFLFVBQVUsTUFBTSxDQUFDLElBQUksSUFBSSxNQUFNLENBQUMsUUFBUSxFQUFFLFVBQVUsTUFBTSxDQUFDLElBQUksSUFBSSxNQUFNLENBQUMsUUFBUSxFQUFFLFVBQVUsSUFBSSxDQUFDLElBQUksSUFBSSxJQUFJLENBQUMsUUFBUSxFQUFFLFVBQVUsWUFBWSxDQUFDLElBQUksSUFBSSxZQUFZLENBQUMsUUFBUSxFQUFFLFVBQVUsYUFBYSxDQUFDLElBQUksSUFBSSxhQUFhLENBQUMsUUFBUSxFQUFFLFVBQVUsV0FBVyxDQUFDLElBQUksSUFBSSxXQUFXLENBQUMsUUFBUSxFQUFFLFVBQVUsZUFBZSxDQUFDLElBQUksSUFBSSxnQkFBZ0IsQ0FBQyxRQUFRLEVBQUUsSUFBSSxTQUFTLENBQUMsUUFBUSxFQUFFLElBQUksVUFBVSxDQUFDLFFBQVEsRUFBRSxHQUFHLENBQUE7SUFFaGQsVUFBVSxJQUFJLHNEQUFzRCxlQUFlLENBQUMsSUFBSSxnRkFBZ0YsQ0FBQTtJQUV4SyxPQUFPLFVBQVUsQ0FBQyxVQUFVLENBQUMsQ0FBQTtBQUMvQjs7QUN6WUE7Ozs7Ozs7Ozs7Ozs7OztTQWVnQixLQUFLLENBQUUsU0FBaUIsRUFBRSxhQUFxQixFQUFFO0lBQy9ELElBQUksU0FBUyxHQUFHLENBQUM7UUFBRSxNQUFNLElBQUksVUFBVSxDQUFDLHVCQUF1QixDQUFDLENBQUE7O0lBR2hFLElBQUksQ0FBQyxXQUFXLEVBQUU7UUFDaEIsSUFBSSxHQUFHLEdBQUcsRUFBRSxDQUFBO1FBQ1osR0FBRztZQUNELEdBQUcsR0FBRyxVQUFVLENBQUMsWUFBWSxDQUFDLFNBQVMsRUFBRSxJQUFJLENBQUMsQ0FBQyxDQUFBO1NBQ2hELFFBQVEsQ0FBQyxnQkFBZ0IsQ0FBQyxHQUFHLEVBQUUsVUFBVSxDQUFDLEVBQUM7UUFDNUMsT0FBTyxJQUFJLE9BQU8sQ0FBQyxDQUFDLE9BQU8sT0FBTyxPQUFPLENBQUMsR0FBRyxDQUFDLENBQUEsRUFBRSxDQUFDLENBQUE7S0FDbEQ7SUFDRCxPQUFPLElBQUksT0FBTyxDQUFDLENBQUMsT0FBTyxFQUFFLE1BQU07UUFDakMsTUFBTSxVQUFVLEdBQWEsRUFBRSxDQUFBO1FBQy9CLE1BQU0sVUFBVSxHQUFHLENBQUMsR0FBb0IsRUFBRSxTQUFpQjtZQUN6RCxJQUFJLEdBQUcsQ0FBQyxPQUFPLEVBQUU7O2dCQUVmLEtBQUssSUFBSSxDQUFDLEdBQUcsQ0FBQyxFQUFFLENBQUMsR0FBRyxVQUFVLENBQUMsTUFBTSxFQUFFLENBQUMsRUFBRSxFQUFFO29CQUMxQyxVQUFVLENBQUMsQ0FBQyxDQUFDLENBQUMsU0FBUyxFQUFFLENBQUE7aUJBQzFCO2dCQUNELE9BQU8sVUFBVSxDQUFDLE1BQU0sR0FBRyxDQUFDLEVBQUU7b0JBQzVCLFVBQVUsQ0FBQyxHQUFHLEVBQUUsQ0FBQTtpQkFDakI7Z0JBQ0QsT0FBTyxDQUFDLEdBQUcsQ0FBQyxLQUFLLENBQUMsQ0FBQTthQUNuQjtpQkFBTTtnQkFDTCxNQUFNLEdBQUcsR0FBRyxZQUFZLENBQUMsU0FBUyxFQUFFLElBQUksQ0FBQyxDQUFBO2dCQUN6QyxNQUFNLEdBQUcsR0FBRyxVQUFVLENBQUMsR0FBRyxDQUFDLENBQUE7Z0JBQzNCLElBQUk7b0JBQ0YsTUFBTSxXQUFXLEdBQW9CO3dCQUNuQyxHQUFHLEVBQUUsR0FBRzt3QkFDUixVQUFVLEVBQUUsVUFBVTt3QkFDdEIsRUFBRSxFQUFFLEdBQUcsQ0FBQyxFQUFFO3FCQUNYLENBQUE7b0JBQ0QsU0FBUyxDQUFDLFdBQVcsQ0FBQyxXQUFXLENBQUMsQ0FBQTtpQkFDbkM7Z0JBQUMsT0FBTyxLQUFLLEVBQUU7O2lCQUVmO2FBQ0Y7U0FDRixDQUFBO1FBQ2U7WUFDZCxNQUFNLFNBQVMsR0FBRyx5QkFBeUIsRUFBRSxDQUFBO1lBQzdDLEtBQUssSUFBSSxDQUFDLEdBQUcsQ0FBQyxFQUFFLENBQUMsR0FBRyxJQUFJLENBQUMsU0FBUyxDQUFDLG1CQUFtQixHQUFHLENBQUMsRUFBRSxDQUFDLEVBQUUsRUFBRTtnQkFDL0QsTUFBTSxTQUFTLEdBQUcsSUFBSSxNQUFNLENBQUMsU0FBUyxDQUFDLENBQUE7Z0JBQ3ZDLFNBQVMsQ0FBQyxTQUFTLEdBQUcsQ0FBQyxLQUFLLEtBQUssVUFBVSxDQUFDLEtBQUssQ0FBQyxJQUFJLEVBQUUsU0FBUyxDQUFDLENBQUE7Z0JBQ2xFLFVBQVUsQ0FBQyxJQUFJLENBQUMsU0FBUyxDQUFDLENBQUE7YUFDM0I7U0FTRjtRQUNELEtBQUssSUFBSSxDQUFDLEdBQUcsQ0FBQyxFQUFFLENBQUMsR0FBRyxVQUFVLENBQUMsTUFBTSxFQUFFLENBQUMsRUFBRSxFQUFFO1lBQzFDLFFBQVEsQ0FBQyxTQUFTLEVBQUUsSUFBSSxDQUFDLENBQUMsSUFBSSxDQUFDLFVBQVUsR0FBc0I7Z0JBQzdELE1BQU0sR0FBRyxHQUFHLFVBQVUsQ0FBQyxHQUFHLENBQUMsQ0FBQTtnQkFDM0IsVUFBVSxDQUFDLENBQUMsQ0FBQyxDQUFDLFdBQVcsQ0FBQztvQkFDeEIsR0FBRyxFQUFFLEdBQUc7b0JBQ1IsVUFBVSxFQUFFLFVBQVU7b0JBQ3RCLEVBQUUsRUFBRSxDQUFDO2lCQUNOLENBQUMsQ0FBQTthQUNILENBQUMsQ0FBQyxLQUFLLENBQUMsTUFBTSxDQUFDLENBQUE7U0FDakI7S0FDRixDQUFDLENBQUE7QUFDSixDQUFDO0FBRUQ7Ozs7Ozs7Ozs7OztTQVlnQixTQUFTLENBQUUsU0FBaUIsRUFBRSxhQUFxQixFQUFFO0lBQ25FLElBQUksU0FBUyxHQUFHLENBQUM7UUFBRSxNQUFNLElBQUksVUFBVSxDQUFDLHVCQUF1QixDQUFDLENBQUE7SUFDaEUsSUFBSSxHQUFHLEdBQUcsRUFBRSxDQUFBO0lBQ1osR0FBRztRQUNELEdBQUcsR0FBRyxVQUFVLENBQUMsWUFBWSxDQUFDLFNBQVMsRUFBRSxJQUFJLENBQUMsQ0FBQyxDQUFBO0tBQ2hELFFBQVEsQ0FBQyxnQkFBZ0IsQ0FBQyxHQUFHLEVBQUUsVUFBVSxDQUFDLEVBQUM7SUFDNUMsT0FBTyxHQUFHLENBQUE7QUFDWjs7OzsifQ== diff --git a/core/third-party/nacl-fast.js b/core/third-party/nacl-fast.js new file mode 100644 index 0000000..7ea5fb5 --- /dev/null +++ b/core/third-party/nacl-fast.js @@ -0,0 +1,2391 @@ +(function(nacl) { +'use strict'; + +// Ported in 2014 by Dmitry Chestnykh and Devi Mandiri. +// Public domain. +// +// Implementation derived from TweetNaCl version 20140427. +// See for details: http://tweetnacl.cr.yp.to/ + +var gf = function(init) { + var i, r = new Float64Array(16); + if (init) for (i = 0; i < init.length; i++) r[i] = init[i]; + return r; +}; + +// Pluggable, initialized in high-level API below. +var randombytes = function(/* x, n */) { throw new Error('no PRNG'); }; + +var _0 = new Uint8Array(16); +var _9 = new Uint8Array(32); _9[0] = 9; + +var gf0 = gf(), + gf1 = gf([1]), + _121665 = gf([0xdb41, 1]), + D = gf([0x78a3, 0x1359, 0x4dca, 0x75eb, 0xd8ab, 0x4141, 0x0a4d, 0x0070, 0xe898, 0x7779, 0x4079, 0x8cc7, 0xfe73, 0x2b6f, 0x6cee, 0x5203]), + D2 = gf([0xf159, 0x26b2, 0x9b94, 0xebd6, 0xb156, 0x8283, 0x149a, 0x00e0, 0xd130, 0xeef3, 0x80f2, 0x198e, 0xfce7, 0x56df, 0xd9dc, 0x2406]), + X = gf([0xd51a, 0x8f25, 0x2d60, 0xc956, 0xa7b2, 0x9525, 0xc760, 0x692c, 0xdc5c, 0xfdd6, 0xe231, 0xc0a4, 0x53fe, 0xcd6e, 0x36d3, 0x2169]), + Y = gf([0x6658, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666]), + I = gf([0xa0b0, 0x4a0e, 0x1b27, 0xc4ee, 0xe478, 0xad2f, 0x1806, 0x2f43, 0xd7a7, 0x3dfb, 0x0099, 0x2b4d, 0xdf0b, 0x4fc1, 0x2480, 0x2b83]); + +function ts64(x, i, h, l) { + x[i] = (h >> 24) & 0xff; + x[i+1] = (h >> 16) & 0xff; + x[i+2] = (h >> 8) & 0xff; + x[i+3] = h & 0xff; + x[i+4] = (l >> 24) & 0xff; + x[i+5] = (l >> 16) & 0xff; + x[i+6] = (l >> 8) & 0xff; + x[i+7] = l & 0xff; +} + +function vn(x, xi, y, yi, n) { + var i,d = 0; + for (i = 0; i < n; i++) d |= x[xi+i]^y[yi+i]; + return (1 & ((d - 1) >>> 8)) - 1; +} + +function crypto_verify_16(x, xi, y, yi) { + return vn(x,xi,y,yi,16); +} + +function crypto_verify_32(x, xi, y, yi) { + return vn(x,xi,y,yi,32); +} + +function core_salsa20(o, p, k, c) { + var j0 = c[ 0] & 0xff | (c[ 1] & 0xff)<<8 | (c[ 2] & 0xff)<<16 | (c[ 3] & 0xff)<<24, + j1 = k[ 0] & 0xff | (k[ 1] & 0xff)<<8 | (k[ 2] & 0xff)<<16 | (k[ 3] & 0xff)<<24, + j2 = k[ 4] & 0xff | (k[ 5] & 0xff)<<8 | (k[ 6] & 0xff)<<16 | (k[ 7] & 0xff)<<24, + j3 = k[ 8] & 0xff | (k[ 9] & 0xff)<<8 | (k[10] & 0xff)<<16 | (k[11] & 0xff)<<24, + j4 = k[12] & 0xff | (k[13] & 0xff)<<8 | (k[14] & 0xff)<<16 | (k[15] & 0xff)<<24, + j5 = c[ 4] & 0xff | (c[ 5] & 0xff)<<8 | (c[ 6] & 0xff)<<16 | (c[ 7] & 0xff)<<24, + j6 = p[ 0] & 0xff | (p[ 1] & 0xff)<<8 | (p[ 2] & 0xff)<<16 | (p[ 3] & 0xff)<<24, + j7 = p[ 4] & 0xff | (p[ 5] & 0xff)<<8 | (p[ 6] & 0xff)<<16 | (p[ 7] & 0xff)<<24, + j8 = p[ 8] & 0xff | (p[ 9] & 0xff)<<8 | (p[10] & 0xff)<<16 | (p[11] & 0xff)<<24, + j9 = p[12] & 0xff | (p[13] & 0xff)<<8 | (p[14] & 0xff)<<16 | (p[15] & 0xff)<<24, + j10 = c[ 8] & 0xff | (c[ 9] & 0xff)<<8 | (c[10] & 0xff)<<16 | (c[11] & 0xff)<<24, + j11 = k[16] & 0xff | (k[17] & 0xff)<<8 | (k[18] & 0xff)<<16 | (k[19] & 0xff)<<24, + j12 = k[20] & 0xff | (k[21] & 0xff)<<8 | (k[22] & 0xff)<<16 | (k[23] & 0xff)<<24, + j13 = k[24] & 0xff | (k[25] & 0xff)<<8 | (k[26] & 0xff)<<16 | (k[27] & 0xff)<<24, + j14 = k[28] & 0xff | (k[29] & 0xff)<<8 | (k[30] & 0xff)<<16 | (k[31] & 0xff)<<24, + j15 = c[12] & 0xff | (c[13] & 0xff)<<8 | (c[14] & 0xff)<<16 | (c[15] & 0xff)<<24; + + var x0 = j0, x1 = j1, x2 = j2, x3 = j3, x4 = j4, x5 = j5, x6 = j6, x7 = j7, + x8 = j8, x9 = j9, x10 = j10, x11 = j11, x12 = j12, x13 = j13, x14 = j14, + x15 = j15, u; + + for (var i = 0; i < 20; i += 2) { + u = x0 + x12 | 0; + x4 ^= u<<7 | u>>>(32-7); + u = x4 + x0 | 0; + x8 ^= u<<9 | u>>>(32-9); + u = x8 + x4 | 0; + x12 ^= u<<13 | u>>>(32-13); + u = x12 + x8 | 0; + x0 ^= u<<18 | u>>>(32-18); + + u = x5 + x1 | 0; + x9 ^= u<<7 | u>>>(32-7); + u = x9 + x5 | 0; + x13 ^= u<<9 | u>>>(32-9); + u = x13 + x9 | 0; + x1 ^= u<<13 | u>>>(32-13); + u = x1 + x13 | 0; + x5 ^= u<<18 | u>>>(32-18); + + u = x10 + x6 | 0; + x14 ^= u<<7 | u>>>(32-7); + u = x14 + x10 | 0; + x2 ^= u<<9 | u>>>(32-9); + u = x2 + x14 | 0; + x6 ^= u<<13 | u>>>(32-13); + u = x6 + x2 | 0; + x10 ^= u<<18 | u>>>(32-18); + + u = x15 + x11 | 0; + x3 ^= u<<7 | u>>>(32-7); + u = x3 + x15 | 0; + x7 ^= u<<9 | u>>>(32-9); + u = x7 + x3 | 0; + x11 ^= u<<13 | u>>>(32-13); + u = x11 + x7 | 0; + x15 ^= u<<18 | u>>>(32-18); + + u = x0 + x3 | 0; + x1 ^= u<<7 | u>>>(32-7); + u = x1 + x0 | 0; + x2 ^= u<<9 | u>>>(32-9); + u = x2 + x1 | 0; + x3 ^= u<<13 | u>>>(32-13); + u = x3 + x2 | 0; + x0 ^= u<<18 | u>>>(32-18); + + u = x5 + x4 | 0; + x6 ^= u<<7 | u>>>(32-7); + u = x6 + x5 | 0; + x7 ^= u<<9 | u>>>(32-9); + u = x7 + x6 | 0; + x4 ^= u<<13 | u>>>(32-13); + u = x4 + x7 | 0; + x5 ^= u<<18 | u>>>(32-18); + + u = x10 + x9 | 0; + x11 ^= u<<7 | u>>>(32-7); + u = x11 + x10 | 0; + x8 ^= u<<9 | u>>>(32-9); + u = x8 + x11 | 0; + x9 ^= u<<13 | u>>>(32-13); + u = x9 + x8 | 0; + x10 ^= u<<18 | u>>>(32-18); + + u = x15 + x14 | 0; + x12 ^= u<<7 | u>>>(32-7); + u = x12 + x15 | 0; + x13 ^= u<<9 | u>>>(32-9); + u = x13 + x12 | 0; + x14 ^= u<<13 | u>>>(32-13); + u = x14 + x13 | 0; + x15 ^= u<<18 | u>>>(32-18); + } + x0 = x0 + j0 | 0; + x1 = x1 + j1 | 0; + x2 = x2 + j2 | 0; + x3 = x3 + j3 | 0; + x4 = x4 + j4 | 0; + x5 = x5 + j5 | 0; + x6 = x6 + j6 | 0; + x7 = x7 + j7 | 0; + x8 = x8 + j8 | 0; + x9 = x9 + j9 | 0; + x10 = x10 + j10 | 0; + x11 = x11 + j11 | 0; + x12 = x12 + j12 | 0; + x13 = x13 + j13 | 0; + x14 = x14 + j14 | 0; + x15 = x15 + j15 | 0; + + o[ 0] = x0 >>> 0 & 0xff; + o[ 1] = x0 >>> 8 & 0xff; + o[ 2] = x0 >>> 16 & 0xff; + o[ 3] = x0 >>> 24 & 0xff; + + o[ 4] = x1 >>> 0 & 0xff; + o[ 5] = x1 >>> 8 & 0xff; + o[ 6] = x1 >>> 16 & 0xff; + o[ 7] = x1 >>> 24 & 0xff; + + o[ 8] = x2 >>> 0 & 0xff; + o[ 9] = x2 >>> 8 & 0xff; + o[10] = x2 >>> 16 & 0xff; + o[11] = x2 >>> 24 & 0xff; + + o[12] = x3 >>> 0 & 0xff; + o[13] = x3 >>> 8 & 0xff; + o[14] = x3 >>> 16 & 0xff; + o[15] = x3 >>> 24 & 0xff; + + o[16] = x4 >>> 0 & 0xff; + o[17] = x4 >>> 8 & 0xff; + o[18] = x4 >>> 16 & 0xff; + o[19] = x4 >>> 24 & 0xff; + + o[20] = x5 >>> 0 & 0xff; + o[21] = x5 >>> 8 & 0xff; + o[22] = x5 >>> 16 & 0xff; + o[23] = x5 >>> 24 & 0xff; + + o[24] = x6 >>> 0 & 0xff; + o[25] = x6 >>> 8 & 0xff; + o[26] = x6 >>> 16 & 0xff; + o[27] = x6 >>> 24 & 0xff; + + o[28] = x7 >>> 0 & 0xff; + o[29] = x7 >>> 8 & 0xff; + o[30] = x7 >>> 16 & 0xff; + o[31] = x7 >>> 24 & 0xff; + + o[32] = x8 >>> 0 & 0xff; + o[33] = x8 >>> 8 & 0xff; + o[34] = x8 >>> 16 & 0xff; + o[35] = x8 >>> 24 & 0xff; + + o[36] = x9 >>> 0 & 0xff; + o[37] = x9 >>> 8 & 0xff; + o[38] = x9 >>> 16 & 0xff; + o[39] = x9 >>> 24 & 0xff; + + o[40] = x10 >>> 0 & 0xff; + o[41] = x10 >>> 8 & 0xff; + o[42] = x10 >>> 16 & 0xff; + o[43] = x10 >>> 24 & 0xff; + + o[44] = x11 >>> 0 & 0xff; + o[45] = x11 >>> 8 & 0xff; + o[46] = x11 >>> 16 & 0xff; + o[47] = x11 >>> 24 & 0xff; + + o[48] = x12 >>> 0 & 0xff; + o[49] = x12 >>> 8 & 0xff; + o[50] = x12 >>> 16 & 0xff; + o[51] = x12 >>> 24 & 0xff; + + o[52] = x13 >>> 0 & 0xff; + o[53] = x13 >>> 8 & 0xff; + o[54] = x13 >>> 16 & 0xff; + o[55] = x13 >>> 24 & 0xff; + + o[56] = x14 >>> 0 & 0xff; + o[57] = x14 >>> 8 & 0xff; + o[58] = x14 >>> 16 & 0xff; + o[59] = x14 >>> 24 & 0xff; + + o[60] = x15 >>> 0 & 0xff; + o[61] = x15 >>> 8 & 0xff; + o[62] = x15 >>> 16 & 0xff; + o[63] = x15 >>> 24 & 0xff; +} + +function core_hsalsa20(o,p,k,c) { + var j0 = c[ 0] & 0xff | (c[ 1] & 0xff)<<8 | (c[ 2] & 0xff)<<16 | (c[ 3] & 0xff)<<24, + j1 = k[ 0] & 0xff | (k[ 1] & 0xff)<<8 | (k[ 2] & 0xff)<<16 | (k[ 3] & 0xff)<<24, + j2 = k[ 4] & 0xff | (k[ 5] & 0xff)<<8 | (k[ 6] & 0xff)<<16 | (k[ 7] & 0xff)<<24, + j3 = k[ 8] & 0xff | (k[ 9] & 0xff)<<8 | (k[10] & 0xff)<<16 | (k[11] & 0xff)<<24, + j4 = k[12] & 0xff | (k[13] & 0xff)<<8 | (k[14] & 0xff)<<16 | (k[15] & 0xff)<<24, + j5 = c[ 4] & 0xff | (c[ 5] & 0xff)<<8 | (c[ 6] & 0xff)<<16 | (c[ 7] & 0xff)<<24, + j6 = p[ 0] & 0xff | (p[ 1] & 0xff)<<8 | (p[ 2] & 0xff)<<16 | (p[ 3] & 0xff)<<24, + j7 = p[ 4] & 0xff | (p[ 5] & 0xff)<<8 | (p[ 6] & 0xff)<<16 | (p[ 7] & 0xff)<<24, + j8 = p[ 8] & 0xff | (p[ 9] & 0xff)<<8 | (p[10] & 0xff)<<16 | (p[11] & 0xff)<<24, + j9 = p[12] & 0xff | (p[13] & 0xff)<<8 | (p[14] & 0xff)<<16 | (p[15] & 0xff)<<24, + j10 = c[ 8] & 0xff | (c[ 9] & 0xff)<<8 | (c[10] & 0xff)<<16 | (c[11] & 0xff)<<24, + j11 = k[16] & 0xff | (k[17] & 0xff)<<8 | (k[18] & 0xff)<<16 | (k[19] & 0xff)<<24, + j12 = k[20] & 0xff | (k[21] & 0xff)<<8 | (k[22] & 0xff)<<16 | (k[23] & 0xff)<<24, + j13 = k[24] & 0xff | (k[25] & 0xff)<<8 | (k[26] & 0xff)<<16 | (k[27] & 0xff)<<24, + j14 = k[28] & 0xff | (k[29] & 0xff)<<8 | (k[30] & 0xff)<<16 | (k[31] & 0xff)<<24, + j15 = c[12] & 0xff | (c[13] & 0xff)<<8 | (c[14] & 0xff)<<16 | (c[15] & 0xff)<<24; + + var x0 = j0, x1 = j1, x2 = j2, x3 = j3, x4 = j4, x5 = j5, x6 = j6, x7 = j7, + x8 = j8, x9 = j9, x10 = j10, x11 = j11, x12 = j12, x13 = j13, x14 = j14, + x15 = j15, u; + + for (var i = 0; i < 20; i += 2) { + u = x0 + x12 | 0; + x4 ^= u<<7 | u>>>(32-7); + u = x4 + x0 | 0; + x8 ^= u<<9 | u>>>(32-9); + u = x8 + x4 | 0; + x12 ^= u<<13 | u>>>(32-13); + u = x12 + x8 | 0; + x0 ^= u<<18 | u>>>(32-18); + + u = x5 + x1 | 0; + x9 ^= u<<7 | u>>>(32-7); + u = x9 + x5 | 0; + x13 ^= u<<9 | u>>>(32-9); + u = x13 + x9 | 0; + x1 ^= u<<13 | u>>>(32-13); + u = x1 + x13 | 0; + x5 ^= u<<18 | u>>>(32-18); + + u = x10 + x6 | 0; + x14 ^= u<<7 | u>>>(32-7); + u = x14 + x10 | 0; + x2 ^= u<<9 | u>>>(32-9); + u = x2 + x14 | 0; + x6 ^= u<<13 | u>>>(32-13); + u = x6 + x2 | 0; + x10 ^= u<<18 | u>>>(32-18); + + u = x15 + x11 | 0; + x3 ^= u<<7 | u>>>(32-7); + u = x3 + x15 | 0; + x7 ^= u<<9 | u>>>(32-9); + u = x7 + x3 | 0; + x11 ^= u<<13 | u>>>(32-13); + u = x11 + x7 | 0; + x15 ^= u<<18 | u>>>(32-18); + + u = x0 + x3 | 0; + x1 ^= u<<7 | u>>>(32-7); + u = x1 + x0 | 0; + x2 ^= u<<9 | u>>>(32-9); + u = x2 + x1 | 0; + x3 ^= u<<13 | u>>>(32-13); + u = x3 + x2 | 0; + x0 ^= u<<18 | u>>>(32-18); + + u = x5 + x4 | 0; + x6 ^= u<<7 | u>>>(32-7); + u = x6 + x5 | 0; + x7 ^= u<<9 | u>>>(32-9); + u = x7 + x6 | 0; + x4 ^= u<<13 | u>>>(32-13); + u = x4 + x7 | 0; + x5 ^= u<<18 | u>>>(32-18); + + u = x10 + x9 | 0; + x11 ^= u<<7 | u>>>(32-7); + u = x11 + x10 | 0; + x8 ^= u<<9 | u>>>(32-9); + u = x8 + x11 | 0; + x9 ^= u<<13 | u>>>(32-13); + u = x9 + x8 | 0; + x10 ^= u<<18 | u>>>(32-18); + + u = x15 + x14 | 0; + x12 ^= u<<7 | u>>>(32-7); + u = x12 + x15 | 0; + x13 ^= u<<9 | u>>>(32-9); + u = x13 + x12 | 0; + x14 ^= u<<13 | u>>>(32-13); + u = x14 + x13 | 0; + x15 ^= u<<18 | u>>>(32-18); + } + + o[ 0] = x0 >>> 0 & 0xff; + o[ 1] = x0 >>> 8 & 0xff; + o[ 2] = x0 >>> 16 & 0xff; + o[ 3] = x0 >>> 24 & 0xff; + + o[ 4] = x5 >>> 0 & 0xff; + o[ 5] = x5 >>> 8 & 0xff; + o[ 6] = x5 >>> 16 & 0xff; + o[ 7] = x5 >>> 24 & 0xff; + + o[ 8] = x10 >>> 0 & 0xff; + o[ 9] = x10 >>> 8 & 0xff; + o[10] = x10 >>> 16 & 0xff; + o[11] = x10 >>> 24 & 0xff; + + o[12] = x15 >>> 0 & 0xff; + o[13] = x15 >>> 8 & 0xff; + o[14] = x15 >>> 16 & 0xff; + o[15] = x15 >>> 24 & 0xff; + + o[16] = x6 >>> 0 & 0xff; + o[17] = x6 >>> 8 & 0xff; + o[18] = x6 >>> 16 & 0xff; + o[19] = x6 >>> 24 & 0xff; + + o[20] = x7 >>> 0 & 0xff; + o[21] = x7 >>> 8 & 0xff; + o[22] = x7 >>> 16 & 0xff; + o[23] = x7 >>> 24 & 0xff; + + o[24] = x8 >>> 0 & 0xff; + o[25] = x8 >>> 8 & 0xff; + o[26] = x8 >>> 16 & 0xff; + o[27] = x8 >>> 24 & 0xff; + + o[28] = x9 >>> 0 & 0xff; + o[29] = x9 >>> 8 & 0xff; + o[30] = x9 >>> 16 & 0xff; + o[31] = x9 >>> 24 & 0xff; +} + +function crypto_core_salsa20(out,inp,k,c) { + core_salsa20(out,inp,k,c); +} + +function crypto_core_hsalsa20(out,inp,k,c) { + core_hsalsa20(out,inp,k,c); +} + +var sigma = new Uint8Array([101, 120, 112, 97, 110, 100, 32, 51, 50, 45, 98, 121, 116, 101, 32, 107]); + // "expand 32-byte k" + +function crypto_stream_salsa20_xor(c,cpos,m,mpos,b,n,k) { + var z = new Uint8Array(16), x = new Uint8Array(64); + var u, i; + for (i = 0; i < 16; i++) z[i] = 0; + for (i = 0; i < 8; i++) z[i] = n[i]; + while (b >= 64) { + crypto_core_salsa20(x,z,k,sigma); + for (i = 0; i < 64; i++) c[cpos+i] = m[mpos+i] ^ x[i]; + u = 1; + for (i = 8; i < 16; i++) { + u = u + (z[i] & 0xff) | 0; + z[i] = u & 0xff; + u >>>= 8; + } + b -= 64; + cpos += 64; + mpos += 64; + } + if (b > 0) { + crypto_core_salsa20(x,z,k,sigma); + for (i = 0; i < b; i++) c[cpos+i] = m[mpos+i] ^ x[i]; + } + return 0; +} + +function crypto_stream_salsa20(c,cpos,b,n,k) { + var z = new Uint8Array(16), x = new Uint8Array(64); + var u, i; + for (i = 0; i < 16; i++) z[i] = 0; + for (i = 0; i < 8; i++) z[i] = n[i]; + while (b >= 64) { + crypto_core_salsa20(x,z,k,sigma); + for (i = 0; i < 64; i++) c[cpos+i] = x[i]; + u = 1; + for (i = 8; i < 16; i++) { + u = u + (z[i] & 0xff) | 0; + z[i] = u & 0xff; + u >>>= 8; + } + b -= 64; + cpos += 64; + } + if (b > 0) { + crypto_core_salsa20(x,z,k,sigma); + for (i = 0; i < b; i++) c[cpos+i] = x[i]; + } + return 0; +} + +function crypto_stream(c,cpos,d,n,k) { + var s = new Uint8Array(32); + crypto_core_hsalsa20(s,n,k,sigma); + var sn = new Uint8Array(8); + for (var i = 0; i < 8; i++) sn[i] = n[i+16]; + return crypto_stream_salsa20(c,cpos,d,sn,s); +} + +function crypto_stream_xor(c,cpos,m,mpos,d,n,k) { + var s = new Uint8Array(32); + crypto_core_hsalsa20(s,n,k,sigma); + var sn = new Uint8Array(8); + for (var i = 0; i < 8; i++) sn[i] = n[i+16]; + return crypto_stream_salsa20_xor(c,cpos,m,mpos,d,sn,s); +} + +/* +* Port of Andrew Moon's Poly1305-donna-16. Public domain. +* https://github.com/floodyberry/poly1305-donna +*/ + +var poly1305 = function(key) { + this.buffer = new Uint8Array(16); + this.r = new Uint16Array(10); + this.h = new Uint16Array(10); + this.pad = new Uint16Array(8); + this.leftover = 0; + this.fin = 0; + + var t0, t1, t2, t3, t4, t5, t6, t7; + + t0 = key[ 0] & 0xff | (key[ 1] & 0xff) << 8; this.r[0] = ( t0 ) & 0x1fff; + t1 = key[ 2] & 0xff | (key[ 3] & 0xff) << 8; this.r[1] = ((t0 >>> 13) | (t1 << 3)) & 0x1fff; + t2 = key[ 4] & 0xff | (key[ 5] & 0xff) << 8; this.r[2] = ((t1 >>> 10) | (t2 << 6)) & 0x1f03; + t3 = key[ 6] & 0xff | (key[ 7] & 0xff) << 8; this.r[3] = ((t2 >>> 7) | (t3 << 9)) & 0x1fff; + t4 = key[ 8] & 0xff | (key[ 9] & 0xff) << 8; this.r[4] = ((t3 >>> 4) | (t4 << 12)) & 0x00ff; + this.r[5] = ((t4 >>> 1)) & 0x1ffe; + t5 = key[10] & 0xff | (key[11] & 0xff) << 8; this.r[6] = ((t4 >>> 14) | (t5 << 2)) & 0x1fff; + t6 = key[12] & 0xff | (key[13] & 0xff) << 8; this.r[7] = ((t5 >>> 11) | (t6 << 5)) & 0x1f81; + t7 = key[14] & 0xff | (key[15] & 0xff) << 8; this.r[8] = ((t6 >>> 8) | (t7 << 8)) & 0x1fff; + this.r[9] = ((t7 >>> 5)) & 0x007f; + + this.pad[0] = key[16] & 0xff | (key[17] & 0xff) << 8; + this.pad[1] = key[18] & 0xff | (key[19] & 0xff) << 8; + this.pad[2] = key[20] & 0xff | (key[21] & 0xff) << 8; + this.pad[3] = key[22] & 0xff | (key[23] & 0xff) << 8; + this.pad[4] = key[24] & 0xff | (key[25] & 0xff) << 8; + this.pad[5] = key[26] & 0xff | (key[27] & 0xff) << 8; + this.pad[6] = key[28] & 0xff | (key[29] & 0xff) << 8; + this.pad[7] = key[30] & 0xff | (key[31] & 0xff) << 8; +}; + +poly1305.prototype.blocks = function(m, mpos, bytes) { + var hibit = this.fin ? 0 : (1 << 11); + var t0, t1, t2, t3, t4, t5, t6, t7, c; + var d0, d1, d2, d3, d4, d5, d6, d7, d8, d9; + + var h0 = this.h[0], + h1 = this.h[1], + h2 = this.h[2], + h3 = this.h[3], + h4 = this.h[4], + h5 = this.h[5], + h6 = this.h[6], + h7 = this.h[7], + h8 = this.h[8], + h9 = this.h[9]; + + var r0 = this.r[0], + r1 = this.r[1], + r2 = this.r[2], + r3 = this.r[3], + r4 = this.r[4], + r5 = this.r[5], + r6 = this.r[6], + r7 = this.r[7], + r8 = this.r[8], + r9 = this.r[9]; + + while (bytes >= 16) { + t0 = m[mpos+ 0] & 0xff | (m[mpos+ 1] & 0xff) << 8; h0 += ( t0 ) & 0x1fff; + t1 = m[mpos+ 2] & 0xff | (m[mpos+ 3] & 0xff) << 8; h1 += ((t0 >>> 13) | (t1 << 3)) & 0x1fff; + t2 = m[mpos+ 4] & 0xff | (m[mpos+ 5] & 0xff) << 8; h2 += ((t1 >>> 10) | (t2 << 6)) & 0x1fff; + t3 = m[mpos+ 6] & 0xff | (m[mpos+ 7] & 0xff) << 8; h3 += ((t2 >>> 7) | (t3 << 9)) & 0x1fff; + t4 = m[mpos+ 8] & 0xff | (m[mpos+ 9] & 0xff) << 8; h4 += ((t3 >>> 4) | (t4 << 12)) & 0x1fff; + h5 += ((t4 >>> 1)) & 0x1fff; + t5 = m[mpos+10] & 0xff | (m[mpos+11] & 0xff) << 8; h6 += ((t4 >>> 14) | (t5 << 2)) & 0x1fff; + t6 = m[mpos+12] & 0xff | (m[mpos+13] & 0xff) << 8; h7 += ((t5 >>> 11) | (t6 << 5)) & 0x1fff; + t7 = m[mpos+14] & 0xff | (m[mpos+15] & 0xff) << 8; h8 += ((t6 >>> 8) | (t7 << 8)) & 0x1fff; + h9 += ((t7 >>> 5)) | hibit; + + c = 0; + + d0 = c; + d0 += h0 * r0; + d0 += h1 * (5 * r9); + d0 += h2 * (5 * r8); + d0 += h3 * (5 * r7); + d0 += h4 * (5 * r6); + c = (d0 >>> 13); d0 &= 0x1fff; + d0 += h5 * (5 * r5); + d0 += h6 * (5 * r4); + d0 += h7 * (5 * r3); + d0 += h8 * (5 * r2); + d0 += h9 * (5 * r1); + c += (d0 >>> 13); d0 &= 0x1fff; + + d1 = c; + d1 += h0 * r1; + d1 += h1 * r0; + d1 += h2 * (5 * r9); + d1 += h3 * (5 * r8); + d1 += h4 * (5 * r7); + c = (d1 >>> 13); d1 &= 0x1fff; + d1 += h5 * (5 * r6); + d1 += h6 * (5 * r5); + d1 += h7 * (5 * r4); + d1 += h8 * (5 * r3); + d1 += h9 * (5 * r2); + c += (d1 >>> 13); d1 &= 0x1fff; + + d2 = c; + d2 += h0 * r2; + d2 += h1 * r1; + d2 += h2 * r0; + d2 += h3 * (5 * r9); + d2 += h4 * (5 * r8); + c = (d2 >>> 13); d2 &= 0x1fff; + d2 += h5 * (5 * r7); + d2 += h6 * (5 * r6); + d2 += h7 * (5 * r5); + d2 += h8 * (5 * r4); + d2 += h9 * (5 * r3); + c += (d2 >>> 13); d2 &= 0x1fff; + + d3 = c; + d3 += h0 * r3; + d3 += h1 * r2; + d3 += h2 * r1; + d3 += h3 * r0; + d3 += h4 * (5 * r9); + c = (d3 >>> 13); d3 &= 0x1fff; + d3 += h5 * (5 * r8); + d3 += h6 * (5 * r7); + d3 += h7 * (5 * r6); + d3 += h8 * (5 * r5); + d3 += h9 * (5 * r4); + c += (d3 >>> 13); d3 &= 0x1fff; + + d4 = c; + d4 += h0 * r4; + d4 += h1 * r3; + d4 += h2 * r2; + d4 += h3 * r1; + d4 += h4 * r0; + c = (d4 >>> 13); d4 &= 0x1fff; + d4 += h5 * (5 * r9); + d4 += h6 * (5 * r8); + d4 += h7 * (5 * r7); + d4 += h8 * (5 * r6); + d4 += h9 * (5 * r5); + c += (d4 >>> 13); d4 &= 0x1fff; + + d5 = c; + d5 += h0 * r5; + d5 += h1 * r4; + d5 += h2 * r3; + d5 += h3 * r2; + d5 += h4 * r1; + c = (d5 >>> 13); d5 &= 0x1fff; + d5 += h5 * r0; + d5 += h6 * (5 * r9); + d5 += h7 * (5 * r8); + d5 += h8 * (5 * r7); + d5 += h9 * (5 * r6); + c += (d5 >>> 13); d5 &= 0x1fff; + + d6 = c; + d6 += h0 * r6; + d6 += h1 * r5; + d6 += h2 * r4; + d6 += h3 * r3; + d6 += h4 * r2; + c = (d6 >>> 13); d6 &= 0x1fff; + d6 += h5 * r1; + d6 += h6 * r0; + d6 += h7 * (5 * r9); + d6 += h8 * (5 * r8); + d6 += h9 * (5 * r7); + c += (d6 >>> 13); d6 &= 0x1fff; + + d7 = c; + d7 += h0 * r7; + d7 += h1 * r6; + d7 += h2 * r5; + d7 += h3 * r4; + d7 += h4 * r3; + c = (d7 >>> 13); d7 &= 0x1fff; + d7 += h5 * r2; + d7 += h6 * r1; + d7 += h7 * r0; + d7 += h8 * (5 * r9); + d7 += h9 * (5 * r8); + c += (d7 >>> 13); d7 &= 0x1fff; + + d8 = c; + d8 += h0 * r8; + d8 += h1 * r7; + d8 += h2 * r6; + d8 += h3 * r5; + d8 += h4 * r4; + c = (d8 >>> 13); d8 &= 0x1fff; + d8 += h5 * r3; + d8 += h6 * r2; + d8 += h7 * r1; + d8 += h8 * r0; + d8 += h9 * (5 * r9); + c += (d8 >>> 13); d8 &= 0x1fff; + + d9 = c; + d9 += h0 * r9; + d9 += h1 * r8; + d9 += h2 * r7; + d9 += h3 * r6; + d9 += h4 * r5; + c = (d9 >>> 13); d9 &= 0x1fff; + d9 += h5 * r4; + d9 += h6 * r3; + d9 += h7 * r2; + d9 += h8 * r1; + d9 += h9 * r0; + c += (d9 >>> 13); d9 &= 0x1fff; + + c = (((c << 2) + c)) | 0; + c = (c + d0) | 0; + d0 = c & 0x1fff; + c = (c >>> 13); + d1 += c; + + h0 = d0; + h1 = d1; + h2 = d2; + h3 = d3; + h4 = d4; + h5 = d5; + h6 = d6; + h7 = d7; + h8 = d8; + h9 = d9; + + mpos += 16; + bytes -= 16; + } + this.h[0] = h0; + this.h[1] = h1; + this.h[2] = h2; + this.h[3] = h3; + this.h[4] = h4; + this.h[5] = h5; + this.h[6] = h6; + this.h[7] = h7; + this.h[8] = h8; + this.h[9] = h9; +}; + +poly1305.prototype.finish = function(mac, macpos) { + var g = new Uint16Array(10); + var c, mask, f, i; + + if (this.leftover) { + i = this.leftover; + this.buffer[i++] = 1; + for (; i < 16; i++) this.buffer[i] = 0; + this.fin = 1; + this.blocks(this.buffer, 0, 16); + } + + c = this.h[1] >>> 13; + this.h[1] &= 0x1fff; + for (i = 2; i < 10; i++) { + this.h[i] += c; + c = this.h[i] >>> 13; + this.h[i] &= 0x1fff; + } + this.h[0] += (c * 5); + c = this.h[0] >>> 13; + this.h[0] &= 0x1fff; + this.h[1] += c; + c = this.h[1] >>> 13; + this.h[1] &= 0x1fff; + this.h[2] += c; + + g[0] = this.h[0] + 5; + c = g[0] >>> 13; + g[0] &= 0x1fff; + for (i = 1; i < 10; i++) { + g[i] = this.h[i] + c; + c = g[i] >>> 13; + g[i] &= 0x1fff; + } + g[9] -= (1 << 13); + + mask = (c ^ 1) - 1; + for (i = 0; i < 10; i++) g[i] &= mask; + mask = ~mask; + for (i = 0; i < 10; i++) this.h[i] = (this.h[i] & mask) | g[i]; + + this.h[0] = ((this.h[0] ) | (this.h[1] << 13) ) & 0xffff; + this.h[1] = ((this.h[1] >>> 3) | (this.h[2] << 10) ) & 0xffff; + this.h[2] = ((this.h[2] >>> 6) | (this.h[3] << 7) ) & 0xffff; + this.h[3] = ((this.h[3] >>> 9) | (this.h[4] << 4) ) & 0xffff; + this.h[4] = ((this.h[4] >>> 12) | (this.h[5] << 1) | (this.h[6] << 14)) & 0xffff; + this.h[5] = ((this.h[6] >>> 2) | (this.h[7] << 11) ) & 0xffff; + this.h[6] = ((this.h[7] >>> 5) | (this.h[8] << 8) ) & 0xffff; + this.h[7] = ((this.h[8] >>> 8) | (this.h[9] << 5) ) & 0xffff; + + f = this.h[0] + this.pad[0]; + this.h[0] = f & 0xffff; + for (i = 1; i < 8; i++) { + f = (((this.h[i] + this.pad[i]) | 0) + (f >>> 16)) | 0; + this.h[i] = f & 0xffff; + } + + mac[macpos+ 0] = (this.h[0] >>> 0) & 0xff; + mac[macpos+ 1] = (this.h[0] >>> 8) & 0xff; + mac[macpos+ 2] = (this.h[1] >>> 0) & 0xff; + mac[macpos+ 3] = (this.h[1] >>> 8) & 0xff; + mac[macpos+ 4] = (this.h[2] >>> 0) & 0xff; + mac[macpos+ 5] = (this.h[2] >>> 8) & 0xff; + mac[macpos+ 6] = (this.h[3] >>> 0) & 0xff; + mac[macpos+ 7] = (this.h[3] >>> 8) & 0xff; + mac[macpos+ 8] = (this.h[4] >>> 0) & 0xff; + mac[macpos+ 9] = (this.h[4] >>> 8) & 0xff; + mac[macpos+10] = (this.h[5] >>> 0) & 0xff; + mac[macpos+11] = (this.h[5] >>> 8) & 0xff; + mac[macpos+12] = (this.h[6] >>> 0) & 0xff; + mac[macpos+13] = (this.h[6] >>> 8) & 0xff; + mac[macpos+14] = (this.h[7] >>> 0) & 0xff; + mac[macpos+15] = (this.h[7] >>> 8) & 0xff; +}; + +poly1305.prototype.update = function(m, mpos, bytes) { + var i, want; + + if (this.leftover) { + want = (16 - this.leftover); + if (want > bytes) + want = bytes; + for (i = 0; i < want; i++) + this.buffer[this.leftover + i] = m[mpos+i]; + bytes -= want; + mpos += want; + this.leftover += want; + if (this.leftover < 16) + return; + this.blocks(this.buffer, 0, 16); + this.leftover = 0; + } + + if (bytes >= 16) { + want = bytes - (bytes % 16); + this.blocks(m, mpos, want); + mpos += want; + bytes -= want; + } + + if (bytes) { + for (i = 0; i < bytes; i++) + this.buffer[this.leftover + i] = m[mpos+i]; + this.leftover += bytes; + } +}; + +function crypto_onetimeauth(out, outpos, m, mpos, n, k) { + var s = new poly1305(k); + s.update(m, mpos, n); + s.finish(out, outpos); + return 0; +} + +function crypto_onetimeauth_verify(h, hpos, m, mpos, n, k) { + var x = new Uint8Array(16); + crypto_onetimeauth(x,0,m,mpos,n,k); + return crypto_verify_16(h,hpos,x,0); +} + +function crypto_secretbox(c,m,d,n,k) { + var i; + if (d < 32) return -1; + crypto_stream_xor(c,0,m,0,d,n,k); + crypto_onetimeauth(c, 16, c, 32, d - 32, c); + for (i = 0; i < 16; i++) c[i] = 0; + return 0; +} + +function crypto_secretbox_open(m,c,d,n,k) { + var i; + var x = new Uint8Array(32); + if (d < 32) return -1; + crypto_stream(x,0,32,n,k); + if (crypto_onetimeauth_verify(c, 16,c, 32,d - 32,x) !== 0) return -1; + crypto_stream_xor(m,0,c,0,d,n,k); + for (i = 0; i < 32; i++) m[i] = 0; + return 0; +} + +function set25519(r, a) { + var i; + for (i = 0; i < 16; i++) r[i] = a[i]|0; +} + +function car25519(o) { + var i, v, c = 1; + for (i = 0; i < 16; i++) { + v = o[i] + c + 65535; + c = Math.floor(v / 65536); + o[i] = v - c * 65536; + } + o[0] += c-1 + 37 * (c-1); +} + +function sel25519(p, q, b) { + var t, c = ~(b-1); + for (var i = 0; i < 16; i++) { + t = c & (p[i] ^ q[i]); + p[i] ^= t; + q[i] ^= t; + } +} + +function pack25519(o, n) { + var i, j, b; + var m = gf(), t = gf(); + for (i = 0; i < 16; i++) t[i] = n[i]; + car25519(t); + car25519(t); + car25519(t); + for (j = 0; j < 2; j++) { + m[0] = t[0] - 0xffed; + for (i = 1; i < 15; i++) { + m[i] = t[i] - 0xffff - ((m[i-1]>>16) & 1); + m[i-1] &= 0xffff; + } + m[15] = t[15] - 0x7fff - ((m[14]>>16) & 1); + b = (m[15]>>16) & 1; + m[14] &= 0xffff; + sel25519(t, m, 1-b); + } + for (i = 0; i < 16; i++) { + o[2*i] = t[i] & 0xff; + o[2*i+1] = t[i]>>8; + } +} + +function neq25519(a, b) { + var c = new Uint8Array(32), d = new Uint8Array(32); + pack25519(c, a); + pack25519(d, b); + return crypto_verify_32(c, 0, d, 0); +} + +function par25519(a) { + var d = new Uint8Array(32); + pack25519(d, a); + return d[0] & 1; +} + +function unpack25519(o, n) { + var i; + for (i = 0; i < 16; i++) o[i] = n[2*i] + (n[2*i+1] << 8); + o[15] &= 0x7fff; +} + +function A(o, a, b) { + for (var i = 0; i < 16; i++) o[i] = a[i] + b[i]; +} + +function Z(o, a, b) { + for (var i = 0; i < 16; i++) o[i] = a[i] - b[i]; +} + +function M(o, a, b) { + var v, c, + t0 = 0, t1 = 0, t2 = 0, t3 = 0, t4 = 0, t5 = 0, t6 = 0, t7 = 0, + t8 = 0, t9 = 0, t10 = 0, t11 = 0, t12 = 0, t13 = 0, t14 = 0, t15 = 0, + t16 = 0, t17 = 0, t18 = 0, t19 = 0, t20 = 0, t21 = 0, t22 = 0, t23 = 0, + t24 = 0, t25 = 0, t26 = 0, t27 = 0, t28 = 0, t29 = 0, t30 = 0, + b0 = b[0], + b1 = b[1], + b2 = b[2], + b3 = b[3], + b4 = b[4], + b5 = b[5], + b6 = b[6], + b7 = b[7], + b8 = b[8], + b9 = b[9], + b10 = b[10], + b11 = b[11], + b12 = b[12], + b13 = b[13], + b14 = b[14], + b15 = b[15]; + + v = a[0]; + t0 += v * b0; + t1 += v * b1; + t2 += v * b2; + t3 += v * b3; + t4 += v * b4; + t5 += v * b5; + t6 += v * b6; + t7 += v * b7; + t8 += v * b8; + t9 += v * b9; + t10 += v * b10; + t11 += v * b11; + t12 += v * b12; + t13 += v * b13; + t14 += v * b14; + t15 += v * b15; + v = a[1]; + t1 += v * b0; + t2 += v * b1; + t3 += v * b2; + t4 += v * b3; + t5 += v * b4; + t6 += v * b5; + t7 += v * b6; + t8 += v * b7; + t9 += v * b8; + t10 += v * b9; + t11 += v * b10; + t12 += v * b11; + t13 += v * b12; + t14 += v * b13; + t15 += v * b14; + t16 += v * b15; + v = a[2]; + t2 += v * b0; + t3 += v * b1; + t4 += v * b2; + t5 += v * b3; + t6 += v * b4; + t7 += v * b5; + t8 += v * b6; + t9 += v * b7; + t10 += v * b8; + t11 += v * b9; + t12 += v * b10; + t13 += v * b11; + t14 += v * b12; + t15 += v * b13; + t16 += v * b14; + t17 += v * b15; + v = a[3]; + t3 += v * b0; + t4 += v * b1; + t5 += v * b2; + t6 += v * b3; + t7 += v * b4; + t8 += v * b5; + t9 += v * b6; + t10 += v * b7; + t11 += v * b8; + t12 += v * b9; + t13 += v * b10; + t14 += v * b11; + t15 += v * b12; + t16 += v * b13; + t17 += v * b14; + t18 += v * b15; + v = a[4]; + t4 += v * b0; + t5 += v * b1; + t6 += v * b2; + t7 += v * b3; + t8 += v * b4; + t9 += v * b5; + t10 += v * b6; + t11 += v * b7; + t12 += v * b8; + t13 += v * b9; + t14 += v * b10; + t15 += v * b11; + t16 += v * b12; + t17 += v * b13; + t18 += v * b14; + t19 += v * b15; + v = a[5]; + t5 += v * b0; + t6 += v * b1; + t7 += v * b2; + t8 += v * b3; + t9 += v * b4; + t10 += v * b5; + t11 += v * b6; + t12 += v * b7; + t13 += v * b8; + t14 += v * b9; + t15 += v * b10; + t16 += v * b11; + t17 += v * b12; + t18 += v * b13; + t19 += v * b14; + t20 += v * b15; + v = a[6]; + t6 += v * b0; + t7 += v * b1; + t8 += v * b2; + t9 += v * b3; + t10 += v * b4; + t11 += v * b5; + t12 += v * b6; + t13 += v * b7; + t14 += v * b8; + t15 += v * b9; + t16 += v * b10; + t17 += v * b11; + t18 += v * b12; + t19 += v * b13; + t20 += v * b14; + t21 += v * b15; + v = a[7]; + t7 += v * b0; + t8 += v * b1; + t9 += v * b2; + t10 += v * b3; + t11 += v * b4; + t12 += v * b5; + t13 += v * b6; + t14 += v * b7; + t15 += v * b8; + t16 += v * b9; + t17 += v * b10; + t18 += v * b11; + t19 += v * b12; + t20 += v * b13; + t21 += v * b14; + t22 += v * b15; + v = a[8]; + t8 += v * b0; + t9 += v * b1; + t10 += v * b2; + t11 += v * b3; + t12 += v * b4; + t13 += v * b5; + t14 += v * b6; + t15 += v * b7; + t16 += v * b8; + t17 += v * b9; + t18 += v * b10; + t19 += v * b11; + t20 += v * b12; + t21 += v * b13; + t22 += v * b14; + t23 += v * b15; + v = a[9]; + t9 += v * b0; + t10 += v * b1; + t11 += v * b2; + t12 += v * b3; + t13 += v * b4; + t14 += v * b5; + t15 += v * b6; + t16 += v * b7; + t17 += v * b8; + t18 += v * b9; + t19 += v * b10; + t20 += v * b11; + t21 += v * b12; + t22 += v * b13; + t23 += v * b14; + t24 += v * b15; + v = a[10]; + t10 += v * b0; + t11 += v * b1; + t12 += v * b2; + t13 += v * b3; + t14 += v * b4; + t15 += v * b5; + t16 += v * b6; + t17 += v * b7; + t18 += v * b8; + t19 += v * b9; + t20 += v * b10; + t21 += v * b11; + t22 += v * b12; + t23 += v * b13; + t24 += v * b14; + t25 += v * b15; + v = a[11]; + t11 += v * b0; + t12 += v * b1; + t13 += v * b2; + t14 += v * b3; + t15 += v * b4; + t16 += v * b5; + t17 += v * b6; + t18 += v * b7; + t19 += v * b8; + t20 += v * b9; + t21 += v * b10; + t22 += v * b11; + t23 += v * b12; + t24 += v * b13; + t25 += v * b14; + t26 += v * b15; + v = a[12]; + t12 += v * b0; + t13 += v * b1; + t14 += v * b2; + t15 += v * b3; + t16 += v * b4; + t17 += v * b5; + t18 += v * b6; + t19 += v * b7; + t20 += v * b8; + t21 += v * b9; + t22 += v * b10; + t23 += v * b11; + t24 += v * b12; + t25 += v * b13; + t26 += v * b14; + t27 += v * b15; + v = a[13]; + t13 += v * b0; + t14 += v * b1; + t15 += v * b2; + t16 += v * b3; + t17 += v * b4; + t18 += v * b5; + t19 += v * b6; + t20 += v * b7; + t21 += v * b8; + t22 += v * b9; + t23 += v * b10; + t24 += v * b11; + t25 += v * b12; + t26 += v * b13; + t27 += v * b14; + t28 += v * b15; + v = a[14]; + t14 += v * b0; + t15 += v * b1; + t16 += v * b2; + t17 += v * b3; + t18 += v * b4; + t19 += v * b5; + t20 += v * b6; + t21 += v * b7; + t22 += v * b8; + t23 += v * b9; + t24 += v * b10; + t25 += v * b11; + t26 += v * b12; + t27 += v * b13; + t28 += v * b14; + t29 += v * b15; + v = a[15]; + t15 += v * b0; + t16 += v * b1; + t17 += v * b2; + t18 += v * b3; + t19 += v * b4; + t20 += v * b5; + t21 += v * b6; + t22 += v * b7; + t23 += v * b8; + t24 += v * b9; + t25 += v * b10; + t26 += v * b11; + t27 += v * b12; + t28 += v * b13; + t29 += v * b14; + t30 += v * b15; + + t0 += 38 * t16; + t1 += 38 * t17; + t2 += 38 * t18; + t3 += 38 * t19; + t4 += 38 * t20; + t5 += 38 * t21; + t6 += 38 * t22; + t7 += 38 * t23; + t8 += 38 * t24; + t9 += 38 * t25; + t10 += 38 * t26; + t11 += 38 * t27; + t12 += 38 * t28; + t13 += 38 * t29; + t14 += 38 * t30; + // t15 left as is + + // first car + c = 1; + v = t0 + c + 65535; c = Math.floor(v / 65536); t0 = v - c * 65536; + v = t1 + c + 65535; c = Math.floor(v / 65536); t1 = v - c * 65536; + v = t2 + c + 65535; c = Math.floor(v / 65536); t2 = v - c * 65536; + v = t3 + c + 65535; c = Math.floor(v / 65536); t3 = v - c * 65536; + v = t4 + c + 65535; c = Math.floor(v / 65536); t4 = v - c * 65536; + v = t5 + c + 65535; c = Math.floor(v / 65536); t5 = v - c * 65536; + v = t6 + c + 65535; c = Math.floor(v / 65536); t6 = v - c * 65536; + v = t7 + c + 65535; c = Math.floor(v / 65536); t7 = v - c * 65536; + v = t8 + c + 65535; c = Math.floor(v / 65536); t8 = v - c * 65536; + v = t9 + c + 65535; c = Math.floor(v / 65536); t9 = v - c * 65536; + v = t10 + c + 65535; c = Math.floor(v / 65536); t10 = v - c * 65536; + v = t11 + c + 65535; c = Math.floor(v / 65536); t11 = v - c * 65536; + v = t12 + c + 65535; c = Math.floor(v / 65536); t12 = v - c * 65536; + v = t13 + c + 65535; c = Math.floor(v / 65536); t13 = v - c * 65536; + v = t14 + c + 65535; c = Math.floor(v / 65536); t14 = v - c * 65536; + v = t15 + c + 65535; c = Math.floor(v / 65536); t15 = v - c * 65536; + t0 += c-1 + 37 * (c-1); + + // second car + c = 1; + v = t0 + c + 65535; c = Math.floor(v / 65536); t0 = v - c * 65536; + v = t1 + c + 65535; c = Math.floor(v / 65536); t1 = v - c * 65536; + v = t2 + c + 65535; c = Math.floor(v / 65536); t2 = v - c * 65536; + v = t3 + c + 65535; c = Math.floor(v / 65536); t3 = v - c * 65536; + v = t4 + c + 65535; c = Math.floor(v / 65536); t4 = v - c * 65536; + v = t5 + c + 65535; c = Math.floor(v / 65536); t5 = v - c * 65536; + v = t6 + c + 65535; c = Math.floor(v / 65536); t6 = v - c * 65536; + v = t7 + c + 65535; c = Math.floor(v / 65536); t7 = v - c * 65536; + v = t8 + c + 65535; c = Math.floor(v / 65536); t8 = v - c * 65536; + v = t9 + c + 65535; c = Math.floor(v / 65536); t9 = v - c * 65536; + v = t10 + c + 65535; c = Math.floor(v / 65536); t10 = v - c * 65536; + v = t11 + c + 65535; c = Math.floor(v / 65536); t11 = v - c * 65536; + v = t12 + c + 65535; c = Math.floor(v / 65536); t12 = v - c * 65536; + v = t13 + c + 65535; c = Math.floor(v / 65536); t13 = v - c * 65536; + v = t14 + c + 65535; c = Math.floor(v / 65536); t14 = v - c * 65536; + v = t15 + c + 65535; c = Math.floor(v / 65536); t15 = v - c * 65536; + t0 += c-1 + 37 * (c-1); + + o[ 0] = t0; + o[ 1] = t1; + o[ 2] = t2; + o[ 3] = t3; + o[ 4] = t4; + o[ 5] = t5; + o[ 6] = t6; + o[ 7] = t7; + o[ 8] = t8; + o[ 9] = t9; + o[10] = t10; + o[11] = t11; + o[12] = t12; + o[13] = t13; + o[14] = t14; + o[15] = t15; +} + +function S(o, a) { + M(o, a, a); +} + +function inv25519(o, i) { + var c = gf(); + var a; + for (a = 0; a < 16; a++) c[a] = i[a]; + for (a = 253; a >= 0; a--) { + S(c, c); + if(a !== 2 && a !== 4) M(c, c, i); + } + for (a = 0; a < 16; a++) o[a] = c[a]; +} + +function pow2523(o, i) { + var c = gf(); + var a; + for (a = 0; a < 16; a++) c[a] = i[a]; + for (a = 250; a >= 0; a--) { + S(c, c); + if(a !== 1) M(c, c, i); + } + for (a = 0; a < 16; a++) o[a] = c[a]; +} + +function crypto_scalarmult(q, n, p) { + var z = new Uint8Array(32); + var x = new Float64Array(80), r, i; + var a = gf(), b = gf(), c = gf(), + d = gf(), e = gf(), f = gf(); + for (i = 0; i < 31; i++) z[i] = n[i]; + z[31]=(n[31]&127)|64; + z[0]&=248; + unpack25519(x,p); + for (i = 0; i < 16; i++) { + b[i]=x[i]; + d[i]=a[i]=c[i]=0; + } + a[0]=d[0]=1; + for (i=254; i>=0; --i) { + r=(z[i>>>3]>>>(i&7))&1; + sel25519(a,b,r); + sel25519(c,d,r); + A(e,a,c); + Z(a,a,c); + A(c,b,d); + Z(b,b,d); + S(d,e); + S(f,a); + M(a,c,a); + M(c,b,e); + A(e,a,c); + Z(a,a,c); + S(b,a); + Z(c,d,f); + M(a,c,_121665); + A(a,a,d); + M(c,c,a); + M(a,d,f); + M(d,b,x); + S(b,e); + sel25519(a,b,r); + sel25519(c,d,r); + } + for (i = 0; i < 16; i++) { + x[i+16]=a[i]; + x[i+32]=c[i]; + x[i+48]=b[i]; + x[i+64]=d[i]; + } + var x32 = x.subarray(32); + var x16 = x.subarray(16); + inv25519(x32,x32); + M(x16,x16,x32); + pack25519(q,x16); + return 0; +} + +function crypto_scalarmult_base(q, n) { + return crypto_scalarmult(q, n, _9); +} + +function crypto_box_keypair(y, x) { + randombytes(x, 32); + return crypto_scalarmult_base(y, x); +} + +function crypto_box_beforenm(k, y, x) { + var s = new Uint8Array(32); + crypto_scalarmult(s, x, y); + return crypto_core_hsalsa20(k, _0, s, sigma); +} + +var crypto_box_afternm = crypto_secretbox; +var crypto_box_open_afternm = crypto_secretbox_open; + +function crypto_box(c, m, d, n, y, x) { + var k = new Uint8Array(32); + crypto_box_beforenm(k, y, x); + return crypto_box_afternm(c, m, d, n, k); +} + +function crypto_box_open(m, c, d, n, y, x) { + var k = new Uint8Array(32); + crypto_box_beforenm(k, y, x); + return crypto_box_open_afternm(m, c, d, n, k); +} + +var K = [ + 0x428a2f98, 0xd728ae22, 0x71374491, 0x23ef65cd, + 0xb5c0fbcf, 0xec4d3b2f, 0xe9b5dba5, 0x8189dbbc, + 0x3956c25b, 0xf348b538, 0x59f111f1, 0xb605d019, + 0x923f82a4, 0xaf194f9b, 0xab1c5ed5, 0xda6d8118, + 0xd807aa98, 0xa3030242, 0x12835b01, 0x45706fbe, + 0x243185be, 0x4ee4b28c, 0x550c7dc3, 0xd5ffb4e2, + 0x72be5d74, 0xf27b896f, 0x80deb1fe, 0x3b1696b1, + 0x9bdc06a7, 0x25c71235, 0xc19bf174, 0xcf692694, + 0xe49b69c1, 0x9ef14ad2, 0xefbe4786, 0x384f25e3, + 0x0fc19dc6, 0x8b8cd5b5, 0x240ca1cc, 0x77ac9c65, + 0x2de92c6f, 0x592b0275, 0x4a7484aa, 0x6ea6e483, + 0x5cb0a9dc, 0xbd41fbd4, 0x76f988da, 0x831153b5, + 0x983e5152, 0xee66dfab, 0xa831c66d, 0x2db43210, + 0xb00327c8, 0x98fb213f, 0xbf597fc7, 0xbeef0ee4, + 0xc6e00bf3, 0x3da88fc2, 0xd5a79147, 0x930aa725, + 0x06ca6351, 0xe003826f, 0x14292967, 0x0a0e6e70, + 0x27b70a85, 0x46d22ffc, 0x2e1b2138, 0x5c26c926, + 0x4d2c6dfc, 0x5ac42aed, 0x53380d13, 0x9d95b3df, + 0x650a7354, 0x8baf63de, 0x766a0abb, 0x3c77b2a8, + 0x81c2c92e, 0x47edaee6, 0x92722c85, 0x1482353b, + 0xa2bfe8a1, 0x4cf10364, 0xa81a664b, 0xbc423001, + 0xc24b8b70, 0xd0f89791, 0xc76c51a3, 0x0654be30, + 0xd192e819, 0xd6ef5218, 0xd6990624, 0x5565a910, + 0xf40e3585, 0x5771202a, 0x106aa070, 0x32bbd1b8, + 0x19a4c116, 0xb8d2d0c8, 0x1e376c08, 0x5141ab53, + 0x2748774c, 0xdf8eeb99, 0x34b0bcb5, 0xe19b48a8, + 0x391c0cb3, 0xc5c95a63, 0x4ed8aa4a, 0xe3418acb, + 0x5b9cca4f, 0x7763e373, 0x682e6ff3, 0xd6b2b8a3, + 0x748f82ee, 0x5defb2fc, 0x78a5636f, 0x43172f60, + 0x84c87814, 0xa1f0ab72, 0x8cc70208, 0x1a6439ec, + 0x90befffa, 0x23631e28, 0xa4506ceb, 0xde82bde9, + 0xbef9a3f7, 0xb2c67915, 0xc67178f2, 0xe372532b, + 0xca273ece, 0xea26619c, 0xd186b8c7, 0x21c0c207, + 0xeada7dd6, 0xcde0eb1e, 0xf57d4f7f, 0xee6ed178, + 0x06f067aa, 0x72176fba, 0x0a637dc5, 0xa2c898a6, + 0x113f9804, 0xbef90dae, 0x1b710b35, 0x131c471b, + 0x28db77f5, 0x23047d84, 0x32caab7b, 0x40c72493, + 0x3c9ebe0a, 0x15c9bebc, 0x431d67c4, 0x9c100d4c, + 0x4cc5d4be, 0xcb3e42b6, 0x597f299c, 0xfc657e2a, + 0x5fcb6fab, 0x3ad6faec, 0x6c44198c, 0x4a475817 +]; + +function crypto_hashblocks_hl(hh, hl, m, n) { + var wh = new Int32Array(16), wl = new Int32Array(16), + bh0, bh1, bh2, bh3, bh4, bh5, bh6, bh7, + bl0, bl1, bl2, bl3, bl4, bl5, bl6, bl7, + th, tl, i, j, h, l, a, b, c, d; + + var ah0 = hh[0], + ah1 = hh[1], + ah2 = hh[2], + ah3 = hh[3], + ah4 = hh[4], + ah5 = hh[5], + ah6 = hh[6], + ah7 = hh[7], + + al0 = hl[0], + al1 = hl[1], + al2 = hl[2], + al3 = hl[3], + al4 = hl[4], + al5 = hl[5], + al6 = hl[6], + al7 = hl[7]; + + var pos = 0; + while (n >= 128) { + for (i = 0; i < 16; i++) { + j = 8 * i + pos; + wh[i] = (m[j+0] << 24) | (m[j+1] << 16) | (m[j+2] << 8) | m[j+3]; + wl[i] = (m[j+4] << 24) | (m[j+5] << 16) | (m[j+6] << 8) | m[j+7]; + } + for (i = 0; i < 80; i++) { + bh0 = ah0; + bh1 = ah1; + bh2 = ah2; + bh3 = ah3; + bh4 = ah4; + bh5 = ah5; + bh6 = ah6; + bh7 = ah7; + + bl0 = al0; + bl1 = al1; + bl2 = al2; + bl3 = al3; + bl4 = al4; + bl5 = al5; + bl6 = al6; + bl7 = al7; + + // add + h = ah7; + l = al7; + + a = l & 0xffff; b = l >>> 16; + c = h & 0xffff; d = h >>> 16; + + // Sigma1 + h = ((ah4 >>> 14) | (al4 << (32-14))) ^ ((ah4 >>> 18) | (al4 << (32-18))) ^ ((al4 >>> (41-32)) | (ah4 << (32-(41-32)))); + l = ((al4 >>> 14) | (ah4 << (32-14))) ^ ((al4 >>> 18) | (ah4 << (32-18))) ^ ((ah4 >>> (41-32)) | (al4 << (32-(41-32)))); + + a += l & 0xffff; b += l >>> 16; + c += h & 0xffff; d += h >>> 16; + + // Ch + h = (ah4 & ah5) ^ (~ah4 & ah6); + l = (al4 & al5) ^ (~al4 & al6); + + a += l & 0xffff; b += l >>> 16; + c += h & 0xffff; d += h >>> 16; + + // K + h = K[i*2]; + l = K[i*2+1]; + + a += l & 0xffff; b += l >>> 16; + c += h & 0xffff; d += h >>> 16; + + // w + h = wh[i%16]; + l = wl[i%16]; + + a += l & 0xffff; b += l >>> 16; + c += h & 0xffff; d += h >>> 16; + + b += a >>> 16; + c += b >>> 16; + d += c >>> 16; + + th = c & 0xffff | d << 16; + tl = a & 0xffff | b << 16; + + // add + h = th; + l = tl; + + a = l & 0xffff; b = l >>> 16; + c = h & 0xffff; d = h >>> 16; + + // Sigma0 + h = ((ah0 >>> 28) | (al0 << (32-28))) ^ ((al0 >>> (34-32)) | (ah0 << (32-(34-32)))) ^ ((al0 >>> (39-32)) | (ah0 << (32-(39-32)))); + l = ((al0 >>> 28) | (ah0 << (32-28))) ^ ((ah0 >>> (34-32)) | (al0 << (32-(34-32)))) ^ ((ah0 >>> (39-32)) | (al0 << (32-(39-32)))); + + a += l & 0xffff; b += l >>> 16; + c += h & 0xffff; d += h >>> 16; + + // Maj + h = (ah0 & ah1) ^ (ah0 & ah2) ^ (ah1 & ah2); + l = (al0 & al1) ^ (al0 & al2) ^ (al1 & al2); + + a += l & 0xffff; b += l >>> 16; + c += h & 0xffff; d += h >>> 16; + + b += a >>> 16; + c += b >>> 16; + d += c >>> 16; + + bh7 = (c & 0xffff) | (d << 16); + bl7 = (a & 0xffff) | (b << 16); + + // add + h = bh3; + l = bl3; + + a = l & 0xffff; b = l >>> 16; + c = h & 0xffff; d = h >>> 16; + + h = th; + l = tl; + + a += l & 0xffff; b += l >>> 16; + c += h & 0xffff; d += h >>> 16; + + b += a >>> 16; + c += b >>> 16; + d += c >>> 16; + + bh3 = (c & 0xffff) | (d << 16); + bl3 = (a & 0xffff) | (b << 16); + + ah1 = bh0; + ah2 = bh1; + ah3 = bh2; + ah4 = bh3; + ah5 = bh4; + ah6 = bh5; + ah7 = bh6; + ah0 = bh7; + + al1 = bl0; + al2 = bl1; + al3 = bl2; + al4 = bl3; + al5 = bl4; + al6 = bl5; + al7 = bl6; + al0 = bl7; + + if (i%16 === 15) { + for (j = 0; j < 16; j++) { + // add + h = wh[j]; + l = wl[j]; + + a = l & 0xffff; b = l >>> 16; + c = h & 0xffff; d = h >>> 16; + + h = wh[(j+9)%16]; + l = wl[(j+9)%16]; + + a += l & 0xffff; b += l >>> 16; + c += h & 0xffff; d += h >>> 16; + + // sigma0 + th = wh[(j+1)%16]; + tl = wl[(j+1)%16]; + h = ((th >>> 1) | (tl << (32-1))) ^ ((th >>> 8) | (tl << (32-8))) ^ (th >>> 7); + l = ((tl >>> 1) | (th << (32-1))) ^ ((tl >>> 8) | (th << (32-8))) ^ ((tl >>> 7) | (th << (32-7))); + + a += l & 0xffff; b += l >>> 16; + c += h & 0xffff; d += h >>> 16; + + // sigma1 + th = wh[(j+14)%16]; + tl = wl[(j+14)%16]; + h = ((th >>> 19) | (tl << (32-19))) ^ ((tl >>> (61-32)) | (th << (32-(61-32)))) ^ (th >>> 6); + l = ((tl >>> 19) | (th << (32-19))) ^ ((th >>> (61-32)) | (tl << (32-(61-32)))) ^ ((tl >>> 6) | (th << (32-6))); + + a += l & 0xffff; b += l >>> 16; + c += h & 0xffff; d += h >>> 16; + + b += a >>> 16; + c += b >>> 16; + d += c >>> 16; + + wh[j] = (c & 0xffff) | (d << 16); + wl[j] = (a & 0xffff) | (b << 16); + } + } + } + + // add + h = ah0; + l = al0; + + a = l & 0xffff; b = l >>> 16; + c = h & 0xffff; d = h >>> 16; + + h = hh[0]; + l = hl[0]; + + a += l & 0xffff; b += l >>> 16; + c += h & 0xffff; d += h >>> 16; + + b += a >>> 16; + c += b >>> 16; + d += c >>> 16; + + hh[0] = ah0 = (c & 0xffff) | (d << 16); + hl[0] = al0 = (a & 0xffff) | (b << 16); + + h = ah1; + l = al1; + + a = l & 0xffff; b = l >>> 16; + c = h & 0xffff; d = h >>> 16; + + h = hh[1]; + l = hl[1]; + + a += l & 0xffff; b += l >>> 16; + c += h & 0xffff; d += h >>> 16; + + b += a >>> 16; + c += b >>> 16; + d += c >>> 16; + + hh[1] = ah1 = (c & 0xffff) | (d << 16); + hl[1] = al1 = (a & 0xffff) | (b << 16); + + h = ah2; + l = al2; + + a = l & 0xffff; b = l >>> 16; + c = h & 0xffff; d = h >>> 16; + + h = hh[2]; + l = hl[2]; + + a += l & 0xffff; b += l >>> 16; + c += h & 0xffff; d += h >>> 16; + + b += a >>> 16; + c += b >>> 16; + d += c >>> 16; + + hh[2] = ah2 = (c & 0xffff) | (d << 16); + hl[2] = al2 = (a & 0xffff) | (b << 16); + + h = ah3; + l = al3; + + a = l & 0xffff; b = l >>> 16; + c = h & 0xffff; d = h >>> 16; + + h = hh[3]; + l = hl[3]; + + a += l & 0xffff; b += l >>> 16; + c += h & 0xffff; d += h >>> 16; + + b += a >>> 16; + c += b >>> 16; + d += c >>> 16; + + hh[3] = ah3 = (c & 0xffff) | (d << 16); + hl[3] = al3 = (a & 0xffff) | (b << 16); + + h = ah4; + l = al4; + + a = l & 0xffff; b = l >>> 16; + c = h & 0xffff; d = h >>> 16; + + h = hh[4]; + l = hl[4]; + + a += l & 0xffff; b += l >>> 16; + c += h & 0xffff; d += h >>> 16; + + b += a >>> 16; + c += b >>> 16; + d += c >>> 16; + + hh[4] = ah4 = (c & 0xffff) | (d << 16); + hl[4] = al4 = (a & 0xffff) | (b << 16); + + h = ah5; + l = al5; + + a = l & 0xffff; b = l >>> 16; + c = h & 0xffff; d = h >>> 16; + + h = hh[5]; + l = hl[5]; + + a += l & 0xffff; b += l >>> 16; + c += h & 0xffff; d += h >>> 16; + + b += a >>> 16; + c += b >>> 16; + d += c >>> 16; + + hh[5] = ah5 = (c & 0xffff) | (d << 16); + hl[5] = al5 = (a & 0xffff) | (b << 16); + + h = ah6; + l = al6; + + a = l & 0xffff; b = l >>> 16; + c = h & 0xffff; d = h >>> 16; + + h = hh[6]; + l = hl[6]; + + a += l & 0xffff; b += l >>> 16; + c += h & 0xffff; d += h >>> 16; + + b += a >>> 16; + c += b >>> 16; + d += c >>> 16; + + hh[6] = ah6 = (c & 0xffff) | (d << 16); + hl[6] = al6 = (a & 0xffff) | (b << 16); + + h = ah7; + l = al7; + + a = l & 0xffff; b = l >>> 16; + c = h & 0xffff; d = h >>> 16; + + h = hh[7]; + l = hl[7]; + + a += l & 0xffff; b += l >>> 16; + c += h & 0xffff; d += h >>> 16; + + b += a >>> 16; + c += b >>> 16; + d += c >>> 16; + + hh[7] = ah7 = (c & 0xffff) | (d << 16); + hl[7] = al7 = (a & 0xffff) | (b << 16); + + pos += 128; + n -= 128; + } + + return n; +} + +function crypto_hash(out, m, n) { + var hh = new Int32Array(8), + hl = new Int32Array(8), + x = new Uint8Array(256), + i, b = n; + + hh[0] = 0x6a09e667; + hh[1] = 0xbb67ae85; + hh[2] = 0x3c6ef372; + hh[3] = 0xa54ff53a; + hh[4] = 0x510e527f; + hh[5] = 0x9b05688c; + hh[6] = 0x1f83d9ab; + hh[7] = 0x5be0cd19; + + hl[0] = 0xf3bcc908; + hl[1] = 0x84caa73b; + hl[2] = 0xfe94f82b; + hl[3] = 0x5f1d36f1; + hl[4] = 0xade682d1; + hl[5] = 0x2b3e6c1f; + hl[6] = 0xfb41bd6b; + hl[7] = 0x137e2179; + + crypto_hashblocks_hl(hh, hl, m, n); + n %= 128; + + for (i = 0; i < n; i++) x[i] = m[b-n+i]; + x[n] = 128; + + n = 256-128*(n<112?1:0); + x[n-9] = 0; + ts64(x, n-8, (b / 0x20000000) | 0, b << 3); + crypto_hashblocks_hl(hh, hl, x, n); + + for (i = 0; i < 8; i++) ts64(out, 8*i, hh[i], hl[i]); + + return 0; +} + +function add(p, q) { + var a = gf(), b = gf(), c = gf(), + d = gf(), e = gf(), f = gf(), + g = gf(), h = gf(), t = gf(); + + Z(a, p[1], p[0]); + Z(t, q[1], q[0]); + M(a, a, t); + A(b, p[0], p[1]); + A(t, q[0], q[1]); + M(b, b, t); + M(c, p[3], q[3]); + M(c, c, D2); + M(d, p[2], q[2]); + A(d, d, d); + Z(e, b, a); + Z(f, d, c); + A(g, d, c); + A(h, b, a); + + M(p[0], e, f); + M(p[1], h, g); + M(p[2], g, f); + M(p[3], e, h); +} + +function cswap(p, q, b) { + var i; + for (i = 0; i < 4; i++) { + sel25519(p[i], q[i], b); + } +} + +function pack(r, p) { + var tx = gf(), ty = gf(), zi = gf(); + inv25519(zi, p[2]); + M(tx, p[0], zi); + M(ty, p[1], zi); + pack25519(r, ty); + r[31] ^= par25519(tx) << 7; +} + +function scalarmult(p, q, s) { + var b, i; + set25519(p[0], gf0); + set25519(p[1], gf1); + set25519(p[2], gf1); + set25519(p[3], gf0); + for (i = 255; i >= 0; --i) { + b = (s[(i/8)|0] >> (i&7)) & 1; + cswap(p, q, b); + add(q, p); + add(p, p); + cswap(p, q, b); + } +} + +function scalarbase(p, s) { + var q = [gf(), gf(), gf(), gf()]; + set25519(q[0], X); + set25519(q[1], Y); + set25519(q[2], gf1); + M(q[3], X, Y); + scalarmult(p, q, s); +} + +function crypto_sign_keypair(pk, sk, seeded) { + var d = new Uint8Array(64); + var p = [gf(), gf(), gf(), gf()]; + var i; + + if (!seeded) randombytes(sk, 32); + crypto_hash(d, sk, 32); + d[0] &= 248; + d[31] &= 127; + d[31] |= 64; + + scalarbase(p, d); + pack(pk, p); + + for (i = 0; i < 32; i++) sk[i+32] = pk[i]; + return 0; +} + +var L = new Float64Array([0xed, 0xd3, 0xf5, 0x5c, 0x1a, 0x63, 0x12, 0x58, 0xd6, 0x9c, 0xf7, 0xa2, 0xde, 0xf9, 0xde, 0x14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x10]); + +function modL(r, x) { + var carry, i, j, k; + for (i = 63; i >= 32; --i) { + carry = 0; + for (j = i - 32, k = i - 12; j < k; ++j) { + x[j] += carry - 16 * x[i] * L[j - (i - 32)]; + carry = Math.floor((x[j] + 128) / 256); + x[j] -= carry * 256; + } + x[j] += carry; + x[i] = 0; + } + carry = 0; + for (j = 0; j < 32; j++) { + x[j] += carry - (x[31] >> 4) * L[j]; + carry = x[j] >> 8; + x[j] &= 255; + } + for (j = 0; j < 32; j++) x[j] -= carry * L[j]; + for (i = 0; i < 32; i++) { + x[i+1] += x[i] >> 8; + r[i] = x[i] & 255; + } +} + +function reduce(r) { + var x = new Float64Array(64), i; + for (i = 0; i < 64; i++) x[i] = r[i]; + for (i = 0; i < 64; i++) r[i] = 0; + modL(r, x); +} + +// Note: difference from C - smlen returned, not passed as argument. +function crypto_sign(sm, m, n, sk) { + var d = new Uint8Array(64), h = new Uint8Array(64), r = new Uint8Array(64); + var i, j, x = new Float64Array(64); + var p = [gf(), gf(), gf(), gf()]; + + crypto_hash(d, sk, 32); + d[0] &= 248; + d[31] &= 127; + d[31] |= 64; + + var smlen = n + 64; + for (i = 0; i < n; i++) sm[64 + i] = m[i]; + for (i = 0; i < 32; i++) sm[32 + i] = d[32 + i]; + + crypto_hash(r, sm.subarray(32), n+32); + reduce(r); + scalarbase(p, r); + pack(sm, p); + + for (i = 32; i < 64; i++) sm[i] = sk[i]; + crypto_hash(h, sm, n + 64); + reduce(h); + + for (i = 0; i < 64; i++) x[i] = 0; + for (i = 0; i < 32; i++) x[i] = r[i]; + for (i = 0; i < 32; i++) { + for (j = 0; j < 32; j++) { + x[i+j] += h[i] * d[j]; + } + } + + modL(sm.subarray(32), x); + return smlen; +} + +function unpackneg(r, p) { + var t = gf(), chk = gf(), num = gf(), + den = gf(), den2 = gf(), den4 = gf(), + den6 = gf(); + + set25519(r[2], gf1); + unpack25519(r[1], p); + S(num, r[1]); + M(den, num, D); + Z(num, num, r[2]); + A(den, r[2], den); + + S(den2, den); + S(den4, den2); + M(den6, den4, den2); + M(t, den6, num); + M(t, t, den); + + pow2523(t, t); + M(t, t, num); + M(t, t, den); + M(t, t, den); + M(r[0], t, den); + + S(chk, r[0]); + M(chk, chk, den); + if (neq25519(chk, num)) M(r[0], r[0], I); + + S(chk, r[0]); + M(chk, chk, den); + if (neq25519(chk, num)) return -1; + + if (par25519(r[0]) === (p[31]>>7)) Z(r[0], gf0, r[0]); + + M(r[3], r[0], r[1]); + return 0; +} + +function crypto_sign_open(m, sm, n, pk) { + var i; + var t = new Uint8Array(32), h = new Uint8Array(64); + var p = [gf(), gf(), gf(), gf()], + q = [gf(), gf(), gf(), gf()]; + + if (n < 64) return -1; + + if (unpackneg(q, pk)) return -1; + + for (i = 0; i < n; i++) m[i] = sm[i]; + for (i = 0; i < 32; i++) m[i+32] = pk[i]; + crypto_hash(h, m, n); + reduce(h); + scalarmult(p, q, h); + + scalarbase(q, sm.subarray(32)); + add(p, q); + pack(t, p); + + n -= 64; + if (crypto_verify_32(sm, 0, t, 0)) { + for (i = 0; i < n; i++) m[i] = 0; + return -1; + } + + for (i = 0; i < n; i++) m[i] = sm[i + 64]; + return n; +} + +var crypto_secretbox_KEYBYTES = 32, + crypto_secretbox_NONCEBYTES = 24, + crypto_secretbox_ZEROBYTES = 32, + crypto_secretbox_BOXZEROBYTES = 16, + crypto_scalarmult_BYTES = 32, + crypto_scalarmult_SCALARBYTES = 32, + crypto_box_PUBLICKEYBYTES = 32, + crypto_box_SECRETKEYBYTES = 32, + crypto_box_BEFORENMBYTES = 32, + crypto_box_NONCEBYTES = crypto_secretbox_NONCEBYTES, + crypto_box_ZEROBYTES = crypto_secretbox_ZEROBYTES, + crypto_box_BOXZEROBYTES = crypto_secretbox_BOXZEROBYTES, + crypto_sign_BYTES = 64, + crypto_sign_PUBLICKEYBYTES = 32, + crypto_sign_SECRETKEYBYTES = 64, + crypto_sign_SEEDBYTES = 32, + crypto_hash_BYTES = 64; + +nacl.lowlevel = { + crypto_core_hsalsa20: crypto_core_hsalsa20, + crypto_stream_xor: crypto_stream_xor, + crypto_stream: crypto_stream, + crypto_stream_salsa20_xor: crypto_stream_salsa20_xor, + crypto_stream_salsa20: crypto_stream_salsa20, + crypto_onetimeauth: crypto_onetimeauth, + crypto_onetimeauth_verify: crypto_onetimeauth_verify, + crypto_verify_16: crypto_verify_16, + crypto_verify_32: crypto_verify_32, + crypto_secretbox: crypto_secretbox, + crypto_secretbox_open: crypto_secretbox_open, + crypto_scalarmult: crypto_scalarmult, + crypto_scalarmult_base: crypto_scalarmult_base, + crypto_box_beforenm: crypto_box_beforenm, + crypto_box_afternm: crypto_box_afternm, + crypto_box: crypto_box, + crypto_box_open: crypto_box_open, + crypto_box_keypair: crypto_box_keypair, + crypto_hash: crypto_hash, + crypto_sign: crypto_sign, + crypto_sign_keypair: crypto_sign_keypair, + crypto_sign_open: crypto_sign_open, + + crypto_secretbox_KEYBYTES: crypto_secretbox_KEYBYTES, + crypto_secretbox_NONCEBYTES: crypto_secretbox_NONCEBYTES, + crypto_secretbox_ZEROBYTES: crypto_secretbox_ZEROBYTES, + crypto_secretbox_BOXZEROBYTES: crypto_secretbox_BOXZEROBYTES, + crypto_scalarmult_BYTES: crypto_scalarmult_BYTES, + crypto_scalarmult_SCALARBYTES: crypto_scalarmult_SCALARBYTES, + crypto_box_PUBLICKEYBYTES: crypto_box_PUBLICKEYBYTES, + crypto_box_SECRETKEYBYTES: crypto_box_SECRETKEYBYTES, + crypto_box_BEFORENMBYTES: crypto_box_BEFORENMBYTES, + crypto_box_NONCEBYTES: crypto_box_NONCEBYTES, + crypto_box_ZEROBYTES: crypto_box_ZEROBYTES, + crypto_box_BOXZEROBYTES: crypto_box_BOXZEROBYTES, + crypto_sign_BYTES: crypto_sign_BYTES, + crypto_sign_PUBLICKEYBYTES: crypto_sign_PUBLICKEYBYTES, + crypto_sign_SECRETKEYBYTES: crypto_sign_SECRETKEYBYTES, + crypto_sign_SEEDBYTES: crypto_sign_SEEDBYTES, + crypto_hash_BYTES: crypto_hash_BYTES, + + gf: gf, + D: D, + L: L, + pack25519: pack25519, + unpack25519: unpack25519, + M: M, + A: A, + S: S, + Z: Z, + pow2523: pow2523, + add: add, + set25519: set25519, + modL: modL, + scalarmult: scalarmult, + scalarbase: scalarbase, +}; + +/* High-level API */ + +function checkLengths(k, n) { + if (k.length !== crypto_secretbox_KEYBYTES) throw new Error('bad key size'); + if (n.length !== crypto_secretbox_NONCEBYTES) throw new Error('bad nonce size'); +} + +function checkBoxLengths(pk, sk) { + if (pk.length !== crypto_box_PUBLICKEYBYTES) throw new Error('bad public key size'); + if (sk.length !== crypto_box_SECRETKEYBYTES) throw new Error('bad secret key size'); +} + +function checkArrayTypes() { + for (var i = 0; i < arguments.length; i++) { + if (!(arguments[i] instanceof Uint8Array)) + throw new TypeError('unexpected type, use Uint8Array'); + } +} + +function cleanup(arr) { + for (var i = 0; i < arr.length; i++) arr[i] = 0; +} + +nacl.randomBytes = function(n) { + var b = new Uint8Array(n); + randombytes(b, n); + return b; +}; + +nacl.secretbox = function(msg, nonce, key) { + checkArrayTypes(msg, nonce, key); + checkLengths(key, nonce); + var m = new Uint8Array(crypto_secretbox_ZEROBYTES + msg.length); + var c = new Uint8Array(m.length); + for (var i = 0; i < msg.length; i++) m[i+crypto_secretbox_ZEROBYTES] = msg[i]; + crypto_secretbox(c, m, m.length, nonce, key); + return c.subarray(crypto_secretbox_BOXZEROBYTES); +}; + +nacl.secretbox.open = function(box, nonce, key) { + checkArrayTypes(box, nonce, key); + checkLengths(key, nonce); + var c = new Uint8Array(crypto_secretbox_BOXZEROBYTES + box.length); + var m = new Uint8Array(c.length); + for (var i = 0; i < box.length; i++) c[i+crypto_secretbox_BOXZEROBYTES] = box[i]; + if (c.length < 32) return null; + if (crypto_secretbox_open(m, c, c.length, nonce, key) !== 0) return null; + return m.subarray(crypto_secretbox_ZEROBYTES); +}; + +nacl.secretbox.keyLength = crypto_secretbox_KEYBYTES; +nacl.secretbox.nonceLength = crypto_secretbox_NONCEBYTES; +nacl.secretbox.overheadLength = crypto_secretbox_BOXZEROBYTES; + +nacl.scalarMult = function(n, p) { + checkArrayTypes(n, p); + if (n.length !== crypto_scalarmult_SCALARBYTES) throw new Error('bad n size'); + if (p.length !== crypto_scalarmult_BYTES) throw new Error('bad p size'); + var q = new Uint8Array(crypto_scalarmult_BYTES); + crypto_scalarmult(q, n, p); + return q; +}; + +nacl.scalarMult.base = function(n) { + checkArrayTypes(n); + if (n.length !== crypto_scalarmult_SCALARBYTES) throw new Error('bad n size'); + var q = new Uint8Array(crypto_scalarmult_BYTES); + crypto_scalarmult_base(q, n); + return q; +}; + +nacl.scalarMult.scalarLength = crypto_scalarmult_SCALARBYTES; +nacl.scalarMult.groupElementLength = crypto_scalarmult_BYTES; + +nacl.box = function(msg, nonce, publicKey, secretKey) { + var k = nacl.box.before(publicKey, secretKey); + return nacl.secretbox(msg, nonce, k); +}; + +nacl.box.before = function(publicKey, secretKey) { + checkArrayTypes(publicKey, secretKey); + checkBoxLengths(publicKey, secretKey); + var k = new Uint8Array(crypto_box_BEFORENMBYTES); + crypto_box_beforenm(k, publicKey, secretKey); + return k; +}; + +nacl.box.after = nacl.secretbox; + +nacl.box.open = function(msg, nonce, publicKey, secretKey) { + var k = nacl.box.before(publicKey, secretKey); + return nacl.secretbox.open(msg, nonce, k); +}; + +nacl.box.open.after = nacl.secretbox.open; + +nacl.box.keyPair = function() { + var pk = new Uint8Array(crypto_box_PUBLICKEYBYTES); + var sk = new Uint8Array(crypto_box_SECRETKEYBYTES); + crypto_box_keypair(pk, sk); + return {publicKey: pk, secretKey: sk}; +}; + +nacl.box.keyPair.fromSecretKey = function(secretKey) { + checkArrayTypes(secretKey); + if (secretKey.length !== crypto_box_SECRETKEYBYTES) + throw new Error('bad secret key size'); + var pk = new Uint8Array(crypto_box_PUBLICKEYBYTES); + crypto_scalarmult_base(pk, secretKey); + return {publicKey: pk, secretKey: new Uint8Array(secretKey)}; +}; + +nacl.box.publicKeyLength = crypto_box_PUBLICKEYBYTES; +nacl.box.secretKeyLength = crypto_box_SECRETKEYBYTES; +nacl.box.sharedKeyLength = crypto_box_BEFORENMBYTES; +nacl.box.nonceLength = crypto_box_NONCEBYTES; +nacl.box.overheadLength = nacl.secretbox.overheadLength; + +nacl.sign = function(msg, secretKey) { + checkArrayTypes(msg, secretKey); + if (secretKey.length !== crypto_sign_SECRETKEYBYTES) + throw new Error('bad secret key size'); + var signedMsg = new Uint8Array(crypto_sign_BYTES+msg.length); + crypto_sign(signedMsg, msg, msg.length, secretKey); + return signedMsg; +}; + +nacl.sign.open = function(signedMsg, publicKey) { + checkArrayTypes(signedMsg, publicKey); + if (publicKey.length !== crypto_sign_PUBLICKEYBYTES) + throw new Error('bad public key size'); + var tmp = new Uint8Array(signedMsg.length); + var mlen = crypto_sign_open(tmp, signedMsg, signedMsg.length, publicKey); + if (mlen < 0) return null; + var m = new Uint8Array(mlen); + for (var i = 0; i < m.length; i++) m[i] = tmp[i]; + return m; +}; + +nacl.sign.detached = function(msg, secretKey) { + var signedMsg = nacl.sign(msg, secretKey); + var sig = new Uint8Array(crypto_sign_BYTES); + for (var i = 0; i < sig.length; i++) sig[i] = signedMsg[i]; + return sig; +}; + +nacl.sign.detached.verify = function(msg, sig, publicKey) { + checkArrayTypes(msg, sig, publicKey); + if (sig.length !== crypto_sign_BYTES) + throw new Error('bad signature size'); + if (publicKey.length !== crypto_sign_PUBLICKEYBYTES) + throw new Error('bad public key size'); + var sm = new Uint8Array(crypto_sign_BYTES + msg.length); + var m = new Uint8Array(crypto_sign_BYTES + msg.length); + var i; + for (i = 0; i < crypto_sign_BYTES; i++) sm[i] = sig[i]; + for (i = 0; i < msg.length; i++) sm[i+crypto_sign_BYTES] = msg[i]; + return (crypto_sign_open(m, sm, sm.length, publicKey) >= 0); +}; + +nacl.sign.keyPair = function() { + var pk = new Uint8Array(crypto_sign_PUBLICKEYBYTES); + var sk = new Uint8Array(crypto_sign_SECRETKEYBYTES); + crypto_sign_keypair(pk, sk); + return {publicKey: pk, secretKey: sk}; +}; + +nacl.sign.keyPair.fromSecretKey = function(secretKey) { + checkArrayTypes(secretKey); + if (secretKey.length !== crypto_sign_SECRETKEYBYTES) + throw new Error('bad secret key size'); + var pk = new Uint8Array(crypto_sign_PUBLICKEYBYTES); + for (var i = 0; i < pk.length; i++) pk[i] = secretKey[32+i]; + return {publicKey: pk, secretKey: new Uint8Array(secretKey)}; +}; + +nacl.sign.keyPair.fromSeed = function(seed) { + checkArrayTypes(seed); + if (seed.length !== crypto_sign_SEEDBYTES) + throw new Error('bad seed size'); + var pk = new Uint8Array(crypto_sign_PUBLICKEYBYTES); + var sk = new Uint8Array(crypto_sign_SECRETKEYBYTES); + for (var i = 0; i < 32; i++) sk[i] = seed[i]; + crypto_sign_keypair(pk, sk, true); + return {publicKey: pk, secretKey: sk}; +}; + +nacl.sign.publicKeyLength = crypto_sign_PUBLICKEYBYTES; +nacl.sign.secretKeyLength = crypto_sign_SECRETKEYBYTES; +nacl.sign.seedLength = crypto_sign_SEEDBYTES; +nacl.sign.signatureLength = crypto_sign_BYTES; + +nacl.hash = function(msg) { + checkArrayTypes(msg); + var h = new Uint8Array(crypto_hash_BYTES); + crypto_hash(h, msg, msg.length); + return h; +}; + +nacl.hash.hashLength = crypto_hash_BYTES; + +nacl.verify = function(x, y) { + checkArrayTypes(x, y); + // Zero length arguments are considered not equal. + if (x.length === 0 || y.length === 0) return false; + if (x.length !== y.length) return false; + return (vn(x, 0, y, 0, x.length) === 0) ? true : false; +}; + +nacl.setPRNG = function(fn) { + randombytes = fn; +}; + +(function() { + // Initialize PRNG if environment provides CSPRNG. + // If not, methods calling randombytes will throw. + var crypto = typeof self !== 'undefined' ? (self.crypto || self.msCrypto) : null; + if (crypto && crypto.getRandomValues) { + // Browsers. + var QUOTA = 65536; + nacl.setPRNG(function(x, n) { + var i, v = new Uint8Array(n); + for (i = 0; i < n; i += QUOTA) { + crypto.getRandomValues(v.subarray(i, i + Math.min(n - i, QUOTA))); + } + for (i = 0; i < n; i++) x[i] = v[i]; + cleanup(v); + }); + } else if (typeof require !== 'undefined') { + // Node.js. + crypto = require('crypto'); + if (crypto && crypto.randomBytes) { + nacl.setPRNG(function(x, n) { + var i, v = crypto.randomBytes(n); + for (i = 0; i < n; i++) x[i] = v[i]; + cleanup(v); + }); + } + } +})(); + +})(typeof module !== 'undefined' && module.exports ? module.exports : (self.nacl = self.nacl || {})); diff --git a/core/third-party/nacl-fast_orig.js b/core/third-party/nacl-fast_orig.js new file mode 100644 index 0000000..7ea5fb5 --- /dev/null +++ b/core/third-party/nacl-fast_orig.js @@ -0,0 +1,2391 @@ +(function(nacl) { +'use strict'; + +// Ported in 2014 by Dmitry Chestnykh and Devi Mandiri. +// Public domain. +// +// Implementation derived from TweetNaCl version 20140427. +// See for details: http://tweetnacl.cr.yp.to/ + +var gf = function(init) { + var i, r = new Float64Array(16); + if (init) for (i = 0; i < init.length; i++) r[i] = init[i]; + return r; +}; + +// Pluggable, initialized in high-level API below. +var randombytes = function(/* x, n */) { throw new Error('no PRNG'); }; + +var _0 = new Uint8Array(16); +var _9 = new Uint8Array(32); _9[0] = 9; + +var gf0 = gf(), + gf1 = gf([1]), + _121665 = gf([0xdb41, 1]), + D = gf([0x78a3, 0x1359, 0x4dca, 0x75eb, 0xd8ab, 0x4141, 0x0a4d, 0x0070, 0xe898, 0x7779, 0x4079, 0x8cc7, 0xfe73, 0x2b6f, 0x6cee, 0x5203]), + D2 = gf([0xf159, 0x26b2, 0x9b94, 0xebd6, 0xb156, 0x8283, 0x149a, 0x00e0, 0xd130, 0xeef3, 0x80f2, 0x198e, 0xfce7, 0x56df, 0xd9dc, 0x2406]), + X = gf([0xd51a, 0x8f25, 0x2d60, 0xc956, 0xa7b2, 0x9525, 0xc760, 0x692c, 0xdc5c, 0xfdd6, 0xe231, 0xc0a4, 0x53fe, 0xcd6e, 0x36d3, 0x2169]), + Y = gf([0x6658, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666]), + I = gf([0xa0b0, 0x4a0e, 0x1b27, 0xc4ee, 0xe478, 0xad2f, 0x1806, 0x2f43, 0xd7a7, 0x3dfb, 0x0099, 0x2b4d, 0xdf0b, 0x4fc1, 0x2480, 0x2b83]); + +function ts64(x, i, h, l) { + x[i] = (h >> 24) & 0xff; + x[i+1] = (h >> 16) & 0xff; + x[i+2] = (h >> 8) & 0xff; + x[i+3] = h & 0xff; + x[i+4] = (l >> 24) & 0xff; + x[i+5] = (l >> 16) & 0xff; + x[i+6] = (l >> 8) & 0xff; + x[i+7] = l & 0xff; +} + +function vn(x, xi, y, yi, n) { + var i,d = 0; + for (i = 0; i < n; i++) d |= x[xi+i]^y[yi+i]; + return (1 & ((d - 1) >>> 8)) - 1; +} + +function crypto_verify_16(x, xi, y, yi) { + return vn(x,xi,y,yi,16); +} + +function crypto_verify_32(x, xi, y, yi) { + return vn(x,xi,y,yi,32); +} + +function core_salsa20(o, p, k, c) { + var j0 = c[ 0] & 0xff | (c[ 1] & 0xff)<<8 | (c[ 2] & 0xff)<<16 | (c[ 3] & 0xff)<<24, + j1 = k[ 0] & 0xff | (k[ 1] & 0xff)<<8 | (k[ 2] & 0xff)<<16 | (k[ 3] & 0xff)<<24, + j2 = k[ 4] & 0xff | (k[ 5] & 0xff)<<8 | (k[ 6] & 0xff)<<16 | (k[ 7] & 0xff)<<24, + j3 = k[ 8] & 0xff | (k[ 9] & 0xff)<<8 | (k[10] & 0xff)<<16 | (k[11] & 0xff)<<24, + j4 = k[12] & 0xff | (k[13] & 0xff)<<8 | (k[14] & 0xff)<<16 | (k[15] & 0xff)<<24, + j5 = c[ 4] & 0xff | (c[ 5] & 0xff)<<8 | (c[ 6] & 0xff)<<16 | (c[ 7] & 0xff)<<24, + j6 = p[ 0] & 0xff | (p[ 1] & 0xff)<<8 | (p[ 2] & 0xff)<<16 | (p[ 3] & 0xff)<<24, + j7 = p[ 4] & 0xff | (p[ 5] & 0xff)<<8 | (p[ 6] & 0xff)<<16 | (p[ 7] & 0xff)<<24, + j8 = p[ 8] & 0xff | (p[ 9] & 0xff)<<8 | (p[10] & 0xff)<<16 | (p[11] & 0xff)<<24, + j9 = p[12] & 0xff | (p[13] & 0xff)<<8 | (p[14] & 0xff)<<16 | (p[15] & 0xff)<<24, + j10 = c[ 8] & 0xff | (c[ 9] & 0xff)<<8 | (c[10] & 0xff)<<16 | (c[11] & 0xff)<<24, + j11 = k[16] & 0xff | (k[17] & 0xff)<<8 | (k[18] & 0xff)<<16 | (k[19] & 0xff)<<24, + j12 = k[20] & 0xff | (k[21] & 0xff)<<8 | (k[22] & 0xff)<<16 | (k[23] & 0xff)<<24, + j13 = k[24] & 0xff | (k[25] & 0xff)<<8 | (k[26] & 0xff)<<16 | (k[27] & 0xff)<<24, + j14 = k[28] & 0xff | (k[29] & 0xff)<<8 | (k[30] & 0xff)<<16 | (k[31] & 0xff)<<24, + j15 = c[12] & 0xff | (c[13] & 0xff)<<8 | (c[14] & 0xff)<<16 | (c[15] & 0xff)<<24; + + var x0 = j0, x1 = j1, x2 = j2, x3 = j3, x4 = j4, x5 = j5, x6 = j6, x7 = j7, + x8 = j8, x9 = j9, x10 = j10, x11 = j11, x12 = j12, x13 = j13, x14 = j14, + x15 = j15, u; + + for (var i = 0; i < 20; i += 2) { + u = x0 + x12 | 0; + x4 ^= u<<7 | u>>>(32-7); + u = x4 + x0 | 0; + x8 ^= u<<9 | u>>>(32-9); + u = x8 + x4 | 0; + x12 ^= u<<13 | u>>>(32-13); + u = x12 + x8 | 0; + x0 ^= u<<18 | u>>>(32-18); + + u = x5 + x1 | 0; + x9 ^= u<<7 | u>>>(32-7); + u = x9 + x5 | 0; + x13 ^= u<<9 | u>>>(32-9); + u = x13 + x9 | 0; + x1 ^= u<<13 | u>>>(32-13); + u = x1 + x13 | 0; + x5 ^= u<<18 | u>>>(32-18); + + u = x10 + x6 | 0; + x14 ^= u<<7 | u>>>(32-7); + u = x14 + x10 | 0; + x2 ^= u<<9 | u>>>(32-9); + u = x2 + x14 | 0; + x6 ^= u<<13 | u>>>(32-13); + u = x6 + x2 | 0; + x10 ^= u<<18 | u>>>(32-18); + + u = x15 + x11 | 0; + x3 ^= u<<7 | u>>>(32-7); + u = x3 + x15 | 0; + x7 ^= u<<9 | u>>>(32-9); + u = x7 + x3 | 0; + x11 ^= u<<13 | u>>>(32-13); + u = x11 + x7 | 0; + x15 ^= u<<18 | u>>>(32-18); + + u = x0 + x3 | 0; + x1 ^= u<<7 | u>>>(32-7); + u = x1 + x0 | 0; + x2 ^= u<<9 | u>>>(32-9); + u = x2 + x1 | 0; + x3 ^= u<<13 | u>>>(32-13); + u = x3 + x2 | 0; + x0 ^= u<<18 | u>>>(32-18); + + u = x5 + x4 | 0; + x6 ^= u<<7 | u>>>(32-7); + u = x6 + x5 | 0; + x7 ^= u<<9 | u>>>(32-9); + u = x7 + x6 | 0; + x4 ^= u<<13 | u>>>(32-13); + u = x4 + x7 | 0; + x5 ^= u<<18 | u>>>(32-18); + + u = x10 + x9 | 0; + x11 ^= u<<7 | u>>>(32-7); + u = x11 + x10 | 0; + x8 ^= u<<9 | u>>>(32-9); + u = x8 + x11 | 0; + x9 ^= u<<13 | u>>>(32-13); + u = x9 + x8 | 0; + x10 ^= u<<18 | u>>>(32-18); + + u = x15 + x14 | 0; + x12 ^= u<<7 | u>>>(32-7); + u = x12 + x15 | 0; + x13 ^= u<<9 | u>>>(32-9); + u = x13 + x12 | 0; + x14 ^= u<<13 | u>>>(32-13); + u = x14 + x13 | 0; + x15 ^= u<<18 | u>>>(32-18); + } + x0 = x0 + j0 | 0; + x1 = x1 + j1 | 0; + x2 = x2 + j2 | 0; + x3 = x3 + j3 | 0; + x4 = x4 + j4 | 0; + x5 = x5 + j5 | 0; + x6 = x6 + j6 | 0; + x7 = x7 + j7 | 0; + x8 = x8 + j8 | 0; + x9 = x9 + j9 | 0; + x10 = x10 + j10 | 0; + x11 = x11 + j11 | 0; + x12 = x12 + j12 | 0; + x13 = x13 + j13 | 0; + x14 = x14 + j14 | 0; + x15 = x15 + j15 | 0; + + o[ 0] = x0 >>> 0 & 0xff; + o[ 1] = x0 >>> 8 & 0xff; + o[ 2] = x0 >>> 16 & 0xff; + o[ 3] = x0 >>> 24 & 0xff; + + o[ 4] = x1 >>> 0 & 0xff; + o[ 5] = x1 >>> 8 & 0xff; + o[ 6] = x1 >>> 16 & 0xff; + o[ 7] = x1 >>> 24 & 0xff; + + o[ 8] = x2 >>> 0 & 0xff; + o[ 9] = x2 >>> 8 & 0xff; + o[10] = x2 >>> 16 & 0xff; + o[11] = x2 >>> 24 & 0xff; + + o[12] = x3 >>> 0 & 0xff; + o[13] = x3 >>> 8 & 0xff; + o[14] = x3 >>> 16 & 0xff; + o[15] = x3 >>> 24 & 0xff; + + o[16] = x4 >>> 0 & 0xff; + o[17] = x4 >>> 8 & 0xff; + o[18] = x4 >>> 16 & 0xff; + o[19] = x4 >>> 24 & 0xff; + + o[20] = x5 >>> 0 & 0xff; + o[21] = x5 >>> 8 & 0xff; + o[22] = x5 >>> 16 & 0xff; + o[23] = x5 >>> 24 & 0xff; + + o[24] = x6 >>> 0 & 0xff; + o[25] = x6 >>> 8 & 0xff; + o[26] = x6 >>> 16 & 0xff; + o[27] = x6 >>> 24 & 0xff; + + o[28] = x7 >>> 0 & 0xff; + o[29] = x7 >>> 8 & 0xff; + o[30] = x7 >>> 16 & 0xff; + o[31] = x7 >>> 24 & 0xff; + + o[32] = x8 >>> 0 & 0xff; + o[33] = x8 >>> 8 & 0xff; + o[34] = x8 >>> 16 & 0xff; + o[35] = x8 >>> 24 & 0xff; + + o[36] = x9 >>> 0 & 0xff; + o[37] = x9 >>> 8 & 0xff; + o[38] = x9 >>> 16 & 0xff; + o[39] = x9 >>> 24 & 0xff; + + o[40] = x10 >>> 0 & 0xff; + o[41] = x10 >>> 8 & 0xff; + o[42] = x10 >>> 16 & 0xff; + o[43] = x10 >>> 24 & 0xff; + + o[44] = x11 >>> 0 & 0xff; + o[45] = x11 >>> 8 & 0xff; + o[46] = x11 >>> 16 & 0xff; + o[47] = x11 >>> 24 & 0xff; + + o[48] = x12 >>> 0 & 0xff; + o[49] = x12 >>> 8 & 0xff; + o[50] = x12 >>> 16 & 0xff; + o[51] = x12 >>> 24 & 0xff; + + o[52] = x13 >>> 0 & 0xff; + o[53] = x13 >>> 8 & 0xff; + o[54] = x13 >>> 16 & 0xff; + o[55] = x13 >>> 24 & 0xff; + + o[56] = x14 >>> 0 & 0xff; + o[57] = x14 >>> 8 & 0xff; + o[58] = x14 >>> 16 & 0xff; + o[59] = x14 >>> 24 & 0xff; + + o[60] = x15 >>> 0 & 0xff; + o[61] = x15 >>> 8 & 0xff; + o[62] = x15 >>> 16 & 0xff; + o[63] = x15 >>> 24 & 0xff; +} + +function core_hsalsa20(o,p,k,c) { + var j0 = c[ 0] & 0xff | (c[ 1] & 0xff)<<8 | (c[ 2] & 0xff)<<16 | (c[ 3] & 0xff)<<24, + j1 = k[ 0] & 0xff | (k[ 1] & 0xff)<<8 | (k[ 2] & 0xff)<<16 | (k[ 3] & 0xff)<<24, + j2 = k[ 4] & 0xff | (k[ 5] & 0xff)<<8 | (k[ 6] & 0xff)<<16 | (k[ 7] & 0xff)<<24, + j3 = k[ 8] & 0xff | (k[ 9] & 0xff)<<8 | (k[10] & 0xff)<<16 | (k[11] & 0xff)<<24, + j4 = k[12] & 0xff | (k[13] & 0xff)<<8 | (k[14] & 0xff)<<16 | (k[15] & 0xff)<<24, + j5 = c[ 4] & 0xff | (c[ 5] & 0xff)<<8 | (c[ 6] & 0xff)<<16 | (c[ 7] & 0xff)<<24, + j6 = p[ 0] & 0xff | (p[ 1] & 0xff)<<8 | (p[ 2] & 0xff)<<16 | (p[ 3] & 0xff)<<24, + j7 = p[ 4] & 0xff | (p[ 5] & 0xff)<<8 | (p[ 6] & 0xff)<<16 | (p[ 7] & 0xff)<<24, + j8 = p[ 8] & 0xff | (p[ 9] & 0xff)<<8 | (p[10] & 0xff)<<16 | (p[11] & 0xff)<<24, + j9 = p[12] & 0xff | (p[13] & 0xff)<<8 | (p[14] & 0xff)<<16 | (p[15] & 0xff)<<24, + j10 = c[ 8] & 0xff | (c[ 9] & 0xff)<<8 | (c[10] & 0xff)<<16 | (c[11] & 0xff)<<24, + j11 = k[16] & 0xff | (k[17] & 0xff)<<8 | (k[18] & 0xff)<<16 | (k[19] & 0xff)<<24, + j12 = k[20] & 0xff | (k[21] & 0xff)<<8 | (k[22] & 0xff)<<16 | (k[23] & 0xff)<<24, + j13 = k[24] & 0xff | (k[25] & 0xff)<<8 | (k[26] & 0xff)<<16 | (k[27] & 0xff)<<24, + j14 = k[28] & 0xff | (k[29] & 0xff)<<8 | (k[30] & 0xff)<<16 | (k[31] & 0xff)<<24, + j15 = c[12] & 0xff | (c[13] & 0xff)<<8 | (c[14] & 0xff)<<16 | (c[15] & 0xff)<<24; + + var x0 = j0, x1 = j1, x2 = j2, x3 = j3, x4 = j4, x5 = j5, x6 = j6, x7 = j7, + x8 = j8, x9 = j9, x10 = j10, x11 = j11, x12 = j12, x13 = j13, x14 = j14, + x15 = j15, u; + + for (var i = 0; i < 20; i += 2) { + u = x0 + x12 | 0; + x4 ^= u<<7 | u>>>(32-7); + u = x4 + x0 | 0; + x8 ^= u<<9 | u>>>(32-9); + u = x8 + x4 | 0; + x12 ^= u<<13 | u>>>(32-13); + u = x12 + x8 | 0; + x0 ^= u<<18 | u>>>(32-18); + + u = x5 + x1 | 0; + x9 ^= u<<7 | u>>>(32-7); + u = x9 + x5 | 0; + x13 ^= u<<9 | u>>>(32-9); + u = x13 + x9 | 0; + x1 ^= u<<13 | u>>>(32-13); + u = x1 + x13 | 0; + x5 ^= u<<18 | u>>>(32-18); + + u = x10 + x6 | 0; + x14 ^= u<<7 | u>>>(32-7); + u = x14 + x10 | 0; + x2 ^= u<<9 | u>>>(32-9); + u = x2 + x14 | 0; + x6 ^= u<<13 | u>>>(32-13); + u = x6 + x2 | 0; + x10 ^= u<<18 | u>>>(32-18); + + u = x15 + x11 | 0; + x3 ^= u<<7 | u>>>(32-7); + u = x3 + x15 | 0; + x7 ^= u<<9 | u>>>(32-9); + u = x7 + x3 | 0; + x11 ^= u<<13 | u>>>(32-13); + u = x11 + x7 | 0; + x15 ^= u<<18 | u>>>(32-18); + + u = x0 + x3 | 0; + x1 ^= u<<7 | u>>>(32-7); + u = x1 + x0 | 0; + x2 ^= u<<9 | u>>>(32-9); + u = x2 + x1 | 0; + x3 ^= u<<13 | u>>>(32-13); + u = x3 + x2 | 0; + x0 ^= u<<18 | u>>>(32-18); + + u = x5 + x4 | 0; + x6 ^= u<<7 | u>>>(32-7); + u = x6 + x5 | 0; + x7 ^= u<<9 | u>>>(32-9); + u = x7 + x6 | 0; + x4 ^= u<<13 | u>>>(32-13); + u = x4 + x7 | 0; + x5 ^= u<<18 | u>>>(32-18); + + u = x10 + x9 | 0; + x11 ^= u<<7 | u>>>(32-7); + u = x11 + x10 | 0; + x8 ^= u<<9 | u>>>(32-9); + u = x8 + x11 | 0; + x9 ^= u<<13 | u>>>(32-13); + u = x9 + x8 | 0; + x10 ^= u<<18 | u>>>(32-18); + + u = x15 + x14 | 0; + x12 ^= u<<7 | u>>>(32-7); + u = x12 + x15 | 0; + x13 ^= u<<9 | u>>>(32-9); + u = x13 + x12 | 0; + x14 ^= u<<13 | u>>>(32-13); + u = x14 + x13 | 0; + x15 ^= u<<18 | u>>>(32-18); + } + + o[ 0] = x0 >>> 0 & 0xff; + o[ 1] = x0 >>> 8 & 0xff; + o[ 2] = x0 >>> 16 & 0xff; + o[ 3] = x0 >>> 24 & 0xff; + + o[ 4] = x5 >>> 0 & 0xff; + o[ 5] = x5 >>> 8 & 0xff; + o[ 6] = x5 >>> 16 & 0xff; + o[ 7] = x5 >>> 24 & 0xff; + + o[ 8] = x10 >>> 0 & 0xff; + o[ 9] = x10 >>> 8 & 0xff; + o[10] = x10 >>> 16 & 0xff; + o[11] = x10 >>> 24 & 0xff; + + o[12] = x15 >>> 0 & 0xff; + o[13] = x15 >>> 8 & 0xff; + o[14] = x15 >>> 16 & 0xff; + o[15] = x15 >>> 24 & 0xff; + + o[16] = x6 >>> 0 & 0xff; + o[17] = x6 >>> 8 & 0xff; + o[18] = x6 >>> 16 & 0xff; + o[19] = x6 >>> 24 & 0xff; + + o[20] = x7 >>> 0 & 0xff; + o[21] = x7 >>> 8 & 0xff; + o[22] = x7 >>> 16 & 0xff; + o[23] = x7 >>> 24 & 0xff; + + o[24] = x8 >>> 0 & 0xff; + o[25] = x8 >>> 8 & 0xff; + o[26] = x8 >>> 16 & 0xff; + o[27] = x8 >>> 24 & 0xff; + + o[28] = x9 >>> 0 & 0xff; + o[29] = x9 >>> 8 & 0xff; + o[30] = x9 >>> 16 & 0xff; + o[31] = x9 >>> 24 & 0xff; +} + +function crypto_core_salsa20(out,inp,k,c) { + core_salsa20(out,inp,k,c); +} + +function crypto_core_hsalsa20(out,inp,k,c) { + core_hsalsa20(out,inp,k,c); +} + +var sigma = new Uint8Array([101, 120, 112, 97, 110, 100, 32, 51, 50, 45, 98, 121, 116, 101, 32, 107]); + // "expand 32-byte k" + +function crypto_stream_salsa20_xor(c,cpos,m,mpos,b,n,k) { + var z = new Uint8Array(16), x = new Uint8Array(64); + var u, i; + for (i = 0; i < 16; i++) z[i] = 0; + for (i = 0; i < 8; i++) z[i] = n[i]; + while (b >= 64) { + crypto_core_salsa20(x,z,k,sigma); + for (i = 0; i < 64; i++) c[cpos+i] = m[mpos+i] ^ x[i]; + u = 1; + for (i = 8; i < 16; i++) { + u = u + (z[i] & 0xff) | 0; + z[i] = u & 0xff; + u >>>= 8; + } + b -= 64; + cpos += 64; + mpos += 64; + } + if (b > 0) { + crypto_core_salsa20(x,z,k,sigma); + for (i = 0; i < b; i++) c[cpos+i] = m[mpos+i] ^ x[i]; + } + return 0; +} + +function crypto_stream_salsa20(c,cpos,b,n,k) { + var z = new Uint8Array(16), x = new Uint8Array(64); + var u, i; + for (i = 0; i < 16; i++) z[i] = 0; + for (i = 0; i < 8; i++) z[i] = n[i]; + while (b >= 64) { + crypto_core_salsa20(x,z,k,sigma); + for (i = 0; i < 64; i++) c[cpos+i] = x[i]; + u = 1; + for (i = 8; i < 16; i++) { + u = u + (z[i] & 0xff) | 0; + z[i] = u & 0xff; + u >>>= 8; + } + b -= 64; + cpos += 64; + } + if (b > 0) { + crypto_core_salsa20(x,z,k,sigma); + for (i = 0; i < b; i++) c[cpos+i] = x[i]; + } + return 0; +} + +function crypto_stream(c,cpos,d,n,k) { + var s = new Uint8Array(32); + crypto_core_hsalsa20(s,n,k,sigma); + var sn = new Uint8Array(8); + for (var i = 0; i < 8; i++) sn[i] = n[i+16]; + return crypto_stream_salsa20(c,cpos,d,sn,s); +} + +function crypto_stream_xor(c,cpos,m,mpos,d,n,k) { + var s = new Uint8Array(32); + crypto_core_hsalsa20(s,n,k,sigma); + var sn = new Uint8Array(8); + for (var i = 0; i < 8; i++) sn[i] = n[i+16]; + return crypto_stream_salsa20_xor(c,cpos,m,mpos,d,sn,s); +} + +/* +* Port of Andrew Moon's Poly1305-donna-16. Public domain. +* https://github.com/floodyberry/poly1305-donna +*/ + +var poly1305 = function(key) { + this.buffer = new Uint8Array(16); + this.r = new Uint16Array(10); + this.h = new Uint16Array(10); + this.pad = new Uint16Array(8); + this.leftover = 0; + this.fin = 0; + + var t0, t1, t2, t3, t4, t5, t6, t7; + + t0 = key[ 0] & 0xff | (key[ 1] & 0xff) << 8; this.r[0] = ( t0 ) & 0x1fff; + t1 = key[ 2] & 0xff | (key[ 3] & 0xff) << 8; this.r[1] = ((t0 >>> 13) | (t1 << 3)) & 0x1fff; + t2 = key[ 4] & 0xff | (key[ 5] & 0xff) << 8; this.r[2] = ((t1 >>> 10) | (t2 << 6)) & 0x1f03; + t3 = key[ 6] & 0xff | (key[ 7] & 0xff) << 8; this.r[3] = ((t2 >>> 7) | (t3 << 9)) & 0x1fff; + t4 = key[ 8] & 0xff | (key[ 9] & 0xff) << 8; this.r[4] = ((t3 >>> 4) | (t4 << 12)) & 0x00ff; + this.r[5] = ((t4 >>> 1)) & 0x1ffe; + t5 = key[10] & 0xff | (key[11] & 0xff) << 8; this.r[6] = ((t4 >>> 14) | (t5 << 2)) & 0x1fff; + t6 = key[12] & 0xff | (key[13] & 0xff) << 8; this.r[7] = ((t5 >>> 11) | (t6 << 5)) & 0x1f81; + t7 = key[14] & 0xff | (key[15] & 0xff) << 8; this.r[8] = ((t6 >>> 8) | (t7 << 8)) & 0x1fff; + this.r[9] = ((t7 >>> 5)) & 0x007f; + + this.pad[0] = key[16] & 0xff | (key[17] & 0xff) << 8; + this.pad[1] = key[18] & 0xff | (key[19] & 0xff) << 8; + this.pad[2] = key[20] & 0xff | (key[21] & 0xff) << 8; + this.pad[3] = key[22] & 0xff | (key[23] & 0xff) << 8; + this.pad[4] = key[24] & 0xff | (key[25] & 0xff) << 8; + this.pad[5] = key[26] & 0xff | (key[27] & 0xff) << 8; + this.pad[6] = key[28] & 0xff | (key[29] & 0xff) << 8; + this.pad[7] = key[30] & 0xff | (key[31] & 0xff) << 8; +}; + +poly1305.prototype.blocks = function(m, mpos, bytes) { + var hibit = this.fin ? 0 : (1 << 11); + var t0, t1, t2, t3, t4, t5, t6, t7, c; + var d0, d1, d2, d3, d4, d5, d6, d7, d8, d9; + + var h0 = this.h[0], + h1 = this.h[1], + h2 = this.h[2], + h3 = this.h[3], + h4 = this.h[4], + h5 = this.h[5], + h6 = this.h[6], + h7 = this.h[7], + h8 = this.h[8], + h9 = this.h[9]; + + var r0 = this.r[0], + r1 = this.r[1], + r2 = this.r[2], + r3 = this.r[3], + r4 = this.r[4], + r5 = this.r[5], + r6 = this.r[6], + r7 = this.r[7], + r8 = this.r[8], + r9 = this.r[9]; + + while (bytes >= 16) { + t0 = m[mpos+ 0] & 0xff | (m[mpos+ 1] & 0xff) << 8; h0 += ( t0 ) & 0x1fff; + t1 = m[mpos+ 2] & 0xff | (m[mpos+ 3] & 0xff) << 8; h1 += ((t0 >>> 13) | (t1 << 3)) & 0x1fff; + t2 = m[mpos+ 4] & 0xff | (m[mpos+ 5] & 0xff) << 8; h2 += ((t1 >>> 10) | (t2 << 6)) & 0x1fff; + t3 = m[mpos+ 6] & 0xff | (m[mpos+ 7] & 0xff) << 8; h3 += ((t2 >>> 7) | (t3 << 9)) & 0x1fff; + t4 = m[mpos+ 8] & 0xff | (m[mpos+ 9] & 0xff) << 8; h4 += ((t3 >>> 4) | (t4 << 12)) & 0x1fff; + h5 += ((t4 >>> 1)) & 0x1fff; + t5 = m[mpos+10] & 0xff | (m[mpos+11] & 0xff) << 8; h6 += ((t4 >>> 14) | (t5 << 2)) & 0x1fff; + t6 = m[mpos+12] & 0xff | (m[mpos+13] & 0xff) << 8; h7 += ((t5 >>> 11) | (t6 << 5)) & 0x1fff; + t7 = m[mpos+14] & 0xff | (m[mpos+15] & 0xff) << 8; h8 += ((t6 >>> 8) | (t7 << 8)) & 0x1fff; + h9 += ((t7 >>> 5)) | hibit; + + c = 0; + + d0 = c; + d0 += h0 * r0; + d0 += h1 * (5 * r9); + d0 += h2 * (5 * r8); + d0 += h3 * (5 * r7); + d0 += h4 * (5 * r6); + c = (d0 >>> 13); d0 &= 0x1fff; + d0 += h5 * (5 * r5); + d0 += h6 * (5 * r4); + d0 += h7 * (5 * r3); + d0 += h8 * (5 * r2); + d0 += h9 * (5 * r1); + c += (d0 >>> 13); d0 &= 0x1fff; + + d1 = c; + d1 += h0 * r1; + d1 += h1 * r0; + d1 += h2 * (5 * r9); + d1 += h3 * (5 * r8); + d1 += h4 * (5 * r7); + c = (d1 >>> 13); d1 &= 0x1fff; + d1 += h5 * (5 * r6); + d1 += h6 * (5 * r5); + d1 += h7 * (5 * r4); + d1 += h8 * (5 * r3); + d1 += h9 * (5 * r2); + c += (d1 >>> 13); d1 &= 0x1fff; + + d2 = c; + d2 += h0 * r2; + d2 += h1 * r1; + d2 += h2 * r0; + d2 += h3 * (5 * r9); + d2 += h4 * (5 * r8); + c = (d2 >>> 13); d2 &= 0x1fff; + d2 += h5 * (5 * r7); + d2 += h6 * (5 * r6); + d2 += h7 * (5 * r5); + d2 += h8 * (5 * r4); + d2 += h9 * (5 * r3); + c += (d2 >>> 13); d2 &= 0x1fff; + + d3 = c; + d3 += h0 * r3; + d3 += h1 * r2; + d3 += h2 * r1; + d3 += h3 * r0; + d3 += h4 * (5 * r9); + c = (d3 >>> 13); d3 &= 0x1fff; + d3 += h5 * (5 * r8); + d3 += h6 * (5 * r7); + d3 += h7 * (5 * r6); + d3 += h8 * (5 * r5); + d3 += h9 * (5 * r4); + c += (d3 >>> 13); d3 &= 0x1fff; + + d4 = c; + d4 += h0 * r4; + d4 += h1 * r3; + d4 += h2 * r2; + d4 += h3 * r1; + d4 += h4 * r0; + c = (d4 >>> 13); d4 &= 0x1fff; + d4 += h5 * (5 * r9); + d4 += h6 * (5 * r8); + d4 += h7 * (5 * r7); + d4 += h8 * (5 * r6); + d4 += h9 * (5 * r5); + c += (d4 >>> 13); d4 &= 0x1fff; + + d5 = c; + d5 += h0 * r5; + d5 += h1 * r4; + d5 += h2 * r3; + d5 += h3 * r2; + d5 += h4 * r1; + c = (d5 >>> 13); d5 &= 0x1fff; + d5 += h5 * r0; + d5 += h6 * (5 * r9); + d5 += h7 * (5 * r8); + d5 += h8 * (5 * r7); + d5 += h9 * (5 * r6); + c += (d5 >>> 13); d5 &= 0x1fff; + + d6 = c; + d6 += h0 * r6; + d6 += h1 * r5; + d6 += h2 * r4; + d6 += h3 * r3; + d6 += h4 * r2; + c = (d6 >>> 13); d6 &= 0x1fff; + d6 += h5 * r1; + d6 += h6 * r0; + d6 += h7 * (5 * r9); + d6 += h8 * (5 * r8); + d6 += h9 * (5 * r7); + c += (d6 >>> 13); d6 &= 0x1fff; + + d7 = c; + d7 += h0 * r7; + d7 += h1 * r6; + d7 += h2 * r5; + d7 += h3 * r4; + d7 += h4 * r3; + c = (d7 >>> 13); d7 &= 0x1fff; + d7 += h5 * r2; + d7 += h6 * r1; + d7 += h7 * r0; + d7 += h8 * (5 * r9); + d7 += h9 * (5 * r8); + c += (d7 >>> 13); d7 &= 0x1fff; + + d8 = c; + d8 += h0 * r8; + d8 += h1 * r7; + d8 += h2 * r6; + d8 += h3 * r5; + d8 += h4 * r4; + c = (d8 >>> 13); d8 &= 0x1fff; + d8 += h5 * r3; + d8 += h6 * r2; + d8 += h7 * r1; + d8 += h8 * r0; + d8 += h9 * (5 * r9); + c += (d8 >>> 13); d8 &= 0x1fff; + + d9 = c; + d9 += h0 * r9; + d9 += h1 * r8; + d9 += h2 * r7; + d9 += h3 * r6; + d9 += h4 * r5; + c = (d9 >>> 13); d9 &= 0x1fff; + d9 += h5 * r4; + d9 += h6 * r3; + d9 += h7 * r2; + d9 += h8 * r1; + d9 += h9 * r0; + c += (d9 >>> 13); d9 &= 0x1fff; + + c = (((c << 2) + c)) | 0; + c = (c + d0) | 0; + d0 = c & 0x1fff; + c = (c >>> 13); + d1 += c; + + h0 = d0; + h1 = d1; + h2 = d2; + h3 = d3; + h4 = d4; + h5 = d5; + h6 = d6; + h7 = d7; + h8 = d8; + h9 = d9; + + mpos += 16; + bytes -= 16; + } + this.h[0] = h0; + this.h[1] = h1; + this.h[2] = h2; + this.h[3] = h3; + this.h[4] = h4; + this.h[5] = h5; + this.h[6] = h6; + this.h[7] = h7; + this.h[8] = h8; + this.h[9] = h9; +}; + +poly1305.prototype.finish = function(mac, macpos) { + var g = new Uint16Array(10); + var c, mask, f, i; + + if (this.leftover) { + i = this.leftover; + this.buffer[i++] = 1; + for (; i < 16; i++) this.buffer[i] = 0; + this.fin = 1; + this.blocks(this.buffer, 0, 16); + } + + c = this.h[1] >>> 13; + this.h[1] &= 0x1fff; + for (i = 2; i < 10; i++) { + this.h[i] += c; + c = this.h[i] >>> 13; + this.h[i] &= 0x1fff; + } + this.h[0] += (c * 5); + c = this.h[0] >>> 13; + this.h[0] &= 0x1fff; + this.h[1] += c; + c = this.h[1] >>> 13; + this.h[1] &= 0x1fff; + this.h[2] += c; + + g[0] = this.h[0] + 5; + c = g[0] >>> 13; + g[0] &= 0x1fff; + for (i = 1; i < 10; i++) { + g[i] = this.h[i] + c; + c = g[i] >>> 13; + g[i] &= 0x1fff; + } + g[9] -= (1 << 13); + + mask = (c ^ 1) - 1; + for (i = 0; i < 10; i++) g[i] &= mask; + mask = ~mask; + for (i = 0; i < 10; i++) this.h[i] = (this.h[i] & mask) | g[i]; + + this.h[0] = ((this.h[0] ) | (this.h[1] << 13) ) & 0xffff; + this.h[1] = ((this.h[1] >>> 3) | (this.h[2] << 10) ) & 0xffff; + this.h[2] = ((this.h[2] >>> 6) | (this.h[3] << 7) ) & 0xffff; + this.h[3] = ((this.h[3] >>> 9) | (this.h[4] << 4) ) & 0xffff; + this.h[4] = ((this.h[4] >>> 12) | (this.h[5] << 1) | (this.h[6] << 14)) & 0xffff; + this.h[5] = ((this.h[6] >>> 2) | (this.h[7] << 11) ) & 0xffff; + this.h[6] = ((this.h[7] >>> 5) | (this.h[8] << 8) ) & 0xffff; + this.h[7] = ((this.h[8] >>> 8) | (this.h[9] << 5) ) & 0xffff; + + f = this.h[0] + this.pad[0]; + this.h[0] = f & 0xffff; + for (i = 1; i < 8; i++) { + f = (((this.h[i] + this.pad[i]) | 0) + (f >>> 16)) | 0; + this.h[i] = f & 0xffff; + } + + mac[macpos+ 0] = (this.h[0] >>> 0) & 0xff; + mac[macpos+ 1] = (this.h[0] >>> 8) & 0xff; + mac[macpos+ 2] = (this.h[1] >>> 0) & 0xff; + mac[macpos+ 3] = (this.h[1] >>> 8) & 0xff; + mac[macpos+ 4] = (this.h[2] >>> 0) & 0xff; + mac[macpos+ 5] = (this.h[2] >>> 8) & 0xff; + mac[macpos+ 6] = (this.h[3] >>> 0) & 0xff; + mac[macpos+ 7] = (this.h[3] >>> 8) & 0xff; + mac[macpos+ 8] = (this.h[4] >>> 0) & 0xff; + mac[macpos+ 9] = (this.h[4] >>> 8) & 0xff; + mac[macpos+10] = (this.h[5] >>> 0) & 0xff; + mac[macpos+11] = (this.h[5] >>> 8) & 0xff; + mac[macpos+12] = (this.h[6] >>> 0) & 0xff; + mac[macpos+13] = (this.h[6] >>> 8) & 0xff; + mac[macpos+14] = (this.h[7] >>> 0) & 0xff; + mac[macpos+15] = (this.h[7] >>> 8) & 0xff; +}; + +poly1305.prototype.update = function(m, mpos, bytes) { + var i, want; + + if (this.leftover) { + want = (16 - this.leftover); + if (want > bytes) + want = bytes; + for (i = 0; i < want; i++) + this.buffer[this.leftover + i] = m[mpos+i]; + bytes -= want; + mpos += want; + this.leftover += want; + if (this.leftover < 16) + return; + this.blocks(this.buffer, 0, 16); + this.leftover = 0; + } + + if (bytes >= 16) { + want = bytes - (bytes % 16); + this.blocks(m, mpos, want); + mpos += want; + bytes -= want; + } + + if (bytes) { + for (i = 0; i < bytes; i++) + this.buffer[this.leftover + i] = m[mpos+i]; + this.leftover += bytes; + } +}; + +function crypto_onetimeauth(out, outpos, m, mpos, n, k) { + var s = new poly1305(k); + s.update(m, mpos, n); + s.finish(out, outpos); + return 0; +} + +function crypto_onetimeauth_verify(h, hpos, m, mpos, n, k) { + var x = new Uint8Array(16); + crypto_onetimeauth(x,0,m,mpos,n,k); + return crypto_verify_16(h,hpos,x,0); +} + +function crypto_secretbox(c,m,d,n,k) { + var i; + if (d < 32) return -1; + crypto_stream_xor(c,0,m,0,d,n,k); + crypto_onetimeauth(c, 16, c, 32, d - 32, c); + for (i = 0; i < 16; i++) c[i] = 0; + return 0; +} + +function crypto_secretbox_open(m,c,d,n,k) { + var i; + var x = new Uint8Array(32); + if (d < 32) return -1; + crypto_stream(x,0,32,n,k); + if (crypto_onetimeauth_verify(c, 16,c, 32,d - 32,x) !== 0) return -1; + crypto_stream_xor(m,0,c,0,d,n,k); + for (i = 0; i < 32; i++) m[i] = 0; + return 0; +} + +function set25519(r, a) { + var i; + for (i = 0; i < 16; i++) r[i] = a[i]|0; +} + +function car25519(o) { + var i, v, c = 1; + for (i = 0; i < 16; i++) { + v = o[i] + c + 65535; + c = Math.floor(v / 65536); + o[i] = v - c * 65536; + } + o[0] += c-1 + 37 * (c-1); +} + +function sel25519(p, q, b) { + var t, c = ~(b-1); + for (var i = 0; i < 16; i++) { + t = c & (p[i] ^ q[i]); + p[i] ^= t; + q[i] ^= t; + } +} + +function pack25519(o, n) { + var i, j, b; + var m = gf(), t = gf(); + for (i = 0; i < 16; i++) t[i] = n[i]; + car25519(t); + car25519(t); + car25519(t); + for (j = 0; j < 2; j++) { + m[0] = t[0] - 0xffed; + for (i = 1; i < 15; i++) { + m[i] = t[i] - 0xffff - ((m[i-1]>>16) & 1); + m[i-1] &= 0xffff; + } + m[15] = t[15] - 0x7fff - ((m[14]>>16) & 1); + b = (m[15]>>16) & 1; + m[14] &= 0xffff; + sel25519(t, m, 1-b); + } + for (i = 0; i < 16; i++) { + o[2*i] = t[i] & 0xff; + o[2*i+1] = t[i]>>8; + } +} + +function neq25519(a, b) { + var c = new Uint8Array(32), d = new Uint8Array(32); + pack25519(c, a); + pack25519(d, b); + return crypto_verify_32(c, 0, d, 0); +} + +function par25519(a) { + var d = new Uint8Array(32); + pack25519(d, a); + return d[0] & 1; +} + +function unpack25519(o, n) { + var i; + for (i = 0; i < 16; i++) o[i] = n[2*i] + (n[2*i+1] << 8); + o[15] &= 0x7fff; +} + +function A(o, a, b) { + for (var i = 0; i < 16; i++) o[i] = a[i] + b[i]; +} + +function Z(o, a, b) { + for (var i = 0; i < 16; i++) o[i] = a[i] - b[i]; +} + +function M(o, a, b) { + var v, c, + t0 = 0, t1 = 0, t2 = 0, t3 = 0, t4 = 0, t5 = 0, t6 = 0, t7 = 0, + t8 = 0, t9 = 0, t10 = 0, t11 = 0, t12 = 0, t13 = 0, t14 = 0, t15 = 0, + t16 = 0, t17 = 0, t18 = 0, t19 = 0, t20 = 0, t21 = 0, t22 = 0, t23 = 0, + t24 = 0, t25 = 0, t26 = 0, t27 = 0, t28 = 0, t29 = 0, t30 = 0, + b0 = b[0], + b1 = b[1], + b2 = b[2], + b3 = b[3], + b4 = b[4], + b5 = b[5], + b6 = b[6], + b7 = b[7], + b8 = b[8], + b9 = b[9], + b10 = b[10], + b11 = b[11], + b12 = b[12], + b13 = b[13], + b14 = b[14], + b15 = b[15]; + + v = a[0]; + t0 += v * b0; + t1 += v * b1; + t2 += v * b2; + t3 += v * b3; + t4 += v * b4; + t5 += v * b5; + t6 += v * b6; + t7 += v * b7; + t8 += v * b8; + t9 += v * b9; + t10 += v * b10; + t11 += v * b11; + t12 += v * b12; + t13 += v * b13; + t14 += v * b14; + t15 += v * b15; + v = a[1]; + t1 += v * b0; + t2 += v * b1; + t3 += v * b2; + t4 += v * b3; + t5 += v * b4; + t6 += v * b5; + t7 += v * b6; + t8 += v * b7; + t9 += v * b8; + t10 += v * b9; + t11 += v * b10; + t12 += v * b11; + t13 += v * b12; + t14 += v * b13; + t15 += v * b14; + t16 += v * b15; + v = a[2]; + t2 += v * b0; + t3 += v * b1; + t4 += v * b2; + t5 += v * b3; + t6 += v * b4; + t7 += v * b5; + t8 += v * b6; + t9 += v * b7; + t10 += v * b8; + t11 += v * b9; + t12 += v * b10; + t13 += v * b11; + t14 += v * b12; + t15 += v * b13; + t16 += v * b14; + t17 += v * b15; + v = a[3]; + t3 += v * b0; + t4 += v * b1; + t5 += v * b2; + t6 += v * b3; + t7 += v * b4; + t8 += v * b5; + t9 += v * b6; + t10 += v * b7; + t11 += v * b8; + t12 += v * b9; + t13 += v * b10; + t14 += v * b11; + t15 += v * b12; + t16 += v * b13; + t17 += v * b14; + t18 += v * b15; + v = a[4]; + t4 += v * b0; + t5 += v * b1; + t6 += v * b2; + t7 += v * b3; + t8 += v * b4; + t9 += v * b5; + t10 += v * b6; + t11 += v * b7; + t12 += v * b8; + t13 += v * b9; + t14 += v * b10; + t15 += v * b11; + t16 += v * b12; + t17 += v * b13; + t18 += v * b14; + t19 += v * b15; + v = a[5]; + t5 += v * b0; + t6 += v * b1; + t7 += v * b2; + t8 += v * b3; + t9 += v * b4; + t10 += v * b5; + t11 += v * b6; + t12 += v * b7; + t13 += v * b8; + t14 += v * b9; + t15 += v * b10; + t16 += v * b11; + t17 += v * b12; + t18 += v * b13; + t19 += v * b14; + t20 += v * b15; + v = a[6]; + t6 += v * b0; + t7 += v * b1; + t8 += v * b2; + t9 += v * b3; + t10 += v * b4; + t11 += v * b5; + t12 += v * b6; + t13 += v * b7; + t14 += v * b8; + t15 += v * b9; + t16 += v * b10; + t17 += v * b11; + t18 += v * b12; + t19 += v * b13; + t20 += v * b14; + t21 += v * b15; + v = a[7]; + t7 += v * b0; + t8 += v * b1; + t9 += v * b2; + t10 += v * b3; + t11 += v * b4; + t12 += v * b5; + t13 += v * b6; + t14 += v * b7; + t15 += v * b8; + t16 += v * b9; + t17 += v * b10; + t18 += v * b11; + t19 += v * b12; + t20 += v * b13; + t21 += v * b14; + t22 += v * b15; + v = a[8]; + t8 += v * b0; + t9 += v * b1; + t10 += v * b2; + t11 += v * b3; + t12 += v * b4; + t13 += v * b5; + t14 += v * b6; + t15 += v * b7; + t16 += v * b8; + t17 += v * b9; + t18 += v * b10; + t19 += v * b11; + t20 += v * b12; + t21 += v * b13; + t22 += v * b14; + t23 += v * b15; + v = a[9]; + t9 += v * b0; + t10 += v * b1; + t11 += v * b2; + t12 += v * b3; + t13 += v * b4; + t14 += v * b5; + t15 += v * b6; + t16 += v * b7; + t17 += v * b8; + t18 += v * b9; + t19 += v * b10; + t20 += v * b11; + t21 += v * b12; + t22 += v * b13; + t23 += v * b14; + t24 += v * b15; + v = a[10]; + t10 += v * b0; + t11 += v * b1; + t12 += v * b2; + t13 += v * b3; + t14 += v * b4; + t15 += v * b5; + t16 += v * b6; + t17 += v * b7; + t18 += v * b8; + t19 += v * b9; + t20 += v * b10; + t21 += v * b11; + t22 += v * b12; + t23 += v * b13; + t24 += v * b14; + t25 += v * b15; + v = a[11]; + t11 += v * b0; + t12 += v * b1; + t13 += v * b2; + t14 += v * b3; + t15 += v * b4; + t16 += v * b5; + t17 += v * b6; + t18 += v * b7; + t19 += v * b8; + t20 += v * b9; + t21 += v * b10; + t22 += v * b11; + t23 += v * b12; + t24 += v * b13; + t25 += v * b14; + t26 += v * b15; + v = a[12]; + t12 += v * b0; + t13 += v * b1; + t14 += v * b2; + t15 += v * b3; + t16 += v * b4; + t17 += v * b5; + t18 += v * b6; + t19 += v * b7; + t20 += v * b8; + t21 += v * b9; + t22 += v * b10; + t23 += v * b11; + t24 += v * b12; + t25 += v * b13; + t26 += v * b14; + t27 += v * b15; + v = a[13]; + t13 += v * b0; + t14 += v * b1; + t15 += v * b2; + t16 += v * b3; + t17 += v * b4; + t18 += v * b5; + t19 += v * b6; + t20 += v * b7; + t21 += v * b8; + t22 += v * b9; + t23 += v * b10; + t24 += v * b11; + t25 += v * b12; + t26 += v * b13; + t27 += v * b14; + t28 += v * b15; + v = a[14]; + t14 += v * b0; + t15 += v * b1; + t16 += v * b2; + t17 += v * b3; + t18 += v * b4; + t19 += v * b5; + t20 += v * b6; + t21 += v * b7; + t22 += v * b8; + t23 += v * b9; + t24 += v * b10; + t25 += v * b11; + t26 += v * b12; + t27 += v * b13; + t28 += v * b14; + t29 += v * b15; + v = a[15]; + t15 += v * b0; + t16 += v * b1; + t17 += v * b2; + t18 += v * b3; + t19 += v * b4; + t20 += v * b5; + t21 += v * b6; + t22 += v * b7; + t23 += v * b8; + t24 += v * b9; + t25 += v * b10; + t26 += v * b11; + t27 += v * b12; + t28 += v * b13; + t29 += v * b14; + t30 += v * b15; + + t0 += 38 * t16; + t1 += 38 * t17; + t2 += 38 * t18; + t3 += 38 * t19; + t4 += 38 * t20; + t5 += 38 * t21; + t6 += 38 * t22; + t7 += 38 * t23; + t8 += 38 * t24; + t9 += 38 * t25; + t10 += 38 * t26; + t11 += 38 * t27; + t12 += 38 * t28; + t13 += 38 * t29; + t14 += 38 * t30; + // t15 left as is + + // first car + c = 1; + v = t0 + c + 65535; c = Math.floor(v / 65536); t0 = v - c * 65536; + v = t1 + c + 65535; c = Math.floor(v / 65536); t1 = v - c * 65536; + v = t2 + c + 65535; c = Math.floor(v / 65536); t2 = v - c * 65536; + v = t3 + c + 65535; c = Math.floor(v / 65536); t3 = v - c * 65536; + v = t4 + c + 65535; c = Math.floor(v / 65536); t4 = v - c * 65536; + v = t5 + c + 65535; c = Math.floor(v / 65536); t5 = v - c * 65536; + v = t6 + c + 65535; c = Math.floor(v / 65536); t6 = v - c * 65536; + v = t7 + c + 65535; c = Math.floor(v / 65536); t7 = v - c * 65536; + v = t8 + c + 65535; c = Math.floor(v / 65536); t8 = v - c * 65536; + v = t9 + c + 65535; c = Math.floor(v / 65536); t9 = v - c * 65536; + v = t10 + c + 65535; c = Math.floor(v / 65536); t10 = v - c * 65536; + v = t11 + c + 65535; c = Math.floor(v / 65536); t11 = v - c * 65536; + v = t12 + c + 65535; c = Math.floor(v / 65536); t12 = v - c * 65536; + v = t13 + c + 65535; c = Math.floor(v / 65536); t13 = v - c * 65536; + v = t14 + c + 65535; c = Math.floor(v / 65536); t14 = v - c * 65536; + v = t15 + c + 65535; c = Math.floor(v / 65536); t15 = v - c * 65536; + t0 += c-1 + 37 * (c-1); + + // second car + c = 1; + v = t0 + c + 65535; c = Math.floor(v / 65536); t0 = v - c * 65536; + v = t1 + c + 65535; c = Math.floor(v / 65536); t1 = v - c * 65536; + v = t2 + c + 65535; c = Math.floor(v / 65536); t2 = v - c * 65536; + v = t3 + c + 65535; c = Math.floor(v / 65536); t3 = v - c * 65536; + v = t4 + c + 65535; c = Math.floor(v / 65536); t4 = v - c * 65536; + v = t5 + c + 65535; c = Math.floor(v / 65536); t5 = v - c * 65536; + v = t6 + c + 65535; c = Math.floor(v / 65536); t6 = v - c * 65536; + v = t7 + c + 65535; c = Math.floor(v / 65536); t7 = v - c * 65536; + v = t8 + c + 65535; c = Math.floor(v / 65536); t8 = v - c * 65536; + v = t9 + c + 65535; c = Math.floor(v / 65536); t9 = v - c * 65536; + v = t10 + c + 65535; c = Math.floor(v / 65536); t10 = v - c * 65536; + v = t11 + c + 65535; c = Math.floor(v / 65536); t11 = v - c * 65536; + v = t12 + c + 65535; c = Math.floor(v / 65536); t12 = v - c * 65536; + v = t13 + c + 65535; c = Math.floor(v / 65536); t13 = v - c * 65536; + v = t14 + c + 65535; c = Math.floor(v / 65536); t14 = v - c * 65536; + v = t15 + c + 65535; c = Math.floor(v / 65536); t15 = v - c * 65536; + t0 += c-1 + 37 * (c-1); + + o[ 0] = t0; + o[ 1] = t1; + o[ 2] = t2; + o[ 3] = t3; + o[ 4] = t4; + o[ 5] = t5; + o[ 6] = t6; + o[ 7] = t7; + o[ 8] = t8; + o[ 9] = t9; + o[10] = t10; + o[11] = t11; + o[12] = t12; + o[13] = t13; + o[14] = t14; + o[15] = t15; +} + +function S(o, a) { + M(o, a, a); +} + +function inv25519(o, i) { + var c = gf(); + var a; + for (a = 0; a < 16; a++) c[a] = i[a]; + for (a = 253; a >= 0; a--) { + S(c, c); + if(a !== 2 && a !== 4) M(c, c, i); + } + for (a = 0; a < 16; a++) o[a] = c[a]; +} + +function pow2523(o, i) { + var c = gf(); + var a; + for (a = 0; a < 16; a++) c[a] = i[a]; + for (a = 250; a >= 0; a--) { + S(c, c); + if(a !== 1) M(c, c, i); + } + for (a = 0; a < 16; a++) o[a] = c[a]; +} + +function crypto_scalarmult(q, n, p) { + var z = new Uint8Array(32); + var x = new Float64Array(80), r, i; + var a = gf(), b = gf(), c = gf(), + d = gf(), e = gf(), f = gf(); + for (i = 0; i < 31; i++) z[i] = n[i]; + z[31]=(n[31]&127)|64; + z[0]&=248; + unpack25519(x,p); + for (i = 0; i < 16; i++) { + b[i]=x[i]; + d[i]=a[i]=c[i]=0; + } + a[0]=d[0]=1; + for (i=254; i>=0; --i) { + r=(z[i>>>3]>>>(i&7))&1; + sel25519(a,b,r); + sel25519(c,d,r); + A(e,a,c); + Z(a,a,c); + A(c,b,d); + Z(b,b,d); + S(d,e); + S(f,a); + M(a,c,a); + M(c,b,e); + A(e,a,c); + Z(a,a,c); + S(b,a); + Z(c,d,f); + M(a,c,_121665); + A(a,a,d); + M(c,c,a); + M(a,d,f); + M(d,b,x); + S(b,e); + sel25519(a,b,r); + sel25519(c,d,r); + } + for (i = 0; i < 16; i++) { + x[i+16]=a[i]; + x[i+32]=c[i]; + x[i+48]=b[i]; + x[i+64]=d[i]; + } + var x32 = x.subarray(32); + var x16 = x.subarray(16); + inv25519(x32,x32); + M(x16,x16,x32); + pack25519(q,x16); + return 0; +} + +function crypto_scalarmult_base(q, n) { + return crypto_scalarmult(q, n, _9); +} + +function crypto_box_keypair(y, x) { + randombytes(x, 32); + return crypto_scalarmult_base(y, x); +} + +function crypto_box_beforenm(k, y, x) { + var s = new Uint8Array(32); + crypto_scalarmult(s, x, y); + return crypto_core_hsalsa20(k, _0, s, sigma); +} + +var crypto_box_afternm = crypto_secretbox; +var crypto_box_open_afternm = crypto_secretbox_open; + +function crypto_box(c, m, d, n, y, x) { + var k = new Uint8Array(32); + crypto_box_beforenm(k, y, x); + return crypto_box_afternm(c, m, d, n, k); +} + +function crypto_box_open(m, c, d, n, y, x) { + var k = new Uint8Array(32); + crypto_box_beforenm(k, y, x); + return crypto_box_open_afternm(m, c, d, n, k); +} + +var K = [ + 0x428a2f98, 0xd728ae22, 0x71374491, 0x23ef65cd, + 0xb5c0fbcf, 0xec4d3b2f, 0xe9b5dba5, 0x8189dbbc, + 0x3956c25b, 0xf348b538, 0x59f111f1, 0xb605d019, + 0x923f82a4, 0xaf194f9b, 0xab1c5ed5, 0xda6d8118, + 0xd807aa98, 0xa3030242, 0x12835b01, 0x45706fbe, + 0x243185be, 0x4ee4b28c, 0x550c7dc3, 0xd5ffb4e2, + 0x72be5d74, 0xf27b896f, 0x80deb1fe, 0x3b1696b1, + 0x9bdc06a7, 0x25c71235, 0xc19bf174, 0xcf692694, + 0xe49b69c1, 0x9ef14ad2, 0xefbe4786, 0x384f25e3, + 0x0fc19dc6, 0x8b8cd5b5, 0x240ca1cc, 0x77ac9c65, + 0x2de92c6f, 0x592b0275, 0x4a7484aa, 0x6ea6e483, + 0x5cb0a9dc, 0xbd41fbd4, 0x76f988da, 0x831153b5, + 0x983e5152, 0xee66dfab, 0xa831c66d, 0x2db43210, + 0xb00327c8, 0x98fb213f, 0xbf597fc7, 0xbeef0ee4, + 0xc6e00bf3, 0x3da88fc2, 0xd5a79147, 0x930aa725, + 0x06ca6351, 0xe003826f, 0x14292967, 0x0a0e6e70, + 0x27b70a85, 0x46d22ffc, 0x2e1b2138, 0x5c26c926, + 0x4d2c6dfc, 0x5ac42aed, 0x53380d13, 0x9d95b3df, + 0x650a7354, 0x8baf63de, 0x766a0abb, 0x3c77b2a8, + 0x81c2c92e, 0x47edaee6, 0x92722c85, 0x1482353b, + 0xa2bfe8a1, 0x4cf10364, 0xa81a664b, 0xbc423001, + 0xc24b8b70, 0xd0f89791, 0xc76c51a3, 0x0654be30, + 0xd192e819, 0xd6ef5218, 0xd6990624, 0x5565a910, + 0xf40e3585, 0x5771202a, 0x106aa070, 0x32bbd1b8, + 0x19a4c116, 0xb8d2d0c8, 0x1e376c08, 0x5141ab53, + 0x2748774c, 0xdf8eeb99, 0x34b0bcb5, 0xe19b48a8, + 0x391c0cb3, 0xc5c95a63, 0x4ed8aa4a, 0xe3418acb, + 0x5b9cca4f, 0x7763e373, 0x682e6ff3, 0xd6b2b8a3, + 0x748f82ee, 0x5defb2fc, 0x78a5636f, 0x43172f60, + 0x84c87814, 0xa1f0ab72, 0x8cc70208, 0x1a6439ec, + 0x90befffa, 0x23631e28, 0xa4506ceb, 0xde82bde9, + 0xbef9a3f7, 0xb2c67915, 0xc67178f2, 0xe372532b, + 0xca273ece, 0xea26619c, 0xd186b8c7, 0x21c0c207, + 0xeada7dd6, 0xcde0eb1e, 0xf57d4f7f, 0xee6ed178, + 0x06f067aa, 0x72176fba, 0x0a637dc5, 0xa2c898a6, + 0x113f9804, 0xbef90dae, 0x1b710b35, 0x131c471b, + 0x28db77f5, 0x23047d84, 0x32caab7b, 0x40c72493, + 0x3c9ebe0a, 0x15c9bebc, 0x431d67c4, 0x9c100d4c, + 0x4cc5d4be, 0xcb3e42b6, 0x597f299c, 0xfc657e2a, + 0x5fcb6fab, 0x3ad6faec, 0x6c44198c, 0x4a475817 +]; + +function crypto_hashblocks_hl(hh, hl, m, n) { + var wh = new Int32Array(16), wl = new Int32Array(16), + bh0, bh1, bh2, bh3, bh4, bh5, bh6, bh7, + bl0, bl1, bl2, bl3, bl4, bl5, bl6, bl7, + th, tl, i, j, h, l, a, b, c, d; + + var ah0 = hh[0], + ah1 = hh[1], + ah2 = hh[2], + ah3 = hh[3], + ah4 = hh[4], + ah5 = hh[5], + ah6 = hh[6], + ah7 = hh[7], + + al0 = hl[0], + al1 = hl[1], + al2 = hl[2], + al3 = hl[3], + al4 = hl[4], + al5 = hl[5], + al6 = hl[6], + al7 = hl[7]; + + var pos = 0; + while (n >= 128) { + for (i = 0; i < 16; i++) { + j = 8 * i + pos; + wh[i] = (m[j+0] << 24) | (m[j+1] << 16) | (m[j+2] << 8) | m[j+3]; + wl[i] = (m[j+4] << 24) | (m[j+5] << 16) | (m[j+6] << 8) | m[j+7]; + } + for (i = 0; i < 80; i++) { + bh0 = ah0; + bh1 = ah1; + bh2 = ah2; + bh3 = ah3; + bh4 = ah4; + bh5 = ah5; + bh6 = ah6; + bh7 = ah7; + + bl0 = al0; + bl1 = al1; + bl2 = al2; + bl3 = al3; + bl4 = al4; + bl5 = al5; + bl6 = al6; + bl7 = al7; + + // add + h = ah7; + l = al7; + + a = l & 0xffff; b = l >>> 16; + c = h & 0xffff; d = h >>> 16; + + // Sigma1 + h = ((ah4 >>> 14) | (al4 << (32-14))) ^ ((ah4 >>> 18) | (al4 << (32-18))) ^ ((al4 >>> (41-32)) | (ah4 << (32-(41-32)))); + l = ((al4 >>> 14) | (ah4 << (32-14))) ^ ((al4 >>> 18) | (ah4 << (32-18))) ^ ((ah4 >>> (41-32)) | (al4 << (32-(41-32)))); + + a += l & 0xffff; b += l >>> 16; + c += h & 0xffff; d += h >>> 16; + + // Ch + h = (ah4 & ah5) ^ (~ah4 & ah6); + l = (al4 & al5) ^ (~al4 & al6); + + a += l & 0xffff; b += l >>> 16; + c += h & 0xffff; d += h >>> 16; + + // K + h = K[i*2]; + l = K[i*2+1]; + + a += l & 0xffff; b += l >>> 16; + c += h & 0xffff; d += h >>> 16; + + // w + h = wh[i%16]; + l = wl[i%16]; + + a += l & 0xffff; b += l >>> 16; + c += h & 0xffff; d += h >>> 16; + + b += a >>> 16; + c += b >>> 16; + d += c >>> 16; + + th = c & 0xffff | d << 16; + tl = a & 0xffff | b << 16; + + // add + h = th; + l = tl; + + a = l & 0xffff; b = l >>> 16; + c = h & 0xffff; d = h >>> 16; + + // Sigma0 + h = ((ah0 >>> 28) | (al0 << (32-28))) ^ ((al0 >>> (34-32)) | (ah0 << (32-(34-32)))) ^ ((al0 >>> (39-32)) | (ah0 << (32-(39-32)))); + l = ((al0 >>> 28) | (ah0 << (32-28))) ^ ((ah0 >>> (34-32)) | (al0 << (32-(34-32)))) ^ ((ah0 >>> (39-32)) | (al0 << (32-(39-32)))); + + a += l & 0xffff; b += l >>> 16; + c += h & 0xffff; d += h >>> 16; + + // Maj + h = (ah0 & ah1) ^ (ah0 & ah2) ^ (ah1 & ah2); + l = (al0 & al1) ^ (al0 & al2) ^ (al1 & al2); + + a += l & 0xffff; b += l >>> 16; + c += h & 0xffff; d += h >>> 16; + + b += a >>> 16; + c += b >>> 16; + d += c >>> 16; + + bh7 = (c & 0xffff) | (d << 16); + bl7 = (a & 0xffff) | (b << 16); + + // add + h = bh3; + l = bl3; + + a = l & 0xffff; b = l >>> 16; + c = h & 0xffff; d = h >>> 16; + + h = th; + l = tl; + + a += l & 0xffff; b += l >>> 16; + c += h & 0xffff; d += h >>> 16; + + b += a >>> 16; + c += b >>> 16; + d += c >>> 16; + + bh3 = (c & 0xffff) | (d << 16); + bl3 = (a & 0xffff) | (b << 16); + + ah1 = bh0; + ah2 = bh1; + ah3 = bh2; + ah4 = bh3; + ah5 = bh4; + ah6 = bh5; + ah7 = bh6; + ah0 = bh7; + + al1 = bl0; + al2 = bl1; + al3 = bl2; + al4 = bl3; + al5 = bl4; + al6 = bl5; + al7 = bl6; + al0 = bl7; + + if (i%16 === 15) { + for (j = 0; j < 16; j++) { + // add + h = wh[j]; + l = wl[j]; + + a = l & 0xffff; b = l >>> 16; + c = h & 0xffff; d = h >>> 16; + + h = wh[(j+9)%16]; + l = wl[(j+9)%16]; + + a += l & 0xffff; b += l >>> 16; + c += h & 0xffff; d += h >>> 16; + + // sigma0 + th = wh[(j+1)%16]; + tl = wl[(j+1)%16]; + h = ((th >>> 1) | (tl << (32-1))) ^ ((th >>> 8) | (tl << (32-8))) ^ (th >>> 7); + l = ((tl >>> 1) | (th << (32-1))) ^ ((tl >>> 8) | (th << (32-8))) ^ ((tl >>> 7) | (th << (32-7))); + + a += l & 0xffff; b += l >>> 16; + c += h & 0xffff; d += h >>> 16; + + // sigma1 + th = wh[(j+14)%16]; + tl = wl[(j+14)%16]; + h = ((th >>> 19) | (tl << (32-19))) ^ ((tl >>> (61-32)) | (th << (32-(61-32)))) ^ (th >>> 6); + l = ((tl >>> 19) | (th << (32-19))) ^ ((th >>> (61-32)) | (tl << (32-(61-32)))) ^ ((tl >>> 6) | (th << (32-6))); + + a += l & 0xffff; b += l >>> 16; + c += h & 0xffff; d += h >>> 16; + + b += a >>> 16; + c += b >>> 16; + d += c >>> 16; + + wh[j] = (c & 0xffff) | (d << 16); + wl[j] = (a & 0xffff) | (b << 16); + } + } + } + + // add + h = ah0; + l = al0; + + a = l & 0xffff; b = l >>> 16; + c = h & 0xffff; d = h >>> 16; + + h = hh[0]; + l = hl[0]; + + a += l & 0xffff; b += l >>> 16; + c += h & 0xffff; d += h >>> 16; + + b += a >>> 16; + c += b >>> 16; + d += c >>> 16; + + hh[0] = ah0 = (c & 0xffff) | (d << 16); + hl[0] = al0 = (a & 0xffff) | (b << 16); + + h = ah1; + l = al1; + + a = l & 0xffff; b = l >>> 16; + c = h & 0xffff; d = h >>> 16; + + h = hh[1]; + l = hl[1]; + + a += l & 0xffff; b += l >>> 16; + c += h & 0xffff; d += h >>> 16; + + b += a >>> 16; + c += b >>> 16; + d += c >>> 16; + + hh[1] = ah1 = (c & 0xffff) | (d << 16); + hl[1] = al1 = (a & 0xffff) | (b << 16); + + h = ah2; + l = al2; + + a = l & 0xffff; b = l >>> 16; + c = h & 0xffff; d = h >>> 16; + + h = hh[2]; + l = hl[2]; + + a += l & 0xffff; b += l >>> 16; + c += h & 0xffff; d += h >>> 16; + + b += a >>> 16; + c += b >>> 16; + d += c >>> 16; + + hh[2] = ah2 = (c & 0xffff) | (d << 16); + hl[2] = al2 = (a & 0xffff) | (b << 16); + + h = ah3; + l = al3; + + a = l & 0xffff; b = l >>> 16; + c = h & 0xffff; d = h >>> 16; + + h = hh[3]; + l = hl[3]; + + a += l & 0xffff; b += l >>> 16; + c += h & 0xffff; d += h >>> 16; + + b += a >>> 16; + c += b >>> 16; + d += c >>> 16; + + hh[3] = ah3 = (c & 0xffff) | (d << 16); + hl[3] = al3 = (a & 0xffff) | (b << 16); + + h = ah4; + l = al4; + + a = l & 0xffff; b = l >>> 16; + c = h & 0xffff; d = h >>> 16; + + h = hh[4]; + l = hl[4]; + + a += l & 0xffff; b += l >>> 16; + c += h & 0xffff; d += h >>> 16; + + b += a >>> 16; + c += b >>> 16; + d += c >>> 16; + + hh[4] = ah4 = (c & 0xffff) | (d << 16); + hl[4] = al4 = (a & 0xffff) | (b << 16); + + h = ah5; + l = al5; + + a = l & 0xffff; b = l >>> 16; + c = h & 0xffff; d = h >>> 16; + + h = hh[5]; + l = hl[5]; + + a += l & 0xffff; b += l >>> 16; + c += h & 0xffff; d += h >>> 16; + + b += a >>> 16; + c += b >>> 16; + d += c >>> 16; + + hh[5] = ah5 = (c & 0xffff) | (d << 16); + hl[5] = al5 = (a & 0xffff) | (b << 16); + + h = ah6; + l = al6; + + a = l & 0xffff; b = l >>> 16; + c = h & 0xffff; d = h >>> 16; + + h = hh[6]; + l = hl[6]; + + a += l & 0xffff; b += l >>> 16; + c += h & 0xffff; d += h >>> 16; + + b += a >>> 16; + c += b >>> 16; + d += c >>> 16; + + hh[6] = ah6 = (c & 0xffff) | (d << 16); + hl[6] = al6 = (a & 0xffff) | (b << 16); + + h = ah7; + l = al7; + + a = l & 0xffff; b = l >>> 16; + c = h & 0xffff; d = h >>> 16; + + h = hh[7]; + l = hl[7]; + + a += l & 0xffff; b += l >>> 16; + c += h & 0xffff; d += h >>> 16; + + b += a >>> 16; + c += b >>> 16; + d += c >>> 16; + + hh[7] = ah7 = (c & 0xffff) | (d << 16); + hl[7] = al7 = (a & 0xffff) | (b << 16); + + pos += 128; + n -= 128; + } + + return n; +} + +function crypto_hash(out, m, n) { + var hh = new Int32Array(8), + hl = new Int32Array(8), + x = new Uint8Array(256), + i, b = n; + + hh[0] = 0x6a09e667; + hh[1] = 0xbb67ae85; + hh[2] = 0x3c6ef372; + hh[3] = 0xa54ff53a; + hh[4] = 0x510e527f; + hh[5] = 0x9b05688c; + hh[6] = 0x1f83d9ab; + hh[7] = 0x5be0cd19; + + hl[0] = 0xf3bcc908; + hl[1] = 0x84caa73b; + hl[2] = 0xfe94f82b; + hl[3] = 0x5f1d36f1; + hl[4] = 0xade682d1; + hl[5] = 0x2b3e6c1f; + hl[6] = 0xfb41bd6b; + hl[7] = 0x137e2179; + + crypto_hashblocks_hl(hh, hl, m, n); + n %= 128; + + for (i = 0; i < n; i++) x[i] = m[b-n+i]; + x[n] = 128; + + n = 256-128*(n<112?1:0); + x[n-9] = 0; + ts64(x, n-8, (b / 0x20000000) | 0, b << 3); + crypto_hashblocks_hl(hh, hl, x, n); + + for (i = 0; i < 8; i++) ts64(out, 8*i, hh[i], hl[i]); + + return 0; +} + +function add(p, q) { + var a = gf(), b = gf(), c = gf(), + d = gf(), e = gf(), f = gf(), + g = gf(), h = gf(), t = gf(); + + Z(a, p[1], p[0]); + Z(t, q[1], q[0]); + M(a, a, t); + A(b, p[0], p[1]); + A(t, q[0], q[1]); + M(b, b, t); + M(c, p[3], q[3]); + M(c, c, D2); + M(d, p[2], q[2]); + A(d, d, d); + Z(e, b, a); + Z(f, d, c); + A(g, d, c); + A(h, b, a); + + M(p[0], e, f); + M(p[1], h, g); + M(p[2], g, f); + M(p[3], e, h); +} + +function cswap(p, q, b) { + var i; + for (i = 0; i < 4; i++) { + sel25519(p[i], q[i], b); + } +} + +function pack(r, p) { + var tx = gf(), ty = gf(), zi = gf(); + inv25519(zi, p[2]); + M(tx, p[0], zi); + M(ty, p[1], zi); + pack25519(r, ty); + r[31] ^= par25519(tx) << 7; +} + +function scalarmult(p, q, s) { + var b, i; + set25519(p[0], gf0); + set25519(p[1], gf1); + set25519(p[2], gf1); + set25519(p[3], gf0); + for (i = 255; i >= 0; --i) { + b = (s[(i/8)|0] >> (i&7)) & 1; + cswap(p, q, b); + add(q, p); + add(p, p); + cswap(p, q, b); + } +} + +function scalarbase(p, s) { + var q = [gf(), gf(), gf(), gf()]; + set25519(q[0], X); + set25519(q[1], Y); + set25519(q[2], gf1); + M(q[3], X, Y); + scalarmult(p, q, s); +} + +function crypto_sign_keypair(pk, sk, seeded) { + var d = new Uint8Array(64); + var p = [gf(), gf(), gf(), gf()]; + var i; + + if (!seeded) randombytes(sk, 32); + crypto_hash(d, sk, 32); + d[0] &= 248; + d[31] &= 127; + d[31] |= 64; + + scalarbase(p, d); + pack(pk, p); + + for (i = 0; i < 32; i++) sk[i+32] = pk[i]; + return 0; +} + +var L = new Float64Array([0xed, 0xd3, 0xf5, 0x5c, 0x1a, 0x63, 0x12, 0x58, 0xd6, 0x9c, 0xf7, 0xa2, 0xde, 0xf9, 0xde, 0x14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x10]); + +function modL(r, x) { + var carry, i, j, k; + for (i = 63; i >= 32; --i) { + carry = 0; + for (j = i - 32, k = i - 12; j < k; ++j) { + x[j] += carry - 16 * x[i] * L[j - (i - 32)]; + carry = Math.floor((x[j] + 128) / 256); + x[j] -= carry * 256; + } + x[j] += carry; + x[i] = 0; + } + carry = 0; + for (j = 0; j < 32; j++) { + x[j] += carry - (x[31] >> 4) * L[j]; + carry = x[j] >> 8; + x[j] &= 255; + } + for (j = 0; j < 32; j++) x[j] -= carry * L[j]; + for (i = 0; i < 32; i++) { + x[i+1] += x[i] >> 8; + r[i] = x[i] & 255; + } +} + +function reduce(r) { + var x = new Float64Array(64), i; + for (i = 0; i < 64; i++) x[i] = r[i]; + for (i = 0; i < 64; i++) r[i] = 0; + modL(r, x); +} + +// Note: difference from C - smlen returned, not passed as argument. +function crypto_sign(sm, m, n, sk) { + var d = new Uint8Array(64), h = new Uint8Array(64), r = new Uint8Array(64); + var i, j, x = new Float64Array(64); + var p = [gf(), gf(), gf(), gf()]; + + crypto_hash(d, sk, 32); + d[0] &= 248; + d[31] &= 127; + d[31] |= 64; + + var smlen = n + 64; + for (i = 0; i < n; i++) sm[64 + i] = m[i]; + for (i = 0; i < 32; i++) sm[32 + i] = d[32 + i]; + + crypto_hash(r, sm.subarray(32), n+32); + reduce(r); + scalarbase(p, r); + pack(sm, p); + + for (i = 32; i < 64; i++) sm[i] = sk[i]; + crypto_hash(h, sm, n + 64); + reduce(h); + + for (i = 0; i < 64; i++) x[i] = 0; + for (i = 0; i < 32; i++) x[i] = r[i]; + for (i = 0; i < 32; i++) { + for (j = 0; j < 32; j++) { + x[i+j] += h[i] * d[j]; + } + } + + modL(sm.subarray(32), x); + return smlen; +} + +function unpackneg(r, p) { + var t = gf(), chk = gf(), num = gf(), + den = gf(), den2 = gf(), den4 = gf(), + den6 = gf(); + + set25519(r[2], gf1); + unpack25519(r[1], p); + S(num, r[1]); + M(den, num, D); + Z(num, num, r[2]); + A(den, r[2], den); + + S(den2, den); + S(den4, den2); + M(den6, den4, den2); + M(t, den6, num); + M(t, t, den); + + pow2523(t, t); + M(t, t, num); + M(t, t, den); + M(t, t, den); + M(r[0], t, den); + + S(chk, r[0]); + M(chk, chk, den); + if (neq25519(chk, num)) M(r[0], r[0], I); + + S(chk, r[0]); + M(chk, chk, den); + if (neq25519(chk, num)) return -1; + + if (par25519(r[0]) === (p[31]>>7)) Z(r[0], gf0, r[0]); + + M(r[3], r[0], r[1]); + return 0; +} + +function crypto_sign_open(m, sm, n, pk) { + var i; + var t = new Uint8Array(32), h = new Uint8Array(64); + var p = [gf(), gf(), gf(), gf()], + q = [gf(), gf(), gf(), gf()]; + + if (n < 64) return -1; + + if (unpackneg(q, pk)) return -1; + + for (i = 0; i < n; i++) m[i] = sm[i]; + for (i = 0; i < 32; i++) m[i+32] = pk[i]; + crypto_hash(h, m, n); + reduce(h); + scalarmult(p, q, h); + + scalarbase(q, sm.subarray(32)); + add(p, q); + pack(t, p); + + n -= 64; + if (crypto_verify_32(sm, 0, t, 0)) { + for (i = 0; i < n; i++) m[i] = 0; + return -1; + } + + for (i = 0; i < n; i++) m[i] = sm[i + 64]; + return n; +} + +var crypto_secretbox_KEYBYTES = 32, + crypto_secretbox_NONCEBYTES = 24, + crypto_secretbox_ZEROBYTES = 32, + crypto_secretbox_BOXZEROBYTES = 16, + crypto_scalarmult_BYTES = 32, + crypto_scalarmult_SCALARBYTES = 32, + crypto_box_PUBLICKEYBYTES = 32, + crypto_box_SECRETKEYBYTES = 32, + crypto_box_BEFORENMBYTES = 32, + crypto_box_NONCEBYTES = crypto_secretbox_NONCEBYTES, + crypto_box_ZEROBYTES = crypto_secretbox_ZEROBYTES, + crypto_box_BOXZEROBYTES = crypto_secretbox_BOXZEROBYTES, + crypto_sign_BYTES = 64, + crypto_sign_PUBLICKEYBYTES = 32, + crypto_sign_SECRETKEYBYTES = 64, + crypto_sign_SEEDBYTES = 32, + crypto_hash_BYTES = 64; + +nacl.lowlevel = { + crypto_core_hsalsa20: crypto_core_hsalsa20, + crypto_stream_xor: crypto_stream_xor, + crypto_stream: crypto_stream, + crypto_stream_salsa20_xor: crypto_stream_salsa20_xor, + crypto_stream_salsa20: crypto_stream_salsa20, + crypto_onetimeauth: crypto_onetimeauth, + crypto_onetimeauth_verify: crypto_onetimeauth_verify, + crypto_verify_16: crypto_verify_16, + crypto_verify_32: crypto_verify_32, + crypto_secretbox: crypto_secretbox, + crypto_secretbox_open: crypto_secretbox_open, + crypto_scalarmult: crypto_scalarmult, + crypto_scalarmult_base: crypto_scalarmult_base, + crypto_box_beforenm: crypto_box_beforenm, + crypto_box_afternm: crypto_box_afternm, + crypto_box: crypto_box, + crypto_box_open: crypto_box_open, + crypto_box_keypair: crypto_box_keypair, + crypto_hash: crypto_hash, + crypto_sign: crypto_sign, + crypto_sign_keypair: crypto_sign_keypair, + crypto_sign_open: crypto_sign_open, + + crypto_secretbox_KEYBYTES: crypto_secretbox_KEYBYTES, + crypto_secretbox_NONCEBYTES: crypto_secretbox_NONCEBYTES, + crypto_secretbox_ZEROBYTES: crypto_secretbox_ZEROBYTES, + crypto_secretbox_BOXZEROBYTES: crypto_secretbox_BOXZEROBYTES, + crypto_scalarmult_BYTES: crypto_scalarmult_BYTES, + crypto_scalarmult_SCALARBYTES: crypto_scalarmult_SCALARBYTES, + crypto_box_PUBLICKEYBYTES: crypto_box_PUBLICKEYBYTES, + crypto_box_SECRETKEYBYTES: crypto_box_SECRETKEYBYTES, + crypto_box_BEFORENMBYTES: crypto_box_BEFORENMBYTES, + crypto_box_NONCEBYTES: crypto_box_NONCEBYTES, + crypto_box_ZEROBYTES: crypto_box_ZEROBYTES, + crypto_box_BOXZEROBYTES: crypto_box_BOXZEROBYTES, + crypto_sign_BYTES: crypto_sign_BYTES, + crypto_sign_PUBLICKEYBYTES: crypto_sign_PUBLICKEYBYTES, + crypto_sign_SECRETKEYBYTES: crypto_sign_SECRETKEYBYTES, + crypto_sign_SEEDBYTES: crypto_sign_SEEDBYTES, + crypto_hash_BYTES: crypto_hash_BYTES, + + gf: gf, + D: D, + L: L, + pack25519: pack25519, + unpack25519: unpack25519, + M: M, + A: A, + S: S, + Z: Z, + pow2523: pow2523, + add: add, + set25519: set25519, + modL: modL, + scalarmult: scalarmult, + scalarbase: scalarbase, +}; + +/* High-level API */ + +function checkLengths(k, n) { + if (k.length !== crypto_secretbox_KEYBYTES) throw new Error('bad key size'); + if (n.length !== crypto_secretbox_NONCEBYTES) throw new Error('bad nonce size'); +} + +function checkBoxLengths(pk, sk) { + if (pk.length !== crypto_box_PUBLICKEYBYTES) throw new Error('bad public key size'); + if (sk.length !== crypto_box_SECRETKEYBYTES) throw new Error('bad secret key size'); +} + +function checkArrayTypes() { + for (var i = 0; i < arguments.length; i++) { + if (!(arguments[i] instanceof Uint8Array)) + throw new TypeError('unexpected type, use Uint8Array'); + } +} + +function cleanup(arr) { + for (var i = 0; i < arr.length; i++) arr[i] = 0; +} + +nacl.randomBytes = function(n) { + var b = new Uint8Array(n); + randombytes(b, n); + return b; +}; + +nacl.secretbox = function(msg, nonce, key) { + checkArrayTypes(msg, nonce, key); + checkLengths(key, nonce); + var m = new Uint8Array(crypto_secretbox_ZEROBYTES + msg.length); + var c = new Uint8Array(m.length); + for (var i = 0; i < msg.length; i++) m[i+crypto_secretbox_ZEROBYTES] = msg[i]; + crypto_secretbox(c, m, m.length, nonce, key); + return c.subarray(crypto_secretbox_BOXZEROBYTES); +}; + +nacl.secretbox.open = function(box, nonce, key) { + checkArrayTypes(box, nonce, key); + checkLengths(key, nonce); + var c = new Uint8Array(crypto_secretbox_BOXZEROBYTES + box.length); + var m = new Uint8Array(c.length); + for (var i = 0; i < box.length; i++) c[i+crypto_secretbox_BOXZEROBYTES] = box[i]; + if (c.length < 32) return null; + if (crypto_secretbox_open(m, c, c.length, nonce, key) !== 0) return null; + return m.subarray(crypto_secretbox_ZEROBYTES); +}; + +nacl.secretbox.keyLength = crypto_secretbox_KEYBYTES; +nacl.secretbox.nonceLength = crypto_secretbox_NONCEBYTES; +nacl.secretbox.overheadLength = crypto_secretbox_BOXZEROBYTES; + +nacl.scalarMult = function(n, p) { + checkArrayTypes(n, p); + if (n.length !== crypto_scalarmult_SCALARBYTES) throw new Error('bad n size'); + if (p.length !== crypto_scalarmult_BYTES) throw new Error('bad p size'); + var q = new Uint8Array(crypto_scalarmult_BYTES); + crypto_scalarmult(q, n, p); + return q; +}; + +nacl.scalarMult.base = function(n) { + checkArrayTypes(n); + if (n.length !== crypto_scalarmult_SCALARBYTES) throw new Error('bad n size'); + var q = new Uint8Array(crypto_scalarmult_BYTES); + crypto_scalarmult_base(q, n); + return q; +}; + +nacl.scalarMult.scalarLength = crypto_scalarmult_SCALARBYTES; +nacl.scalarMult.groupElementLength = crypto_scalarmult_BYTES; + +nacl.box = function(msg, nonce, publicKey, secretKey) { + var k = nacl.box.before(publicKey, secretKey); + return nacl.secretbox(msg, nonce, k); +}; + +nacl.box.before = function(publicKey, secretKey) { + checkArrayTypes(publicKey, secretKey); + checkBoxLengths(publicKey, secretKey); + var k = new Uint8Array(crypto_box_BEFORENMBYTES); + crypto_box_beforenm(k, publicKey, secretKey); + return k; +}; + +nacl.box.after = nacl.secretbox; + +nacl.box.open = function(msg, nonce, publicKey, secretKey) { + var k = nacl.box.before(publicKey, secretKey); + return nacl.secretbox.open(msg, nonce, k); +}; + +nacl.box.open.after = nacl.secretbox.open; + +nacl.box.keyPair = function() { + var pk = new Uint8Array(crypto_box_PUBLICKEYBYTES); + var sk = new Uint8Array(crypto_box_SECRETKEYBYTES); + crypto_box_keypair(pk, sk); + return {publicKey: pk, secretKey: sk}; +}; + +nacl.box.keyPair.fromSecretKey = function(secretKey) { + checkArrayTypes(secretKey); + if (secretKey.length !== crypto_box_SECRETKEYBYTES) + throw new Error('bad secret key size'); + var pk = new Uint8Array(crypto_box_PUBLICKEYBYTES); + crypto_scalarmult_base(pk, secretKey); + return {publicKey: pk, secretKey: new Uint8Array(secretKey)}; +}; + +nacl.box.publicKeyLength = crypto_box_PUBLICKEYBYTES; +nacl.box.secretKeyLength = crypto_box_SECRETKEYBYTES; +nacl.box.sharedKeyLength = crypto_box_BEFORENMBYTES; +nacl.box.nonceLength = crypto_box_NONCEBYTES; +nacl.box.overheadLength = nacl.secretbox.overheadLength; + +nacl.sign = function(msg, secretKey) { + checkArrayTypes(msg, secretKey); + if (secretKey.length !== crypto_sign_SECRETKEYBYTES) + throw new Error('bad secret key size'); + var signedMsg = new Uint8Array(crypto_sign_BYTES+msg.length); + crypto_sign(signedMsg, msg, msg.length, secretKey); + return signedMsg; +}; + +nacl.sign.open = function(signedMsg, publicKey) { + checkArrayTypes(signedMsg, publicKey); + if (publicKey.length !== crypto_sign_PUBLICKEYBYTES) + throw new Error('bad public key size'); + var tmp = new Uint8Array(signedMsg.length); + var mlen = crypto_sign_open(tmp, signedMsg, signedMsg.length, publicKey); + if (mlen < 0) return null; + var m = new Uint8Array(mlen); + for (var i = 0; i < m.length; i++) m[i] = tmp[i]; + return m; +}; + +nacl.sign.detached = function(msg, secretKey) { + var signedMsg = nacl.sign(msg, secretKey); + var sig = new Uint8Array(crypto_sign_BYTES); + for (var i = 0; i < sig.length; i++) sig[i] = signedMsg[i]; + return sig; +}; + +nacl.sign.detached.verify = function(msg, sig, publicKey) { + checkArrayTypes(msg, sig, publicKey); + if (sig.length !== crypto_sign_BYTES) + throw new Error('bad signature size'); + if (publicKey.length !== crypto_sign_PUBLICKEYBYTES) + throw new Error('bad public key size'); + var sm = new Uint8Array(crypto_sign_BYTES + msg.length); + var m = new Uint8Array(crypto_sign_BYTES + msg.length); + var i; + for (i = 0; i < crypto_sign_BYTES; i++) sm[i] = sig[i]; + for (i = 0; i < msg.length; i++) sm[i+crypto_sign_BYTES] = msg[i]; + return (crypto_sign_open(m, sm, sm.length, publicKey) >= 0); +}; + +nacl.sign.keyPair = function() { + var pk = new Uint8Array(crypto_sign_PUBLICKEYBYTES); + var sk = new Uint8Array(crypto_sign_SECRETKEYBYTES); + crypto_sign_keypair(pk, sk); + return {publicKey: pk, secretKey: sk}; +}; + +nacl.sign.keyPair.fromSecretKey = function(secretKey) { + checkArrayTypes(secretKey); + if (secretKey.length !== crypto_sign_SECRETKEYBYTES) + throw new Error('bad secret key size'); + var pk = new Uint8Array(crypto_sign_PUBLICKEYBYTES); + for (var i = 0; i < pk.length; i++) pk[i] = secretKey[32+i]; + return {publicKey: pk, secretKey: new Uint8Array(secretKey)}; +}; + +nacl.sign.keyPair.fromSeed = function(seed) { + checkArrayTypes(seed); + if (seed.length !== crypto_sign_SEEDBYTES) + throw new Error('bad seed size'); + var pk = new Uint8Array(crypto_sign_PUBLICKEYBYTES); + var sk = new Uint8Array(crypto_sign_SECRETKEYBYTES); + for (var i = 0; i < 32; i++) sk[i] = seed[i]; + crypto_sign_keypair(pk, sk, true); + return {publicKey: pk, secretKey: sk}; +}; + +nacl.sign.publicKeyLength = crypto_sign_PUBLICKEYBYTES; +nacl.sign.secretKeyLength = crypto_sign_SECRETKEYBYTES; +nacl.sign.seedLength = crypto_sign_SEEDBYTES; +nacl.sign.signatureLength = crypto_sign_BYTES; + +nacl.hash = function(msg) { + checkArrayTypes(msg); + var h = new Uint8Array(crypto_hash_BYTES); + crypto_hash(h, msg, msg.length); + return h; +}; + +nacl.hash.hashLength = crypto_hash_BYTES; + +nacl.verify = function(x, y) { + checkArrayTypes(x, y); + // Zero length arguments are considered not equal. + if (x.length === 0 || y.length === 0) return false; + if (x.length !== y.length) return false; + return (vn(x, 0, y, 0, x.length) === 0) ? true : false; +}; + +nacl.setPRNG = function(fn) { + randombytes = fn; +}; + +(function() { + // Initialize PRNG if environment provides CSPRNG. + // If not, methods calling randombytes will throw. + var crypto = typeof self !== 'undefined' ? (self.crypto || self.msCrypto) : null; + if (crypto && crypto.getRandomValues) { + // Browsers. + var QUOTA = 65536; + nacl.setPRNG(function(x, n) { + var i, v = new Uint8Array(n); + for (i = 0; i < n; i += QUOTA) { + crypto.getRandomValues(v.subarray(i, i + Math.min(n - i, QUOTA))); + } + for (i = 0; i < n; i++) x[i] = v[i]; + cleanup(v); + }); + } else if (typeof require !== 'undefined') { + // Node.js. + crypto = require('crypto'); + if (crypto && crypto.randomBytes) { + nacl.setPRNG(function(x, n) { + var i, v = crypto.randomBytes(n); + for (i = 0; i < n; i++) x[i] = v[i]; + cleanup(v); + }); + } + } +})(); + +})(typeof module !== 'undefined' && module.exports ? module.exports : (self.nacl = self.nacl || {})); diff --git a/core/third-party/pako.js b/core/third-party/pako.js new file mode 100644 index 0000000..ce30a03 --- /dev/null +++ b/core/third-party/pako.js @@ -0,0 +1,6373 @@ +/* pako 0.2.6 nodeca/pako */(function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.pako = f()}})(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o Array + * + * Chunks of output data, if [[Deflate#onData]] not overriden. + **/ + +/** + * Deflate.result -> Uint8Array|Array + * + * Compressed result, generated by default [[Deflate#onData]] + * and [[Deflate#onEnd]] handlers. Filled after you push last chunk + * (call [[Deflate#push]] with `Z_FINISH` / `true` param). + **/ + +/** + * Deflate.err -> Number + * + * Error code after deflate finished. 0 (Z_OK) on success. + * You will not need it in real life, because deflate errors + * are possible only on wrong options or bad `onData` / `onEnd` + * custom handlers. + **/ + +/** + * Deflate.msg -> String + * + * Error message, if [[Deflate.err]] != 0 + **/ + + +/** + * new Deflate(options) + * - options (Object): zlib deflate options. + * + * Creates new deflator instance with specified params. Throws exception + * on bad params. Supported options: + * + * - `level` + * - `windowBits` + * - `memLevel` + * - `strategy` + * + * [http://zlib.net/manual.html#Advanced](http://zlib.net/manual.html#Advanced) + * for more information on these. + * + * Additional options, for internal needs: + * + * - `chunkSize` - size of generated data chunks (16K by default) + * - `raw` (Boolean) - do raw deflate + * - `gzip` (Boolean) - create gzip wrapper + * - `to` (String) - if equal to 'string', then result will be "binary string" + * (each char code [0..255]) + * - `header` (Object) - custom header for gzip + * - `text` (Boolean) - true if compressed data believed to be text + * - `time` (Number) - modification time, unix timestamp + * - `os` (Number) - operation system code + * - `extra` (Array) - array of bytes with extra data (max 65536) + * - `name` (String) - file name (binary string) + * - `comment` (String) - comment (binary string) + * - `hcrc` (Boolean) - true if header crc should be added + * + * ##### Example: + * + * ```javascript + * var pako = require('pako') + * , chunk1 = Uint8Array([1,2,3,4,5,6,7,8,9]) + * , chunk2 = Uint8Array([10,11,12,13,14,15,16,17,18,19]); + * + * var deflate = new pako.Deflate({ level: 3}); + * + * deflate.push(chunk1, false); + * deflate.push(chunk2, true); // true -> last chunk + * + * if (deflate.err) { throw new Error(deflate.err); } + * + * console.log(deflate.result); + * ``` + **/ +var Deflate = function(options) { + + this.options = utils.assign({ + level: Z_DEFAULT_COMPRESSION, + method: Z_DEFLATED, + chunkSize: 16384, + windowBits: 15, + memLevel: 8, + strategy: Z_DEFAULT_STRATEGY, + to: '' + }, options || {}); + + var opt = this.options; + + if (opt.raw && (opt.windowBits > 0)) { + opt.windowBits = -opt.windowBits; + } + + else if (opt.gzip && (opt.windowBits > 0) && (opt.windowBits < 16)) { + opt.windowBits += 16; + } + + this.err = 0; // error code, if happens (0 = Z_OK) + this.msg = ''; // error message + this.ended = false; // used to avoid multiple onEnd() calls + this.chunks = []; // chunks of compressed data + + this.strm = new zstream(); + this.strm.avail_out = 0; + + var status = zlib_deflate.deflateInit2( + this.strm, + opt.level, + opt.method, + opt.windowBits, + opt.memLevel, + opt.strategy + ); + + if (status !== Z_OK) { + throw new Error(msg[status]); + } + + if (opt.header) { + zlib_deflate.deflateSetHeader(this.strm, opt.header); + } +}; + +/** + * Deflate#push(data[, mode]) -> Boolean + * - data (Uint8Array|Array|ArrayBuffer|String): input data. Strings will be + * converted to utf8 byte sequence. + * - mode (Number|Boolean): 0..6 for corresponding Z_NO_FLUSH..Z_TREE modes. + * See constants. Skipped or `false` means Z_NO_FLUSH, `true` meansh Z_FINISH. + * + * Sends input data to deflate pipe, generating [[Deflate#onData]] calls with + * new compressed chunks. Returns `true` on success. The last data block must have + * mode Z_FINISH (or `true`). That flush internal pending buffers and call + * [[Deflate#onEnd]]. + * + * On fail call [[Deflate#onEnd]] with error code and return false. + * + * We strongly recommend to use `Uint8Array` on input for best speed (output + * array format is detected automatically). Also, don't skip last param and always + * use the same type in your code (boolean or number). That will improve JS speed. + * + * For regular `Array`-s make sure all elements are [0..255]. + * + * ##### Example + * + * ```javascript + * push(chunk, false); // push one of data chunks + * ... + * push(chunk, true); // push last chunk + * ``` + **/ +Deflate.prototype.push = function(data, mode) { + var strm = this.strm; + var chunkSize = this.options.chunkSize; + var status, _mode; + + if (this.ended) { return false; } + + _mode = (mode === ~~mode) ? mode : ((mode === true) ? Z_FINISH : Z_NO_FLUSH); + + // Convert data if needed + if (typeof data === 'string') { + // If we need to compress text, change encoding to utf8. + strm.input = strings.string2buf(data); + } else if (toString.call(data) === '[object ArrayBuffer]') { + strm.input = new Uint8Array(data); + } else { + strm.input = data; + } + + strm.next_in = 0; + strm.avail_in = strm.input.length; + + do { + if (strm.avail_out === 0) { + strm.output = new utils.Buf8(chunkSize); + strm.next_out = 0; + strm.avail_out = chunkSize; + } + status = zlib_deflate.deflate(strm, _mode); /* no bad return value */ + + if (status !== Z_STREAM_END && status !== Z_OK) { + this.onEnd(status); + this.ended = true; + return false; + } + if (strm.avail_out === 0 || (strm.avail_in === 0 && _mode === Z_FINISH)) { + if (this.options.to === 'string') { + this.onData(strings.buf2binstring(utils.shrinkBuf(strm.output, strm.next_out))); + } else { + this.onData(utils.shrinkBuf(strm.output, strm.next_out)); + } + } + } while ((strm.avail_in > 0 || strm.avail_out === 0) && status !== Z_STREAM_END); + + // Finalize on the last chunk. + if (_mode === Z_FINISH) { + status = zlib_deflate.deflateEnd(this.strm); + this.onEnd(status); + this.ended = true; + return status === Z_OK; + } + + return true; +}; + + +/** + * Deflate#onData(chunk) -> Void + * - chunk (Uint8Array|Array|String): ouput data. Type of array depends + * on js engine support. When string output requested, each chunk + * will be string. + * + * By default, stores data blocks in `chunks[]` property and glue + * those in `onEnd`. Override this handler, if you need another behaviour. + **/ +Deflate.prototype.onData = function(chunk) { + this.chunks.push(chunk); +}; + + +/** + * Deflate#onEnd(status) -> Void + * - status (Number): deflate status. 0 (Z_OK) on success, + * other if not. + * + * Called once after you tell deflate that input stream complete + * or error happenned. By default - join collected chunks, + * free memory and fill `results` / `err` properties. + **/ +Deflate.prototype.onEnd = function(status) { + // On success - join + if (status === Z_OK) { + if (this.options.to === 'string') { + this.result = this.chunks.join(''); + } else { + this.result = utils.flattenChunks(this.chunks); + } + } + this.chunks = []; + this.err = status; + this.msg = this.strm.msg; +}; + + +/** + * deflate(data[, options]) -> Uint8Array|Array|String + * - data (Uint8Array|Array|String): input data to compress. + * - options (Object): zlib deflate options. + * + * Compress `data` with deflate alrorythm and `options`. + * + * Supported options are: + * + * - level + * - windowBits + * - memLevel + * - strategy + * + * [http://zlib.net/manual.html#Advanced](http://zlib.net/manual.html#Advanced) + * for more information on these. + * + * Sugar (options): + * + * - `raw` (Boolean) - say that we work with raw stream, if you don't wish to specify + * negative windowBits implicitly. + * - `to` (String) - if equal to 'string', then result will be "binary string" + * (each char code [0..255]) + * + * ##### Example: + * + * ```javascript + * var pako = require('pako') + * , data = Uint8Array([1,2,3,4,5,6,7,8,9]); + * + * console.log(pako.deflate(data)); + * ``` + **/ +function deflate(input, options) { + var deflator = new Deflate(options); + + deflator.push(input, true); + + // That will never happens, if you don't cheat with options :) + if (deflator.err) { throw deflator.msg; } + + return deflator.result; +} + + +/** + * deflateRaw(data[, options]) -> Uint8Array|Array|String + * - data (Uint8Array|Array|String): input data to compress. + * - options (Object): zlib deflate options. + * + * The same as [[deflate]], but creates raw data, without wrapper + * (header and adler32 crc). + **/ +function deflateRaw(input, options) { + options = options || {}; + options.raw = true; + return deflate(input, options); +} + + +/** + * gzip(data[, options]) -> Uint8Array|Array|String + * - data (Uint8Array|Array|String): input data to compress. + * - options (Object): zlib deflate options. + * + * The same as [[deflate]], but create gzip wrapper instead of + * deflate one. + **/ +function gzip(input, options) { + options = options || {}; + options.gzip = true; + return deflate(input, options); +} + + +exports.Deflate = Deflate; +exports.deflate = deflate; +exports.deflateRaw = deflateRaw; +exports.gzip = gzip; +},{"./utils/common":3,"./utils/strings":4,"./zlib/deflate.js":8,"./zlib/messages":13,"./zlib/zstream":15}],2:[function(require,module,exports){ +'use strict'; + + +var zlib_inflate = require('./zlib/inflate.js'); +var utils = require('./utils/common'); +var strings = require('./utils/strings'); +var c = require('./zlib/constants'); +var msg = require('./zlib/messages'); +var zstream = require('./zlib/zstream'); +var gzheader = require('./zlib/gzheader'); + +var toString = Object.prototype.toString; + +/** + * class Inflate + * + * Generic JS-style wrapper for zlib calls. If you don't need + * streaming behaviour - use more simple functions: [[inflate]] + * and [[inflateRaw]]. + **/ + +/* internal + * inflate.chunks -> Array + * + * Chunks of output data, if [[Inflate#onData]] not overriden. + **/ + +/** + * Inflate.result -> Uint8Array|Array|String + * + * Uncompressed result, generated by default [[Inflate#onData]] + * and [[Inflate#onEnd]] handlers. Filled after you push last chunk + * (call [[Inflate#push]] with `Z_FINISH` / `true` param). + **/ + +/** + * Inflate.err -> Number + * + * Error code after inflate finished. 0 (Z_OK) on success. + * Should be checked if broken data possible. + **/ + +/** + * Inflate.msg -> String + * + * Error message, if [[Inflate.err]] != 0 + **/ + + +/** + * new Inflate(options) + * - options (Object): zlib inflate options. + * + * Creates new inflator instance with specified params. Throws exception + * on bad params. Supported options: + * + * - `windowBits` + * + * [http://zlib.net/manual.html#Advanced](http://zlib.net/manual.html#Advanced) + * for more information on these. + * + * Additional options, for internal needs: + * + * - `chunkSize` - size of generated data chunks (16K by default) + * - `raw` (Boolean) - do raw inflate + * - `to` (String) - if equal to 'string', then result will be converted + * from utf8 to utf16 (javascript) string. When string output requested, + * chunk length can differ from `chunkSize`, depending on content. + * + * By default, when no options set, autodetect deflate/gzip data format via + * wrapper header. + * + * ##### Example: + * + * ```javascript + * var pako = require('pako') + * , chunk1 = Uint8Array([1,2,3,4,5,6,7,8,9]) + * , chunk2 = Uint8Array([10,11,12,13,14,15,16,17,18,19]); + * + * var inflate = new pako.Inflate({ level: 3}); + * + * inflate.push(chunk1, false); + * inflate.push(chunk2, true); // true -> last chunk + * + * if (inflate.err) { throw new Error(inflate.err); } + * + * console.log(inflate.result); + * ``` + **/ +var Inflate = function(options) { + + this.options = utils.assign({ + chunkSize: 16384, + windowBits: 0, + to: '' + }, options || {}); + + var opt = this.options; + + // Force window size for `raw` data, if not set directly, + // because we have no header for autodetect. + if (opt.raw && (opt.windowBits >= 0) && (opt.windowBits < 16)) { + opt.windowBits = -opt.windowBits; + if (opt.windowBits === 0) { opt.windowBits = -15; } + } + + // If `windowBits` not defined (and mode not raw) - set autodetect flag for gzip/deflate + if ((opt.windowBits >= 0) && (opt.windowBits < 16) && + !(options && options.windowBits)) { + opt.windowBits += 32; + } + + // Gzip header has no info about windows size, we can do autodetect only + // for deflate. So, if window size not set, force it to max when gzip possible + if ((opt.windowBits > 15) && (opt.windowBits < 48)) { + // bit 3 (16) -> gzipped data + // bit 4 (32) -> autodetect gzip/deflate + if ((opt.windowBits & 15) === 0) { + opt.windowBits |= 15; + } + } + + this.err = 0; // error code, if happens (0 = Z_OK) + this.msg = ''; // error message + this.ended = false; // used to avoid multiple onEnd() calls + this.chunks = []; // chunks of compressed data + + this.strm = new zstream(); + this.strm.avail_out = 0; + + var status = zlib_inflate.inflateInit2( + this.strm, + opt.windowBits + ); + + if (status !== c.Z_OK) { + throw new Error(msg[status]); + } + + this.header = new gzheader(); + + zlib_inflate.inflateGetHeader(this.strm, this.header); +}; + +/** + * Inflate#push(data[, mode]) -> Boolean + * - data (Uint8Array|Array|ArrayBuffer|String): input data + * - mode (Number|Boolean): 0..6 for corresponding Z_NO_FLUSH..Z_TREE modes. + * See constants. Skipped or `false` means Z_NO_FLUSH, `true` meansh Z_FINISH. + * + * Sends input data to inflate pipe, generating [[Inflate#onData]] calls with + * new output chunks. Returns `true` on success. The last data block must have + * mode Z_FINISH (or `true`). That flush internal pending buffers and call + * [[Inflate#onEnd]]. + * + * On fail call [[Inflate#onEnd]] with error code and return false. + * + * We strongly recommend to use `Uint8Array` on input for best speed (output + * format is detected automatically). Also, don't skip last param and always + * use the same type in your code (boolean or number). That will improve JS speed. + * + * For regular `Array`-s make sure all elements are [0..255]. + * + * ##### Example + * + * ```javascript + * push(chunk, false); // push one of data chunks + * ... + * push(chunk, true); // push last chunk + * ``` + **/ +Inflate.prototype.push = function(data, mode) { + var strm = this.strm; + var chunkSize = this.options.chunkSize; + var status, _mode; + var next_out_utf8, tail, utf8str; + + if (this.ended) { return false; } + _mode = (mode === ~~mode) ? mode : ((mode === true) ? c.Z_FINISH : c.Z_NO_FLUSH); + + // Convert data if needed + if (typeof data === 'string') { + // Only binary strings can be decompressed on practice + strm.input = strings.binstring2buf(data); + } else if (toString.call(data) === '[object ArrayBuffer]') { + strm.input = new Uint8Array(data); + } else { + strm.input = data; + } + + strm.next_in = 0; + strm.avail_in = strm.input.length; + + do { + if (strm.avail_out === 0) { + strm.output = new utils.Buf8(chunkSize); + strm.next_out = 0; + strm.avail_out = chunkSize; + } + + status = zlib_inflate.inflate(strm, c.Z_NO_FLUSH); /* no bad return value */ + + if (status !== c.Z_STREAM_END && status !== c.Z_OK) { + this.onEnd(status); + this.ended = true; + return false; + } + + if (strm.next_out) { + if (strm.avail_out === 0 || status === c.Z_STREAM_END || (strm.avail_in === 0 && _mode === c.Z_FINISH)) { + + if (this.options.to === 'string') { + + next_out_utf8 = strings.utf8border(strm.output, strm.next_out); + + tail = strm.next_out - next_out_utf8; + utf8str = strings.buf2string(strm.output, next_out_utf8); + + // move tail + strm.next_out = tail; + strm.avail_out = chunkSize - tail; + if (tail) { utils.arraySet(strm.output, strm.output, next_out_utf8, tail, 0); } + + this.onData(utf8str); + + } else { + this.onData(utils.shrinkBuf(strm.output, strm.next_out)); + } + } + } + } while ((strm.avail_in > 0) && status !== c.Z_STREAM_END); + + if (status === c.Z_STREAM_END) { + _mode = c.Z_FINISH; + } + // Finalize on the last chunk. + if (_mode === c.Z_FINISH) { + status = zlib_inflate.inflateEnd(this.strm); + this.onEnd(status); + this.ended = true; + return status === c.Z_OK; + } + + return true; +}; + + +/** + * Inflate#onData(chunk) -> Void + * - chunk (Uint8Array|Array|String): ouput data. Type of array depends + * on js engine support. When string output requested, each chunk + * will be string. + * + * By default, stores data blocks in `chunks[]` property and glue + * those in `onEnd`. Override this handler, if you need another behaviour. + **/ +Inflate.prototype.onData = function(chunk) { + this.chunks.push(chunk); +}; + + +/** + * Inflate#onEnd(status) -> Void + * - status (Number): inflate status. 0 (Z_OK) on success, + * other if not. + * + * Called once after you tell inflate that input stream complete + * or error happenned. By default - join collected chunks, + * free memory and fill `results` / `err` properties. + **/ +Inflate.prototype.onEnd = function(status) { + // On success - join + if (status === c.Z_OK) { + if (this.options.to === 'string') { + // Glue & convert here, until we teach pako to send + // utf8 alligned strings to onData + this.result = this.chunks.join(''); + } else { + this.result = utils.flattenChunks(this.chunks); + } + } + this.chunks = []; + this.err = status; + this.msg = this.strm.msg; +}; + + +/** + * inflate(data[, options]) -> Uint8Array|Array|String + * - data (Uint8Array|Array|String): input data to decompress. + * - options (Object): zlib inflate options. + * + * Decompress `data` with inflate/ungzip and `options`. Autodetect + * format via wrapper header by default. That's why we don't provide + * separate `ungzip` method. + * + * Supported options are: + * + * - windowBits + * + * [http://zlib.net/manual.html#Advanced](http://zlib.net/manual.html#Advanced) + * for more information. + * + * Sugar (options): + * + * - `raw` (Boolean) - say that we work with raw stream, if you don't wish to specify + * negative windowBits implicitly. + * - `to` (String) - if equal to 'string', then result will be converted + * from utf8 to utf16 (javascript) string. When string output requested, + * chunk length can differ from `chunkSize`, depending on content. + * + * + * ##### Example: + * + * ```javascript + * var pako = require('pako') + * , input = pako.deflate([1,2,3,4,5,6,7,8,9]) + * , output; + * + * try { + * output = pako.inflate(input); + * } catch (err) + * console.log(err); + * } + * ``` + **/ +function inflate(input, options) { + var inflator = new Inflate(options); + + inflator.push(input, true); + + // That will never happens, if you don't cheat with options :) + if (inflator.err) { throw inflator.msg; } + + return inflator.result; +} + + +/** + * inflateRaw(data[, options]) -> Uint8Array|Array|String + * - data (Uint8Array|Array|String): input data to decompress. + * - options (Object): zlib inflate options. + * + * The same as [[inflate]], but creates raw data, without wrapper + * (header and adler32 crc). + **/ +function inflateRaw(input, options) { + options = options || {}; + options.raw = true; + return inflate(input, options); +} + + +/** + * ungzip(data[, options]) -> Uint8Array|Array|String + * - data (Uint8Array|Array|String): input data to decompress. + * - options (Object): zlib inflate options. + * + * Just shortcut to [[inflate]], because it autodetects format + * by header.content. Done for convenience. + **/ + + +exports.Inflate = Inflate; +exports.inflate = inflate; +exports.inflateRaw = inflateRaw; +exports.ungzip = inflate; + +},{"./utils/common":3,"./utils/strings":4,"./zlib/constants":6,"./zlib/gzheader":9,"./zlib/inflate.js":11,"./zlib/messages":13,"./zlib/zstream":15}],3:[function(require,module,exports){ +'use strict'; + + +var TYPED_OK = (typeof Uint8Array !== 'undefined') && + (typeof Uint16Array !== 'undefined') && + (typeof Int32Array !== 'undefined'); + + +exports.assign = function (obj /*from1, from2, from3, ...*/) { + var sources = Array.prototype.slice.call(arguments, 1); + while (sources.length) { + var source = sources.shift(); + if (!source) { continue; } + + if (typeof(source) !== 'object') { + throw new TypeError(source + 'must be non-object'); + } + + for (var p in source) { + if (source.hasOwnProperty(p)) { + obj[p] = source[p]; + } + } + } + + return obj; +}; + + +// reduce buffer size, avoiding mem copy +exports.shrinkBuf = function (buf, size) { + if (buf.length === size) { return buf; } + if (buf.subarray) { return buf.subarray(0, size); } + buf.length = size; + return buf; +}; + + +var fnTyped = { + arraySet: function (dest, src, src_offs, len, dest_offs) { + if (src.subarray && dest.subarray) { + dest.set(src.subarray(src_offs, src_offs+len), dest_offs); + return; + } + // Fallback to ordinary array + for(var i=0; i= 252 ? 6 : i >= 248 ? 5 : i >= 240 ? 4 : i >= 224 ? 3 : i >= 192 ? 2 : 1); +} +_utf8len[254]=_utf8len[254]=1; // Invalid sequence start + + +// convert string to array (typed, when possible) +exports.string2buf = function (str) { + var buf, c, c2, m_pos, i, str_len = str.length, buf_len = 0; + + // count binary size + for (m_pos = 0; m_pos < str_len; m_pos++) { + c = str.charCodeAt(m_pos); + if ((c & 0xfc00) === 0xd800 && (m_pos+1 < str_len)) { + c2 = str.charCodeAt(m_pos+1); + if ((c2 & 0xfc00) === 0xdc00) { + c = 0x10000 + ((c - 0xd800) << 10) + (c2 - 0xdc00); + m_pos++; + } + } + buf_len += c < 0x80 ? 1 : c < 0x800 ? 2 : c < 0x10000 ? 3 : 4; + } + + // allocate buffer + buf = new utils.Buf8(buf_len); + + // convert + for (i=0, m_pos = 0; i < buf_len; m_pos++) { + c = str.charCodeAt(m_pos); + if ((c & 0xfc00) === 0xd800 && (m_pos+1 < str_len)) { + c2 = str.charCodeAt(m_pos+1); + if ((c2 & 0xfc00) === 0xdc00) { + c = 0x10000 + ((c - 0xd800) << 10) + (c2 - 0xdc00); + m_pos++; + } + } + if (c < 0x80) { + /* one byte */ + buf[i++] = c; + } else if (c < 0x800) { + /* two bytes */ + buf[i++] = 0xC0 | (c >>> 6); + buf[i++] = 0x80 | (c & 0x3f); + } else if (c < 0x10000) { + /* three bytes */ + buf[i++] = 0xE0 | (c >>> 12); + buf[i++] = 0x80 | (c >>> 6 & 0x3f); + buf[i++] = 0x80 | (c & 0x3f); + } else { + /* four bytes */ + buf[i++] = 0xf0 | (c >>> 18); + buf[i++] = 0x80 | (c >>> 12 & 0x3f); + buf[i++] = 0x80 | (c >>> 6 & 0x3f); + buf[i++] = 0x80 | (c & 0x3f); + } + } + + return buf; +}; + +// Helper (used in 2 places) +function buf2binstring(buf, len) { + // use fallback for big arrays to avoid stack overflow + if (len < 65537) { + if ((buf.subarray && STR_APPLY_UIA_OK) || (!buf.subarray && STR_APPLY_OK)) { + return String.fromCharCode.apply(null, utils.shrinkBuf(buf, len)); + } + } + + var result = ''; + for(var i=0; i < len; i++) { + result += String.fromCharCode(buf[i]); + } + return result; +} + + +// Convert byte array to binary string +exports.buf2binstring = function(buf) { + return buf2binstring(buf, buf.length); +}; + + +// Convert binary string (typed, when possible) +exports.binstring2buf = function(str) { + var buf = new utils.Buf8(str.length); + for(var i=0, len=buf.length; i < len; i++) { + buf[i] = str.charCodeAt(i); + } + return buf; +}; + + +// convert array to string +exports.buf2string = function (buf, max) { + var i, out, c, c_len; + var len = max || buf.length; + + // Reserve max possible length (2 words per char) + // NB: by unknown reasons, Array is significantly faster for + // String.fromCharCode.apply than Uint16Array. + var utf16buf = new Array(len*2); + + for (out=0, i=0; i 4) { utf16buf[out++] = 0xfffd; i += c_len-1; continue; } + + // apply mask on first byte + c &= c_len === 2 ? 0x1f : c_len === 3 ? 0x0f : 0x07; + // join the rest + while (c_len > 1 && i < len) { + c = (c << 6) | (buf[i++] & 0x3f); + c_len--; + } + + // terminated by end of string? + if (c_len > 1) { utf16buf[out++] = 0xfffd; continue; } + + if (c < 0x10000) { + utf16buf[out++] = c; + } else { + c -= 0x10000; + utf16buf[out++] = 0xd800 | ((c >> 10) & 0x3ff); + utf16buf[out++] = 0xdc00 | (c & 0x3ff); + } + } + + return buf2binstring(utf16buf, out); +}; + + +// Calculate max possible position in utf8 buffer, +// that will not break sequence. If that's not possible +// - (very small limits) return max size as is. +// +// buf[] - utf8 bytes array +// max - length limit (mandatory); +exports.utf8border = function(buf, max) { + var pos; + + max = max || buf.length; + if (max > buf.length) { max = buf.length; } + + // go back from last position, until start of sequence found + pos = max-1; + while (pos >= 0 && (buf[pos] & 0xC0) === 0x80) { pos--; } + + // Fuckup - very small and broken sequence, + // return max, because we should return something anyway. + if (pos < 0) { return max; } + + // If we came to start of buffer - that means vuffer is too small, + // return max too. + if (pos === 0) { return max; } + + return (pos + _utf8len[buf[pos]] > max) ? pos : max; +}; + +},{"./common":3}],5:[function(require,module,exports){ +'use strict'; + +// Note: adler32 takes 12% for level 0 and 2% for level 6. +// It doesn't worth to make additional optimizationa as in original. +// Small size is preferable. + +function adler32(adler, buf, len, pos) { + var s1 = (adler & 0xffff) |0 + , s2 = ((adler >>> 16) & 0xffff) |0 + , n = 0; + + while (len !== 0) { + // Set limit ~ twice less than 5552, to keep + // s2 in 31-bits, because we force signed ints. + // in other case %= will fail. + n = len > 2000 ? 2000 : len; + len -= n; + + do { + s1 = (s1 + buf[pos++]) |0; + s2 = (s2 + s1) |0; + } while (--n); + + s1 %= 65521; + s2 %= 65521; + } + + return (s1 | (s2 << 16)) |0; +} + + +module.exports = adler32; +},{}],6:[function(require,module,exports){ +module.exports = { + + /* Allowed flush values; see deflate() and inflate() below for details */ + Z_NO_FLUSH: 0, + Z_PARTIAL_FLUSH: 1, + Z_SYNC_FLUSH: 2, + Z_FULL_FLUSH: 3, + Z_FINISH: 4, + Z_BLOCK: 5, + Z_TREES: 6, + + /* Return codes for the compression/decompression functions. Negative values + * are errors, positive values are used for special but normal events. + */ + Z_OK: 0, + Z_STREAM_END: 1, + Z_NEED_DICT: 2, + Z_ERRNO: -1, + Z_STREAM_ERROR: -2, + Z_DATA_ERROR: -3, + //Z_MEM_ERROR: -4, + Z_BUF_ERROR: -5, + //Z_VERSION_ERROR: -6, + + /* compression levels */ + Z_NO_COMPRESSION: 0, + Z_BEST_SPEED: 1, + Z_BEST_COMPRESSION: 9, + Z_DEFAULT_COMPRESSION: -1, + + + Z_FILTERED: 1, + Z_HUFFMAN_ONLY: 2, + Z_RLE: 3, + Z_FIXED: 4, + Z_DEFAULT_STRATEGY: 0, + + /* Possible values of the data_type field (though see inflate()) */ + Z_BINARY: 0, + Z_TEXT: 1, + //Z_ASCII: 1, // = Z_TEXT (deprecated) + Z_UNKNOWN: 2, + + /* The deflate compression method */ + Z_DEFLATED: 8 + //Z_NULL: null // Use -1 or null inline, depending on var type +}; +},{}],7:[function(require,module,exports){ +'use strict'; + +// Note: we can't get significant speed boost here. +// So write code to minimize size - no pregenerated tables +// and array tools dependencies. + + +// Use ordinary array, since untyped makes no boost here +function makeTable() { + var c, table = []; + + for(var n =0; n < 256; n++){ + c = n; + for(var k =0; k < 8; k++){ + c = ((c&1) ? (0xEDB88320 ^ (c >>> 1)) : (c >>> 1)); + } + table[n] = c; + } + + return table; +} + +// Create table on load. Just 255 signed longs. Not a problem. +var crcTable = makeTable(); + + +function crc32(crc, buf, len, pos) { + var t = crcTable + , end = pos + len; + + crc = crc ^ (-1); + + for (var i = pos; i < end; i++ ) { + crc = (crc >>> 8) ^ t[(crc ^ buf[i]) & 0xFF]; + } + + return (crc ^ (-1)); // >>> 0; +} + + +module.exports = crc32; +},{}],8:[function(require,module,exports){ +'use strict'; + +var utils = require('../utils/common'); +var trees = require('./trees'); +var adler32 = require('./adler32'); +var crc32 = require('./crc32'); +var msg = require('./messages'); + +/* Public constants ==========================================================*/ +/* ===========================================================================*/ + + +/* Allowed flush values; see deflate() and inflate() below for details */ +var Z_NO_FLUSH = 0; +var Z_PARTIAL_FLUSH = 1; +//var Z_SYNC_FLUSH = 2; +var Z_FULL_FLUSH = 3; +var Z_FINISH = 4; +var Z_BLOCK = 5; +//var Z_TREES = 6; + + +/* Return codes for the compression/decompression functions. Negative values + * are errors, positive values are used for special but normal events. + */ +var Z_OK = 0; +var Z_STREAM_END = 1; +//var Z_NEED_DICT = 2; +//var Z_ERRNO = -1; +var Z_STREAM_ERROR = -2; +var Z_DATA_ERROR = -3; +//var Z_MEM_ERROR = -4; +var Z_BUF_ERROR = -5; +//var Z_VERSION_ERROR = -6; + + +/* compression levels */ +//var Z_NO_COMPRESSION = 0; +//var Z_BEST_SPEED = 1; +//var Z_BEST_COMPRESSION = 9; +var Z_DEFAULT_COMPRESSION = -1; + + +var Z_FILTERED = 1; +var Z_HUFFMAN_ONLY = 2; +var Z_RLE = 3; +var Z_FIXED = 4; +var Z_DEFAULT_STRATEGY = 0; + +/* Possible values of the data_type field (though see inflate()) */ +//var Z_BINARY = 0; +//var Z_TEXT = 1; +//var Z_ASCII = 1; // = Z_TEXT +var Z_UNKNOWN = 2; + + +/* The deflate compression method */ +var Z_DEFLATED = 8; + +/*============================================================================*/ + + +var MAX_MEM_LEVEL = 9; +/* Maximum value for memLevel in deflateInit2 */ +var MAX_WBITS = 15; +/* 32K LZ77 window */ +var DEF_MEM_LEVEL = 8; + + +var LENGTH_CODES = 29; +/* number of length codes, not counting the special END_BLOCK code */ +var LITERALS = 256; +/* number of literal bytes 0..255 */ +var L_CODES = LITERALS + 1 + LENGTH_CODES; +/* number of Literal or Length codes, including the END_BLOCK code */ +var D_CODES = 30; +/* number of distance codes */ +var BL_CODES = 19; +/* number of codes used to transfer the bit lengths */ +var HEAP_SIZE = 2*L_CODES + 1; +/* maximum heap size */ +var MAX_BITS = 15; +/* All codes must not exceed MAX_BITS bits */ + +var MIN_MATCH = 3; +var MAX_MATCH = 258; +var MIN_LOOKAHEAD = (MAX_MATCH + MIN_MATCH + 1); + +var PRESET_DICT = 0x20; + +var INIT_STATE = 42; +var EXTRA_STATE = 69; +var NAME_STATE = 73; +var COMMENT_STATE = 91; +var HCRC_STATE = 103; +var BUSY_STATE = 113; +var FINISH_STATE = 666; + +var BS_NEED_MORE = 1; /* block not completed, need more input or more output */ +var BS_BLOCK_DONE = 2; /* block flush performed */ +var BS_FINISH_STARTED = 3; /* finish started, need only more output at next deflate */ +var BS_FINISH_DONE = 4; /* finish done, accept no more input or output */ + +var OS_CODE = 0x03; // Unix :) . Don't detect, use this default. + +function err(strm, errorCode) { + strm.msg = msg[errorCode]; + return errorCode; +} + +function rank(f) { + return ((f) << 1) - ((f) > 4 ? 9 : 0); +} + +function zero(buf) { var len = buf.length; while (--len >= 0) { buf[len] = 0; } } + + +/* ========================================================================= + * Flush as much pending output as possible. All deflate() output goes + * through this function so some applications may wish to modify it + * to avoid allocating a large strm->output buffer and copying into it. + * (See also read_buf()). + */ +function flush_pending(strm) { + var s = strm.state; + + //_tr_flush_bits(s); + var len = s.pending; + if (len > strm.avail_out) { + len = strm.avail_out; + } + if (len === 0) { return; } + + utils.arraySet(strm.output, s.pending_buf, s.pending_out, len, strm.next_out); + strm.next_out += len; + s.pending_out += len; + strm.total_out += len; + strm.avail_out -= len; + s.pending -= len; + if (s.pending === 0) { + s.pending_out = 0; + } +} + + +function flush_block_only (s, last) { + trees._tr_flush_block(s, (s.block_start >= 0 ? s.block_start : -1), s.strstart - s.block_start, last); + s.block_start = s.strstart; + flush_pending(s.strm); +} + + +function put_byte(s, b) { + s.pending_buf[s.pending++] = b; +} + + +/* ========================================================================= + * Put a short in the pending buffer. The 16-bit value is put in MSB order. + * IN assertion: the stream state is correct and there is enough room in + * pending_buf. + */ +function putShortMSB(s, b) { +// put_byte(s, (Byte)(b >> 8)); +// put_byte(s, (Byte)(b & 0xff)); + s.pending_buf[s.pending++] = (b >>> 8) & 0xff; + s.pending_buf[s.pending++] = b & 0xff; +} + + +/* =========================================================================== + * Read a new buffer from the current input stream, update the adler32 + * and total number of bytes read. All deflate() input goes through + * this function so some applications may wish to modify it to avoid + * allocating a large strm->input buffer and copying from it. + * (See also flush_pending()). + */ +function read_buf(strm, buf, start, size) { + var len = strm.avail_in; + + if (len > size) { len = size; } + if (len === 0) { return 0; } + + strm.avail_in -= len; + + utils.arraySet(buf, strm.input, strm.next_in, len, start); + if (strm.state.wrap === 1) { + strm.adler = adler32(strm.adler, buf, len, start); + } + + else if (strm.state.wrap === 2) { + strm.adler = crc32(strm.adler, buf, len, start); + } + + strm.next_in += len; + strm.total_in += len; + + return len; +} + + +/* =========================================================================== + * Set match_start to the longest match starting at the given string and + * return its length. Matches shorter or equal to prev_length are discarded, + * in which case the result is equal to prev_length and match_start is + * garbage. + * IN assertions: cur_match is the head of the hash chain for the current + * string (strstart) and its distance is <= MAX_DIST, and prev_length >= 1 + * OUT assertion: the match length is not greater than s->lookahead. + */ +function longest_match(s, cur_match) { + var chain_length = s.max_chain_length; /* max hash chain length */ + var scan = s.strstart; /* current string */ + var match; /* matched string */ + var len; /* length of current match */ + var best_len = s.prev_length; /* best match length so far */ + var nice_match = s.nice_match; /* stop if match long enough */ + var limit = (s.strstart > (s.w_size - MIN_LOOKAHEAD)) ? + s.strstart - (s.w_size - MIN_LOOKAHEAD) : 0/*NIL*/; + + var _win = s.window; // shortcut + + var wmask = s.w_mask; + var prev = s.prev; + + /* Stop when cur_match becomes <= limit. To simplify the code, + * we prevent matches with the string of window index 0. + */ + + var strend = s.strstart + MAX_MATCH; + var scan_end1 = _win[scan + best_len - 1]; + var scan_end = _win[scan + best_len]; + + /* The code is optimized for HASH_BITS >= 8 and MAX_MATCH-2 multiple of 16. + * It is easy to get rid of this optimization if necessary. + */ + // Assert(s->hash_bits >= 8 && MAX_MATCH == 258, "Code too clever"); + + /* Do not waste too much time if we already have a good match: */ + if (s.prev_length >= s.good_match) { + chain_length >>= 2; + } + /* Do not look for matches beyond the end of the input. This is necessary + * to make deflate deterministic. + */ + if (nice_match > s.lookahead) { nice_match = s.lookahead; } + + // Assert((ulg)s->strstart <= s->window_size-MIN_LOOKAHEAD, "need lookahead"); + + do { + // Assert(cur_match < s->strstart, "no future"); + match = cur_match; + + /* Skip to next match if the match length cannot increase + * or if the match length is less than 2. Note that the checks below + * for insufficient lookahead only occur occasionally for performance + * reasons. Therefore uninitialized memory will be accessed, and + * conditional jumps will be made that depend on those values. + * However the length of the match is limited to the lookahead, so + * the output of deflate is not affected by the uninitialized values. + */ + + if (_win[match + best_len] !== scan_end || + _win[match + best_len - 1] !== scan_end1 || + _win[match] !== _win[scan] || + _win[++match] !== _win[scan + 1]) { + continue; + } + + /* The check at best_len-1 can be removed because it will be made + * again later. (This heuristic is not always a win.) + * It is not necessary to compare scan[2] and match[2] since they + * are always equal when the other bytes match, given that + * the hash keys are equal and that HASH_BITS >= 8. + */ + scan += 2; + match++; + // Assert(*scan == *match, "match[2]?"); + + /* We check for insufficient lookahead only every 8th comparison; + * the 256th check will be made at strstart+258. + */ + do { + /*jshint noempty:false*/ + } while (_win[++scan] === _win[++match] && _win[++scan] === _win[++match] && + _win[++scan] === _win[++match] && _win[++scan] === _win[++match] && + _win[++scan] === _win[++match] && _win[++scan] === _win[++match] && + _win[++scan] === _win[++match] && _win[++scan] === _win[++match] && + scan < strend); + + // Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan"); + + len = MAX_MATCH - (strend - scan); + scan = strend - MAX_MATCH; + + if (len > best_len) { + s.match_start = cur_match; + best_len = len; + if (len >= nice_match) { + break; + } + scan_end1 = _win[scan + best_len - 1]; + scan_end = _win[scan + best_len]; + } + } while ((cur_match = prev[cur_match & wmask]) > limit && --chain_length !== 0); + + if (best_len <= s.lookahead) { + return best_len; + } + return s.lookahead; +} + + +/* =========================================================================== + * Fill the window when the lookahead becomes insufficient. + * Updates strstart and lookahead. + * + * IN assertion: lookahead < MIN_LOOKAHEAD + * OUT assertions: strstart <= window_size-MIN_LOOKAHEAD + * At least one byte has been read, or avail_in == 0; reads are + * performed for at least two bytes (required for the zip translate_eol + * option -- not supported here). + */ +function fill_window(s) { + var _w_size = s.w_size; + var p, n, m, more, str; + + //Assert(s->lookahead < MIN_LOOKAHEAD, "already enough lookahead"); + + do { + more = s.window_size - s.lookahead - s.strstart; + + // JS ints have 32 bit, block below not needed + /* Deal with !@#$% 64K limit: */ + //if (sizeof(int) <= 2) { + // if (more == 0 && s->strstart == 0 && s->lookahead == 0) { + // more = wsize; + // + // } else if (more == (unsigned)(-1)) { + // /* Very unlikely, but possible on 16 bit machine if + // * strstart == 0 && lookahead == 1 (input done a byte at time) + // */ + // more--; + // } + //} + + + /* If the window is almost full and there is insufficient lookahead, + * move the upper half to the lower one to make room in the upper half. + */ + if (s.strstart >= _w_size + (_w_size - MIN_LOOKAHEAD)) { + + utils.arraySet(s.window, s.window, _w_size, _w_size, 0); + s.match_start -= _w_size; + s.strstart -= _w_size; + /* we now have strstart >= MAX_DIST */ + s.block_start -= _w_size; + + /* Slide the hash table (could be avoided with 32 bit values + at the expense of memory usage). We slide even when level == 0 + to keep the hash table consistent if we switch back to level > 0 + later. (Using level 0 permanently is not an optimal usage of + zlib, so we don't care about this pathological case.) + */ + + n = s.hash_size; + p = n; + do { + m = s.head[--p]; + s.head[p] = (m >= _w_size ? m - _w_size : 0); + } while (--n); + + n = _w_size; + p = n; + do { + m = s.prev[--p]; + s.prev[p] = (m >= _w_size ? m - _w_size : 0); + /* If n is not on any hash chain, prev[n] is garbage but + * its value will never be used. + */ + } while (--n); + + more += _w_size; + } + if (s.strm.avail_in === 0) { + break; + } + + /* If there was no sliding: + * strstart <= WSIZE+MAX_DIST-1 && lookahead <= MIN_LOOKAHEAD - 1 && + * more == window_size - lookahead - strstart + * => more >= window_size - (MIN_LOOKAHEAD-1 + WSIZE + MAX_DIST-1) + * => more >= window_size - 2*WSIZE + 2 + * In the BIG_MEM or MMAP case (not yet supported), + * window_size == input_size + MIN_LOOKAHEAD && + * strstart + s->lookahead <= input_size => more >= MIN_LOOKAHEAD. + * Otherwise, window_size == 2*WSIZE so more >= 2. + * If there was sliding, more >= WSIZE. So in all cases, more >= 2. + */ + //Assert(more >= 2, "more < 2"); + n = read_buf(s.strm, s.window, s.strstart + s.lookahead, more); + s.lookahead += n; + + /* Initialize the hash value now that we have some input: */ + if (s.lookahead + s.insert >= MIN_MATCH) { + str = s.strstart - s.insert; + s.ins_h = s.window[str]; + + /* UPDATE_HASH(s, s->ins_h, s->window[str + 1]); */ + s.ins_h = ((s.ins_h << s.hash_shift) ^ s.window[str + 1]) & s.hash_mask; +//#if MIN_MATCH != 3 +// Call update_hash() MIN_MATCH-3 more times +//#endif + while (s.insert) { + /* UPDATE_HASH(s, s->ins_h, s->window[str + MIN_MATCH-1]); */ + s.ins_h = ((s.ins_h << s.hash_shift) ^ s.window[str + MIN_MATCH-1]) & s.hash_mask; + + s.prev[str & s.w_mask] = s.head[s.ins_h]; + s.head[s.ins_h] = str; + str++; + s.insert--; + if (s.lookahead + s.insert < MIN_MATCH) { + break; + } + } + } + /* If the whole input has less than MIN_MATCH bytes, ins_h is garbage, + * but this is not important since only literal bytes will be emitted. + */ + + } while (s.lookahead < MIN_LOOKAHEAD && s.strm.avail_in !== 0); + + /* If the WIN_INIT bytes after the end of the current data have never been + * written, then zero those bytes in order to avoid memory check reports of + * the use of uninitialized (or uninitialised as Julian writes) bytes by + * the longest match routines. Update the high water mark for the next + * time through here. WIN_INIT is set to MAX_MATCH since the longest match + * routines allow scanning to strstart + MAX_MATCH, ignoring lookahead. + */ +// if (s.high_water < s.window_size) { +// var curr = s.strstart + s.lookahead; +// var init = 0; +// +// if (s.high_water < curr) { +// /* Previous high water mark below current data -- zero WIN_INIT +// * bytes or up to end of window, whichever is less. +// */ +// init = s.window_size - curr; +// if (init > WIN_INIT) +// init = WIN_INIT; +// zmemzero(s->window + curr, (unsigned)init); +// s->high_water = curr + init; +// } +// else if (s->high_water < (ulg)curr + WIN_INIT) { +// /* High water mark at or above current data, but below current data +// * plus WIN_INIT -- zero out to current data plus WIN_INIT, or up +// * to end of window, whichever is less. +// */ +// init = (ulg)curr + WIN_INIT - s->high_water; +// if (init > s->window_size - s->high_water) +// init = s->window_size - s->high_water; +// zmemzero(s->window + s->high_water, (unsigned)init); +// s->high_water += init; +// } +// } +// +// Assert((ulg)s->strstart <= s->window_size - MIN_LOOKAHEAD, +// "not enough room for search"); +} + +/* =========================================================================== + * Copy without compression as much as possible from the input stream, return + * the current block state. + * This function does not insert new strings in the dictionary since + * uncompressible data is probably not useful. This function is used + * only for the level=0 compression option. + * NOTE: this function should be optimized to avoid extra copying from + * window to pending_buf. + */ +function deflate_stored(s, flush) { + /* Stored blocks are limited to 0xffff bytes, pending_buf is limited + * to pending_buf_size, and each stored block has a 5 byte header: + */ + var max_block_size = 0xffff; + + if (max_block_size > s.pending_buf_size - 5) { + max_block_size = s.pending_buf_size - 5; + } + + /* Copy as much as possible from input to output: */ + for (;;) { + /* Fill the window as much as possible: */ + if (s.lookahead <= 1) { + + //Assert(s->strstart < s->w_size+MAX_DIST(s) || + // s->block_start >= (long)s->w_size, "slide too late"); +// if (!(s.strstart < s.w_size + (s.w_size - MIN_LOOKAHEAD) || +// s.block_start >= s.w_size)) { +// throw new Error("slide too late"); +// } + + fill_window(s); + if (s.lookahead === 0 && flush === Z_NO_FLUSH) { + return BS_NEED_MORE; + } + + if (s.lookahead === 0) { + break; + } + /* flush the current block */ + } + //Assert(s->block_start >= 0L, "block gone"); +// if (s.block_start < 0) throw new Error("block gone"); + + s.strstart += s.lookahead; + s.lookahead = 0; + + /* Emit a stored block if pending_buf will be full: */ + var max_start = s.block_start + max_block_size; + + if (s.strstart === 0 || s.strstart >= max_start) { + /* strstart == 0 is possible when wraparound on 16-bit machine */ + s.lookahead = s.strstart - max_start; + s.strstart = max_start; + /*** FLUSH_BLOCK(s, 0); ***/ + flush_block_only(s, false); + if (s.strm.avail_out === 0) { + return BS_NEED_MORE; + } + /***/ + + + } + /* Flush if we may have to slide, otherwise block_start may become + * negative and the data will be gone: + */ + if (s.strstart - s.block_start >= (s.w_size - MIN_LOOKAHEAD)) { + /*** FLUSH_BLOCK(s, 0); ***/ + flush_block_only(s, false); + if (s.strm.avail_out === 0) { + return BS_NEED_MORE; + } + /***/ + } + } + + s.insert = 0; + + if (flush === Z_FINISH) { + /*** FLUSH_BLOCK(s, 1); ***/ + flush_block_only(s, true); + if (s.strm.avail_out === 0) { + return BS_FINISH_STARTED; + } + /***/ + return BS_FINISH_DONE; + } + + if (s.strstart > s.block_start) { + /*** FLUSH_BLOCK(s, 0); ***/ + flush_block_only(s, false); + if (s.strm.avail_out === 0) { + return BS_NEED_MORE; + } + /***/ + } + + return BS_NEED_MORE; +} + +/* =========================================================================== + * Compress as much as possible from the input stream, return the current + * block state. + * This function does not perform lazy evaluation of matches and inserts + * new strings in the dictionary only for unmatched strings or for short + * matches. It is used only for the fast compression options. + */ +function deflate_fast(s, flush) { + var hash_head; /* head of the hash chain */ + var bflush; /* set if current block must be flushed */ + + for (;;) { + /* Make sure that we always have enough lookahead, except + * at the end of the input file. We need MAX_MATCH bytes + * for the next match, plus MIN_MATCH bytes to insert the + * string following the next match. + */ + if (s.lookahead < MIN_LOOKAHEAD) { + fill_window(s); + if (s.lookahead < MIN_LOOKAHEAD && flush === Z_NO_FLUSH) { + return BS_NEED_MORE; + } + if (s.lookahead === 0) { + break; /* flush the current block */ + } + } + + /* Insert the string window[strstart .. strstart+2] in the + * dictionary, and set hash_head to the head of the hash chain: + */ + hash_head = 0/*NIL*/; + if (s.lookahead >= MIN_MATCH) { + /*** INSERT_STRING(s, s.strstart, hash_head); ***/ + s.ins_h = ((s.ins_h << s.hash_shift) ^ s.window[s.strstart + MIN_MATCH - 1]) & s.hash_mask; + hash_head = s.prev[s.strstart & s.w_mask] = s.head[s.ins_h]; + s.head[s.ins_h] = s.strstart; + /***/ + } + + /* Find the longest match, discarding those <= prev_length. + * At this point we have always match_length < MIN_MATCH + */ + if (hash_head !== 0/*NIL*/ && ((s.strstart - hash_head) <= (s.w_size - MIN_LOOKAHEAD))) { + /* To simplify the code, we prevent matches with the string + * of window index 0 (in particular we have to avoid a match + * of the string with itself at the start of the input file). + */ + s.match_length = longest_match(s, hash_head); + /* longest_match() sets match_start */ + } + if (s.match_length >= MIN_MATCH) { + // check_match(s, s.strstart, s.match_start, s.match_length); // for debug only + + /*** _tr_tally_dist(s, s.strstart - s.match_start, + s.match_length - MIN_MATCH, bflush); ***/ + bflush = trees._tr_tally(s, s.strstart - s.match_start, s.match_length - MIN_MATCH); + + s.lookahead -= s.match_length; + + /* Insert new strings in the hash table only if the match length + * is not too large. This saves time but degrades compression. + */ + if (s.match_length <= s.max_lazy_match/*max_insert_length*/ && s.lookahead >= MIN_MATCH) { + s.match_length--; /* string at strstart already in table */ + do { + s.strstart++; + /*** INSERT_STRING(s, s.strstart, hash_head); ***/ + s.ins_h = ((s.ins_h << s.hash_shift) ^ s.window[s.strstart + MIN_MATCH - 1]) & s.hash_mask; + hash_head = s.prev[s.strstart & s.w_mask] = s.head[s.ins_h]; + s.head[s.ins_h] = s.strstart; + /***/ + /* strstart never exceeds WSIZE-MAX_MATCH, so there are + * always MIN_MATCH bytes ahead. + */ + } while (--s.match_length !== 0); + s.strstart++; + } else + { + s.strstart += s.match_length; + s.match_length = 0; + s.ins_h = s.window[s.strstart]; + /* UPDATE_HASH(s, s.ins_h, s.window[s.strstart+1]); */ + s.ins_h = ((s.ins_h << s.hash_shift) ^ s.window[s.strstart + 1]) & s.hash_mask; + +//#if MIN_MATCH != 3 +// Call UPDATE_HASH() MIN_MATCH-3 more times +//#endif + /* If lookahead < MIN_MATCH, ins_h is garbage, but it does not + * matter since it will be recomputed at next deflate call. + */ + } + } else { + /* No match, output a literal byte */ + //Tracevv((stderr,"%c", s.window[s.strstart])); + /*** _tr_tally_lit(s, s.window[s.strstart], bflush); ***/ + bflush = trees._tr_tally(s, 0, s.window[s.strstart]); + + s.lookahead--; + s.strstart++; + } + if (bflush) { + /*** FLUSH_BLOCK(s, 0); ***/ + flush_block_only(s, false); + if (s.strm.avail_out === 0) { + return BS_NEED_MORE; + } + /***/ + } + } + s.insert = ((s.strstart < (MIN_MATCH-1)) ? s.strstart : MIN_MATCH-1); + if (flush === Z_FINISH) { + /*** FLUSH_BLOCK(s, 1); ***/ + flush_block_only(s, true); + if (s.strm.avail_out === 0) { + return BS_FINISH_STARTED; + } + /***/ + return BS_FINISH_DONE; + } + if (s.last_lit) { + /*** FLUSH_BLOCK(s, 0); ***/ + flush_block_only(s, false); + if (s.strm.avail_out === 0) { + return BS_NEED_MORE; + } + /***/ + } + return BS_BLOCK_DONE; +} + +/* =========================================================================== + * Same as above, but achieves better compression. We use a lazy + * evaluation for matches: a match is finally adopted only if there is + * no better match at the next window position. + */ +function deflate_slow(s, flush) { + var hash_head; /* head of hash chain */ + var bflush; /* set if current block must be flushed */ + + var max_insert; + + /* Process the input block. */ + for (;;) { + /* Make sure that we always have enough lookahead, except + * at the end of the input file. We need MAX_MATCH bytes + * for the next match, plus MIN_MATCH bytes to insert the + * string following the next match. + */ + if (s.lookahead < MIN_LOOKAHEAD) { + fill_window(s); + if (s.lookahead < MIN_LOOKAHEAD && flush === Z_NO_FLUSH) { + return BS_NEED_MORE; + } + if (s.lookahead === 0) { break; } /* flush the current block */ + } + + /* Insert the string window[strstart .. strstart+2] in the + * dictionary, and set hash_head to the head of the hash chain: + */ + hash_head = 0/*NIL*/; + if (s.lookahead >= MIN_MATCH) { + /*** INSERT_STRING(s, s.strstart, hash_head); ***/ + s.ins_h = ((s.ins_h << s.hash_shift) ^ s.window[s.strstart + MIN_MATCH - 1]) & s.hash_mask; + hash_head = s.prev[s.strstart & s.w_mask] = s.head[s.ins_h]; + s.head[s.ins_h] = s.strstart; + /***/ + } + + /* Find the longest match, discarding those <= prev_length. + */ + s.prev_length = s.match_length; + s.prev_match = s.match_start; + s.match_length = MIN_MATCH-1; + + if (hash_head !== 0/*NIL*/ && s.prev_length < s.max_lazy_match && + s.strstart - hash_head <= (s.w_size-MIN_LOOKAHEAD)/*MAX_DIST(s)*/) { + /* To simplify the code, we prevent matches with the string + * of window index 0 (in particular we have to avoid a match + * of the string with itself at the start of the input file). + */ + s.match_length = longest_match(s, hash_head); + /* longest_match() sets match_start */ + + if (s.match_length <= 5 && + (s.strategy === Z_FILTERED || (s.match_length === MIN_MATCH && s.strstart - s.match_start > 4096/*TOO_FAR*/))) { + + /* If prev_match is also MIN_MATCH, match_start is garbage + * but we will ignore the current match anyway. + */ + s.match_length = MIN_MATCH-1; + } + } + /* If there was a match at the previous step and the current + * match is not better, output the previous match: + */ + if (s.prev_length >= MIN_MATCH && s.match_length <= s.prev_length) { + max_insert = s.strstart + s.lookahead - MIN_MATCH; + /* Do not insert strings in hash table beyond this. */ + + //check_match(s, s.strstart-1, s.prev_match, s.prev_length); + + /***_tr_tally_dist(s, s.strstart - 1 - s.prev_match, + s.prev_length - MIN_MATCH, bflush);***/ + bflush = trees._tr_tally(s, s.strstart - 1- s.prev_match, s.prev_length - MIN_MATCH); + /* Insert in hash table all strings up to the end of the match. + * strstart-1 and strstart are already inserted. If there is not + * enough lookahead, the last two strings are not inserted in + * the hash table. + */ + s.lookahead -= s.prev_length-1; + s.prev_length -= 2; + do { + if (++s.strstart <= max_insert) { + /*** INSERT_STRING(s, s.strstart, hash_head); ***/ + s.ins_h = ((s.ins_h << s.hash_shift) ^ s.window[s.strstart + MIN_MATCH - 1]) & s.hash_mask; + hash_head = s.prev[s.strstart & s.w_mask] = s.head[s.ins_h]; + s.head[s.ins_h] = s.strstart; + /***/ + } + } while (--s.prev_length !== 0); + s.match_available = 0; + s.match_length = MIN_MATCH-1; + s.strstart++; + + if (bflush) { + /*** FLUSH_BLOCK(s, 0); ***/ + flush_block_only(s, false); + if (s.strm.avail_out === 0) { + return BS_NEED_MORE; + } + /***/ + } + + } else if (s.match_available) { + /* If there was no match at the previous position, output a + * single literal. If there was a match but the current match + * is longer, truncate the previous match to a single literal. + */ + //Tracevv((stderr,"%c", s->window[s->strstart-1])); + /*** _tr_tally_lit(s, s.window[s.strstart-1], bflush); ***/ + bflush = trees._tr_tally(s, 0, s.window[s.strstart-1]); + + if (bflush) { + /*** FLUSH_BLOCK_ONLY(s, 0) ***/ + flush_block_only(s, false); + /***/ + } + s.strstart++; + s.lookahead--; + if (s.strm.avail_out === 0) { + return BS_NEED_MORE; + } + } else { + /* There is no previous match to compare with, wait for + * the next step to decide. + */ + s.match_available = 1; + s.strstart++; + s.lookahead--; + } + } + //Assert (flush != Z_NO_FLUSH, "no flush?"); + if (s.match_available) { + //Tracevv((stderr,"%c", s->window[s->strstart-1])); + /*** _tr_tally_lit(s, s.window[s.strstart-1], bflush); ***/ + bflush = trees._tr_tally(s, 0, s.window[s.strstart-1]); + + s.match_available = 0; + } + s.insert = s.strstart < MIN_MATCH-1 ? s.strstart : MIN_MATCH-1; + if (flush === Z_FINISH) { + /*** FLUSH_BLOCK(s, 1); ***/ + flush_block_only(s, true); + if (s.strm.avail_out === 0) { + return BS_FINISH_STARTED; + } + /***/ + return BS_FINISH_DONE; + } + if (s.last_lit) { + /*** FLUSH_BLOCK(s, 0); ***/ + flush_block_only(s, false); + if (s.strm.avail_out === 0) { + return BS_NEED_MORE; + } + /***/ + } + + return BS_BLOCK_DONE; +} + + +/* =========================================================================== + * For Z_RLE, simply look for runs of bytes, generate matches only of distance + * one. Do not maintain a hash table. (It will be regenerated if this run of + * deflate switches away from Z_RLE.) + */ +function deflate_rle(s, flush) { + var bflush; /* set if current block must be flushed */ + var prev; /* byte at distance one to match */ + var scan, strend; /* scan goes up to strend for length of run */ + + var _win = s.window; + + for (;;) { + /* Make sure that we always have enough lookahead, except + * at the end of the input file. We need MAX_MATCH bytes + * for the longest run, plus one for the unrolled loop. + */ + if (s.lookahead <= MAX_MATCH) { + fill_window(s); + if (s.lookahead <= MAX_MATCH && flush === Z_NO_FLUSH) { + return BS_NEED_MORE; + } + if (s.lookahead === 0) { break; } /* flush the current block */ + } + + /* See how many times the previous byte repeats */ + s.match_length = 0; + if (s.lookahead >= MIN_MATCH && s.strstart > 0) { + scan = s.strstart - 1; + prev = _win[scan]; + if (prev === _win[++scan] && prev === _win[++scan] && prev === _win[++scan]) { + strend = s.strstart + MAX_MATCH; + do { + /*jshint noempty:false*/ + } while (prev === _win[++scan] && prev === _win[++scan] && + prev === _win[++scan] && prev === _win[++scan] && + prev === _win[++scan] && prev === _win[++scan] && + prev === _win[++scan] && prev === _win[++scan] && + scan < strend); + s.match_length = MAX_MATCH - (strend - scan); + if (s.match_length > s.lookahead) { + s.match_length = s.lookahead; + } + } + //Assert(scan <= s->window+(uInt)(s->window_size-1), "wild scan"); + } + + /* Emit match if have run of MIN_MATCH or longer, else emit literal */ + if (s.match_length >= MIN_MATCH) { + //check_match(s, s.strstart, s.strstart - 1, s.match_length); + + /*** _tr_tally_dist(s, 1, s.match_length - MIN_MATCH, bflush); ***/ + bflush = trees._tr_tally(s, 1, s.match_length - MIN_MATCH); + + s.lookahead -= s.match_length; + s.strstart += s.match_length; + s.match_length = 0; + } else { + /* No match, output a literal byte */ + //Tracevv((stderr,"%c", s->window[s->strstart])); + /*** _tr_tally_lit(s, s.window[s.strstart], bflush); ***/ + bflush = trees._tr_tally(s, 0, s.window[s.strstart]); + + s.lookahead--; + s.strstart++; + } + if (bflush) { + /*** FLUSH_BLOCK(s, 0); ***/ + flush_block_only(s, false); + if (s.strm.avail_out === 0) { + return BS_NEED_MORE; + } + /***/ + } + } + s.insert = 0; + if (flush === Z_FINISH) { + /*** FLUSH_BLOCK(s, 1); ***/ + flush_block_only(s, true); + if (s.strm.avail_out === 0) { + return BS_FINISH_STARTED; + } + /***/ + return BS_FINISH_DONE; + } + if (s.last_lit) { + /*** FLUSH_BLOCK(s, 0); ***/ + flush_block_only(s, false); + if (s.strm.avail_out === 0) { + return BS_NEED_MORE; + } + /***/ + } + return BS_BLOCK_DONE; +} + +/* =========================================================================== + * For Z_HUFFMAN_ONLY, do not look for matches. Do not maintain a hash table. + * (It will be regenerated if this run of deflate switches away from Huffman.) + */ +function deflate_huff(s, flush) { + var bflush; /* set if current block must be flushed */ + + for (;;) { + /* Make sure that we have a literal to write. */ + if (s.lookahead === 0) { + fill_window(s); + if (s.lookahead === 0) { + if (flush === Z_NO_FLUSH) { + return BS_NEED_MORE; + } + break; /* flush the current block */ + } + } + + /* Output a literal byte */ + s.match_length = 0; + //Tracevv((stderr,"%c", s->window[s->strstart])); + /*** _tr_tally_lit(s, s.window[s.strstart], bflush); ***/ + bflush = trees._tr_tally(s, 0, s.window[s.strstart]); + s.lookahead--; + s.strstart++; + if (bflush) { + /*** FLUSH_BLOCK(s, 0); ***/ + flush_block_only(s, false); + if (s.strm.avail_out === 0) { + return BS_NEED_MORE; + } + /***/ + } + } + s.insert = 0; + if (flush === Z_FINISH) { + /*** FLUSH_BLOCK(s, 1); ***/ + flush_block_only(s, true); + if (s.strm.avail_out === 0) { + return BS_FINISH_STARTED; + } + /***/ + return BS_FINISH_DONE; + } + if (s.last_lit) { + /*** FLUSH_BLOCK(s, 0); ***/ + flush_block_only(s, false); + if (s.strm.avail_out === 0) { + return BS_NEED_MORE; + } + /***/ + } + return BS_BLOCK_DONE; +} + +/* Values for max_lazy_match, good_match and max_chain_length, depending on + * the desired pack level (0..9). The values given below have been tuned to + * exclude worst case performance for pathological files. Better values may be + * found for specific files. + */ +var Config = function (good_length, max_lazy, nice_length, max_chain, func) { + this.good_length = good_length; + this.max_lazy = max_lazy; + this.nice_length = nice_length; + this.max_chain = max_chain; + this.func = func; +}; + +var configuration_table; + +configuration_table = [ + /* good lazy nice chain */ + new Config(0, 0, 0, 0, deflate_stored), /* 0 store only */ + new Config(4, 4, 8, 4, deflate_fast), /* 1 max speed, no lazy matches */ + new Config(4, 5, 16, 8, deflate_fast), /* 2 */ + new Config(4, 6, 32, 32, deflate_fast), /* 3 */ + + new Config(4, 4, 16, 16, deflate_slow), /* 4 lazy matches */ + new Config(8, 16, 32, 32, deflate_slow), /* 5 */ + new Config(8, 16, 128, 128, deflate_slow), /* 6 */ + new Config(8, 32, 128, 256, deflate_slow), /* 7 */ + new Config(32, 128, 258, 1024, deflate_slow), /* 8 */ + new Config(32, 258, 258, 4096, deflate_slow) /* 9 max compression */ +]; + + +/* =========================================================================== + * Initialize the "longest match" routines for a new zlib stream + */ +function lm_init(s) { + s.window_size = 2 * s.w_size; + + /*** CLEAR_HASH(s); ***/ + zero(s.head); // Fill with NIL (= 0); + + /* Set the default configuration parameters: + */ + s.max_lazy_match = configuration_table[s.level].max_lazy; + s.good_match = configuration_table[s.level].good_length; + s.nice_match = configuration_table[s.level].nice_length; + s.max_chain_length = configuration_table[s.level].max_chain; + + s.strstart = 0; + s.block_start = 0; + s.lookahead = 0; + s.insert = 0; + s.match_length = s.prev_length = MIN_MATCH - 1; + s.match_available = 0; + s.ins_h = 0; +} + + +function DeflateState() { + this.strm = null; /* pointer back to this zlib stream */ + this.status = 0; /* as the name implies */ + this.pending_buf = null; /* output still pending */ + this.pending_buf_size = 0; /* size of pending_buf */ + this.pending_out = 0; /* next pending byte to output to the stream */ + this.pending = 0; /* nb of bytes in the pending buffer */ + this.wrap = 0; /* bit 0 true for zlib, bit 1 true for gzip */ + this.gzhead = null; /* gzip header information to write */ + this.gzindex = 0; /* where in extra, name, or comment */ + this.method = Z_DEFLATED; /* can only be DEFLATED */ + this.last_flush = -1; /* value of flush param for previous deflate call */ + + this.w_size = 0; /* LZ77 window size (32K by default) */ + this.w_bits = 0; /* log2(w_size) (8..16) */ + this.w_mask = 0; /* w_size - 1 */ + + this.window = null; + /* Sliding window. Input bytes are read into the second half of the window, + * and move to the first half later to keep a dictionary of at least wSize + * bytes. With this organization, matches are limited to a distance of + * wSize-MAX_MATCH bytes, but this ensures that IO is always + * performed with a length multiple of the block size. + */ + + this.window_size = 0; + /* Actual size of window: 2*wSize, except when the user input buffer + * is directly used as sliding window. + */ + + this.prev = null; + /* Link to older string with same hash index. To limit the size of this + * array to 64K, this link is maintained only for the last 32K strings. + * An index in this array is thus a window index modulo 32K. + */ + + this.head = null; /* Heads of the hash chains or NIL. */ + + this.ins_h = 0; /* hash index of string to be inserted */ + this.hash_size = 0; /* number of elements in hash table */ + this.hash_bits = 0; /* log2(hash_size) */ + this.hash_mask = 0; /* hash_size-1 */ + + this.hash_shift = 0; + /* Number of bits by which ins_h must be shifted at each input + * step. It must be such that after MIN_MATCH steps, the oldest + * byte no longer takes part in the hash key, that is: + * hash_shift * MIN_MATCH >= hash_bits + */ + + this.block_start = 0; + /* Window position at the beginning of the current output block. Gets + * negative when the window is moved backwards. + */ + + this.match_length = 0; /* length of best match */ + this.prev_match = 0; /* previous match */ + this.match_available = 0; /* set if previous match exists */ + this.strstart = 0; /* start of string to insert */ + this.match_start = 0; /* start of matching string */ + this.lookahead = 0; /* number of valid bytes ahead in window */ + + this.prev_length = 0; + /* Length of the best match at previous step. Matches not greater than this + * are discarded. This is used in the lazy match evaluation. + */ + + this.max_chain_length = 0; + /* To speed up deflation, hash chains are never searched beyond this + * length. A higher limit improves compression ratio but degrades the + * speed. + */ + + this.max_lazy_match = 0; + /* Attempt to find a better match only when the current match is strictly + * smaller than this value. This mechanism is used only for compression + * levels >= 4. + */ + // That's alias to max_lazy_match, don't use directly + //this.max_insert_length = 0; + /* Insert new strings in the hash table only if the match length is not + * greater than this length. This saves time but degrades compression. + * max_insert_length is used only for compression levels <= 3. + */ + + this.level = 0; /* compression level (1..9) */ + this.strategy = 0; /* favor or force Huffman coding*/ + + this.good_match = 0; + /* Use a faster search when the previous match is longer than this */ + + this.nice_match = 0; /* Stop searching when current match exceeds this */ + + /* used by trees.c: */ + + /* Didn't use ct_data typedef below to suppress compiler warning */ + + // struct ct_data_s dyn_ltree[HEAP_SIZE]; /* literal and length tree */ + // struct ct_data_s dyn_dtree[2*D_CODES+1]; /* distance tree */ + // struct ct_data_s bl_tree[2*BL_CODES+1]; /* Huffman tree for bit lengths */ + + // Use flat array of DOUBLE size, with interleaved fata, + // because JS does not support effective + this.dyn_ltree = new utils.Buf16(HEAP_SIZE * 2); + this.dyn_dtree = new utils.Buf16((2*D_CODES+1) * 2); + this.bl_tree = new utils.Buf16((2*BL_CODES+1) * 2); + zero(this.dyn_ltree); + zero(this.dyn_dtree); + zero(this.bl_tree); + + this.l_desc = null; /* desc. for literal tree */ + this.d_desc = null; /* desc. for distance tree */ + this.bl_desc = null; /* desc. for bit length tree */ + + //ush bl_count[MAX_BITS+1]; + this.bl_count = new utils.Buf16(MAX_BITS+1); + /* number of codes at each bit length for an optimal tree */ + + //int heap[2*L_CODES+1]; /* heap used to build the Huffman trees */ + this.heap = new utils.Buf16(2*L_CODES+1); /* heap used to build the Huffman trees */ + zero(this.heap); + + this.heap_len = 0; /* number of elements in the heap */ + this.heap_max = 0; /* element of largest frequency */ + /* The sons of heap[n] are heap[2*n] and heap[2*n+1]. heap[0] is not used. + * The same heap array is used to build all trees. + */ + + this.depth = new utils.Buf16(2*L_CODES+1); //uch depth[2*L_CODES+1]; + zero(this.depth); + /* Depth of each subtree used as tie breaker for trees of equal frequency + */ + + this.l_buf = 0; /* buffer index for literals or lengths */ + + this.lit_bufsize = 0; + /* Size of match buffer for literals/lengths. There are 4 reasons for + * limiting lit_bufsize to 64K: + * - frequencies can be kept in 16 bit counters + * - if compression is not successful for the first block, all input + * data is still in the window so we can still emit a stored block even + * when input comes from standard input. (This can also be done for + * all blocks if lit_bufsize is not greater than 32K.) + * - if compression is not successful for a file smaller than 64K, we can + * even emit a stored file instead of a stored block (saving 5 bytes). + * This is applicable only for zip (not gzip or zlib). + * - creating new Huffman trees less frequently may not provide fast + * adaptation to changes in the input data statistics. (Take for + * example a binary file with poorly compressible code followed by + * a highly compressible string table.) Smaller buffer sizes give + * fast adaptation but have of course the overhead of transmitting + * trees more frequently. + * - I can't count above 4 + */ + + this.last_lit = 0; /* running index in l_buf */ + + this.d_buf = 0; + /* Buffer index for distances. To simplify the code, d_buf and l_buf have + * the same number of elements. To use different lengths, an extra flag + * array would be necessary. + */ + + this.opt_len = 0; /* bit length of current block with optimal trees */ + this.static_len = 0; /* bit length of current block with static trees */ + this.matches = 0; /* number of string matches in current block */ + this.insert = 0; /* bytes at end of window left to insert */ + + + this.bi_buf = 0; + /* Output buffer. bits are inserted starting at the bottom (least + * significant bits). + */ + this.bi_valid = 0; + /* Number of valid bits in bi_buf. All bits above the last valid bit + * are always zero. + */ + + // Used for window memory init. We safely ignore it for JS. That makes + // sense only for pointers and memory check tools. + //this.high_water = 0; + /* High water mark offset in window for initialized bytes -- bytes above + * this are set to zero in order to avoid memory check warnings when + * longest match routines access bytes past the input. This is then + * updated to the new high water mark. + */ +} + + +function deflateResetKeep(strm) { + var s; + + if (!strm || !strm.state) { + return err(strm, Z_STREAM_ERROR); + } + + strm.total_in = strm.total_out = 0; + strm.data_type = Z_UNKNOWN; + + s = strm.state; + s.pending = 0; + s.pending_out = 0; + + if (s.wrap < 0) { + s.wrap = -s.wrap; + /* was made negative by deflate(..., Z_FINISH); */ + } + s.status = (s.wrap ? INIT_STATE : BUSY_STATE); + strm.adler = (s.wrap === 2) ? + 0 // crc32(0, Z_NULL, 0) + : + 1; // adler32(0, Z_NULL, 0) + s.last_flush = Z_NO_FLUSH; + trees._tr_init(s); + return Z_OK; +} + + +function deflateReset(strm) { + var ret = deflateResetKeep(strm); + if (ret === Z_OK) { + lm_init(strm.state); + } + return ret; +} + + +function deflateSetHeader(strm, head) { + if (!strm || !strm.state) { return Z_STREAM_ERROR; } + if (strm.state.wrap !== 2) { return Z_STREAM_ERROR; } + strm.state.gzhead = head; + return Z_OK; +} + + +function deflateInit2(strm, level, method, windowBits, memLevel, strategy) { + if (!strm) { // === Z_NULL + return Z_STREAM_ERROR; + } + var wrap = 1; + + if (level === Z_DEFAULT_COMPRESSION) { + level = 6; + } + + if (windowBits < 0) { /* suppress zlib wrapper */ + wrap = 0; + windowBits = -windowBits; + } + + else if (windowBits > 15) { + wrap = 2; /* write gzip wrapper instead */ + windowBits -= 16; + } + + + if (memLevel < 1 || memLevel > MAX_MEM_LEVEL || method !== Z_DEFLATED || + windowBits < 8 || windowBits > 15 || level < 0 || level > 9 || + strategy < 0 || strategy > Z_FIXED) { + return err(strm, Z_STREAM_ERROR); + } + + + if (windowBits === 8) { + windowBits = 9; + } + /* until 256-byte window bug fixed */ + + var s = new DeflateState(); + + strm.state = s; + s.strm = strm; + + s.wrap = wrap; + s.gzhead = null; + s.w_bits = windowBits; + s.w_size = 1 << s.w_bits; + s.w_mask = s.w_size - 1; + + s.hash_bits = memLevel + 7; + s.hash_size = 1 << s.hash_bits; + s.hash_mask = s.hash_size - 1; + s.hash_shift = ~~((s.hash_bits + MIN_MATCH - 1) / MIN_MATCH); + + s.window = new utils.Buf8(s.w_size * 2); + s.head = new utils.Buf16(s.hash_size); + s.prev = new utils.Buf16(s.w_size); + + // Don't need mem init magic for JS. + //s.high_water = 0; /* nothing written to s->window yet */ + + s.lit_bufsize = 1 << (memLevel + 6); /* 16K elements by default */ + + s.pending_buf_size = s.lit_bufsize * 4; + s.pending_buf = new utils.Buf8(s.pending_buf_size); + + s.d_buf = s.lit_bufsize >> 1; + s.l_buf = (1 + 2) * s.lit_bufsize; + + s.level = level; + s.strategy = strategy; + s.method = method; + + return deflateReset(strm); +} + +function deflateInit(strm, level) { + return deflateInit2(strm, level, Z_DEFLATED, MAX_WBITS, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY); +} + + +function deflate(strm, flush) { + var old_flush, s; + var beg, val; // for gzip header write only + + if (!strm || !strm.state || + flush > Z_BLOCK || flush < 0) { + return strm ? err(strm, Z_STREAM_ERROR) : Z_STREAM_ERROR; + } + + s = strm.state; + + if (!strm.output || + (!strm.input && strm.avail_in !== 0) || + (s.status === FINISH_STATE && flush !== Z_FINISH)) { + return err(strm, (strm.avail_out === 0) ? Z_BUF_ERROR : Z_STREAM_ERROR); + } + + s.strm = strm; /* just in case */ + old_flush = s.last_flush; + s.last_flush = flush; + + /* Write the header */ + if (s.status === INIT_STATE) { + + if (s.wrap === 2) { // GZIP header + strm.adler = 0; //crc32(0L, Z_NULL, 0); + put_byte(s, 31); + put_byte(s, 139); + put_byte(s, 8); + if (!s.gzhead) { // s->gzhead == Z_NULL + put_byte(s, 0); + put_byte(s, 0); + put_byte(s, 0); + put_byte(s, 0); + put_byte(s, 0); + put_byte(s, s.level === 9 ? 2 : + (s.strategy >= Z_HUFFMAN_ONLY || s.level < 2 ? + 4 : 0)); + put_byte(s, OS_CODE); + s.status = BUSY_STATE; + } + else { + put_byte(s, (s.gzhead.text ? 1 : 0) + + (s.gzhead.hcrc ? 2 : 0) + + (!s.gzhead.extra ? 0 : 4) + + (!s.gzhead.name ? 0 : 8) + + (!s.gzhead.comment ? 0 : 16) + ); + put_byte(s, s.gzhead.time & 0xff); + put_byte(s, (s.gzhead.time >> 8) & 0xff); + put_byte(s, (s.gzhead.time >> 16) & 0xff); + put_byte(s, (s.gzhead.time >> 24) & 0xff); + put_byte(s, s.level === 9 ? 2 : + (s.strategy >= Z_HUFFMAN_ONLY || s.level < 2 ? + 4 : 0)); + put_byte(s, s.gzhead.os & 0xff); + if (s.gzhead.extra && s.gzhead.extra.length) { + put_byte(s, s.gzhead.extra.length & 0xff); + put_byte(s, (s.gzhead.extra.length >> 8) & 0xff); + } + if (s.gzhead.hcrc) { + strm.adler = crc32(strm.adler, s.pending_buf, s.pending, 0); + } + s.gzindex = 0; + s.status = EXTRA_STATE; + } + } + else // DEFLATE header + { + var header = (Z_DEFLATED + ((s.w_bits - 8) << 4)) << 8; + var level_flags = -1; + + if (s.strategy >= Z_HUFFMAN_ONLY || s.level < 2) { + level_flags = 0; + } else if (s.level < 6) { + level_flags = 1; + } else if (s.level === 6) { + level_flags = 2; + } else { + level_flags = 3; + } + header |= (level_flags << 6); + if (s.strstart !== 0) { header |= PRESET_DICT; } + header += 31 - (header % 31); + + s.status = BUSY_STATE; + putShortMSB(s, header); + + /* Save the adler32 of the preset dictionary: */ + if (s.strstart !== 0) { + putShortMSB(s, strm.adler >>> 16); + putShortMSB(s, strm.adler & 0xffff); + } + strm.adler = 1; // adler32(0L, Z_NULL, 0); + } + } + +//#ifdef GZIP + if (s.status === EXTRA_STATE) { + if (s.gzhead.extra/* != Z_NULL*/) { + beg = s.pending; /* start of bytes to update crc */ + + while (s.gzindex < (s.gzhead.extra.length & 0xffff)) { + if (s.pending === s.pending_buf_size) { + if (s.gzhead.hcrc && s.pending > beg) { + strm.adler = crc32(strm.adler, s.pending_buf, s.pending - beg, beg); + } + flush_pending(strm); + beg = s.pending; + if (s.pending === s.pending_buf_size) { + break; + } + } + put_byte(s, s.gzhead.extra[s.gzindex] & 0xff); + s.gzindex++; + } + if (s.gzhead.hcrc && s.pending > beg) { + strm.adler = crc32(strm.adler, s.pending_buf, s.pending - beg, beg); + } + if (s.gzindex === s.gzhead.extra.length) { + s.gzindex = 0; + s.status = NAME_STATE; + } + } + else { + s.status = NAME_STATE; + } + } + if (s.status === NAME_STATE) { + if (s.gzhead.name/* != Z_NULL*/) { + beg = s.pending; /* start of bytes to update crc */ + //int val; + + do { + if (s.pending === s.pending_buf_size) { + if (s.gzhead.hcrc && s.pending > beg) { + strm.adler = crc32(strm.adler, s.pending_buf, s.pending - beg, beg); + } + flush_pending(strm); + beg = s.pending; + if (s.pending === s.pending_buf_size) { + val = 1; + break; + } + } + // JS specific: little magic to add zero terminator to end of string + if (s.gzindex < s.gzhead.name.length) { + val = s.gzhead.name.charCodeAt(s.gzindex++) & 0xff; + } else { + val = 0; + } + put_byte(s, val); + } while (val !== 0); + + if (s.gzhead.hcrc && s.pending > beg){ + strm.adler = crc32(strm.adler, s.pending_buf, s.pending - beg, beg); + } + if (val === 0) { + s.gzindex = 0; + s.status = COMMENT_STATE; + } + } + else { + s.status = COMMENT_STATE; + } + } + if (s.status === COMMENT_STATE) { + if (s.gzhead.comment/* != Z_NULL*/) { + beg = s.pending; /* start of bytes to update crc */ + //int val; + + do { + if (s.pending === s.pending_buf_size) { + if (s.gzhead.hcrc && s.pending > beg) { + strm.adler = crc32(strm.adler, s.pending_buf, s.pending - beg, beg); + } + flush_pending(strm); + beg = s.pending; + if (s.pending === s.pending_buf_size) { + val = 1; + break; + } + } + // JS specific: little magic to add zero terminator to end of string + if (s.gzindex < s.gzhead.comment.length) { + val = s.gzhead.comment.charCodeAt(s.gzindex++) & 0xff; + } else { + val = 0; + } + put_byte(s, val); + } while (val !== 0); + + if (s.gzhead.hcrc && s.pending > beg) { + strm.adler = crc32(strm.adler, s.pending_buf, s.pending - beg, beg); + } + if (val === 0) { + s.status = HCRC_STATE; + } + } + else { + s.status = HCRC_STATE; + } + } + if (s.status === HCRC_STATE) { + if (s.gzhead.hcrc) { + if (s.pending + 2 > s.pending_buf_size) { + flush_pending(strm); + } + if (s.pending + 2 <= s.pending_buf_size) { + put_byte(s, strm.adler & 0xff); + put_byte(s, (strm.adler >> 8) & 0xff); + strm.adler = 0; //crc32(0L, Z_NULL, 0); + s.status = BUSY_STATE; + } + } + else { + s.status = BUSY_STATE; + } + } +//#endif + + /* Flush as much pending output as possible */ + if (s.pending !== 0) { + flush_pending(strm); + if (strm.avail_out === 0) { + /* Since avail_out is 0, deflate will be called again with + * more output space, but possibly with both pending and + * avail_in equal to zero. There won't be anything to do, + * but this is not an error situation so make sure we + * return OK instead of BUF_ERROR at next call of deflate: + */ + s.last_flush = -1; + return Z_OK; + } + + /* Make sure there is something to do and avoid duplicate consecutive + * flushes. For repeated and useless calls with Z_FINISH, we keep + * returning Z_STREAM_END instead of Z_BUF_ERROR. + */ + } else if (strm.avail_in === 0 && rank(flush) <= rank(old_flush) && + flush !== Z_FINISH) { + return err(strm, Z_BUF_ERROR); + } + + /* User must not provide more input after the first FINISH: */ + if (s.status === FINISH_STATE && strm.avail_in !== 0) { + return err(strm, Z_BUF_ERROR); + } + + /* Start a new block or continue the current one. + */ + if (strm.avail_in !== 0 || s.lookahead !== 0 || + (flush !== Z_NO_FLUSH && s.status !== FINISH_STATE)) { + var bstate = (s.strategy === Z_HUFFMAN_ONLY) ? deflate_huff(s, flush) : + (s.strategy === Z_RLE ? deflate_rle(s, flush) : + configuration_table[s.level].func(s, flush)); + + if (bstate === BS_FINISH_STARTED || bstate === BS_FINISH_DONE) { + s.status = FINISH_STATE; + } + if (bstate === BS_NEED_MORE || bstate === BS_FINISH_STARTED) { + if (strm.avail_out === 0) { + s.last_flush = -1; + /* avoid BUF_ERROR next call, see above */ + } + return Z_OK; + /* If flush != Z_NO_FLUSH && avail_out == 0, the next call + * of deflate should use the same flush parameter to make sure + * that the flush is complete. So we don't have to output an + * empty block here, this will be done at next call. This also + * ensures that for a very small output buffer, we emit at most + * one empty block. + */ + } + if (bstate === BS_BLOCK_DONE) { + if (flush === Z_PARTIAL_FLUSH) { + trees._tr_align(s); + } + else if (flush !== Z_BLOCK) { /* FULL_FLUSH or SYNC_FLUSH */ + + trees._tr_stored_block(s, 0, 0, false); + /* For a full flush, this empty block will be recognized + * as a special marker by inflate_sync(). + */ + if (flush === Z_FULL_FLUSH) { + /*** CLEAR_HASH(s); ***/ /* forget history */ + zero(s.head); // Fill with NIL (= 0); + + if (s.lookahead === 0) { + s.strstart = 0; + s.block_start = 0; + s.insert = 0; + } + } + } + flush_pending(strm); + if (strm.avail_out === 0) { + s.last_flush = -1; /* avoid BUF_ERROR at next call, see above */ + return Z_OK; + } + } + } + //Assert(strm->avail_out > 0, "bug2"); + //if (strm.avail_out <= 0) { throw new Error("bug2");} + + if (flush !== Z_FINISH) { return Z_OK; } + if (s.wrap <= 0) { return Z_STREAM_END; } + + /* Write the trailer */ + if (s.wrap === 2) { + put_byte(s, strm.adler & 0xff); + put_byte(s, (strm.adler >> 8) & 0xff); + put_byte(s, (strm.adler >> 16) & 0xff); + put_byte(s, (strm.adler >> 24) & 0xff); + put_byte(s, strm.total_in & 0xff); + put_byte(s, (strm.total_in >> 8) & 0xff); + put_byte(s, (strm.total_in >> 16) & 0xff); + put_byte(s, (strm.total_in >> 24) & 0xff); + } + else + { + putShortMSB(s, strm.adler >>> 16); + putShortMSB(s, strm.adler & 0xffff); + } + + flush_pending(strm); + /* If avail_out is zero, the application will call deflate again + * to flush the rest. + */ + if (s.wrap > 0) { s.wrap = -s.wrap; } + /* write the trailer only once! */ + return s.pending !== 0 ? Z_OK : Z_STREAM_END; +} + +function deflateEnd(strm) { + var status; + + if (!strm/*== Z_NULL*/ || !strm.state/*== Z_NULL*/) { + return Z_STREAM_ERROR; + } + + status = strm.state.status; + if (status !== INIT_STATE && + status !== EXTRA_STATE && + status !== NAME_STATE && + status !== COMMENT_STATE && + status !== HCRC_STATE && + status !== BUSY_STATE && + status !== FINISH_STATE + ) { + return err(strm, Z_STREAM_ERROR); + } + + strm.state = null; + + return status === BUSY_STATE ? err(strm, Z_DATA_ERROR) : Z_OK; +} + +/* ========================================================================= + * Copy the source state to the destination state + */ +//function deflateCopy(dest, source) { +// +//} + +exports.deflateInit = deflateInit; +exports.deflateInit2 = deflateInit2; +exports.deflateReset = deflateReset; +exports.deflateResetKeep = deflateResetKeep; +exports.deflateSetHeader = deflateSetHeader; +exports.deflate = deflate; +exports.deflateEnd = deflateEnd; +exports.deflateInfo = 'pako deflate (from Nodeca project)'; + +/* Not implemented +exports.deflateBound = deflateBound; +exports.deflateCopy = deflateCopy; +exports.deflateSetDictionary = deflateSetDictionary; +exports.deflateParams = deflateParams; +exports.deflatePending = deflatePending; +exports.deflatePrime = deflatePrime; +exports.deflateTune = deflateTune; +*/ +},{"../utils/common":3,"./adler32":5,"./crc32":7,"./messages":13,"./trees":14}],9:[function(require,module,exports){ +'use strict'; + + +function GZheader() { + /* true if compressed data believed to be text */ + this.text = 0; + /* modification time */ + this.time = 0; + /* extra flags (not used when writing a gzip file) */ + this.xflags = 0; + /* operating system */ + this.os = 0; + /* pointer to extra field or Z_NULL if none */ + this.extra = null; + /* extra field length (valid if extra != Z_NULL) */ + this.extra_len = 0; // Actually, we don't need it in JS, + // but leave for few code modifications + + // + // Setup limits is not necessary because in js we should not preallocate memory + // for inflate use constant limit in 65536 bytes + // + + /* space at extra (only when reading header) */ + // this.extra_max = 0; + /* pointer to zero-terminated file name or Z_NULL */ + this.name = ''; + /* space at name (only when reading header) */ + // this.name_max = 0; + /* pointer to zero-terminated comment or Z_NULL */ + this.comment = ''; + /* space at comment (only when reading header) */ + // this.comm_max = 0; + /* true if there was or will be a header crc */ + this.hcrc = 0; + /* true when done reading gzip header (not used when writing a gzip file) */ + this.done = false; +} + +module.exports = GZheader; +},{}],10:[function(require,module,exports){ +'use strict'; + +// See state defs from inflate.js +var BAD = 30; /* got a data error -- remain here until reset */ +var TYPE = 12; /* i: waiting for type bits, including last-flag bit */ + +/* + Decode literal, length, and distance codes and write out the resulting + literal and match bytes until either not enough input or output is + available, an end-of-block is encountered, or a data error is encountered. + When large enough input and output buffers are supplied to inflate(), for + example, a 16K input buffer and a 64K output buffer, more than 95% of the + inflate execution time is spent in this routine. + + Entry assumptions: + + state.mode === LEN + strm.avail_in >= 6 + strm.avail_out >= 258 + start >= strm.avail_out + state.bits < 8 + + On return, state.mode is one of: + + LEN -- ran out of enough output space or enough available input + TYPE -- reached end of block code, inflate() to interpret next block + BAD -- error in block data + + Notes: + + - The maximum input bits used by a length/distance pair is 15 bits for the + length code, 5 bits for the length extra, 15 bits for the distance code, + and 13 bits for the distance extra. This totals 48 bits, or six bytes. + Therefore if strm.avail_in >= 6, then there is enough input to avoid + checking for available input while decoding. + + - The maximum bytes that a single length/distance pair can output is 258 + bytes, which is the maximum length that can be coded. inflate_fast() + requires strm.avail_out >= 258 for each loop to avoid checking for + output space. + */ +module.exports = function inflate_fast(strm, start) { + var state; + var _in; /* local strm.input */ + var last; /* have enough input while in < last */ + var _out; /* local strm.output */ + var beg; /* inflate()'s initial strm.output */ + var end; /* while out < end, enough space available */ +//#ifdef INFLATE_STRICT + var dmax; /* maximum distance from zlib header */ +//#endif + var wsize; /* window size or zero if not using window */ + var whave; /* valid bytes in the window */ + var wnext; /* window write index */ + var window; /* allocated sliding window, if wsize != 0 */ + var hold; /* local strm.hold */ + var bits; /* local strm.bits */ + var lcode; /* local strm.lencode */ + var dcode; /* local strm.distcode */ + var lmask; /* mask for first level of length codes */ + var dmask; /* mask for first level of distance codes */ + var here; /* retrieved table entry */ + var op; /* code bits, operation, extra bits, or */ + /* window position, window bytes to copy */ + var len; /* match length, unused bytes */ + var dist; /* match distance */ + var from; /* where to copy match from */ + var from_source; + + + var input, output; // JS specific, because we have no pointers + + /* copy state to local variables */ + state = strm.state; + //here = state.here; + _in = strm.next_in; + input = strm.input; + last = _in + (strm.avail_in - 5); + _out = strm.next_out; + output = strm.output; + beg = _out - (start - strm.avail_out); + end = _out + (strm.avail_out - 257); +//#ifdef INFLATE_STRICT + dmax = state.dmax; +//#endif + wsize = state.wsize; + whave = state.whave; + wnext = state.wnext; + window = state.window; + hold = state.hold; + bits = state.bits; + lcode = state.lencode; + dcode = state.distcode; + lmask = (1 << state.lenbits) - 1; + dmask = (1 << state.distbits) - 1; + + + /* decode literals and length/distances until end-of-block or not enough + input data or output space */ + + top: + do { + if (bits < 15) { + hold += input[_in++] << bits; + bits += 8; + hold += input[_in++] << bits; + bits += 8; + } + + here = lcode[hold & lmask]; + + dolen: + for (;;) { // Goto emulation + op = here >>> 24/*here.bits*/; + hold >>>= op; + bits -= op; + op = (here >>> 16) & 0xff/*here.op*/; + if (op === 0) { /* literal */ + //Tracevv((stderr, here.val >= 0x20 && here.val < 0x7f ? + // "inflate: literal '%c'\n" : + // "inflate: literal 0x%02x\n", here.val)); + output[_out++] = here & 0xffff/*here.val*/; + } + else if (op & 16) { /* length base */ + len = here & 0xffff/*here.val*/; + op &= 15; /* number of extra bits */ + if (op) { + if (bits < op) { + hold += input[_in++] << bits; + bits += 8; + } + len += hold & ((1 << op) - 1); + hold >>>= op; + bits -= op; + } + //Tracevv((stderr, "inflate: length %u\n", len)); + if (bits < 15) { + hold += input[_in++] << bits; + bits += 8; + hold += input[_in++] << bits; + bits += 8; + } + here = dcode[hold & dmask]; + + dodist: + for (;;) { // goto emulation + op = here >>> 24/*here.bits*/; + hold >>>= op; + bits -= op; + op = (here >>> 16) & 0xff/*here.op*/; + + if (op & 16) { /* distance base */ + dist = here & 0xffff/*here.val*/; + op &= 15; /* number of extra bits */ + if (bits < op) { + hold += input[_in++] << bits; + bits += 8; + if (bits < op) { + hold += input[_in++] << bits; + bits += 8; + } + } + dist += hold & ((1 << op) - 1); +//#ifdef INFLATE_STRICT + if (dist > dmax) { + strm.msg = 'invalid distance too far back'; + state.mode = BAD; + break top; + } +//#endif + hold >>>= op; + bits -= op; + //Tracevv((stderr, "inflate: distance %u\n", dist)); + op = _out - beg; /* max distance in output */ + if (dist > op) { /* see if copy from window */ + op = dist - op; /* distance back in window */ + if (op > whave) { + if (state.sane) { + strm.msg = 'invalid distance too far back'; + state.mode = BAD; + break top; + } + +// (!) This block is disabled in zlib defailts, +// don't enable it for binary compatibility +//#ifdef INFLATE_ALLOW_INVALID_DISTANCE_TOOFAR_ARRR +// if (len <= op - whave) { +// do { +// output[_out++] = 0; +// } while (--len); +// continue top; +// } +// len -= op - whave; +// do { +// output[_out++] = 0; +// } while (--op > whave); +// if (op === 0) { +// from = _out - dist; +// do { +// output[_out++] = output[from++]; +// } while (--len); +// continue top; +// } +//#endif + } + from = 0; // window index + from_source = window; + if (wnext === 0) { /* very common case */ + from += wsize - op; + if (op < len) { /* some from window */ + len -= op; + do { + output[_out++] = window[from++]; + } while (--op); + from = _out - dist; /* rest from output */ + from_source = output; + } + } + else if (wnext < op) { /* wrap around window */ + from += wsize + wnext - op; + op -= wnext; + if (op < len) { /* some from end of window */ + len -= op; + do { + output[_out++] = window[from++]; + } while (--op); + from = 0; + if (wnext < len) { /* some from start of window */ + op = wnext; + len -= op; + do { + output[_out++] = window[from++]; + } while (--op); + from = _out - dist; /* rest from output */ + from_source = output; + } + } + } + else { /* contiguous in window */ + from += wnext - op; + if (op < len) { /* some from window */ + len -= op; + do { + output[_out++] = window[from++]; + } while (--op); + from = _out - dist; /* rest from output */ + from_source = output; + } + } + while (len > 2) { + output[_out++] = from_source[from++]; + output[_out++] = from_source[from++]; + output[_out++] = from_source[from++]; + len -= 3; + } + if (len) { + output[_out++] = from_source[from++]; + if (len > 1) { + output[_out++] = from_source[from++]; + } + } + } + else { + from = _out - dist; /* copy direct from output */ + do { /* minimum length is three */ + output[_out++] = output[from++]; + output[_out++] = output[from++]; + output[_out++] = output[from++]; + len -= 3; + } while (len > 2); + if (len) { + output[_out++] = output[from++]; + if (len > 1) { + output[_out++] = output[from++]; + } + } + } + } + else if ((op & 64) === 0) { /* 2nd level distance code */ + here = dcode[(here & 0xffff)/*here.val*/ + (hold & ((1 << op) - 1))]; + continue dodist; + } + else { + strm.msg = 'invalid distance code'; + state.mode = BAD; + break top; + } + + break; // need to emulate goto via "continue" + } + } + else if ((op & 64) === 0) { /* 2nd level length code */ + here = lcode[(here & 0xffff)/*here.val*/ + (hold & ((1 << op) - 1))]; + continue dolen; + } + else if (op & 32) { /* end-of-block */ + //Tracevv((stderr, "inflate: end of block\n")); + state.mode = TYPE; + break top; + } + else { + strm.msg = 'invalid literal/length code'; + state.mode = BAD; + break top; + } + + break; // need to emulate goto via "continue" + } + } while (_in < last && _out < end); + + /* return unused bytes (on entry, bits < 8, so in won't go too far back) */ + len = bits >> 3; + _in -= len; + bits -= len << 3; + hold &= (1 << bits) - 1; + + /* update state and return */ + strm.next_in = _in; + strm.next_out = _out; + strm.avail_in = (_in < last ? 5 + (last - _in) : 5 - (_in - last)); + strm.avail_out = (_out < end ? 257 + (end - _out) : 257 - (_out - end)); + state.hold = hold; + state.bits = bits; + return; +}; + +},{}],11:[function(require,module,exports){ +'use strict'; + + +var utils = require('../utils/common'); +var adler32 = require('./adler32'); +var crc32 = require('./crc32'); +var inflate_fast = require('./inffast'); +var inflate_table = require('./inftrees'); + +var CODES = 0; +var LENS = 1; +var DISTS = 2; + +/* Public constants ==========================================================*/ +/* ===========================================================================*/ + + +/* Allowed flush values; see deflate() and inflate() below for details */ +//var Z_NO_FLUSH = 0; +//var Z_PARTIAL_FLUSH = 1; +//var Z_SYNC_FLUSH = 2; +//var Z_FULL_FLUSH = 3; +var Z_FINISH = 4; +var Z_BLOCK = 5; +var Z_TREES = 6; + + +/* Return codes for the compression/decompression functions. Negative values + * are errors, positive values are used for special but normal events. + */ +var Z_OK = 0; +var Z_STREAM_END = 1; +var Z_NEED_DICT = 2; +//var Z_ERRNO = -1; +var Z_STREAM_ERROR = -2; +var Z_DATA_ERROR = -3; +var Z_MEM_ERROR = -4; +var Z_BUF_ERROR = -5; +//var Z_VERSION_ERROR = -6; + +/* The deflate compression method */ +var Z_DEFLATED = 8; + + +/* STATES ====================================================================*/ +/* ===========================================================================*/ + + +var HEAD = 1; /* i: waiting for magic header */ +var FLAGS = 2; /* i: waiting for method and flags (gzip) */ +var TIME = 3; /* i: waiting for modification time (gzip) */ +var OS = 4; /* i: waiting for extra flags and operating system (gzip) */ +var EXLEN = 5; /* i: waiting for extra length (gzip) */ +var EXTRA = 6; /* i: waiting for extra bytes (gzip) */ +var NAME = 7; /* i: waiting for end of file name (gzip) */ +var COMMENT = 8; /* i: waiting for end of comment (gzip) */ +var HCRC = 9; /* i: waiting for header crc (gzip) */ +var DICTID = 10; /* i: waiting for dictionary check value */ +var DICT = 11; /* waiting for inflateSetDictionary() call */ +var TYPE = 12; /* i: waiting for type bits, including last-flag bit */ +var TYPEDO = 13; /* i: same, but skip check to exit inflate on new block */ +var STORED = 14; /* i: waiting for stored size (length and complement) */ +var COPY_ = 15; /* i/o: same as COPY below, but only first time in */ +var COPY = 16; /* i/o: waiting for input or output to copy stored block */ +var TABLE = 17; /* i: waiting for dynamic block table lengths */ +var LENLENS = 18; /* i: waiting for code length code lengths */ +var CODELENS = 19; /* i: waiting for length/lit and distance code lengths */ +var LEN_ = 20; /* i: same as LEN below, but only first time in */ +var LEN = 21; /* i: waiting for length/lit/eob code */ +var LENEXT = 22; /* i: waiting for length extra bits */ +var DIST = 23; /* i: waiting for distance code */ +var DISTEXT = 24; /* i: waiting for distance extra bits */ +var MATCH = 25; /* o: waiting for output space to copy string */ +var LIT = 26; /* o: waiting for output space to write literal */ +var CHECK = 27; /* i: waiting for 32-bit check value */ +var LENGTH = 28; /* i: waiting for 32-bit length (gzip) */ +var DONE = 29; /* finished check, done -- remain here until reset */ +var BAD = 30; /* got a data error -- remain here until reset */ +var MEM = 31; /* got an inflate() memory error -- remain here until reset */ +var SYNC = 32; /* looking for synchronization bytes to restart inflate() */ + +/* ===========================================================================*/ + + + +var ENOUGH_LENS = 852; +var ENOUGH_DISTS = 592; +//var ENOUGH = (ENOUGH_LENS+ENOUGH_DISTS); + +var MAX_WBITS = 15; +/* 32K LZ77 window */ +var DEF_WBITS = MAX_WBITS; + + +function ZSWAP32(q) { + return (((q >>> 24) & 0xff) + + ((q >>> 8) & 0xff00) + + ((q & 0xff00) << 8) + + ((q & 0xff) << 24)); +} + + +function InflateState() { + this.mode = 0; /* current inflate mode */ + this.last = false; /* true if processing last block */ + this.wrap = 0; /* bit 0 true for zlib, bit 1 true for gzip */ + this.havedict = false; /* true if dictionary provided */ + this.flags = 0; /* gzip header method and flags (0 if zlib) */ + this.dmax = 0; /* zlib header max distance (INFLATE_STRICT) */ + this.check = 0; /* protected copy of check value */ + this.total = 0; /* protected copy of output count */ + // TODO: may be {} + this.head = null; /* where to save gzip header information */ + + /* sliding window */ + this.wbits = 0; /* log base 2 of requested window size */ + this.wsize = 0; /* window size or zero if not using window */ + this.whave = 0; /* valid bytes in the window */ + this.wnext = 0; /* window write index */ + this.window = null; /* allocated sliding window, if needed */ + + /* bit accumulator */ + this.hold = 0; /* input bit accumulator */ + this.bits = 0; /* number of bits in "in" */ + + /* for string and stored block copying */ + this.length = 0; /* literal or length of data to copy */ + this.offset = 0; /* distance back to copy string from */ + + /* for table and code decoding */ + this.extra = 0; /* extra bits needed */ + + /* fixed and dynamic code tables */ + this.lencode = null; /* starting table for length/literal codes */ + this.distcode = null; /* starting table for distance codes */ + this.lenbits = 0; /* index bits for lencode */ + this.distbits = 0; /* index bits for distcode */ + + /* dynamic table building */ + this.ncode = 0; /* number of code length code lengths */ + this.nlen = 0; /* number of length code lengths */ + this.ndist = 0; /* number of distance code lengths */ + this.have = 0; /* number of code lengths in lens[] */ + this.next = null; /* next available space in codes[] */ + + this.lens = new utils.Buf16(320); /* temporary storage for code lengths */ + this.work = new utils.Buf16(288); /* work area for code table building */ + + /* + because we don't have pointers in js, we use lencode and distcode directly + as buffers so we don't need codes + */ + //this.codes = new utils.Buf32(ENOUGH); /* space for code tables */ + this.lendyn = null; /* dynamic table for length/literal codes (JS specific) */ + this.distdyn = null; /* dynamic table for distance codes (JS specific) */ + this.sane = 0; /* if false, allow invalid distance too far */ + this.back = 0; /* bits back of last unprocessed length/lit */ + this.was = 0; /* initial length of match */ +} + +function inflateResetKeep(strm) { + var state; + + if (!strm || !strm.state) { return Z_STREAM_ERROR; } + state = strm.state; + strm.total_in = strm.total_out = state.total = 0; + strm.msg = ''; /*Z_NULL*/ + if (state.wrap) { /* to support ill-conceived Java test suite */ + strm.adler = state.wrap & 1; + } + state.mode = HEAD; + state.last = 0; + state.havedict = 0; + state.dmax = 32768; + state.head = null/*Z_NULL*/; + state.hold = 0; + state.bits = 0; + //state.lencode = state.distcode = state.next = state.codes; + state.lencode = state.lendyn = new utils.Buf32(ENOUGH_LENS); + state.distcode = state.distdyn = new utils.Buf32(ENOUGH_DISTS); + + state.sane = 1; + state.back = -1; + //Tracev((stderr, "inflate: reset\n")); + return Z_OK; +} + +function inflateReset(strm) { + var state; + + if (!strm || !strm.state) { return Z_STREAM_ERROR; } + state = strm.state; + state.wsize = 0; + state.whave = 0; + state.wnext = 0; + return inflateResetKeep(strm); + +} + +function inflateReset2(strm, windowBits) { + var wrap; + var state; + + /* get the state */ + if (!strm || !strm.state) { return Z_STREAM_ERROR; } + state = strm.state; + + /* extract wrap request from windowBits parameter */ + if (windowBits < 0) { + wrap = 0; + windowBits = -windowBits; + } + else { + wrap = (windowBits >> 4) + 1; + if (windowBits < 48) { + windowBits &= 15; + } + } + + /* set number of window bits, free window if different */ + if (windowBits && (windowBits < 8 || windowBits > 15)) { + return Z_STREAM_ERROR; + } + if (state.window !== null && state.wbits !== windowBits) { + state.window = null; + } + + /* update state and reset the rest of it */ + state.wrap = wrap; + state.wbits = windowBits; + return inflateReset(strm); +} + +function inflateInit2(strm, windowBits) { + var ret; + var state; + + if (!strm) { return Z_STREAM_ERROR; } + //strm.msg = Z_NULL; /* in case we return an error */ + + state = new InflateState(); + + //if (state === Z_NULL) return Z_MEM_ERROR; + //Tracev((stderr, "inflate: allocated\n")); + strm.state = state; + state.window = null/*Z_NULL*/; + ret = inflateReset2(strm, windowBits); + if (ret !== Z_OK) { + strm.state = null/*Z_NULL*/; + } + return ret; +} + +function inflateInit(strm) { + return inflateInit2(strm, DEF_WBITS); +} + + +/* + Return state with length and distance decoding tables and index sizes set to + fixed code decoding. Normally this returns fixed tables from inffixed.h. + If BUILDFIXED is defined, then instead this routine builds the tables the + first time it's called, and returns those tables the first time and + thereafter. This reduces the size of the code by about 2K bytes, in + exchange for a little execution time. However, BUILDFIXED should not be + used for threaded applications, since the rewriting of the tables and virgin + may not be thread-safe. + */ +var virgin = true; + +var lenfix, distfix; // We have no pointers in JS, so keep tables separate + +function fixedtables(state) { + /* build fixed huffman tables if first call (may not be thread safe) */ + if (virgin) { + var sym; + + lenfix = new utils.Buf32(512); + distfix = new utils.Buf32(32); + + /* literal/length table */ + sym = 0; + while (sym < 144) { state.lens[sym++] = 8; } + while (sym < 256) { state.lens[sym++] = 9; } + while (sym < 280) { state.lens[sym++] = 7; } + while (sym < 288) { state.lens[sym++] = 8; } + + inflate_table(LENS, state.lens, 0, 288, lenfix, 0, state.work, {bits: 9}); + + /* distance table */ + sym = 0; + while (sym < 32) { state.lens[sym++] = 5; } + + inflate_table(DISTS, state.lens, 0, 32, distfix, 0, state.work, {bits: 5}); + + /* do this just once */ + virgin = false; + } + + state.lencode = lenfix; + state.lenbits = 9; + state.distcode = distfix; + state.distbits = 5; +} + + +/* + Update the window with the last wsize (normally 32K) bytes written before + returning. If window does not exist yet, create it. This is only called + when a window is already in use, or when output has been written during this + inflate call, but the end of the deflate stream has not been reached yet. + It is also called to create a window for dictionary data when a dictionary + is loaded. + + Providing output buffers larger than 32K to inflate() should provide a speed + advantage, since only the last 32K of output is copied to the sliding window + upon return from inflate(), and since all distances after the first 32K of + output will fall in the output data, making match copies simpler and faster. + The advantage may be dependent on the size of the processor's data caches. + */ +function updatewindow(strm, src, end, copy) { + var dist; + var state = strm.state; + + /* if it hasn't been done already, allocate space for the window */ + if (state.window === null) { + state.wsize = 1 << state.wbits; + state.wnext = 0; + state.whave = 0; + + state.window = new utils.Buf8(state.wsize); + } + + /* copy state->wsize or less output bytes into the circular window */ + if (copy >= state.wsize) { + utils.arraySet(state.window,src, end - state.wsize, state.wsize, 0); + state.wnext = 0; + state.whave = state.wsize; + } + else { + dist = state.wsize - state.wnext; + if (dist > copy) { + dist = copy; + } + //zmemcpy(state->window + state->wnext, end - copy, dist); + utils.arraySet(state.window,src, end - copy, dist, state.wnext); + copy -= dist; + if (copy) { + //zmemcpy(state->window, end - copy, copy); + utils.arraySet(state.window,src, end - copy, copy, 0); + state.wnext = copy; + state.whave = state.wsize; + } + else { + state.wnext += dist; + if (state.wnext === state.wsize) { state.wnext = 0; } + if (state.whave < state.wsize) { state.whave += dist; } + } + } + return 0; +} + +function inflate(strm, flush) { + var state; + var input, output; // input/output buffers + var next; /* next input INDEX */ + var put; /* next output INDEX */ + var have, left; /* available input and output */ + var hold; /* bit buffer */ + var bits; /* bits in bit buffer */ + var _in, _out; /* save starting available input and output */ + var copy; /* number of stored or match bytes to copy */ + var from; /* where to copy match bytes from */ + var from_source; + var here = 0; /* current decoding table entry */ + var here_bits, here_op, here_val; // paked "here" denormalized (JS specific) + //var last; /* parent table entry */ + var last_bits, last_op, last_val; // paked "last" denormalized (JS specific) + var len; /* length to copy for repeats, bits to drop */ + var ret; /* return code */ + var hbuf = new utils.Buf8(4); /* buffer for gzip header crc calculation */ + var opts; + + var n; // temporary var for NEED_BITS + + var order = /* permutation of code lengths */ + [16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15]; + + + if (!strm || !strm.state || !strm.output || + (!strm.input && strm.avail_in !== 0)) { + return Z_STREAM_ERROR; + } + + state = strm.state; + if (state.mode === TYPE) { state.mode = TYPEDO; } /* skip check */ + + + //--- LOAD() --- + put = strm.next_out; + output = strm.output; + left = strm.avail_out; + next = strm.next_in; + input = strm.input; + have = strm.avail_in; + hold = state.hold; + bits = state.bits; + //--- + + _in = have; + _out = left; + ret = Z_OK; + + inf_leave: // goto emulation + for (;;) { + switch (state.mode) { + case HEAD: + if (state.wrap === 0) { + state.mode = TYPEDO; + break; + } + //=== NEEDBITS(16); + while (bits < 16) { + if (have === 0) { break inf_leave; } + have--; + hold += input[next++] << bits; + bits += 8; + } + //===// + if ((state.wrap & 2) && hold === 0x8b1f) { /* gzip header */ + state.check = 0/*crc32(0L, Z_NULL, 0)*/; + //=== CRC2(state.check, hold); + hbuf[0] = hold & 0xff; + hbuf[1] = (hold >>> 8) & 0xff; + state.check = crc32(state.check, hbuf, 2, 0); + //===// + + //=== INITBITS(); + hold = 0; + bits = 0; + //===// + state.mode = FLAGS; + break; + } + state.flags = 0; /* expect zlib header */ + if (state.head) { + state.head.done = false; + } + if (!(state.wrap & 1) || /* check if zlib header allowed */ + (((hold & 0xff)/*BITS(8)*/ << 8) + (hold >> 8)) % 31) { + strm.msg = 'incorrect header check'; + state.mode = BAD; + break; + } + if ((hold & 0x0f)/*BITS(4)*/ !== Z_DEFLATED) { + strm.msg = 'unknown compression method'; + state.mode = BAD; + break; + } + //--- DROPBITS(4) ---// + hold >>>= 4; + bits -= 4; + //---// + len = (hold & 0x0f)/*BITS(4)*/ + 8; + if (state.wbits === 0) { + state.wbits = len; + } + else if (len > state.wbits) { + strm.msg = 'invalid window size'; + state.mode = BAD; + break; + } + state.dmax = 1 << len; + //Tracev((stderr, "inflate: zlib header ok\n")); + strm.adler = state.check = 1/*adler32(0L, Z_NULL, 0)*/; + state.mode = hold & 0x200 ? DICTID : TYPE; + //=== INITBITS(); + hold = 0; + bits = 0; + //===// + break; + case FLAGS: + //=== NEEDBITS(16); */ + while (bits < 16) { + if (have === 0) { break inf_leave; } + have--; + hold += input[next++] << bits; + bits += 8; + } + //===// + state.flags = hold; + if ((state.flags & 0xff) !== Z_DEFLATED) { + strm.msg = 'unknown compression method'; + state.mode = BAD; + break; + } + if (state.flags & 0xe000) { + strm.msg = 'unknown header flags set'; + state.mode = BAD; + break; + } + if (state.head) { + state.head.text = ((hold >> 8) & 1); + } + if (state.flags & 0x0200) { + //=== CRC2(state.check, hold); + hbuf[0] = hold & 0xff; + hbuf[1] = (hold >>> 8) & 0xff; + state.check = crc32(state.check, hbuf, 2, 0); + //===// + } + //=== INITBITS(); + hold = 0; + bits = 0; + //===// + state.mode = TIME; + /* falls through */ + case TIME: + //=== NEEDBITS(32); */ + while (bits < 32) { + if (have === 0) { break inf_leave; } + have--; + hold += input[next++] << bits; + bits += 8; + } + //===// + if (state.head) { + state.head.time = hold; + } + if (state.flags & 0x0200) { + //=== CRC4(state.check, hold) + hbuf[0] = hold & 0xff; + hbuf[1] = (hold >>> 8) & 0xff; + hbuf[2] = (hold >>> 16) & 0xff; + hbuf[3] = (hold >>> 24) & 0xff; + state.check = crc32(state.check, hbuf, 4, 0); + //=== + } + //=== INITBITS(); + hold = 0; + bits = 0; + //===// + state.mode = OS; + /* falls through */ + case OS: + //=== NEEDBITS(16); */ + while (bits < 16) { + if (have === 0) { break inf_leave; } + have--; + hold += input[next++] << bits; + bits += 8; + } + //===// + if (state.head) { + state.head.xflags = (hold & 0xff); + state.head.os = (hold >> 8); + } + if (state.flags & 0x0200) { + //=== CRC2(state.check, hold); + hbuf[0] = hold & 0xff; + hbuf[1] = (hold >>> 8) & 0xff; + state.check = crc32(state.check, hbuf, 2, 0); + //===// + } + //=== INITBITS(); + hold = 0; + bits = 0; + //===// + state.mode = EXLEN; + /* falls through */ + case EXLEN: + if (state.flags & 0x0400) { + //=== NEEDBITS(16); */ + while (bits < 16) { + if (have === 0) { break inf_leave; } + have--; + hold += input[next++] << bits; + bits += 8; + } + //===// + state.length = hold; + if (state.head) { + state.head.extra_len = hold; + } + if (state.flags & 0x0200) { + //=== CRC2(state.check, hold); + hbuf[0] = hold & 0xff; + hbuf[1] = (hold >>> 8) & 0xff; + state.check = crc32(state.check, hbuf, 2, 0); + //===// + } + //=== INITBITS(); + hold = 0; + bits = 0; + //===// + } + else if (state.head) { + state.head.extra = null/*Z_NULL*/; + } + state.mode = EXTRA; + /* falls through */ + case EXTRA: + if (state.flags & 0x0400) { + copy = state.length; + if (copy > have) { copy = have; } + if (copy) { + if (state.head) { + len = state.head.extra_len - state.length; + if (!state.head.extra) { + // Use untyped array for more conveniend processing later + state.head.extra = new Array(state.head.extra_len); + } + utils.arraySet( + state.head.extra, + input, + next, + // extra field is limited to 65536 bytes + // - no need for additional size check + copy, + /*len + copy > state.head.extra_max - len ? state.head.extra_max : copy,*/ + len + ); + //zmemcpy(state.head.extra + len, next, + // len + copy > state.head.extra_max ? + // state.head.extra_max - len : copy); + } + if (state.flags & 0x0200) { + state.check = crc32(state.check, input, copy, next); + } + have -= copy; + next += copy; + state.length -= copy; + } + if (state.length) { break inf_leave; } + } + state.length = 0; + state.mode = NAME; + /* falls through */ + case NAME: + if (state.flags & 0x0800) { + if (have === 0) { break inf_leave; } + copy = 0; + do { + // TODO: 2 or 1 bytes? + len = input[next + copy++]; + /* use constant limit because in js we should not preallocate memory */ + if (state.head && len && + (state.length < 65536 /*state.head.name_max*/)) { + state.head.name += String.fromCharCode(len); + } + } while (len && copy < have); + + if (state.flags & 0x0200) { + state.check = crc32(state.check, input, copy, next); + } + have -= copy; + next += copy; + if (len) { break inf_leave; } + } + else if (state.head) { + state.head.name = null; + } + state.length = 0; + state.mode = COMMENT; + /* falls through */ + case COMMENT: + if (state.flags & 0x1000) { + if (have === 0) { break inf_leave; } + copy = 0; + do { + len = input[next + copy++]; + /* use constant limit because in js we should not preallocate memory */ + if (state.head && len && + (state.length < 65536 /*state.head.comm_max*/)) { + state.head.comment += String.fromCharCode(len); + } + } while (len && copy < have); + if (state.flags & 0x0200) { + state.check = crc32(state.check, input, copy, next); + } + have -= copy; + next += copy; + if (len) { break inf_leave; } + } + else if (state.head) { + state.head.comment = null; + } + state.mode = HCRC; + /* falls through */ + case HCRC: + if (state.flags & 0x0200) { + //=== NEEDBITS(16); */ + while (bits < 16) { + if (have === 0) { break inf_leave; } + have--; + hold += input[next++] << bits; + bits += 8; + } + //===// + if (hold !== (state.check & 0xffff)) { + strm.msg = 'header crc mismatch'; + state.mode = BAD; + break; + } + //=== INITBITS(); + hold = 0; + bits = 0; + //===// + } + if (state.head) { + state.head.hcrc = ((state.flags >> 9) & 1); + state.head.done = true; + } + strm.adler = state.check = 0 /*crc32(0L, Z_NULL, 0)*/; + state.mode = TYPE; + break; + case DICTID: + //=== NEEDBITS(32); */ + while (bits < 32) { + if (have === 0) { break inf_leave; } + have--; + hold += input[next++] << bits; + bits += 8; + } + //===// + strm.adler = state.check = ZSWAP32(hold); + //=== INITBITS(); + hold = 0; + bits = 0; + //===// + state.mode = DICT; + /* falls through */ + case DICT: + if (state.havedict === 0) { + //--- RESTORE() --- + strm.next_out = put; + strm.avail_out = left; + strm.next_in = next; + strm.avail_in = have; + state.hold = hold; + state.bits = bits; + //--- + return Z_NEED_DICT; + } + strm.adler = state.check = 1/*adler32(0L, Z_NULL, 0)*/; + state.mode = TYPE; + /* falls through */ + case TYPE: + if (flush === Z_BLOCK || flush === Z_TREES) { break inf_leave; } + /* falls through */ + case TYPEDO: + if (state.last) { + //--- BYTEBITS() ---// + hold >>>= bits & 7; + bits -= bits & 7; + //---// + state.mode = CHECK; + break; + } + //=== NEEDBITS(3); */ + while (bits < 3) { + if (have === 0) { break inf_leave; } + have--; + hold += input[next++] << bits; + bits += 8; + } + //===// + state.last = (hold & 0x01)/*BITS(1)*/; + //--- DROPBITS(1) ---// + hold >>>= 1; + bits -= 1; + //---// + + switch ((hold & 0x03)/*BITS(2)*/) { + case 0: /* stored block */ + //Tracev((stderr, "inflate: stored block%s\n", + // state.last ? " (last)" : "")); + state.mode = STORED; + break; + case 1: /* fixed block */ + fixedtables(state); + //Tracev((stderr, "inflate: fixed codes block%s\n", + // state.last ? " (last)" : "")); + state.mode = LEN_; /* decode codes */ + if (flush === Z_TREES) { + //--- DROPBITS(2) ---// + hold >>>= 2; + bits -= 2; + //---// + break inf_leave; + } + break; + case 2: /* dynamic block */ + //Tracev((stderr, "inflate: dynamic codes block%s\n", + // state.last ? " (last)" : "")); + state.mode = TABLE; + break; + case 3: + strm.msg = 'invalid block type'; + state.mode = BAD; + } + //--- DROPBITS(2) ---// + hold >>>= 2; + bits -= 2; + //---// + break; + case STORED: + //--- BYTEBITS() ---// /* go to byte boundary */ + hold >>>= bits & 7; + bits -= bits & 7; + //---// + //=== NEEDBITS(32); */ + while (bits < 32) { + if (have === 0) { break inf_leave; } + have--; + hold += input[next++] << bits; + bits += 8; + } + //===// + if ((hold & 0xffff) !== ((hold >>> 16) ^ 0xffff)) { + strm.msg = 'invalid stored block lengths'; + state.mode = BAD; + break; + } + state.length = hold & 0xffff; + //Tracev((stderr, "inflate: stored length %u\n", + // state.length)); + //=== INITBITS(); + hold = 0; + bits = 0; + //===// + state.mode = COPY_; + if (flush === Z_TREES) { break inf_leave; } + /* falls through */ + case COPY_: + state.mode = COPY; + /* falls through */ + case COPY: + copy = state.length; + if (copy) { + if (copy > have) { copy = have; } + if (copy > left) { copy = left; } + if (copy === 0) { break inf_leave; } + //--- zmemcpy(put, next, copy); --- + utils.arraySet(output, input, next, copy, put); + //---// + have -= copy; + next += copy; + left -= copy; + put += copy; + state.length -= copy; + break; + } + //Tracev((stderr, "inflate: stored end\n")); + state.mode = TYPE; + break; + case TABLE: + //=== NEEDBITS(14); */ + while (bits < 14) { + if (have === 0) { break inf_leave; } + have--; + hold += input[next++] << bits; + bits += 8; + } + //===// + state.nlen = (hold & 0x1f)/*BITS(5)*/ + 257; + //--- DROPBITS(5) ---// + hold >>>= 5; + bits -= 5; + //---// + state.ndist = (hold & 0x1f)/*BITS(5)*/ + 1; + //--- DROPBITS(5) ---// + hold >>>= 5; + bits -= 5; + //---// + state.ncode = (hold & 0x0f)/*BITS(4)*/ + 4; + //--- DROPBITS(4) ---// + hold >>>= 4; + bits -= 4; + //---// +//#ifndef PKZIP_BUG_WORKAROUND + if (state.nlen > 286 || state.ndist > 30) { + strm.msg = 'too many length or distance symbols'; + state.mode = BAD; + break; + } +//#endif + //Tracev((stderr, "inflate: table sizes ok\n")); + state.have = 0; + state.mode = LENLENS; + /* falls through */ + case LENLENS: + while (state.have < state.ncode) { + //=== NEEDBITS(3); + while (bits < 3) { + if (have === 0) { break inf_leave; } + have--; + hold += input[next++] << bits; + bits += 8; + } + //===// + state.lens[order[state.have++]] = (hold & 0x07);//BITS(3); + //--- DROPBITS(3) ---// + hold >>>= 3; + bits -= 3; + //---// + } + while (state.have < 19) { + state.lens[order[state.have++]] = 0; + } + // We have separate tables & no pointers. 2 commented lines below not needed. + //state.next = state.codes; + //state.lencode = state.next; + // Switch to use dynamic table + state.lencode = state.lendyn; + state.lenbits = 7; + + opts = {bits: state.lenbits}; + ret = inflate_table(CODES, state.lens, 0, 19, state.lencode, 0, state.work, opts); + state.lenbits = opts.bits; + + if (ret) { + strm.msg = 'invalid code lengths set'; + state.mode = BAD; + break; + } + //Tracev((stderr, "inflate: code lengths ok\n")); + state.have = 0; + state.mode = CODELENS; + /* falls through */ + case CODELENS: + while (state.have < state.nlen + state.ndist) { + for (;;) { + here = state.lencode[hold & ((1 << state.lenbits) - 1)];/*BITS(state.lenbits)*/ + here_bits = here >>> 24; + here_op = (here >>> 16) & 0xff; + here_val = here & 0xffff; + + if ((here_bits) <= bits) { break; } + //--- PULLBYTE() ---// + if (have === 0) { break inf_leave; } + have--; + hold += input[next++] << bits; + bits += 8; + //---// + } + if (here_val < 16) { + //--- DROPBITS(here.bits) ---// + hold >>>= here_bits; + bits -= here_bits; + //---// + state.lens[state.have++] = here_val; + } + else { + if (here_val === 16) { + //=== NEEDBITS(here.bits + 2); + n = here_bits + 2; + while (bits < n) { + if (have === 0) { break inf_leave; } + have--; + hold += input[next++] << bits; + bits += 8; + } + //===// + //--- DROPBITS(here.bits) ---// + hold >>>= here_bits; + bits -= here_bits; + //---// + if (state.have === 0) { + strm.msg = 'invalid bit length repeat'; + state.mode = BAD; + break; + } + len = state.lens[state.have - 1]; + copy = 3 + (hold & 0x03);//BITS(2); + //--- DROPBITS(2) ---// + hold >>>= 2; + bits -= 2; + //---// + } + else if (here_val === 17) { + //=== NEEDBITS(here.bits + 3); + n = here_bits + 3; + while (bits < n) { + if (have === 0) { break inf_leave; } + have--; + hold += input[next++] << bits; + bits += 8; + } + //===// + //--- DROPBITS(here.bits) ---// + hold >>>= here_bits; + bits -= here_bits; + //---// + len = 0; + copy = 3 + (hold & 0x07);//BITS(3); + //--- DROPBITS(3) ---// + hold >>>= 3; + bits -= 3; + //---// + } + else { + //=== NEEDBITS(here.bits + 7); + n = here_bits + 7; + while (bits < n) { + if (have === 0) { break inf_leave; } + have--; + hold += input[next++] << bits; + bits += 8; + } + //===// + //--- DROPBITS(here.bits) ---// + hold >>>= here_bits; + bits -= here_bits; + //---// + len = 0; + copy = 11 + (hold & 0x7f);//BITS(7); + //--- DROPBITS(7) ---// + hold >>>= 7; + bits -= 7; + //---// + } + if (state.have + copy > state.nlen + state.ndist) { + strm.msg = 'invalid bit length repeat'; + state.mode = BAD; + break; + } + while (copy--) { + state.lens[state.have++] = len; + } + } + } + + /* handle error breaks in while */ + if (state.mode === BAD) { break; } + + /* check for end-of-block code (better have one) */ + if (state.lens[256] === 0) { + strm.msg = 'invalid code -- missing end-of-block'; + state.mode = BAD; + break; + } + + /* build code tables -- note: do not change the lenbits or distbits + values here (9 and 6) without reading the comments in inftrees.h + concerning the ENOUGH constants, which depend on those values */ + state.lenbits = 9; + + opts = {bits: state.lenbits}; + ret = inflate_table(LENS, state.lens, 0, state.nlen, state.lencode, 0, state.work, opts); + // We have separate tables & no pointers. 2 commented lines below not needed. + // state.next_index = opts.table_index; + state.lenbits = opts.bits; + // state.lencode = state.next; + + if (ret) { + strm.msg = 'invalid literal/lengths set'; + state.mode = BAD; + break; + } + + state.distbits = 6; + //state.distcode.copy(state.codes); + // Switch to use dynamic table + state.distcode = state.distdyn; + opts = {bits: state.distbits}; + ret = inflate_table(DISTS, state.lens, state.nlen, state.ndist, state.distcode, 0, state.work, opts); + // We have separate tables & no pointers. 2 commented lines below not needed. + // state.next_index = opts.table_index; + state.distbits = opts.bits; + // state.distcode = state.next; + + if (ret) { + strm.msg = 'invalid distances set'; + state.mode = BAD; + break; + } + //Tracev((stderr, 'inflate: codes ok\n')); + state.mode = LEN_; + if (flush === Z_TREES) { break inf_leave; } + /* falls through */ + case LEN_: + state.mode = LEN; + /* falls through */ + case LEN: + if (have >= 6 && left >= 258) { + //--- RESTORE() --- + strm.next_out = put; + strm.avail_out = left; + strm.next_in = next; + strm.avail_in = have; + state.hold = hold; + state.bits = bits; + //--- + inflate_fast(strm, _out); + //--- LOAD() --- + put = strm.next_out; + output = strm.output; + left = strm.avail_out; + next = strm.next_in; + input = strm.input; + have = strm.avail_in; + hold = state.hold; + bits = state.bits; + //--- + + if (state.mode === TYPE) { + state.back = -1; + } + break; + } + state.back = 0; + for (;;) { + here = state.lencode[hold & ((1 << state.lenbits) -1)]; /*BITS(state.lenbits)*/ + here_bits = here >>> 24; + here_op = (here >>> 16) & 0xff; + here_val = here & 0xffff; + + if (here_bits <= bits) { break; } + //--- PULLBYTE() ---// + if (have === 0) { break inf_leave; } + have--; + hold += input[next++] << bits; + bits += 8; + //---// + } + if (here_op && (here_op & 0xf0) === 0) { + last_bits = here_bits; + last_op = here_op; + last_val = here_val; + for (;;) { + here = state.lencode[last_val + + ((hold & ((1 << (last_bits + last_op)) -1))/*BITS(last.bits + last.op)*/ >> last_bits)]; + here_bits = here >>> 24; + here_op = (here >>> 16) & 0xff; + here_val = here & 0xffff; + + if ((last_bits + here_bits) <= bits) { break; } + //--- PULLBYTE() ---// + if (have === 0) { break inf_leave; } + have--; + hold += input[next++] << bits; + bits += 8; + //---// + } + //--- DROPBITS(last.bits) ---// + hold >>>= last_bits; + bits -= last_bits; + //---// + state.back += last_bits; + } + //--- DROPBITS(here.bits) ---// + hold >>>= here_bits; + bits -= here_bits; + //---// + state.back += here_bits; + state.length = here_val; + if (here_op === 0) { + //Tracevv((stderr, here.val >= 0x20 && here.val < 0x7f ? + // "inflate: literal '%c'\n" : + // "inflate: literal 0x%02x\n", here.val)); + state.mode = LIT; + break; + } + if (here_op & 32) { + //Tracevv((stderr, "inflate: end of block\n")); + state.back = -1; + state.mode = TYPE; + break; + } + if (here_op & 64) { + strm.msg = 'invalid literal/length code'; + state.mode = BAD; + break; + } + state.extra = here_op & 15; + state.mode = LENEXT; + /* falls through */ + case LENEXT: + if (state.extra) { + //=== NEEDBITS(state.extra); + n = state.extra; + while (bits < n) { + if (have === 0) { break inf_leave; } + have--; + hold += input[next++] << bits; + bits += 8; + } + //===// + state.length += hold & ((1 << state.extra) -1)/*BITS(state.extra)*/; + //--- DROPBITS(state.extra) ---// + hold >>>= state.extra; + bits -= state.extra; + //---// + state.back += state.extra; + } + //Tracevv((stderr, "inflate: length %u\n", state.length)); + state.was = state.length; + state.mode = DIST; + /* falls through */ + case DIST: + for (;;) { + here = state.distcode[hold & ((1 << state.distbits) -1)];/*BITS(state.distbits)*/ + here_bits = here >>> 24; + here_op = (here >>> 16) & 0xff; + here_val = here & 0xffff; + + if ((here_bits) <= bits) { break; } + //--- PULLBYTE() ---// + if (have === 0) { break inf_leave; } + have--; + hold += input[next++] << bits; + bits += 8; + //---// + } + if ((here_op & 0xf0) === 0) { + last_bits = here_bits; + last_op = here_op; + last_val = here_val; + for (;;) { + here = state.distcode[last_val + + ((hold & ((1 << (last_bits + last_op)) -1))/*BITS(last.bits + last.op)*/ >> last_bits)]; + here_bits = here >>> 24; + here_op = (here >>> 16) & 0xff; + here_val = here & 0xffff; + + if ((last_bits + here_bits) <= bits) { break; } + //--- PULLBYTE() ---// + if (have === 0) { break inf_leave; } + have--; + hold += input[next++] << bits; + bits += 8; + //---// + } + //--- DROPBITS(last.bits) ---// + hold >>>= last_bits; + bits -= last_bits; + //---// + state.back += last_bits; + } + //--- DROPBITS(here.bits) ---// + hold >>>= here_bits; + bits -= here_bits; + //---// + state.back += here_bits; + if (here_op & 64) { + strm.msg = 'invalid distance code'; + state.mode = BAD; + break; + } + state.offset = here_val; + state.extra = (here_op) & 15; + state.mode = DISTEXT; + /* falls through */ + case DISTEXT: + if (state.extra) { + //=== NEEDBITS(state.extra); + n = state.extra; + while (bits < n) { + if (have === 0) { break inf_leave; } + have--; + hold += input[next++] << bits; + bits += 8; + } + //===// + state.offset += hold & ((1 << state.extra) -1)/*BITS(state.extra)*/; + //--- DROPBITS(state.extra) ---// + hold >>>= state.extra; + bits -= state.extra; + //---// + state.back += state.extra; + } +//#ifdef INFLATE_STRICT + if (state.offset > state.dmax) { + strm.msg = 'invalid distance too far back'; + state.mode = BAD; + break; + } +//#endif + //Tracevv((stderr, "inflate: distance %u\n", state.offset)); + state.mode = MATCH; + /* falls through */ + case MATCH: + if (left === 0) { break inf_leave; } + copy = _out - left; + if (state.offset > copy) { /* copy from window */ + copy = state.offset - copy; + if (copy > state.whave) { + if (state.sane) { + strm.msg = 'invalid distance too far back'; + state.mode = BAD; + break; + } +// (!) This block is disabled in zlib defailts, +// don't enable it for binary compatibility +//#ifdef INFLATE_ALLOW_INVALID_DISTANCE_TOOFAR_ARRR +// Trace((stderr, "inflate.c too far\n")); +// copy -= state.whave; +// if (copy > state.length) { copy = state.length; } +// if (copy > left) { copy = left; } +// left -= copy; +// state.length -= copy; +// do { +// output[put++] = 0; +// } while (--copy); +// if (state.length === 0) { state.mode = LEN; } +// break; +//#endif + } + if (copy > state.wnext) { + copy -= state.wnext; + from = state.wsize - copy; + } + else { + from = state.wnext - copy; + } + if (copy > state.length) { copy = state.length; } + from_source = state.window; + } + else { /* copy from output */ + from_source = output; + from = put - state.offset; + copy = state.length; + } + if (copy > left) { copy = left; } + left -= copy; + state.length -= copy; + do { + output[put++] = from_source[from++]; + } while (--copy); + if (state.length === 0) { state.mode = LEN; } + break; + case LIT: + if (left === 0) { break inf_leave; } + output[put++] = state.length; + left--; + state.mode = LEN; + break; + case CHECK: + if (state.wrap) { + //=== NEEDBITS(32); + while (bits < 32) { + if (have === 0) { break inf_leave; } + have--; + // Use '|' insdead of '+' to make sure that result is signed + hold |= input[next++] << bits; + bits += 8; + } + //===// + _out -= left; + strm.total_out += _out; + state.total += _out; + if (_out) { + strm.adler = state.check = + /*UPDATE(state.check, put - _out, _out);*/ + (state.flags ? crc32(state.check, output, _out, put - _out) : adler32(state.check, output, _out, put - _out)); + + } + _out = left; + // NB: crc32 stored as signed 32-bit int, ZSWAP32 returns signed too + if ((state.flags ? hold : ZSWAP32(hold)) !== state.check) { + strm.msg = 'incorrect data check'; + state.mode = BAD; + break; + } + //=== INITBITS(); + hold = 0; + bits = 0; + //===// + //Tracev((stderr, "inflate: check matches trailer\n")); + } + state.mode = LENGTH; + /* falls through */ + case LENGTH: + if (state.wrap && state.flags) { + //=== NEEDBITS(32); + while (bits < 32) { + if (have === 0) { break inf_leave; } + have--; + hold += input[next++] << bits; + bits += 8; + } + //===// + if (hold !== (state.total & 0xffffffff)) { + strm.msg = 'incorrect length check'; + state.mode = BAD; + break; + } + //=== INITBITS(); + hold = 0; + bits = 0; + //===// + //Tracev((stderr, "inflate: length matches trailer\n")); + } + state.mode = DONE; + /* falls through */ + case DONE: + ret = Z_STREAM_END; + break inf_leave; + case BAD: + ret = Z_DATA_ERROR; + break inf_leave; + case MEM: + return Z_MEM_ERROR; + case SYNC: + /* falls through */ + default: + return Z_STREAM_ERROR; + } + } + + // inf_leave <- here is real place for "goto inf_leave", emulated via "break inf_leave" + + /* + Return from inflate(), updating the total counts and the check value. + If there was no progress during the inflate() call, return a buffer + error. Call updatewindow() to create and/or update the window state. + Note: a memory error from inflate() is non-recoverable. + */ + + //--- RESTORE() --- + strm.next_out = put; + strm.avail_out = left; + strm.next_in = next; + strm.avail_in = have; + state.hold = hold; + state.bits = bits; + //--- + + if (state.wsize || (_out !== strm.avail_out && state.mode < BAD && + (state.mode < CHECK || flush !== Z_FINISH))) { + if (updatewindow(strm, strm.output, strm.next_out, _out - strm.avail_out)) { + state.mode = MEM; + return Z_MEM_ERROR; + } + } + _in -= strm.avail_in; + _out -= strm.avail_out; + strm.total_in += _in; + strm.total_out += _out; + state.total += _out; + if (state.wrap && _out) { + strm.adler = state.check = /*UPDATE(state.check, strm.next_out - _out, _out);*/ + (state.flags ? crc32(state.check, output, _out, strm.next_out - _out) : adler32(state.check, output, _out, strm.next_out - _out)); + } + strm.data_type = state.bits + (state.last ? 64 : 0) + + (state.mode === TYPE ? 128 : 0) + + (state.mode === LEN_ || state.mode === COPY_ ? 256 : 0); + if (((_in === 0 && _out === 0) || flush === Z_FINISH) && ret === Z_OK) { + ret = Z_BUF_ERROR; + } + return ret; +} + +function inflateEnd(strm) { + + if (!strm || !strm.state /*|| strm->zfree == (free_func)0*/) { + return Z_STREAM_ERROR; + } + + var state = strm.state; + if (state.window) { + state.window = null; + } + strm.state = null; + return Z_OK; +} + +function inflateGetHeader(strm, head) { + var state; + + /* check state */ + if (!strm || !strm.state) { return Z_STREAM_ERROR; } + state = strm.state; + if ((state.wrap & 2) === 0) { return Z_STREAM_ERROR; } + + /* save header structure */ + state.head = head; + head.done = false; + return Z_OK; +} + + +exports.inflateReset = inflateReset; +exports.inflateReset2 = inflateReset2; +exports.inflateResetKeep = inflateResetKeep; +exports.inflateInit = inflateInit; +exports.inflateInit2 = inflateInit2; +exports.inflate = inflate; +exports.inflateEnd = inflateEnd; +exports.inflateGetHeader = inflateGetHeader; +exports.inflateInfo = 'pako inflate (from Nodeca project)'; + +/* Not implemented +exports.inflateCopy = inflateCopy; +exports.inflateGetDictionary = inflateGetDictionary; +exports.inflateMark = inflateMark; +exports.inflatePrime = inflatePrime; +exports.inflateSetDictionary = inflateSetDictionary; +exports.inflateSync = inflateSync; +exports.inflateSyncPoint = inflateSyncPoint; +exports.inflateUndermine = inflateUndermine; +*/ +},{"../utils/common":3,"./adler32":5,"./crc32":7,"./inffast":10,"./inftrees":12}],12:[function(require,module,exports){ +'use strict'; + + +var utils = require('../utils/common'); + +var MAXBITS = 15; +var ENOUGH_LENS = 852; +var ENOUGH_DISTS = 592; +//var ENOUGH = (ENOUGH_LENS+ENOUGH_DISTS); + +var CODES = 0; +var LENS = 1; +var DISTS = 2; + +var lbase = [ /* Length codes 257..285 base */ + 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31, + 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0 +]; + +var lext = [ /* Length codes 257..285 extra */ + 16, 16, 16, 16, 16, 16, 16, 16, 17, 17, 17, 17, 18, 18, 18, 18, + 19, 19, 19, 19, 20, 20, 20, 20, 21, 21, 21, 21, 16, 72, 78 +]; + +var dbase = [ /* Distance codes 0..29 base */ + 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, + 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145, + 8193, 12289, 16385, 24577, 0, 0 +]; + +var dext = [ /* Distance codes 0..29 extra */ + 16, 16, 16, 16, 17, 17, 18, 18, 19, 19, 20, 20, 21, 21, 22, 22, + 23, 23, 24, 24, 25, 25, 26, 26, 27, 27, + 28, 28, 29, 29, 64, 64 +]; + +module.exports = function inflate_table(type, lens, lens_index, codes, table, table_index, work, opts) +{ + var bits = opts.bits; + //here = opts.here; /* table entry for duplication */ + + var len = 0; /* a code's length in bits */ + var sym = 0; /* index of code symbols */ + var min = 0, max = 0; /* minimum and maximum code lengths */ + var root = 0; /* number of index bits for root table */ + var curr = 0; /* number of index bits for current table */ + var drop = 0; /* code bits to drop for sub-table */ + var left = 0; /* number of prefix codes available */ + var used = 0; /* code entries in table used */ + var huff = 0; /* Huffman code */ + var incr; /* for incrementing code, index */ + var fill; /* index for replicating entries */ + var low; /* low bits for current root entry */ + var mask; /* mask for low root bits */ + var next; /* next available space in table */ + var base = null; /* base value table to use */ + var base_index = 0; +// var shoextra; /* extra bits table to use */ + var end; /* use base and extra for symbol > end */ + var count = new utils.Buf16(MAXBITS+1); //[MAXBITS+1]; /* number of codes of each length */ + var offs = new utils.Buf16(MAXBITS+1); //[MAXBITS+1]; /* offsets in table for each length */ + var extra = null; + var extra_index = 0; + + var here_bits, here_op, here_val; + + /* + Process a set of code lengths to create a canonical Huffman code. The + code lengths are lens[0..codes-1]. Each length corresponds to the + symbols 0..codes-1. The Huffman code is generated by first sorting the + symbols by length from short to long, and retaining the symbol order + for codes with equal lengths. Then the code starts with all zero bits + for the first code of the shortest length, and the codes are integer + increments for the same length, and zeros are appended as the length + increases. For the deflate format, these bits are stored backwards + from their more natural integer increment ordering, and so when the + decoding tables are built in the large loop below, the integer codes + are incremented backwards. + + This routine assumes, but does not check, that all of the entries in + lens[] are in the range 0..MAXBITS. The caller must assure this. + 1..MAXBITS is interpreted as that code length. zero means that that + symbol does not occur in this code. + + The codes are sorted by computing a count of codes for each length, + creating from that a table of starting indices for each length in the + sorted table, and then entering the symbols in order in the sorted + table. The sorted table is work[], with that space being provided by + the caller. + + The length counts are used for other purposes as well, i.e. finding + the minimum and maximum length codes, determining if there are any + codes at all, checking for a valid set of lengths, and looking ahead + at length counts to determine sub-table sizes when building the + decoding tables. + */ + + /* accumulate lengths for codes (assumes lens[] all in 0..MAXBITS) */ + for (len = 0; len <= MAXBITS; len++) { + count[len] = 0; + } + for (sym = 0; sym < codes; sym++) { + count[lens[lens_index + sym]]++; + } + + /* bound code lengths, force root to be within code lengths */ + root = bits; + for (max = MAXBITS; max >= 1; max--) { + if (count[max] !== 0) { break; } + } + if (root > max) { + root = max; + } + if (max === 0) { /* no symbols to code at all */ + //table.op[opts.table_index] = 64; //here.op = (var char)64; /* invalid code marker */ + //table.bits[opts.table_index] = 1; //here.bits = (var char)1; + //table.val[opts.table_index++] = 0; //here.val = (var short)0; + table[table_index++] = (1 << 24) | (64 << 16) | 0; + + + //table.op[opts.table_index] = 64; + //table.bits[opts.table_index] = 1; + //table.val[opts.table_index++] = 0; + table[table_index++] = (1 << 24) | (64 << 16) | 0; + + opts.bits = 1; + return 0; /* no symbols, but wait for decoding to report error */ + } + for (min = 1; min < max; min++) { + if (count[min] !== 0) { break; } + } + if (root < min) { + root = min; + } + + /* check for an over-subscribed or incomplete set of lengths */ + left = 1; + for (len = 1; len <= MAXBITS; len++) { + left <<= 1; + left -= count[len]; + if (left < 0) { + return -1; + } /* over-subscribed */ + } + if (left > 0 && (type === CODES || max !== 1)) { + return -1; /* incomplete set */ + } + + /* generate offsets into symbol table for each length for sorting */ + offs[1] = 0; + for (len = 1; len < MAXBITS; len++) { + offs[len + 1] = offs[len] + count[len]; + } + + /* sort symbols by length, by symbol order within each length */ + for (sym = 0; sym < codes; sym++) { + if (lens[lens_index + sym] !== 0) { + work[offs[lens[lens_index + sym]]++] = sym; + } + } + + /* + Create and fill in decoding tables. In this loop, the table being + filled is at next and has curr index bits. The code being used is huff + with length len. That code is converted to an index by dropping drop + bits off of the bottom. For codes where len is less than drop + curr, + those top drop + curr - len bits are incremented through all values to + fill the table with replicated entries. + + root is the number of index bits for the root table. When len exceeds + root, sub-tables are created pointed to by the root entry with an index + of the low root bits of huff. This is saved in low to check for when a + new sub-table should be started. drop is zero when the root table is + being filled, and drop is root when sub-tables are being filled. + + When a new sub-table is needed, it is necessary to look ahead in the + code lengths to determine what size sub-table is needed. The length + counts are used for this, and so count[] is decremented as codes are + entered in the tables. + + used keeps track of how many table entries have been allocated from the + provided *table space. It is checked for LENS and DIST tables against + the constants ENOUGH_LENS and ENOUGH_DISTS to guard against changes in + the initial root table size constants. See the comments in inftrees.h + for more information. + + sym increments through all symbols, and the loop terminates when + all codes of length max, i.e. all codes, have been processed. This + routine permits incomplete codes, so another loop after this one fills + in the rest of the decoding tables with invalid code markers. + */ + + /* set up for code type */ + // poor man optimization - use if-else instead of switch, + // to avoid deopts in old v8 + if (type === CODES) { + base = extra = work; /* dummy value--not used */ + end = 19; + } else if (type === LENS) { + base = lbase; + base_index -= 257; + extra = lext; + extra_index -= 257; + end = 256; + } else { /* DISTS */ + base = dbase; + extra = dext; + end = -1; + } + + /* initialize opts for loop */ + huff = 0; /* starting code */ + sym = 0; /* starting code symbol */ + len = min; /* starting code length */ + next = table_index; /* current table to fill in */ + curr = root; /* current table index bits */ + drop = 0; /* current bits to drop from code for index */ + low = -1; /* trigger new sub-table when len > root */ + used = 1 << root; /* use root table entries */ + mask = used - 1; /* mask for comparing low */ + + /* check available table space */ + if ((type === LENS && used > ENOUGH_LENS) || + (type === DISTS && used > ENOUGH_DISTS)) { + return 1; + } + + var i=0; + /* process all codes and make table entries */ + for (;;) { + i++; + /* create table entry */ + here_bits = len - drop; + if (work[sym] < end) { + here_op = 0; + here_val = work[sym]; + } + else if (work[sym] > end) { + here_op = extra[extra_index + work[sym]]; + here_val = base[base_index + work[sym]]; + } + else { + here_op = 32 + 64; /* end of block */ + here_val = 0; + } + + /* replicate for those indices with low len bits equal to huff */ + incr = 1 << (len - drop); + fill = 1 << curr; + min = fill; /* save offset to next table */ + do { + fill -= incr; + table[next + (huff >> drop) + fill] = (here_bits << 24) | (here_op << 16) | here_val |0; + } while (fill !== 0); + + /* backwards increment the len-bit code huff */ + incr = 1 << (len - 1); + while (huff & incr) { + incr >>= 1; + } + if (incr !== 0) { + huff &= incr - 1; + huff += incr; + } else { + huff = 0; + } + + /* go to next symbol, update count, len */ + sym++; + if (--count[len] === 0) { + if (len === max) { break; } + len = lens[lens_index + work[sym]]; + } + + /* create new sub-table if needed */ + if (len > root && (huff & mask) !== low) { + /* if first time, transition to sub-tables */ + if (drop === 0) { + drop = root; + } + + /* increment past last table */ + next += min; /* here min is 1 << curr */ + + /* determine length of next table */ + curr = len - drop; + left = 1 << curr; + while (curr + drop < max) { + left -= count[curr + drop]; + if (left <= 0) { break; } + curr++; + left <<= 1; + } + + /* check for enough space */ + used += 1 << curr; + if ((type === LENS && used > ENOUGH_LENS) || + (type === DISTS && used > ENOUGH_DISTS)) { + return 1; + } + + /* point entry in root table to sub-table */ + low = huff & mask; + /*table.op[low] = curr; + table.bits[low] = root; + table.val[low] = next - opts.table_index;*/ + table[low] = (root << 24) | (curr << 16) | (next - table_index) |0; + } + } + + /* fill in remaining table entry if code is incomplete (guaranteed to have + at most one remaining entry, since if the code is incomplete, the + maximum code length that was allowed to get this far is one bit) */ + if (huff !== 0) { + //table.op[next + huff] = 64; /* invalid code marker */ + //table.bits[next + huff] = len - drop; + //table.val[next + huff] = 0; + table[next + huff] = ((len - drop) << 24) | (64 << 16) |0; + } + + /* set return parameters */ + //opts.table_index += used; + opts.bits = root; + return 0; +}; + +},{"../utils/common":3}],13:[function(require,module,exports){ +'use strict'; + +module.exports = { + '2': 'need dictionary', /* Z_NEED_DICT 2 */ + '1': 'stream end', /* Z_STREAM_END 1 */ + '0': '', /* Z_OK 0 */ + '-1': 'file error', /* Z_ERRNO (-1) */ + '-2': 'stream error', /* Z_STREAM_ERROR (-2) */ + '-3': 'data error', /* Z_DATA_ERROR (-3) */ + '-4': 'insufficient memory', /* Z_MEM_ERROR (-4) */ + '-5': 'buffer error', /* Z_BUF_ERROR (-5) */ + '-6': 'incompatible version' /* Z_VERSION_ERROR (-6) */ +}; +},{}],14:[function(require,module,exports){ +'use strict'; + + +var utils = require('../utils/common'); + +/* Public constants ==========================================================*/ +/* ===========================================================================*/ + + +//var Z_FILTERED = 1; +//var Z_HUFFMAN_ONLY = 2; +//var Z_RLE = 3; +var Z_FIXED = 4; +//var Z_DEFAULT_STRATEGY = 0; + +/* Possible values of the data_type field (though see inflate()) */ +var Z_BINARY = 0; +var Z_TEXT = 1; +//var Z_ASCII = 1; // = Z_TEXT +var Z_UNKNOWN = 2; + +/*============================================================================*/ + + +function zero(buf) { var len = buf.length; while (--len >= 0) { buf[len] = 0; } } + +// From zutil.h + +var STORED_BLOCK = 0; +var STATIC_TREES = 1; +var DYN_TREES = 2; +/* The three kinds of block type */ + +var MIN_MATCH = 3; +var MAX_MATCH = 258; +/* The minimum and maximum match lengths */ + +// From deflate.h +/* =========================================================================== + * Internal compression state. + */ + +var LENGTH_CODES = 29; +/* number of length codes, not counting the special END_BLOCK code */ + +var LITERALS = 256; +/* number of literal bytes 0..255 */ + +var L_CODES = LITERALS + 1 + LENGTH_CODES; +/* number of Literal or Length codes, including the END_BLOCK code */ + +var D_CODES = 30; +/* number of distance codes */ + +var BL_CODES = 19; +/* number of codes used to transfer the bit lengths */ + +var HEAP_SIZE = 2*L_CODES + 1; +/* maximum heap size */ + +var MAX_BITS = 15; +/* All codes must not exceed MAX_BITS bits */ + +var Buf_size = 16; +/* size of bit buffer in bi_buf */ + + +/* =========================================================================== + * Constants + */ + +var MAX_BL_BITS = 7; +/* Bit length codes must not exceed MAX_BL_BITS bits */ + +var END_BLOCK = 256; +/* end of block literal code */ + +var REP_3_6 = 16; +/* repeat previous bit length 3-6 times (2 bits of repeat count) */ + +var REPZ_3_10 = 17; +/* repeat a zero length 3-10 times (3 bits of repeat count) */ + +var REPZ_11_138 = 18; +/* repeat a zero length 11-138 times (7 bits of repeat count) */ + +var extra_lbits = /* extra bits for each length code */ + [0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0]; + +var extra_dbits = /* extra bits for each distance code */ + [0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13]; + +var extra_blbits = /* extra bits for each bit length code */ + [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,7]; + +var bl_order = + [16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15]; +/* The lengths of the bit length codes are sent in order of decreasing + * probability, to avoid transmitting the lengths for unused bit length codes. + */ + +/* =========================================================================== + * Local data. These are initialized only once. + */ + +// We pre-fill arrays with 0 to avoid uninitialized gaps + +var DIST_CODE_LEN = 512; /* see definition of array dist_code below */ + +// !!!! Use flat array insdead of structure, Freq = i*2, Len = i*2+1 +var static_ltree = new Array((L_CODES+2) * 2); +zero(static_ltree); +/* The static literal tree. Since the bit lengths are imposed, there is no + * need for the L_CODES extra codes used during heap construction. However + * The codes 286 and 287 are needed to build a canonical tree (see _tr_init + * below). + */ + +var static_dtree = new Array(D_CODES * 2); +zero(static_dtree); +/* The static distance tree. (Actually a trivial tree since all codes use + * 5 bits.) + */ + +var _dist_code = new Array(DIST_CODE_LEN); +zero(_dist_code); +/* Distance codes. The first 256 values correspond to the distances + * 3 .. 258, the last 256 values correspond to the top 8 bits of + * the 15 bit distances. + */ + +var _length_code = new Array(MAX_MATCH-MIN_MATCH+1); +zero(_length_code); +/* length code for each normalized match length (0 == MIN_MATCH) */ + +var base_length = new Array(LENGTH_CODES); +zero(base_length); +/* First normalized length for each code (0 = MIN_MATCH) */ + +var base_dist = new Array(D_CODES); +zero(base_dist); +/* First normalized distance for each code (0 = distance of 1) */ + + +var StaticTreeDesc = function (static_tree, extra_bits, extra_base, elems, max_length) { + + this.static_tree = static_tree; /* static tree or NULL */ + this.extra_bits = extra_bits; /* extra bits for each code or NULL */ + this.extra_base = extra_base; /* base index for extra_bits */ + this.elems = elems; /* max number of elements in the tree */ + this.max_length = max_length; /* max bit length for the codes */ + + // show if `static_tree` has data or dummy - needed for monomorphic objects + this.has_stree = static_tree && static_tree.length; +}; + + +var static_l_desc; +var static_d_desc; +var static_bl_desc; + + +var TreeDesc = function(dyn_tree, stat_desc) { + this.dyn_tree = dyn_tree; /* the dynamic tree */ + this.max_code = 0; /* largest code with non zero frequency */ + this.stat_desc = stat_desc; /* the corresponding static tree */ +}; + + + +function d_code(dist) { + return dist < 256 ? _dist_code[dist] : _dist_code[256 + (dist >>> 7)]; +} + + +/* =========================================================================== + * Output a short LSB first on the stream. + * IN assertion: there is enough room in pendingBuf. + */ +function put_short (s, w) { +// put_byte(s, (uch)((w) & 0xff)); +// put_byte(s, (uch)((ush)(w) >> 8)); + s.pending_buf[s.pending++] = (w) & 0xff; + s.pending_buf[s.pending++] = (w >>> 8) & 0xff; +} + + +/* =========================================================================== + * Send a value on a given number of bits. + * IN assertion: length <= 16 and value fits in length bits. + */ +function send_bits(s, value, length) { + if (s.bi_valid > (Buf_size - length)) { + s.bi_buf |= (value << s.bi_valid) & 0xffff; + put_short(s, s.bi_buf); + s.bi_buf = value >> (Buf_size - s.bi_valid); + s.bi_valid += length - Buf_size; + } else { + s.bi_buf |= (value << s.bi_valid) & 0xffff; + s.bi_valid += length; + } +} + + +function send_code(s, c, tree) { + send_bits(s, tree[c*2]/*.Code*/, tree[c*2 + 1]/*.Len*/); +} + + +/* =========================================================================== + * Reverse the first len bits of a code, using straightforward code (a faster + * method would use a table) + * IN assertion: 1 <= len <= 15 + */ +function bi_reverse(code, len) { + var res = 0; + do { + res |= code & 1; + code >>>= 1; + res <<= 1; + } while (--len > 0); + return res >>> 1; +} + + +/* =========================================================================== + * Flush the bit buffer, keeping at most 7 bits in it. + */ +function bi_flush(s) { + if (s.bi_valid === 16) { + put_short(s, s.bi_buf); + s.bi_buf = 0; + s.bi_valid = 0; + + } else if (s.bi_valid >= 8) { + s.pending_buf[s.pending++] = s.bi_buf & 0xff; + s.bi_buf >>= 8; + s.bi_valid -= 8; + } +} + + +/* =========================================================================== + * Compute the optimal bit lengths for a tree and update the total bit length + * for the current block. + * IN assertion: the fields freq and dad are set, heap[heap_max] and + * above are the tree nodes sorted by increasing frequency. + * OUT assertions: the field len is set to the optimal bit length, the + * array bl_count contains the frequencies for each bit length. + * The length opt_len is updated; static_len is also updated if stree is + * not null. + */ +function gen_bitlen(s, desc) +// deflate_state *s; +// tree_desc *desc; /* the tree descriptor */ +{ + var tree = desc.dyn_tree; + var max_code = desc.max_code; + var stree = desc.stat_desc.static_tree; + var has_stree = desc.stat_desc.has_stree; + var extra = desc.stat_desc.extra_bits; + var base = desc.stat_desc.extra_base; + var max_length = desc.stat_desc.max_length; + var h; /* heap index */ + var n, m; /* iterate over the tree elements */ + var bits; /* bit length */ + var xbits; /* extra bits */ + var f; /* frequency */ + var overflow = 0; /* number of elements with bit length too large */ + + for (bits = 0; bits <= MAX_BITS; bits++) { + s.bl_count[bits] = 0; + } + + /* In a first pass, compute the optimal bit lengths (which may + * overflow in the case of the bit length tree). + */ + tree[s.heap[s.heap_max]*2 + 1]/*.Len*/ = 0; /* root of the heap */ + + for (h = s.heap_max+1; h < HEAP_SIZE; h++) { + n = s.heap[h]; + bits = tree[tree[n*2 +1]/*.Dad*/ * 2 + 1]/*.Len*/ + 1; + if (bits > max_length) { + bits = max_length; + overflow++; + } + tree[n*2 + 1]/*.Len*/ = bits; + /* We overwrite tree[n].Dad which is no longer needed */ + + if (n > max_code) { continue; } /* not a leaf node */ + + s.bl_count[bits]++; + xbits = 0; + if (n >= base) { + xbits = extra[n-base]; + } + f = tree[n * 2]/*.Freq*/; + s.opt_len += f * (bits + xbits); + if (has_stree) { + s.static_len += f * (stree[n*2 + 1]/*.Len*/ + xbits); + } + } + if (overflow === 0) { return; } + + // Trace((stderr,"\nbit length overflow\n")); + /* This happens for example on obj2 and pic of the Calgary corpus */ + + /* Find the first bit length which could increase: */ + do { + bits = max_length-1; + while (s.bl_count[bits] === 0) { bits--; } + s.bl_count[bits]--; /* move one leaf down the tree */ + s.bl_count[bits+1] += 2; /* move one overflow item as its brother */ + s.bl_count[max_length]--; + /* The brother of the overflow item also moves one step up, + * but this does not affect bl_count[max_length] + */ + overflow -= 2; + } while (overflow > 0); + + /* Now recompute all bit lengths, scanning in increasing frequency. + * h is still equal to HEAP_SIZE. (It is simpler to reconstruct all + * lengths instead of fixing only the wrong ones. This idea is taken + * from 'ar' written by Haruhiko Okumura.) + */ + for (bits = max_length; bits !== 0; bits--) { + n = s.bl_count[bits]; + while (n !== 0) { + m = s.heap[--h]; + if (m > max_code) { continue; } + if (tree[m*2 + 1]/*.Len*/ !== bits) { + // Trace((stderr,"code %d bits %d->%d\n", m, tree[m].Len, bits)); + s.opt_len += (bits - tree[m*2 + 1]/*.Len*/)*tree[m*2]/*.Freq*/; + tree[m*2 + 1]/*.Len*/ = bits; + } + n--; + } + } +} + + +/* =========================================================================== + * Generate the codes for a given tree and bit counts (which need not be + * optimal). + * IN assertion: the array bl_count contains the bit length statistics for + * the given tree and the field len is set for all tree elements. + * OUT assertion: the field code is set for all tree elements of non + * zero code length. + */ +function gen_codes(tree, max_code, bl_count) +// ct_data *tree; /* the tree to decorate */ +// int max_code; /* largest code with non zero frequency */ +// ushf *bl_count; /* number of codes at each bit length */ +{ + var next_code = new Array(MAX_BITS+1); /* next code value for each bit length */ + var code = 0; /* running code value */ + var bits; /* bit index */ + var n; /* code index */ + + /* The distribution counts are first used to generate the code values + * without bit reversal. + */ + for (bits = 1; bits <= MAX_BITS; bits++) { + next_code[bits] = code = (code + bl_count[bits-1]) << 1; + } + /* Check that the bit counts in bl_count are consistent. The last code + * must be all ones. + */ + //Assert (code + bl_count[MAX_BITS]-1 == (1< length code (0..28) */ + length = 0; + for (code = 0; code < LENGTH_CODES-1; code++) { + base_length[code] = length; + for (n = 0; n < (1< dist code (0..29) */ + dist = 0; + for (code = 0 ; code < 16; code++) { + base_dist[code] = dist; + for (n = 0; n < (1<>= 7; /* from now on, all distances are divided by 128 */ + for ( ; code < D_CODES; code++) { + base_dist[code] = dist << 7; + for (n = 0; n < (1<<(extra_dbits[code]-7)); n++) { + _dist_code[256 + dist++] = code; + } + } + //Assert (dist == 256, "tr_static_init: 256+dist != 512"); + + /* Construct the codes of the static literal tree */ + for (bits = 0; bits <= MAX_BITS; bits++) { + bl_count[bits] = 0; + } + + n = 0; + while (n <= 143) { + static_ltree[n*2 + 1]/*.Len*/ = 8; + n++; + bl_count[8]++; + } + while (n <= 255) { + static_ltree[n*2 + 1]/*.Len*/ = 9; + n++; + bl_count[9]++; + } + while (n <= 279) { + static_ltree[n*2 + 1]/*.Len*/ = 7; + n++; + bl_count[7]++; + } + while (n <= 287) { + static_ltree[n*2 + 1]/*.Len*/ = 8; + n++; + bl_count[8]++; + } + /* Codes 286 and 287 do not exist, but we must include them in the + * tree construction to get a canonical Huffman tree (longest code + * all ones) + */ + gen_codes(static_ltree, L_CODES+1, bl_count); + + /* The static distance tree is trivial: */ + for (n = 0; n < D_CODES; n++) { + static_dtree[n*2 + 1]/*.Len*/ = 5; + static_dtree[n*2]/*.Code*/ = bi_reverse(n, 5); + } + + // Now data ready and we can init static trees + static_l_desc = new StaticTreeDesc(static_ltree, extra_lbits, LITERALS+1, L_CODES, MAX_BITS); + static_d_desc = new StaticTreeDesc(static_dtree, extra_dbits, 0, D_CODES, MAX_BITS); + static_bl_desc =new StaticTreeDesc(new Array(0), extra_blbits, 0, BL_CODES, MAX_BL_BITS); + + //static_init_done = true; +} + + +/* =========================================================================== + * Initialize a new block. + */ +function init_block(s) { + var n; /* iterates over tree elements */ + + /* Initialize the trees. */ + for (n = 0; n < L_CODES; n++) { s.dyn_ltree[n*2]/*.Freq*/ = 0; } + for (n = 0; n < D_CODES; n++) { s.dyn_dtree[n*2]/*.Freq*/ = 0; } + for (n = 0; n < BL_CODES; n++) { s.bl_tree[n*2]/*.Freq*/ = 0; } + + s.dyn_ltree[END_BLOCK*2]/*.Freq*/ = 1; + s.opt_len = s.static_len = 0; + s.last_lit = s.matches = 0; +} + + +/* =========================================================================== + * Flush the bit buffer and align the output on a byte boundary + */ +function bi_windup(s) +{ + if (s.bi_valid > 8) { + put_short(s, s.bi_buf); + } else if (s.bi_valid > 0) { + //put_byte(s, (Byte)s->bi_buf); + s.pending_buf[s.pending++] = s.bi_buf; + } + s.bi_buf = 0; + s.bi_valid = 0; +} + +/* =========================================================================== + * Copy a stored block, storing first the length and its + * one's complement if requested. + */ +function copy_block(s, buf, len, header) +//DeflateState *s; +//charf *buf; /* the input data */ +//unsigned len; /* its length */ +//int header; /* true if block header must be written */ +{ + bi_windup(s); /* align on byte boundary */ + + if (header) { + put_short(s, len); + put_short(s, ~len); + } +// while (len--) { +// put_byte(s, *buf++); +// } + utils.arraySet(s.pending_buf, s.window, buf, len, s.pending); + s.pending += len; +} + +/* =========================================================================== + * Compares to subtrees, using the tree depth as tie breaker when + * the subtrees have equal frequency. This minimizes the worst case length. + */ +function smaller(tree, n, m, depth) { + var _n2 = n*2; + var _m2 = m*2; + return (tree[_n2]/*.Freq*/ < tree[_m2]/*.Freq*/ || + (tree[_n2]/*.Freq*/ === tree[_m2]/*.Freq*/ && depth[n] <= depth[m])); +} + +/* =========================================================================== + * Restore the heap property by moving down the tree starting at node k, + * exchanging a node with the smallest of its two sons if necessary, stopping + * when the heap property is re-established (each father smaller than its + * two sons). + */ +function pqdownheap(s, tree, k) +// deflate_state *s; +// ct_data *tree; /* the tree to restore */ +// int k; /* node to move down */ +{ + var v = s.heap[k]; + var j = k << 1; /* left son of k */ + while (j <= s.heap_len) { + /* Set j to the smallest of the two sons: */ + if (j < s.heap_len && + smaller(tree, s.heap[j+1], s.heap[j], s.depth)) { + j++; + } + /* Exit if v is smaller than both sons */ + if (smaller(tree, v, s.heap[j], s.depth)) { break; } + + /* Exchange v with the smallest son */ + s.heap[k] = s.heap[j]; + k = j; + + /* And continue down the tree, setting j to the left son of k */ + j <<= 1; + } + s.heap[k] = v; +} + + +// inlined manually +// var SMALLEST = 1; + +/* =========================================================================== + * Send the block data compressed using the given Huffman trees + */ +function compress_block(s, ltree, dtree) +// deflate_state *s; +// const ct_data *ltree; /* literal tree */ +// const ct_data *dtree; /* distance tree */ +{ + var dist; /* distance of matched string */ + var lc; /* match length or unmatched char (if dist == 0) */ + var lx = 0; /* running index in l_buf */ + var code; /* the code to send */ + var extra; /* number of extra bits to send */ + + if (s.last_lit !== 0) { + do { + dist = (s.pending_buf[s.d_buf + lx*2] << 8) | (s.pending_buf[s.d_buf + lx*2 + 1]); + lc = s.pending_buf[s.l_buf + lx]; + lx++; + + if (dist === 0) { + send_code(s, lc, ltree); /* send a literal byte */ + //Tracecv(isgraph(lc), (stderr," '%c' ", lc)); + } else { + /* Here, lc is the match length - MIN_MATCH */ + code = _length_code[lc]; + send_code(s, code+LITERALS+1, ltree); /* send the length code */ + extra = extra_lbits[code]; + if (extra !== 0) { + lc -= base_length[code]; + send_bits(s, lc, extra); /* send the extra length bits */ + } + dist--; /* dist is now the match distance - 1 */ + code = d_code(dist); + //Assert (code < D_CODES, "bad d_code"); + + send_code(s, code, dtree); /* send the distance code */ + extra = extra_dbits[code]; + if (extra !== 0) { + dist -= base_dist[code]; + send_bits(s, dist, extra); /* send the extra distance bits */ + } + } /* literal or match pair ? */ + + /* Check that the overlay between pending_buf and d_buf+l_buf is ok: */ + //Assert((uInt)(s->pending) < s->lit_bufsize + 2*lx, + // "pendingBuf overflow"); + + } while (lx < s.last_lit); + } + + send_code(s, END_BLOCK, ltree); +} + + +/* =========================================================================== + * Construct one Huffman tree and assigns the code bit strings and lengths. + * Update the total bit length for the current block. + * IN assertion: the field freq is set for all tree elements. + * OUT assertions: the fields len and code are set to the optimal bit length + * and corresponding code. The length opt_len is updated; static_len is + * also updated if stree is not null. The field max_code is set. + */ +function build_tree(s, desc) +// deflate_state *s; +// tree_desc *desc; /* the tree descriptor */ +{ + var tree = desc.dyn_tree; + var stree = desc.stat_desc.static_tree; + var has_stree = desc.stat_desc.has_stree; + var elems = desc.stat_desc.elems; + var n, m; /* iterate over heap elements */ + var max_code = -1; /* largest code with non zero frequency */ + var node; /* new node being created */ + + /* Construct the initial heap, with least frequent element in + * heap[SMALLEST]. The sons of heap[n] are heap[2*n] and heap[2*n+1]. + * heap[0] is not used. + */ + s.heap_len = 0; + s.heap_max = HEAP_SIZE; + + for (n = 0; n < elems; n++) { + if (tree[n * 2]/*.Freq*/ !== 0) { + s.heap[++s.heap_len] = max_code = n; + s.depth[n] = 0; + + } else { + tree[n*2 + 1]/*.Len*/ = 0; + } + } + + /* The pkzip format requires that at least one distance code exists, + * and that at least one bit should be sent even if there is only one + * possible code. So to avoid special checks later on we force at least + * two codes of non zero frequency. + */ + while (s.heap_len < 2) { + node = s.heap[++s.heap_len] = (max_code < 2 ? ++max_code : 0); + tree[node * 2]/*.Freq*/ = 1; + s.depth[node] = 0; + s.opt_len--; + + if (has_stree) { + s.static_len -= stree[node*2 + 1]/*.Len*/; + } + /* node is 0 or 1 so it does not have extra bits */ + } + desc.max_code = max_code; + + /* The elements heap[heap_len/2+1 .. heap_len] are leaves of the tree, + * establish sub-heaps of increasing lengths: + */ + for (n = (s.heap_len >> 1/*int /2*/); n >= 1; n--) { pqdownheap(s, tree, n); } + + /* Construct the Huffman tree by repeatedly combining the least two + * frequent nodes. + */ + node = elems; /* next internal node of the tree */ + do { + //pqremove(s, tree, n); /* n = node of least frequency */ + /*** pqremove ***/ + n = s.heap[1/*SMALLEST*/]; + s.heap[1/*SMALLEST*/] = s.heap[s.heap_len--]; + pqdownheap(s, tree, 1/*SMALLEST*/); + /***/ + + m = s.heap[1/*SMALLEST*/]; /* m = node of next least frequency */ + + s.heap[--s.heap_max] = n; /* keep the nodes sorted by frequency */ + s.heap[--s.heap_max] = m; + + /* Create a new node father of n and m */ + tree[node * 2]/*.Freq*/ = tree[n * 2]/*.Freq*/ + tree[m * 2]/*.Freq*/; + s.depth[node] = (s.depth[n] >= s.depth[m] ? s.depth[n] : s.depth[m]) + 1; + tree[n*2 + 1]/*.Dad*/ = tree[m*2 + 1]/*.Dad*/ = node; + + /* and insert the new node in the heap */ + s.heap[1/*SMALLEST*/] = node++; + pqdownheap(s, tree, 1/*SMALLEST*/); + + } while (s.heap_len >= 2); + + s.heap[--s.heap_max] = s.heap[1/*SMALLEST*/]; + + /* At this point, the fields freq and dad are set. We can now + * generate the bit lengths. + */ + gen_bitlen(s, desc); + + /* The field len is now set, we can generate the bit codes */ + gen_codes(tree, max_code, s.bl_count); +} + + +/* =========================================================================== + * Scan a literal or distance tree to determine the frequencies of the codes + * in the bit length tree. + */ +function scan_tree(s, tree, max_code) +// deflate_state *s; +// ct_data *tree; /* the tree to be scanned */ +// int max_code; /* and its largest code of non zero frequency */ +{ + var n; /* iterates over all tree elements */ + var prevlen = -1; /* last emitted length */ + var curlen; /* length of current code */ + + var nextlen = tree[0*2 + 1]/*.Len*/; /* length of next code */ + + var count = 0; /* repeat count of the current code */ + var max_count = 7; /* max repeat count */ + var min_count = 4; /* min repeat count */ + + if (nextlen === 0) { + max_count = 138; + min_count = 3; + } + tree[(max_code+1)*2 + 1]/*.Len*/ = 0xffff; /* guard */ + + for (n = 0; n <= max_code; n++) { + curlen = nextlen; + nextlen = tree[(n+1)*2 + 1]/*.Len*/; + + if (++count < max_count && curlen === nextlen) { + continue; + + } else if (count < min_count) { + s.bl_tree[curlen * 2]/*.Freq*/ += count; + + } else if (curlen !== 0) { + + if (curlen !== prevlen) { s.bl_tree[curlen * 2]/*.Freq*/++; } + s.bl_tree[REP_3_6*2]/*.Freq*/++; + + } else if (count <= 10) { + s.bl_tree[REPZ_3_10*2]/*.Freq*/++; + + } else { + s.bl_tree[REPZ_11_138*2]/*.Freq*/++; + } + + count = 0; + prevlen = curlen; + + if (nextlen === 0) { + max_count = 138; + min_count = 3; + + } else if (curlen === nextlen) { + max_count = 6; + min_count = 3; + + } else { + max_count = 7; + min_count = 4; + } + } +} + + +/* =========================================================================== + * Send a literal or distance tree in compressed form, using the codes in + * bl_tree. + */ +function send_tree(s, tree, max_code) +// deflate_state *s; +// ct_data *tree; /* the tree to be scanned */ +// int max_code; /* and its largest code of non zero frequency */ +{ + var n; /* iterates over all tree elements */ + var prevlen = -1; /* last emitted length */ + var curlen; /* length of current code */ + + var nextlen = tree[0*2 + 1]/*.Len*/; /* length of next code */ + + var count = 0; /* repeat count of the current code */ + var max_count = 7; /* max repeat count */ + var min_count = 4; /* min repeat count */ + + /* tree[max_code+1].Len = -1; */ /* guard already set */ + if (nextlen === 0) { + max_count = 138; + min_count = 3; + } + + for (n = 0; n <= max_code; n++) { + curlen = nextlen; + nextlen = tree[(n+1)*2 + 1]/*.Len*/; + + if (++count < max_count && curlen === nextlen) { + continue; + + } else if (count < min_count) { + do { send_code(s, curlen, s.bl_tree); } while (--count !== 0); + + } else if (curlen !== 0) { + if (curlen !== prevlen) { + send_code(s, curlen, s.bl_tree); + count--; + } + //Assert(count >= 3 && count <= 6, " 3_6?"); + send_code(s, REP_3_6, s.bl_tree); + send_bits(s, count-3, 2); + + } else if (count <= 10) { + send_code(s, REPZ_3_10, s.bl_tree); + send_bits(s, count-3, 3); + + } else { + send_code(s, REPZ_11_138, s.bl_tree); + send_bits(s, count-11, 7); + } + + count = 0; + prevlen = curlen; + if (nextlen === 0) { + max_count = 138; + min_count = 3; + + } else if (curlen === nextlen) { + max_count = 6; + min_count = 3; + + } else { + max_count = 7; + min_count = 4; + } + } +} + + +/* =========================================================================== + * Construct the Huffman tree for the bit lengths and return the index in + * bl_order of the last bit length code to send. + */ +function build_bl_tree(s) { + var max_blindex; /* index of last bit length code of non zero freq */ + + /* Determine the bit length frequencies for literal and distance trees */ + scan_tree(s, s.dyn_ltree, s.l_desc.max_code); + scan_tree(s, s.dyn_dtree, s.d_desc.max_code); + + /* Build the bit length tree: */ + build_tree(s, s.bl_desc); + /* opt_len now includes the length of the tree representations, except + * the lengths of the bit lengths codes and the 5+5+4 bits for the counts. + */ + + /* Determine the number of bit length codes to send. The pkzip format + * requires that at least 4 bit length codes be sent. (appnote.txt says + * 3 but the actual value used is 4.) + */ + for (max_blindex = BL_CODES-1; max_blindex >= 3; max_blindex--) { + if (s.bl_tree[bl_order[max_blindex]*2 + 1]/*.Len*/ !== 0) { + break; + } + } + /* Update opt_len to include the bit length tree and counts */ + s.opt_len += 3*(max_blindex+1) + 5+5+4; + //Tracev((stderr, "\ndyn trees: dyn %ld, stat %ld", + // s->opt_len, s->static_len)); + + return max_blindex; +} + + +/* =========================================================================== + * Send the header for a block using dynamic Huffman trees: the counts, the + * lengths of the bit length codes, the literal tree and the distance tree. + * IN assertion: lcodes >= 257, dcodes >= 1, blcodes >= 4. + */ +function send_all_trees(s, lcodes, dcodes, blcodes) +// deflate_state *s; +// int lcodes, dcodes, blcodes; /* number of codes for each tree */ +{ + var rank; /* index in bl_order */ + + //Assert (lcodes >= 257 && dcodes >= 1 && blcodes >= 4, "not enough codes"); + //Assert (lcodes <= L_CODES && dcodes <= D_CODES && blcodes <= BL_CODES, + // "too many codes"); + //Tracev((stderr, "\nbl counts: ")); + send_bits(s, lcodes-257, 5); /* not +255 as stated in appnote.txt */ + send_bits(s, dcodes-1, 5); + send_bits(s, blcodes-4, 4); /* not -3 as stated in appnote.txt */ + for (rank = 0; rank < blcodes; rank++) { + //Tracev((stderr, "\nbl code %2d ", bl_order[rank])); + send_bits(s, s.bl_tree[bl_order[rank]*2 + 1]/*.Len*/, 3); + } + //Tracev((stderr, "\nbl tree: sent %ld", s->bits_sent)); + + send_tree(s, s.dyn_ltree, lcodes-1); /* literal tree */ + //Tracev((stderr, "\nlit tree: sent %ld", s->bits_sent)); + + send_tree(s, s.dyn_dtree, dcodes-1); /* distance tree */ + //Tracev((stderr, "\ndist tree: sent %ld", s->bits_sent)); +} + + +/* =========================================================================== + * Check if the data type is TEXT or BINARY, using the following algorithm: + * - TEXT if the two conditions below are satisfied: + * a) There are no non-portable control characters belonging to the + * "black list" (0..6, 14..25, 28..31). + * b) There is at least one printable character belonging to the + * "white list" (9 {TAB}, 10 {LF}, 13 {CR}, 32..255). + * - BINARY otherwise. + * - The following partially-portable control characters form a + * "gray list" that is ignored in this detection algorithm: + * (7 {BEL}, 8 {BS}, 11 {VT}, 12 {FF}, 26 {SUB}, 27 {ESC}). + * IN assertion: the fields Freq of dyn_ltree are set. + */ +function detect_data_type(s) { + /* black_mask is the bit mask of black-listed bytes + * set bits 0..6, 14..25, and 28..31 + * 0xf3ffc07f = binary 11110011111111111100000001111111 + */ + var black_mask = 0xf3ffc07f; + var n; + + /* Check for non-textual ("black-listed") bytes. */ + for (n = 0; n <= 31; n++, black_mask >>>= 1) { + if ((black_mask & 1) && (s.dyn_ltree[n*2]/*.Freq*/ !== 0)) { + return Z_BINARY; + } + } + + /* Check for textual ("white-listed") bytes. */ + if (s.dyn_ltree[9 * 2]/*.Freq*/ !== 0 || s.dyn_ltree[10 * 2]/*.Freq*/ !== 0 || + s.dyn_ltree[13 * 2]/*.Freq*/ !== 0) { + return Z_TEXT; + } + for (n = 32; n < LITERALS; n++) { + if (s.dyn_ltree[n * 2]/*.Freq*/ !== 0) { + return Z_TEXT; + } + } + + /* There are no "black-listed" or "white-listed" bytes: + * this stream either is empty or has tolerated ("gray-listed") bytes only. + */ + return Z_BINARY; +} + + +var static_init_done = false; + +/* =========================================================================== + * Initialize the tree data structures for a new zlib stream. + */ +function _tr_init(s) +{ + + if (!static_init_done) { + tr_static_init(); + static_init_done = true; + } + + s.l_desc = new TreeDesc(s.dyn_ltree, static_l_desc); + s.d_desc = new TreeDesc(s.dyn_dtree, static_d_desc); + s.bl_desc = new TreeDesc(s.bl_tree, static_bl_desc); + + s.bi_buf = 0; + s.bi_valid = 0; + + /* Initialize the first block of the first file: */ + init_block(s); +} + + +/* =========================================================================== + * Send a stored block + */ +function _tr_stored_block(s, buf, stored_len, last) +//DeflateState *s; +//charf *buf; /* input block */ +//ulg stored_len; /* length of input block */ +//int last; /* one if this is the last block for a file */ +{ + send_bits(s, (STORED_BLOCK<<1)+(last ? 1 : 0), 3); /* send block type */ + copy_block(s, buf, stored_len, true); /* with header */ +} + + +/* =========================================================================== + * Send one empty static block to give enough lookahead for inflate. + * This takes 10 bits, of which 7 may remain in the bit buffer. + */ +function _tr_align(s) { + send_bits(s, STATIC_TREES<<1, 3); + send_code(s, END_BLOCK, static_ltree); + bi_flush(s); +} + + +/* =========================================================================== + * Determine the best encoding for the current block: dynamic trees, static + * trees or store, and output the encoded block to the zip file. + */ +function _tr_flush_block(s, buf, stored_len, last) +//DeflateState *s; +//charf *buf; /* input block, or NULL if too old */ +//ulg stored_len; /* length of input block */ +//int last; /* one if this is the last block for a file */ +{ + var opt_lenb, static_lenb; /* opt_len and static_len in bytes */ + var max_blindex = 0; /* index of last bit length code of non zero freq */ + + /* Build the Huffman trees unless a stored block is forced */ + if (s.level > 0) { + + /* Check if the file is binary or text */ + if (s.strm.data_type === Z_UNKNOWN) { + s.strm.data_type = detect_data_type(s); + } + + /* Construct the literal and distance trees */ + build_tree(s, s.l_desc); + // Tracev((stderr, "\nlit data: dyn %ld, stat %ld", s->opt_len, + // s->static_len)); + + build_tree(s, s.d_desc); + // Tracev((stderr, "\ndist data: dyn %ld, stat %ld", s->opt_len, + // s->static_len)); + /* At this point, opt_len and static_len are the total bit lengths of + * the compressed block data, excluding the tree representations. + */ + + /* Build the bit length tree for the above two trees, and get the index + * in bl_order of the last bit length code to send. + */ + max_blindex = build_bl_tree(s); + + /* Determine the best encoding. Compute the block lengths in bytes. */ + opt_lenb = (s.opt_len+3+7) >>> 3; + static_lenb = (s.static_len+3+7) >>> 3; + + // Tracev((stderr, "\nopt %lu(%lu) stat %lu(%lu) stored %lu lit %u ", + // opt_lenb, s->opt_len, static_lenb, s->static_len, stored_len, + // s->last_lit)); + + if (static_lenb <= opt_lenb) { opt_lenb = static_lenb; } + + } else { + // Assert(buf != (char*)0, "lost buf"); + opt_lenb = static_lenb = stored_len + 5; /* force a stored block */ + } + + if ((stored_len+4 <= opt_lenb) && (buf !== -1)) { + /* 4: two words for the lengths */ + + /* The test buf != NULL is only necessary if LIT_BUFSIZE > WSIZE. + * Otherwise we can't have processed more than WSIZE input bytes since + * the last block flush, because compression would have been + * successful. If LIT_BUFSIZE <= WSIZE, it is never too late to + * transform a block into a stored block. + */ + _tr_stored_block(s, buf, stored_len, last); + + } else if (s.strategy === Z_FIXED || static_lenb === opt_lenb) { + + send_bits(s, (STATIC_TREES<<1) + (last ? 1 : 0), 3); + compress_block(s, static_ltree, static_dtree); + + } else { + send_bits(s, (DYN_TREES<<1) + (last ? 1 : 0), 3); + send_all_trees(s, s.l_desc.max_code+1, s.d_desc.max_code+1, max_blindex+1); + compress_block(s, s.dyn_ltree, s.dyn_dtree); + } + // Assert (s->compressed_len == s->bits_sent, "bad compressed size"); + /* The above check is made mod 2^32, for files larger than 512 MB + * and uLong implemented on 32 bits. + */ + init_block(s); + + if (last) { + bi_windup(s); + } + // Tracev((stderr,"\ncomprlen %lu(%lu) ", s->compressed_len>>3, + // s->compressed_len-7*last)); +} + +/* =========================================================================== + * Save the match info and tally the frequency counts. Return true if + * the current block must be flushed. + */ +function _tr_tally(s, dist, lc) +// deflate_state *s; +// unsigned dist; /* distance of matched string */ +// unsigned lc; /* match length-MIN_MATCH or unmatched char (if dist==0) */ +{ + //var out_length, in_length, dcode; + + s.pending_buf[s.d_buf + s.last_lit * 2] = (dist >>> 8) & 0xff; + s.pending_buf[s.d_buf + s.last_lit * 2 + 1] = dist & 0xff; + + s.pending_buf[s.l_buf + s.last_lit] = lc & 0xff; + s.last_lit++; + + if (dist === 0) { + /* lc is the unmatched char */ + s.dyn_ltree[lc*2]/*.Freq*/++; + } else { + s.matches++; + /* Here, lc is the match length - MIN_MATCH */ + dist--; /* dist = match distance - 1 */ + //Assert((ush)dist < (ush)MAX_DIST(s) && + // (ush)lc <= (ush)(MAX_MATCH-MIN_MATCH) && + // (ush)d_code(dist) < (ush)D_CODES, "_tr_tally: bad match"); + + s.dyn_ltree[(_length_code[lc]+LITERALS+1) * 2]/*.Freq*/++; + s.dyn_dtree[d_code(dist) * 2]/*.Freq*/++; + } + +// (!) This block is disabled in zlib defailts, +// don't enable it for binary compatibility + +//#ifdef TRUNCATE_BLOCK +// /* Try to guess if it is profitable to stop the current block here */ +// if ((s.last_lit & 0x1fff) === 0 && s.level > 2) { +// /* Compute an upper bound for the compressed length */ +// out_length = s.last_lit*8; +// in_length = s.strstart - s.block_start; +// +// for (dcode = 0; dcode < D_CODES; dcode++) { +// out_length += s.dyn_dtree[dcode*2]/*.Freq*/ * (5 + extra_dbits[dcode]); +// } +// out_length >>>= 3; +// //Tracev((stderr,"\nlast_lit %u, in %ld, out ~%ld(%ld%%) ", +// // s->last_lit, in_length, out_length, +// // 100L - out_length*100L/in_length)); +// if (s.matches < (s.last_lit>>1)/*int /2*/ && out_length < (in_length>>1)/*int /2*/) { +// return true; +// } +// } +//#endif + + return (s.last_lit === s.lit_bufsize-1); + /* We avoid equality with lit_bufsize because of wraparound at 64K + * on 16 bit machines and because stored blocks are restricted to + * 64K-1 bytes. + */ +} + +exports._tr_init = _tr_init; +exports._tr_stored_block = _tr_stored_block; +exports._tr_flush_block = _tr_flush_block; +exports._tr_tally = _tr_tally; +exports._tr_align = _tr_align; +},{"../utils/common":3}],15:[function(require,module,exports){ +'use strict'; + + +function ZStream() { + /* next input byte */ + this.input = null; // JS specific, because we have no pointers + this.next_in = 0; + /* number of bytes available at input */ + this.avail_in = 0; + /* total number of input bytes read so far */ + this.total_in = 0; + /* next output byte should be put there */ + this.output = null; // JS specific, because we have no pointers + this.next_out = 0; + /* remaining free space at output */ + this.avail_out = 0; + /* total number of bytes output so far */ + this.total_out = 0; + /* last error message, NULL if no error */ + this.msg = ''/*Z_NULL*/; + /* not visible by applications */ + this.state = null; + /* best guess about the data type: binary or text */ + this.data_type = 2/*Z_UNKNOWN*/; + /* adler32 value of the uncompressed data */ + this.adler = 0; +} + +module.exports = ZStream; +},{}],"/":[function(require,module,exports){ +// Top level file is just a mixin of submodules & constants +'use strict'; + +var assign = require('./lib/utils/common').assign; + +var deflate = require('./lib/deflate'); +var inflate = require('./lib/inflate'); +var constants = require('./lib/zlib/constants'); + +var pako = {}; + +assign(pako, deflate, inflate, constants); + +module.exports = pako; +},{"./lib/deflate":1,"./lib/inflate":2,"./lib/utils/common":3,"./lib/zlib/constants":6}]},{},[])("/") +}); \ No newline at end of file diff --git a/core/third-party/pkijs/AccessDescription.js b/core/third-party/pkijs/AccessDescription.js new file mode 100644 index 0000000..2eb9d53 --- /dev/null +++ b/core/third-party/pkijs/AccessDescription.js @@ -0,0 +1,153 @@ +import * as asn1js from "./asn1.js"; +import { getParametersValue, clearProps } from "./pvutils.js"; +import GeneralName from "./GeneralName.js"; +//************************************************************************************** +/** + * Class from RFC5280 + */ +export default class AccessDescription +{ + //********************************************************************************** + /** + * Constructor for AccessDescription class + * @param {Object} [parameters={}] + * @param {Object} [parameters.schema] asn1js parsed value to initialize the class from + */ + constructor(parameters = {}) + { + //region Internal properties of the object + /** + * @type {string} + * @desc The type and format of the information are specified by the accessMethod field. This profile defines two accessMethod OIDs: id-ad-caIssuers and id-ad-ocsp + */ + this.accessMethod = getParametersValue(parameters, "accessMethod", AccessDescription.defaultValues("accessMethod")); + /** + * @type {GeneralName} + * @desc The accessLocation field specifies the location of the information + */ + this.accessLocation = getParametersValue(parameters, "accessLocation", AccessDescription.defaultValues("accessLocation")); + //endregion + + //region If input argument array contains "schema" for this object + if("schema" in parameters) + this.fromSchema(parameters.schema); + //endregion + } + //********************************************************************************** + /** + * Return default values for all class members + * @param {string} memberName String name for a class member + */ + static defaultValues(memberName) + { + switch(memberName) + { + case "accessMethod": + return ""; + case "accessLocation": + return new GeneralName(); + default: + throw new Error(`Invalid member name for AccessDescription class: ${memberName}`); + } + } + //********************************************************************************** + /** + * Return value of pre-defined ASN.1 schema for current class + * + * ASN.1 schema: + * ```asn1 + * AccessDescription ::= SEQUENCE { + * accessMethod OBJECT IDENTIFIER, + * accessLocation GeneralName } + * ``` + * + * @param {Object} parameters Input parameters for the schema + * @returns {Object} asn1js schema object + */ + static schema(parameters = {}) + { + /** + * @type {Object} + * @property {string} [blockName] + * @property {string} [accessMethod] + * @property {string} [accessLocation] + */ + const names = getParametersValue(parameters, "names", {}); + + return (new asn1js.Sequence({ + name: (names.blockName || ""), + value: [ + new asn1js.ObjectIdentifier({ name: (names.accessMethod || "") }), + GeneralName.schema(names.accessLocation || {}) + ] + })); + } + //********************************************************************************** + /** + * Convert parsed asn1js object into current class + * @param {!Object} schema + */ + fromSchema(schema) + { + //region Clear input data first + clearProps(schema, [ + "accessMethod", + "accessLocation" + ]); + //endregion + + //region Check the schema is valid + const asn1 = asn1js.compareSchema(schema, + schema, + AccessDescription.schema({ + names: { + accessMethod: "accessMethod", + accessLocation: { + names: { + blockName: "accessLocation" + } + } + } + }) + ); + + if(asn1.verified === false) + throw new Error("Object's schema was not verified against input data for AccessDescription"); + //endregion + + //region Get internal properties from parsed schema + this.accessMethod = asn1.result.accessMethod.valueBlock.toString(); + this.accessLocation = new GeneralName({ schema: asn1.result.accessLocation }); + //endregion + } + //********************************************************************************** + /** + * Convert current object to asn1js object and set correct values + * @returns {Object} asn1js object + */ + toSchema() + { + //region Construct and return new ASN.1 schema for this object + return (new asn1js.Sequence({ + value: [ + new asn1js.ObjectIdentifier({ value: this.accessMethod }), + this.accessLocation.toSchema() + ] + })); + //endregion + } + //********************************************************************************** + /** + * Convertion for the class to JSON object + * @returns {Object} + */ + toJSON() + { + return { + accessMethod: this.accessMethod, + accessLocation: this.accessLocation.toJSON() + }; + } + //********************************************************************************** +} +//************************************************************************************** diff --git a/core/third-party/pkijs/Accuracy.js b/core/third-party/pkijs/Accuracy.js new file mode 100644 index 0000000..268dffa --- /dev/null +++ b/core/third-party/pkijs/Accuracy.js @@ -0,0 +1,249 @@ +import * as asn1js from "./asn1.js"; +import { getParametersValue, clearProps } from "./pvutils.js"; +//************************************************************************************** +/** + * Class from RFC3161. Accuracy represents the time deviation around the UTC time contained in GeneralizedTime. + */ +export default class Accuracy +{ + //********************************************************************************** + /** + * Constructor for Accuracy class + * @param {Object} [parameters={}] + * @param {Object} [parameters.schema] asn1js parsed value to initialize the class from + */ + constructor(parameters = {}) + { + //region Internal properties of the object + if("seconds" in parameters) + /** + * @type {number} + * @desc seconds + */ + this.seconds = getParametersValue(parameters, "seconds", Accuracy.defaultValues("seconds")); + + if("millis" in parameters) + /** + * @type {number} + * @desc millis + */ + this.millis = getParametersValue(parameters, "millis", Accuracy.defaultValues("millis")); + + if("micros" in parameters) + /** + * @type {number} + * @desc micros + */ + this.micros = getParametersValue(parameters, "micros", Accuracy.defaultValues("micros")); + //endregion + + //region If input argument array contains "schema" for this object + if("schema" in parameters) + this.fromSchema(parameters.schema); + //endregion + } + //********************************************************************************** + /** + * Return default values for all class members + * @param {string} memberName String name for a class member + */ + static defaultValues(memberName) + { + switch(memberName) + { + case "seconds": + case "millis": + case "micros": + return 0; + default: + throw new Error(`Invalid member name for Accuracy class: ${memberName}`); + } + } + //********************************************************************************** + /** + * Compare values with default values for all class members + * @param {string} memberName String name for a class member + * @param {*} memberValue Value to compare with default value + */ + static compareWithDefault(memberName, memberValue) + { + switch(memberName) + { + case "seconds": + case "millis": + case "micros": + return (memberValue === Accuracy.defaultValues(memberName)); + default: + throw new Error(`Invalid member name for Accuracy class: ${memberName}`); + } + } + //********************************************************************************** + /** + * Return value of pre-defined ASN.1 schema for current class + * + * ASN.1 schema: + * ```asn1 + * Accuracy ::= SEQUENCE { + * seconds INTEGER OPTIONAL, + * millis [0] INTEGER (1..999) OPTIONAL, + * micros [1] INTEGER (1..999) OPTIONAL } + * ``` + * + * @param {Object} parameters Input parameters for the schema + * @returns {Object} asn1js schema object + */ + static schema(parameters = {}) + { + /** + * @type {Object} + * @property {string} [blockName] + * @property {string} [seconds] + * @property {string} [millis] + * @property {string} [micros] + */ + const names = getParametersValue(parameters, "names", {}); + + return (new asn1js.Sequence({ + name: (names.blockName || ""), + optional: true, + value: [ + new asn1js.Integer({ + optional: true, + name: (names.seconds || "") + }), + new asn1js.Primitive({ + name: (names.millis || ""), + optional: true, + idBlock: { + tagClass: 3, // CONTEXT-SPECIFIC + tagNumber: 0 // [0] + } + }), + new asn1js.Primitive({ + name: (names.micros || ""), + optional: true, + idBlock: { + tagClass: 3, // CONTEXT-SPECIFIC + tagNumber: 1 // [1] + } + }) + ] + })); + } + //********************************************************************************** + /** + * Convert parsed asn1js object into current class + * @param {!Object} schema + */ + fromSchema(schema) + { + //region Clear input data first + clearProps(schema, [ + "seconds", + "millis", + "micros" + ]); + //endregion + + //region Check the schema is valid + const asn1 = asn1js.compareSchema(schema, + schema, + Accuracy.schema({ + names: { + seconds: "seconds", + millis: "millis", + micros: "micros" + } + }) + ); + + if(asn1.verified === false) + throw new Error("Object's schema was not verified against input data for Accuracy"); + //endregion + + //region Get internal properties from parsed schema + if("seconds" in asn1.result) + this.seconds = asn1.result.seconds.valueBlock.valueDec; + + if("millis" in asn1.result) + { + const intMillis = new asn1js.Integer({ valueHex: asn1.result.millis.valueBlock.valueHex }); + this.millis = intMillis.valueBlock.valueDec; + } + + if("micros" in asn1.result) + { + const intMicros = new asn1js.Integer({ valueHex: asn1.result.micros.valueBlock.valueHex }); + this.micros = intMicros.valueBlock.valueDec; + } + //endregion + } + //********************************************************************************** + /** + * Convert current object to asn1js object and set correct values + * @returns {Object} asn1js object + */ + toSchema() + { + //region Create array of output sequence + const outputArray = []; + + if("seconds" in this) + outputArray.push(new asn1js.Integer({ value: this.seconds })); + + if("millis" in this) + { + const intMillis = new asn1js.Integer({ value: this.millis }); + + outputArray.push(new asn1js.Primitive({ + idBlock: { + tagClass: 3, // CONTEXT-SPECIFIC + tagNumber: 0 // [0] + }, + valueHex: intMillis.valueBlock.valueHex + })); + } + + if("micros" in this) + { + const intMicros = new asn1js.Integer({ value: this.micros }); + + outputArray.push(new asn1js.Primitive({ + idBlock: { + tagClass: 3, // CONTEXT-SPECIFIC + tagNumber: 1 // [1] + }, + valueHex: intMicros.valueBlock.valueHex + })); + } + //endregion + + //region Construct and return new ASN.1 schema for this object + return (new asn1js.Sequence({ + value: outputArray + })); + //endregion + } + //********************************************************************************** + /** + * Convertion for the class to JSON object + * @returns {Object} + */ + toJSON() + { + const _object = {}; + + if("seconds" in this) + _object.seconds = this.seconds; + + if("millis" in this) + _object.millis = this.millis; + + if("micros" in this) + _object.micros = this.micros; + + return _object; + } + //********************************************************************************** +} +//************************************************************************************** diff --git a/core/third-party/pkijs/AlgorithmIdentifier.js b/core/third-party/pkijs/AlgorithmIdentifier.js new file mode 100644 index 0000000..99045c7 --- /dev/null +++ b/core/third-party/pkijs/AlgorithmIdentifier.js @@ -0,0 +1,212 @@ +import * as asn1js from "./asn1.js"; +import { getParametersValue, clearProps } from "./pvutils.js"; +//************************************************************************************** +/** + * Class from RFC5280 + */ +export default class AlgorithmIdentifier +{ + //********************************************************************************** + /** + * Constructor for AlgorithmIdentifier class + * @param {Object} [parameters={}] + * @param {Object} [parameters.schema] asn1js parsed value to initialize the class from + * @property {string} [algorithmId] ObjectIdentifier for algorithm (string representation) + */ + constructor(parameters = {}) + { + //region Internal properties of the object + /** + * @type {string} + * @desc ObjectIdentifier for algorithm (string representation) + */ + this.algorithmId = getParametersValue(parameters, "algorithmId", AlgorithmIdentifier.defaultValues("algorithmId")); + + if("algorithmParams" in parameters) + /** + * @type {Object} + * @desc Any algorithm parameters + */ + this.algorithmParams = getParametersValue(parameters, "algorithmParams", AlgorithmIdentifier.defaultValues("algorithmParams")); + //endregion + + //region If input argument array contains "schema" for this object + if("schema" in parameters) + this.fromSchema(parameters.schema); + //endregion + } + //********************************************************************************** + /** + * Return default values for all class members + * @param {string} memberName String name for a class member + */ + static defaultValues(memberName) + { + switch(memberName) + { + case "algorithmId": + return ""; + case "algorithmParams": + return new asn1js.Any(); + default: + throw new Error(`Invalid member name for AlgorithmIdentifier class: ${memberName}`); + } + } + //********************************************************************************** + /** + * Compare values with default values for all class members + * @param {string} memberName String name for a class member + * @param {*} memberValue Value to compare with default value + */ + static compareWithDefault(memberName, memberValue) + { + switch(memberName) + { + case "algorithmId": + return (memberValue === ""); + case "algorithmParams": + return (memberValue instanceof asn1js.Any); + default: + throw new Error(`Invalid member name for AlgorithmIdentifier class: ${memberName}`); + } + } + //********************************************************************************** + /** + * Return value of pre-defined ASN.1 schema for current class + * + * ASN.1 schema: + * ```asn1 + * AlgorithmIdentifier ::= Sequence { + * algorithm OBJECT IDENTIFIER, + * parameters ANY DEFINED BY algorithm OPTIONAL } + * ``` + * + * @param {Object} parameters Input parameters for the schema + * @returns {Object} asn1js schema object + */ + static schema(parameters = {}) + { + /** + * @type {Object} + * @property {string} algorithmIdentifier ObjectIdentifier for the algorithm + * @property {string} algorithmParams Any algorithm parameters + */ + const names = getParametersValue(parameters, "names", {}); + + return (new asn1js.Sequence({ + name: (names.blockName || ""), + optional: (names.optional || false), + value: [ + new asn1js.ObjectIdentifier({ name: (names.algorithmIdentifier || "") }), + new asn1js.Any({ name: (names.algorithmParams || ""), optional: true }) + ] + })); + } + //********************************************************************************** + /** + * Convert parsed asn1js object into current class + * @param {!Object} schema + */ + fromSchema(schema) + { + //region Clear input data first + clearProps(schema, [ + "algorithm", + "params" + ]); + //endregion + + //region Check the schema is valid + const asn1 = asn1js.compareSchema(schema, + schema, + AlgorithmIdentifier.schema({ + names: { + algorithmIdentifier: "algorithm", + algorithmParams: "params" + } + }) + ); + + if(asn1.verified === false) + throw new Error("Object's schema was not verified against input data for AlgorithmIdentifier"); + //endregion + + //region Get internal properties from parsed schema + this.algorithmId = asn1.result.algorithm.valueBlock.toString(); + if("params" in asn1.result) + this.algorithmParams = asn1.result.params; + //endregion + } + //********************************************************************************** + /** + * Convert current object to asn1js object and set correct values + * @returns {Object} asn1js object + */ + toSchema() + { + //region Create array for output sequence + const outputArray = []; + + outputArray.push(new asn1js.ObjectIdentifier({ value: this.algorithmId })); + if(("algorithmParams" in this) && ((this.algorithmParams instanceof asn1js.Any) === false)) + outputArray.push(this.algorithmParams); + //endregion + + //region Construct and return new ASN.1 schema for this object + return (new asn1js.Sequence({ + value: outputArray + })); + //endregion + } + //********************************************************************************** + /** + * Convertion for the class to JSON object + * @returns {Object} + */ + toJSON() + { + const object = { + algorithmId: this.algorithmId + }; + + if(("algorithmParams" in this) && ((this.algorithmParams instanceof asn1js.Any) === false)) + object.algorithmParams = this.algorithmParams.toJSON(); + + return object; + } + //********************************************************************************** + /** + * Check that two "AlgorithmIdentifiers" are equal + * @param {AlgorithmIdentifier} algorithmIdentifier + * @returns {boolean} + */ + isEqual(algorithmIdentifier) + { + //region Check input type + if((algorithmIdentifier instanceof AlgorithmIdentifier) === false) + return false; + //endregion + + //region Check "algorithm_id" + if(this.algorithmId !== algorithmIdentifier.algorithmId) + return false; + //endregion + + //region Check "algorithm_params" + if("algorithmParams" in this) + { + if("algorithmParams" in algorithmIdentifier) + return JSON.stringify(this.algorithmParams) === JSON.stringify(algorithmIdentifier.algorithmParams); + + return false; + } + + if("algorithmParams" in algorithmIdentifier) + return false; + //endregion + + return true; + } + //********************************************************************************** +} +//************************************************************************************** diff --git a/core/third-party/pkijs/AltName.js b/core/third-party/pkijs/AltName.js new file mode 100644 index 0000000..09e73b1 --- /dev/null +++ b/core/third-party/pkijs/AltName.js @@ -0,0 +1,135 @@ +import * as asn1js from "./asn1.js"; +import { getParametersValue, clearProps } from "./pvutils.js"; +import GeneralName from "./GeneralName.js"; +//************************************************************************************** +/** + * Class from RFC5280 + */ +export default class AltName +{ + //********************************************************************************** + /** + * Constructor for AltName class + * @param {Object} [parameters={}] + * @param {Object} [parameters.schema] asn1js parsed value to initialize the class from + */ + constructor(parameters = {}) + { + //region Internal properties of the object + /** + * @type {Array.} + * @desc Array of alternative names in GeneralName type + */ + this.altNames = getParametersValue(parameters, "altNames", AltName.defaultValues("altNames")); + //endregion + + //region If input argument array contains "schema" for this object + if("schema" in parameters) + this.fromSchema(parameters.schema); + //endregion + } + //********************************************************************************** + /** + * Return default values for all class members + * @param {string} memberName String name for a class member + */ + static defaultValues(memberName) + { + switch(memberName) + { + case "altNames": + return []; + default: + throw new Error(`Invalid member name for AltName class: ${memberName}`); + } + } + //********************************************************************************** + /** + * Return value of pre-defined ASN.1 schema for current class + * + * ASN.1 schema: + * ```asn1 + * AltName ::= GeneralNames + * ``` + * + * @param {Object} parameters Input parameters for the schema + * @returns {Object} asn1js schema object + */ + static schema(parameters = {}) + { + /** + * @type {Object} + * @property {string} [blockName] + * @property {string} [altNames] + */ + const names = getParametersValue(parameters, "names", {}); + + return (new asn1js.Sequence({ + name: (names.blockName || ""), + value: [ + new asn1js.Repeated({ + name: (names.altNames || ""), + value: GeneralName.schema() + }) + ] + })); + } + //********************************************************************************** + /** + * Convert parsed asn1js object into current class + * @param {!Object} schema + */ + fromSchema(schema) + { + //region Clear input data first + clearProps(schema, [ + "altNames" + ]); + //endregion + + //region Check the schema is valid + const asn1 = asn1js.compareSchema(schema, + schema, + AltName.schema({ + names: { + altNames: "altNames" + } + }) + ); + + if(asn1.verified === false) + throw new Error("Object's schema was not verified against input data for AltName"); + //endregion + + //region Get internal properties from parsed schema + if("altNames" in asn1.result) + this.altNames = Array.from(asn1.result.altNames, element => new GeneralName({ schema: element })); + //endregion + } + //********************************************************************************** + /** + * Convert current object to asn1js object and set correct values + * @returns {Object} asn1js object + */ + toSchema() + { + //region Construct and return new ASN.1 schema for this object + return (new asn1js.Sequence({ + value: Array.from(this.altNames, element => element.toSchema()) + })); + //endregion + } + //********************************************************************************** + /** + * Convertion for the class to JSON object + * @returns {Object} + */ + toJSON() + { + return { + altNames: Array.from(this.altNames, element => element.toJSON()) + }; + } + //********************************************************************************** +} +//************************************************************************************** diff --git a/core/third-party/pkijs/Attribute.js b/core/third-party/pkijs/Attribute.js new file mode 100644 index 0000000..4499288 --- /dev/null +++ b/core/third-party/pkijs/Attribute.js @@ -0,0 +1,177 @@ +import * as asn1js from "./asn1.js"; +import { getParametersValue, clearProps } from "./pvutils.js"; +//************************************************************************************** +/** + * Class from RFC2986 + */ +export default class Attribute { + //********************************************************************************** + /** + * Constructor for Attribute class + * @param {Object} [parameters={}] + * @param {Object} [parameters.schema] asn1js parsed value to initialize the class from + */ + constructor(parameters = {}) + { + //region Internal properties of the object + /** + * @type {string} + * @desc ObjectIdentifier for attribute (string representation) + */ + this.type = getParametersValue(parameters, "type", Attribute.defaultValues("type")); + /** + * @type {Array} + * @desc Any attribute values + */ + this.values = getParametersValue(parameters, "values", Attribute.defaultValues("values")); + //endregion + + //region If input argument array contains "schema" for this object + if("schema" in parameters) + this.fromSchema(parameters.schema); + //endregion + } + //********************************************************************************** + /** + * Return default values for all class members + * @param {string} memberName String name for a class member + */ + static defaultValues(memberName) + { + switch(memberName) + { + case "type": + return ""; + case "values": + return []; + default: + throw new Error(`Invalid member name for Attribute class: ${memberName}`); + } + } + //********************************************************************************** + /** + * Compare values with default values for all class members + * @param {string} memberName String name for a class member + * @param {*} memberValue Value to compare with default value + */ + static compareWithDefault(memberName, memberValue) + { + switch(memberName) + { + case "type": + return (memberValue === ""); + case "values": + return (memberValue.length === 0); + default: + throw new Error(`Invalid member name for Attribute class: ${memberName}`); + } + } + //********************************************************************************** + /** + * Return value of pre-defined ASN.1 schema for current class + * + * ASN.1 schema: + * ```asn1 + * Attribute { ATTRIBUTE:IOSet } ::= SEQUENCE { + * type ATTRIBUTE.&id({IOSet}), + * values SET SIZE(1..MAX) OF ATTRIBUTE.&Type({IOSet}{@type}) + * } + * ``` + * + * @param {Object} parameters Input parameters for the schema + * @returns {Object} asn1js schema object + */ + static schema(parameters = {}) + { + /** + * @type {Object} + * @property {string} [blockName] + * @property {string} [type] + * @property {string} [setName] + * @property {string} [values] + */ + const names = getParametersValue(parameters, "names", {}); + + return (new asn1js.Sequence({ + name: (names.blockName || ""), + value: [ + new asn1js.ObjectIdentifier({ name: (names.type || "") }), + new asn1js.Set({ + name: (names.setName || ""), + value: [ + new asn1js.Repeated({ + name: (names.values || ""), + value: new asn1js.Any() + }) + ] + }) + ] + })); + } + //********************************************************************************** + /** + * Convert parsed asn1js object into current class + * @param {!Object} schema + */ + fromSchema(schema) + { + //region Clear input data first + clearProps(schema, [ + "type", + "values" + ]); + //endregion + + //region Check the schema is valid + const asn1 = asn1js.compareSchema(schema, + schema, + Attribute.schema({ + names: { + type: "type", + values: "values" + } + }) + ); + + if(asn1.verified === false) + throw new Error("Object's schema was not verified against input data for Attribute"); + //endregion + + //region Get internal properties from parsed schema + this.type = asn1.result.type.valueBlock.toString(); + this.values = asn1.result.values; + //endregion + } + //********************************************************************************** + /** + * Convert current object to asn1js object and set correct values + * @returns {Object} asn1js object + */ + toSchema() + { + //region Construct and return new ASN.1 schema for this object + return (new asn1js.Sequence({ + value: [ + new asn1js.ObjectIdentifier({ value: this.type }), + new asn1js.Set({ + value: this.values + }) + ] + })); + //endregion + } + //********************************************************************************** + /** + * Convertion for the class to JSON object + * @returns {Object} + */ + toJSON() + { + return { + type: this.type, + values: Array.from(this.values, element => element.toJSON()) + }; + } + //********************************************************************************** +} +//************************************************************************************** diff --git a/core/third-party/pkijs/AttributeCertificateV1.js b/core/third-party/pkijs/AttributeCertificateV1.js new file mode 100644 index 0000000..13a5227 --- /dev/null +++ b/core/third-party/pkijs/AttributeCertificateV1.js @@ -0,0 +1,871 @@ +import * as asn1js from "./asn1.js"; +import { getParametersValue, clearProps } from "./pvutils.js"; +import GeneralNames from "./GeneralNames.js"; +import AlgorithmIdentifier from "./AlgorithmIdentifier.js"; +import Attribute from "./Attribute.js"; +import Extensions from "./Extensions.js"; +//************************************************************************************** +/** + * Class from RFC5755 + */ +export class AttCertValidityPeriod +{ + //********************************************************************************** + /** + * Constructor for AttCertValidityPeriod class + * @param {Object} [parameters={}] + * @param {Object} [parameters.schema] asn1js parsed value to initialize the class from + */ + constructor(parameters = {}) + { + //region Internal properties of the object + /** + * @type {GeneralizedTime} + * @desc notBeforeTime + */ + this.notBeforeTime = getParametersValue(parameters, "notBeforeTime", AttCertValidityPeriod.defaultValues("notBeforeTime")); + /** + * @type {GeneralizedTime} + * @desc notAfterTime + */ + this.notAfterTime = getParametersValue(parameters, "notAfterTime", AttCertValidityPeriod.defaultValues("notAfterTime")); + //endregion + + //region If input argument array contains "schema" for this object + if("schema" in parameters) + this.fromSchema(parameters.schema); + //endregion + } + //********************************************************************************** + /** + * Return default values for all class members + * @param {string} memberName String name for a class member + */ + static defaultValues(memberName) + { + switch(memberName) + { + case "notBeforeTime": + case "notAfterTime": + return new Date(0, 0, 0); + default: + throw new Error(`Invalid member name for AttCertValidityPeriod class: ${memberName}`); + } + } + //********************************************************************************** + /** + * Return value of pre-defined ASN.1 schema for current class + * + * ASN.1 schema: + * ```asn1 + * AttCertValidityPeriod ::= SEQUENCE { + * notBeforeTime GeneralizedTime, + * notAfterTime GeneralizedTime + * } + * ``` + * + * @param {Object} parameters Input parameters for the schema + * @returns {Object} asn1js schema object + */ + static schema(parameters = {}) + { + /** + * @type {Object} + * @property {string} [blockName] + * @property {string} [notBeforeTime] + * @property {string} [notAfterTime] + */ + const names = getParametersValue(parameters, "names", {}); + + return (new asn1js.Sequence({ + name: (names.blockName || ""), + value: [ + new asn1js.GeneralizedTime({ name: (names.notBeforeTime || "") }), + new asn1js.GeneralizedTime({ name: (names.notAfterTime || "") }) + ] + })); + } + //********************************************************************************** + /** + * Convert parsed asn1js object into current class + * @param {!Object} schema + */ + fromSchema(schema) + { + //region Clear input data first + clearProps(schema, [ + "notBeforeTime", + "notAfterTime" + ]); + //endregion + + //region Check the schema is valid + const asn1 = asn1js.compareSchema(schema, + schema, + AttCertValidityPeriod.schema({ + names: { + notBeforeTime: "notBeforeTime", + notAfterTime: "notAfterTime" + } + }) + ); + + if(asn1.verified === false) + throw new Error("Object's schema was not verified against input data for AttCertValidityPeriod"); + //endregion + + //region Get internal properties from parsed schema + this.notBeforeTime = asn1.result.notBeforeTime.toDate(); + this.notAfterTime = asn1.result.notAfterTime.toDate(); + //endregion + } + //********************************************************************************** + /** + * Convert current object to asn1js object and set correct values + * @returns {Object} asn1js object + */ + toSchema() + { + //region Construct and return new ASN.1 schema for this object + return (new asn1js.Sequence({ + value: [ + new asn1js.GeneralizedTime({ valueDate: this.notBeforeTime }), + new asn1js.GeneralizedTime({ valueDate: this.notAfterTime }), + ] + })); + //endregion + } + //********************************************************************************** + /** + * Convertion for the class to JSON object + * @returns {Object} + */ + toJSON() + { + return { + notBeforeTime: this.notBeforeTime, + notAfterTime: this.notAfterTime + }; + } + //********************************************************************************** +} +//************************************************************************************** +/** + * Class from RFC5755 + */ +export class IssuerSerial +{ + //********************************************************************************** + /** + * Constructor for IssuerSerial class + * @param {Object} [parameters={}] + * @param {Object} [parameters.schema] asn1js parsed value to initialize the class from + */ + constructor(parameters = {}) + { + //region Internal properties of the object + /** + * @type {RelativeDistinguishedNames} + * @desc issuer + */ + this.issuer = getParametersValue(parameters, "issuer", IssuerSerial.defaultValues("issuer")); + /** + * @type {Integer} + * @desc serialNumber + */ + this.serialNumber = getParametersValue(parameters, "serialNumber", IssuerSerial.defaultValues("serialNumber")); + + if("issuerUID" in parameters) + /** + * @type {BitString} + * @desc issuerUID + */ + this.issuerUID = getParametersValue(parameters, "issuerUID", IssuerSerial.defaultValues("issuerUID")); + //endregion + + //region If input argument array contains "schema" for this object + if("schema" in parameters) + this.fromSchema(parameters.schema); + //endregion + } + //********************************************************************************** + /** + * Return default values for all class members + * @param {string} memberName String name for a class member + */ + static defaultValues(memberName) + { + switch(memberName) + { + case "issuer": + return new GeneralNames(); + case "serialNumber": + return new asn1js.Integer(); + case "issuerUID": + return new asn1js.BitString(); + default: + throw new Error(`Invalid member name for IssuerSerial class: ${memberName}`); + } + } + //********************************************************************************** + /** + * Return value of pre-defined ASN.1 schema for current class + * + * ASN.1 schema: + * ```asn1 + * IssuerSerial ::= SEQUENCE { + * issuer GeneralNames, + * serial CertificateSerialNumber, + * issuerUID UniqueIdentifier OPTIONAL + * } + * + * CertificateSerialNumber ::= INTEGER + * UniqueIdentifier ::= BIT STRING + * ``` + * + * @param {Object} parameters Input parameters for the schema + * @returns {Object} asn1js schema object + */ + static schema(parameters = {}) + { + /** + * @type {Object} + * @property {string} [blockName] + * @property {string} [issuer] + * @property {string} [serialNumber] + * @property {string} [issuerUID] + */ + const names = getParametersValue(parameters, "names", {}); + + return (new asn1js.Sequence({ + name: (names.blockName || ""), + value: [ + GeneralNames.schema(names.issuer || {}), + new asn1js.Integer({ name: (names.serialNumber || "") }), + new asn1js.BitString({ + optional: true, + name: (names.issuerUID || "") + }) + ] + })); + } + //********************************************************************************** + /** + * Convert parsed asn1js object into current class + * @param {!Object} schema + */ + fromSchema(schema) + { + //region Clear input data first + clearProps(schema, [ + "issuer", + "serialNumber", + "issuerUID" + ]); + //endregion + + //region Check the schema is valid + const asn1 = asn1js.compareSchema(schema, + schema, + IssuerSerial.schema({ + names: { + issuer: { + names: { + blockName: "issuer" + } + }, + serialNumber: "serialNumber", + issuerUID: "issuerUID" + } + }) + ); + + if(asn1.verified === false) + throw new Error("Object's schema was not verified against input data for IssuerSerial"); + //endregion + + //region Get internal properties from parsed schema + this.issuer = new GeneralNames({ schema: asn1.result.issuer }); + this.serialNumber = asn1.result.serialNumber; + + if("issuerUID" in asn1.result) + this.issuerUID = asn1.result.issuerUID; + //endregion + } + //********************************************************************************** + /** + * Convert current object to asn1js object and set correct values + * @returns {Object} asn1js object + */ + toSchema() + { + const result = new asn1js.Sequence({ + value: [ + this.issuer.toSchema(), + this.serialNumber + ] + }); + + if("issuerUID" in this) + result.valueBlock.value.push(this.issuerUID); + + //region Construct and return new ASN.1 schema for this object + return result; + //endregion + } + //********************************************************************************** + /** + * Convertion for the class to JSON object + * @returns {Object} + */ + toJSON() + { + const result = { + issuer: this.issuer.toJSON(), + serialNumber: this.serialNumber.toJSON() + }; + + if("issuerUID" in this) + result.issuerUID = this.issuerUID.toJSON(); + + return result; + } + //********************************************************************************** +} +//************************************************************************************** +/** + * Class from RFC5755 + */ +export class AttributeCertificateInfoV1 +{ + //********************************************************************************** + /** + * Constructor for AttributeCertificateInfoV1 class + * @param {Object} [parameters={}] + * @param {Object} [parameters.schema] asn1js parsed value to initialize the class from + */ + constructor(parameters = {}) + { + //region Internal properties of the object + /** + * @type {Number} + * @desc version + */ + this.version = getParametersValue(parameters, "version", AttributeCertificateInfoV1.defaultValues("version")); + + if("baseCertificateID" in parameters) + /** + * @type {IssuerSerial} + * @desc baseCertificateID + */ + this.baseCertificateID = getParametersValue(parameters, "baseCertificateID", AttributeCertificateInfoV1.defaultValues("baseCertificateID")); + + if("subjectName" in parameters) + /** + * @type {GeneralNames} + * @desc subjectName + */ + this.subjectName = getParametersValue(parameters, "subjectName", AttributeCertificateInfoV1.defaultValues("subjectName")); + + /** + * @type {GeneralNames} + * @desc issuer + */ + this.issuer = getParametersValue(parameters, "issuer", AttributeCertificateInfoV1.defaultValues("issuer")); + /** + * @type {AlgorithmIdentifier} + * @desc signature + */ + this.signature = getParametersValue(parameters, "signature", AttributeCertificateInfoV1.defaultValues("signature")); + /** + * @type {Integer} + * @desc serialNumber + */ + this.serialNumber = getParametersValue(parameters, "serialNumber", AttributeCertificateInfoV1.defaultValues("serialNumber")); + /** + * @type {AttCertValidityPeriod} + * @desc attrCertValidityPeriod + */ + this.attrCertValidityPeriod = getParametersValue(parameters, "attrCertValidityPeriod", AttributeCertificateInfoV1.defaultValues("attrCertValidityPeriod")); + /** + * @type {Array.} + * @desc attributes + */ + this.attributes = getParametersValue(parameters, "attributes", AttributeCertificateInfoV1.defaultValues("attributes")); + + if("issuerUniqueID" in parameters) + /** + * @type {BitString} + * @desc issuerUniqueID + */ + this.issuerUniqueID = getParametersValue(parameters, "issuerUniqueID", AttributeCertificateInfoV1.defaultValues("issuerUniqueID")); + + if("extensions" in parameters) + /** + * @type {Extensions} + * @desc extensions + */ + this.extensions = getParametersValue(parameters, "extensions", AttributeCertificateInfoV1.defaultValues("extensions")); + //endregion + + //region If input argument array contains "schema" for this object + if("schema" in parameters) + this.fromSchema(parameters.schema); + //endregion + } + //********************************************************************************** + /** + * Return default values for all class members + * @param {string} memberName String name for a class member + */ + static defaultValues(memberName) + { + switch(memberName) + { + case "version": + return 0; + case "baseCertificateID": + return new IssuerSerial(); + case "subjectName": + return new GeneralNames(); + case "issuer": + return {}; + case "signature": + return new AlgorithmIdentifier(); + case "serialNumber": + return new asn1js.Integer(); + case "attrCertValidityPeriod": + return new AttCertValidityPeriod(); + case "attributes": + return []; + case "issuerUniqueID": + return new asn1js.BitString(); + case "extensions": + return new Extensions(); + default: + throw new Error(`Invalid member name for AttributeCertificateInfoV1 class: ${memberName}`); + } + } + //********************************************************************************** + /** + * Return value of pre-defined ASN.1 schema for current class + * + * ASN.1 schema: + * ```asn1 + * AttributeCertificateInfo ::= SEQUENCE { + * version Version DEFAULT v1, + * subject CHOICE { + * baseCertificateID [0] IssuerSerial, -- associated with a Public Key Certificate + * subjectName [1] GeneralNames }, -- associated with a name + * issuer GeneralNames, -- CA issuing the attribute certificate + * signature AlgorithmIdentifier, + * serialNumber CertificateSerialNumber, + * attrCertValidityPeriod AttCertValidityPeriod, + * attributes SEQUENCE OF Attribute, + * issuerUniqueID UniqueIdentifier OPTIONAL, + * extensions Extensions OPTIONAL + * } + * ``` + * + * @param {Object} parameters Input parameters for the schema + * @returns {Object} asn1js schema object + */ + static schema(parameters = {}) + { + /** + * @type {Object} + * @property {string} [blockName] + * @property {string} [issuer] + * @property {string} [serialNumber] + */ + const names = getParametersValue(parameters, "names", {}); + + return (new asn1js.Sequence({ + name: (names.blockName || ""), + value: [ + new asn1js.Integer({ name: (names.version || "") }), + new asn1js.Choice({ + value: [ + new asn1js.Constructed({ + name: (names.baseCertificateID || ""), + idBlock: { + tagClass: 3, + tagNumber: 0 // [0] + }, + value: IssuerSerial.schema().valueBlock.value + }), + new asn1js.Constructed({ + name: (names.subjectName || ""), + idBlock: { + tagClass: 3, + tagNumber: 1 // [2] + }, + value: GeneralNames.schema().valueBlock.value + }), + ] + }), + GeneralNames.schema({ + names: { + blockName: (names.issuer || "") + } + }), + AlgorithmIdentifier.schema(names.signature || {}), + new asn1js.Integer({ name: (names.serialNumber || "") }), + AttCertValidityPeriod.schema(names.attrCertValidityPeriod || {}), + new asn1js.Sequence({ + name: (names.attributes || ""), + value: [ + new asn1js.Repeated({ + value: Attribute.schema() + }) + ] + }), + new asn1js.BitString({ + optional: true, + name: (names.issuerUniqueID || "") + }), + Extensions.schema(names.extensions || {}, true) + ] + })); + } + //********************************************************************************** + /** + * Convert parsed asn1js object into current class + * @param {!Object} schema + */ + fromSchema(schema) + { + //region Clear input data first + clearProps(schema, [ + "version", + "baseCertificateID", + "subjectName", + "issuer", + "signature", + "serialNumber", + "attrCertValidityPeriod", + "attributes", + "issuerUniqueID", + "extensions" + ]); + //endregion + + //region Check the schema is valid + const asn1 = asn1js.compareSchema(schema, + schema, + AttributeCertificateInfoV1.schema({ + names: { + version: "version", + baseCertificateID: "baseCertificateID", + subjectName: "subjectName", + issuer: "issuer", + signature: { + names: { + blockName: "signature" + } + }, + serialNumber: "serialNumber", + attrCertValidityPeriod: { + names: { + blockName: "attrCertValidityPeriod" + } + }, + attributes: "attributes", + issuerUniqueID: "issuerUniqueID", + extensions: { + names: { + blockName: "extensions" + } + } + } + }) + ); + + if(asn1.verified === false) + throw new Error("Object's schema was not verified against input data for AttributeCertificateInfoV1"); + //endregion + + //region Get internal properties from parsed schema + this.version = asn1.result.version.valueBlock.valueDec; + + if("baseCertificateID" in asn1.result) + { + this.baseCertificateID = new IssuerSerial({ + schema: new asn1js.Sequence({ + value: asn1.result.baseCertificateID.valueBlock.value + }) + }); + } + + if("subjectName" in asn1.result) + { + this.subjectName = new GeneralNames({ + schema: new asn1js.Sequence({ + value: asn1.result.subjectName.valueBlock.value + }) + }); + } + + this.issuer = asn1.result.issuer; + this.signature = new AlgorithmIdentifier({ schema: asn1.result.signature }); + this.serialNumber = asn1.result.serialNumber; + this.attrCertValidityPeriod = new AttCertValidityPeriod({ schema: asn1.result.attrCertValidityPeriod }); + this.attributes = Array.from(asn1.result.attributes.valueBlock.value, element => new Attribute({ schema: element })); + + if("issuerUniqueID" in asn1.result) + this.issuerUniqueID = asn1.result.issuerUniqueID; + + if("extensions" in asn1.result) + this.extensions = new Extensions({ schema: asn1.result.extensions }); + //endregion + } + //********************************************************************************** + /** + * Convert current object to asn1js object and set correct values + * @returns {Object} asn1js object + */ + toSchema() + { + const result = new asn1js.Sequence({ + value: [new asn1js.Integer({ value: this.version })] + }); + + if("baseCertificateID" in this) + { + result.valueBlock.value.push(new asn1js.Constructed({ + idBlock: { + tagClass: 3, + tagNumber: 0 // [0] + }, + value: this.baseCertificateID.toSchema().valueBlock.value + })); + } + + if("subjectName" in this) + { + result.valueBlock.value.push(new asn1js.Constructed({ + idBlock: { + tagClass: 3, + tagNumber: 1 // [1] + }, + value: this.subjectName.toSchema().valueBlock.value + })); + } + + result.valueBlock.value.push(this.issuer.toSchema()); + result.valueBlock.value.push(this.signature.toSchema()); + result.valueBlock.value.push(this.serialNumber); + result.valueBlock.value.push(this.attrCertValidityPeriod.toSchema()); + result.valueBlock.value.push(new asn1js.Sequence({ + value: Array.from(this.attributes, element => element.toSchema()) + })); + + if("issuerUniqueID" in this) + result.valueBlock.value.push(this.issuerUniqueID); + + if("extensions" in this) + result.valueBlock.value.push(this.extensions.toSchema()); + + return result; + } + //********************************************************************************** + /** + * Convertion for the class to JSON object + * @returns {Object} + */ + toJSON() + { + const result = { + version: this.version + }; + + if("baseCertificateID" in this) + result.baseCertificateID = this.baseCertificateID.toJSON(); + + if("subjectName" in this) + result.subjectName = this.subjectName.toJSON(); + + result.issuer = this.issuer.toJSON(); + result.signature = this.signature.toJSON(); + result.serialNumber = this.serialNumber.toJSON(); + result.attrCertValidityPeriod = this.attrCertValidityPeriod.toJSON(); + result.attributes = Array.from(this.attributes, element => element.toJSON()); + + if("issuerUniqueID" in this) + result.issuerUniqueID = this.issuerUniqueID.toJSON(); + + if("extensions" in this) + result.extensions = this.extensions.toJSON(); + + return result; + } + //********************************************************************************** +} +//************************************************************************************** +/** + * Class from X.509:1997 + */ +export default class AttributeCertificateV1 +{ + //********************************************************************************** + /** + * Constructor for AttributeCertificateV1 class + * @param {Object} [parameters={}] + * @param {Object} [parameters.schema] asn1js parsed value to initialize the class from + */ + constructor(parameters = {}) + { + //region Internal properties of the object + /** + * @type {AttributeCertificateInfoV1} + * @desc acinfo + */ + this.acinfo = getParametersValue(parameters, "acinfo", AttributeCertificateV1.defaultValues("acinfo")); + /** + * @type {AlgorithmIdentifier} + * @desc signatureAlgorithm + */ + this.signatureAlgorithm = getParametersValue(parameters, "signatureAlgorithm", AttributeCertificateV1.defaultValues("signatureAlgorithm")); + /** + * @type {BitString} + * @desc signatureValue + */ + this.signatureValue = getParametersValue(parameters, "signatureValue", AttributeCertificateV1.defaultValues("signatureValue")); + //endregion + + //region If input argument array contains "schema" for this object + if("schema" in parameters) + this.fromSchema(parameters.schema); + //endregion + } + //********************************************************************************** + /** + * Return default values for all class members + * @param {string} memberName String name for a class member + */ + static defaultValues(memberName) + { + switch(memberName) + { + case "acinfo": + return new AttributeCertificateInfoV1(); + case "signatureAlgorithm": + return new AlgorithmIdentifier(); + case "signatureValue": + return new asn1js.BitString(); + default: + throw new Error(`Invalid member name for AttributeCertificateV1 class: ${memberName}`); + } + } + //********************************************************************************** + /** + * Return value of pre-defined ASN.1 schema for current class + * + * ASN.1 schema: + * ```asn1 + * AttributeCertificate ::= SEQUENCE { + * acinfo AttributeCertificateInfoV1, + * signatureAlgorithm AlgorithmIdentifier, + * signatureValue BIT STRING + * } + * ``` + * + * @param {Object} parameters Input parameters for the schema + * @returns {Object} asn1js schema object + */ + static schema(parameters = {}) + { + /** + * @type {Object} + * @property {string} [blockName] + * @property {Object} [acinfo] + * @property {Object} [signatureAlgorithm] + * @property {string} [signatureValue] + */ + const names = getParametersValue(parameters, "names", {}); + + return (new asn1js.Sequence({ + name: (names.blockName || ""), + value: [ + AttributeCertificateInfoV1.schema(names.acinfo || {}), + AlgorithmIdentifier.schema(names.signatureAlgorithm || {}), + new asn1js.BitString({ name: (names.signatureValue || "") }) + ] + })); + } + //********************************************************************************** + /** + * Convert parsed asn1js object into current class + * @param {!Object} schema + */ + fromSchema(schema) + { + //region Clear input data first + clearProps(schema, [ + "acinfo", + "signatureValue", + "signatureAlgorithm" + ]); + //endregion + + //region Check the schema is valid + const asn1 = asn1js.compareSchema(schema, + schema, + AttributeCertificateV1.schema({ + names: { + acinfo: { + names: { + blockName: "acinfo" + } + }, + signatureAlgorithm: { + names: { + blockName: "signatureAlgorithm" + } + }, + signatureValue: "signatureValue" + } + }) + ); + + if(asn1.verified === false) + throw new Error("Object's schema was not verified against input data for AttributeCertificateV1"); + //endregion + + //region Get internal properties from parsed schema + this.acinfo = new AttributeCertificateInfoV1({ schema: asn1.result.acinfo }); + this.signatureAlgorithm = new AlgorithmIdentifier({ schema: asn1.result.signatureAlgorithm }); + this.signatureValue = asn1.result.signatureValue; + //endregion + } + //********************************************************************************** + /** + * Convert current object to asn1js object and set correct values + * @returns {Object} asn1js object + */ + toSchema() + { + return (new asn1js.Sequence({ + value: [ + this.acinfo.toSchema(), + this.signatureAlgorithm.toSchema(), + this.signatureValue + ] + })); + } + //********************************************************************************** + /** + * Convertion for the class to JSON object + * @returns {Object} + */ + toJSON() + { + return { + acinfo: this.acinfo.toJSON(), + signatureAlgorithm: this.signatureAlgorithm.toJSON(), + signatureValue: this.signatureValue.toJSON() + }; + } + //********************************************************************************** +} +//************************************************************************************** diff --git a/core/third-party/pkijs/AttributeCertificateV2.js b/core/third-party/pkijs/AttributeCertificateV2.js new file mode 100644 index 0000000..ceb29df --- /dev/null +++ b/core/third-party/pkijs/AttributeCertificateV2.js @@ -0,0 +1,1187 @@ +import * as asn1js from "./asn1.js"; +import { getParametersValue, clearProps } from "./pvutils.js"; +import GeneralNames from "./GeneralNames.js"; +import AlgorithmIdentifier from "./AlgorithmIdentifier.js"; +import Attribute from "./Attribute.js"; +import Extensions from "./Extensions.js"; +import { AttCertValidityPeriod, IssuerSerial } from "./AttributeCertificateV1.js"; +//************************************************************************************** +/** + * Class from RFC5755 + */ +export class ObjectDigestInfo +{ + //********************************************************************************** + /** + * Constructor for ObjectDigestInfo class + * @param {Object} [parameters={}] + * @param {Object} [parameters.schema] asn1js parsed value to initialize the class from + */ + constructor(parameters = {}) + { + //region Internal properties of the object + /** + * @type {Enumerated} + * @desc digestedObjectType + */ + this.digestedObjectType = getParametersValue(parameters, "digestedObjectType", ObjectDigestInfo.defaultValues("digestedObjectType")); + + if("otherObjectTypeID" in parameters) + /** + * @type {ObjectIdentifier} + * @desc otherObjectTypeID + */ + this.otherObjectTypeID = getParametersValue(parameters, "otherObjectTypeID", ObjectDigestInfo.defaultValues("otherObjectTypeID")); + + /** + * @type {AlgorithmIdentifier} + * @desc digestAlgorithm + */ + this.digestAlgorithm = getParametersValue(parameters, "digestAlgorithm", ObjectDigestInfo.defaultValues("digestAlgorithm")); + /** + * @type {BitString} + * @desc objectDigest + */ + this.objectDigest = getParametersValue(parameters, "objectDigest", ObjectDigestInfo.defaultValues("objectDigest")); + //endregion + + //region If input argument array contains "schema" for this object + if("schema" in parameters) + this.fromSchema(parameters.schema); + //endregion + } + //********************************************************************************** + /** + * Return default values for all class members + * @param {string} memberName String name for a class member + */ + static defaultValues(memberName) + { + switch(memberName) + { + case "digestedObjectType": + return new asn1js.Enumerated(); + case "otherObjectTypeID": + return new asn1js.ObjectIdentifier(); + case "digestAlgorithm": + return new AlgorithmIdentifier(); + case "objectDigest": + return new asn1js.BitString(); + default: + throw new Error(`Invalid member name for ObjectDigestInfo class: ${memberName}`); + } + } + //********************************************************************************** + /** + * Return value of pre-defined ASN.1 schema for current class + * + * ASN.1 schema: + * ```asn1 + * ObjectDigestInfo ::= SEQUENCE { + * digestedObjectType ENUMERATED { + * publicKey (0), + * publicKeyCert (1), + * otherObjectTypes (2) }, + * -- otherObjectTypes MUST NOT + * -- be used in this profile + * otherObjectTypeID OBJECT IDENTIFIER OPTIONAL, + * digestAlgorithm AlgorithmIdentifier, + * objectDigest BIT STRING + * } + * ``` + * + * @param {Object} parameters Input parameters for the schema + * @returns {Object} asn1js schema object + */ + static schema(parameters = {}) + { + /** + * @type {Object} + * @property {string} [blockName] + * @property {string} [digestedObjectType] + * @property {string} [otherObjectTypeID] + * @property {string} [digestAlgorithm] + * @property {string} [objectDigest] + */ + const names = getParametersValue(parameters, "names", {}); + + return (new asn1js.Sequence({ + name: (names.blockName || ""), + value: [ + new asn1js.Enumerated({ name: (names.digestedObjectType || "") }), + new asn1js.ObjectIdentifier({ + optional: true, + name: (names.otherObjectTypeID || "") + }), + AlgorithmIdentifier.schema(names.digestAlgorithm || {}), + new asn1js.BitString({ name: (names.objectDigest || "") }), + ] + })); + } + //********************************************************************************** + /** + * Convert parsed asn1js object into current class + * @param {!Object} schema + */ + fromSchema(schema) + { + //region Clear input data first + clearProps(schema, [ + "digestedObjectType", + "otherObjectTypeID", + "digestAlgorithm", + "objectDigest" + ]); + //endregion + + //region Check the schema is valid + const asn1 = asn1js.compareSchema(schema, + schema, + ObjectDigestInfo.schema({ + names: { + digestedObjectType: "digestedObjectType", + otherObjectTypeID: "otherObjectTypeID", + digestAlgorithm: { + names: { + blockName: "digestAlgorithm" + } + }, + objectDigest: "objectDigest" + } + }) + ); + + if(asn1.verified === false) + throw new Error("Object's schema was not verified against input data for ObjectDigestInfo"); + //endregion + + //region Get internal properties from parsed schema + this.digestedObjectType = asn1.result.digestedObjectType; + + if("otherObjectTypeID" in asn1.result) + this.otherObjectTypeID = asn1.result.otherObjectTypeID; + + this.digestAlgorithm = new AlgorithmIdentifier({ schema: asn1.result.digestAlgorithm }); + this.objectDigest = asn1.result.objectDigest; + //endregion + } + //********************************************************************************** + /** + * Convert current object to asn1js object and set correct values + * @returns {Object} asn1js object + */ + toSchema() + { + const result = new asn1js.Sequence({ + value: [this.digestedObjectType] + }); + + if("otherObjectTypeID" in this) + result.value.push(this.otherObjectTypeID); + + result.value.push(this.digestAlgorithm.toSchema()); + result.value.push(this.objectDigest); + + return result; + } + //********************************************************************************** + /** + * Convertion for the class to JSON object + * @returns {Object} + */ + toJSON() + { + const result = { + digestedObjectType: this.digestedObjectType.toJSON() + }; + + if("otherObjectTypeID" in this) + result.otherObjectTypeID = this.otherObjectTypeID.toJSON(); + + result.digestAlgorithm = this.digestAlgorithm.toJSON(); + result.objectDigest = this.objectDigest.toJSON(); + + return result; + } + //********************************************************************************** +} +//************************************************************************************** +/** + * Class from RFC5755 + */ +export class V2Form +{ + //********************************************************************************** + /** + * Constructor for V2Form class + * @param {Object} [parameters={}] + * @param {Object} [parameters.schema] asn1js parsed value to initialize the class from + */ + constructor(parameters = {}) + { + //region Internal properties of the object + if("issuerName" in parameters) + /** + * @type {GeneralNames} + * @desc issuerName + */ + this.issuerName = getParametersValue(parameters, "issuerName", V2Form.defaultValues("issuerName")); + + if("baseCertificateID" in parameters) + /** + * @type {IssuerSerial} + * @desc baseCertificateID + */ + this.baseCertificateID = getParametersValue(parameters, "baseCertificateID", V2Form.defaultValues("baseCertificateID")); + + if("objectDigestInfo" in parameters) + /** + * @type {ObjectDigestInfo} + * @desc objectDigestInfo + */ + this.objectDigestInfo = getParametersValue(parameters, "objectDigestInfo", V2Form.defaultValues("objectDigestInfo")); + //endregion + + //region If input argument array contains "schema" for this object + if("schema" in parameters) + this.fromSchema(parameters.schema); + //endregion + } + //********************************************************************************** + /** + * Return default values for all class members + * @param {string} memberName String name for a class member + */ + static defaultValues(memberName) + { + switch(memberName) + { + case "issuerName": + return new GeneralNames(); + case "baseCertificateID": + return new IssuerSerial(); + case "objectDigestInfo": + return new ObjectDigestInfo(); + default: + throw new Error(`Invalid member name for V2Form class: ${memberName}`); + } + } + //********************************************************************************** + /** + * Return value of pre-defined ASN.1 schema for current class + * + * ASN.1 schema: + * ```asn1 + * V2Form ::= SEQUENCE { + * issuerName GeneralNames OPTIONAL, + * baseCertificateID [0] IssuerSerial OPTIONAL, + * objectDigestInfo [1] ObjectDigestInfo OPTIONAL + * -- issuerName MUST be present in this profile + * -- baseCertificateID and objectDigestInfo MUST NOT + * -- be present in this profile + * } + * ``` + * + * @param {Object} parameters Input parameters for the schema + * @returns {Object} asn1js schema object + */ + static schema(parameters = {}) + { + /** + * @type {Object} + * @property {string} [blockName] + * @property {string} [issuerName] + * @property {string} [baseCertificateID] + * @property {string} [objectDigestInfo] + */ + const names = getParametersValue(parameters, "names", {}); + + return (new asn1js.Sequence({ + name: (names.blockName || ""), + value: [ + GeneralNames.schema({ + names: { + blockName: names.issuerName + } + }, true), + new asn1js.Constructed({ + optional: true, + name: (names.baseCertificateID || ""), + idBlock: { + tagClass: 3, + tagNumber: 0 // [0] + }, + value: IssuerSerial.schema().valueBlock.value + }), + new asn1js.Constructed({ + optional: true, + name: (names.objectDigestInfo || ""), + idBlock: { + tagClass: 3, + tagNumber: 1 // [1] + }, + value: ObjectDigestInfo.schema().valueBlock.value + }) + ] + })); + } + //********************************************************************************** + /** + * Convert parsed asn1js object into current class + * @param {!Object} schema + */ + fromSchema(schema) + { + //region Clear input data first + clearProps(schema, [ + "issuerName", + "baseCertificateID", + "objectDigestInfo" + ]); + //endregion + + //region Check the schema is valid + const asn1 = asn1js.compareSchema(schema, + schema, + V2Form.schema({ + names: { + issuerName: "issuerName", + baseCertificateID: "baseCertificateID", + objectDigestInfo: "objectDigestInfo" + } + }) + ); + + if(asn1.verified === false) + throw new Error("Object's schema was not verified against input data for V2Form"); + //endregion + + //region Get internal properties from parsed schema + if("issuerName" in asn1.result) + this.issuerName = new GeneralNames({ schema: asn1.result.issuerName }); + + if("baseCertificateID" in asn1.result) + { + this.baseCertificateID = new IssuerSerial({ + schema: new asn1js.Sequence({ + value: asn1.result.baseCertificateID.valueBlock.value + }) + }); + } + + if("objectDigestInfo" in asn1.result) + { + this.objectDigestInfo = new ObjectDigestInfo({ + schema: new asn1js.Sequence({ + value: asn1.result.objectDigestInfo.valueBlock.value + }) + }); + } + //endregion + } + //********************************************************************************** + /** + * Convert current object to asn1js object and set correct values + * @returns {Object} asn1js object + */ + toSchema() + { + const result = new asn1js.Sequence(); + + if("issuerName" in this) + result.valueBlock.value.push(this.issuerName.toSchema()); + + if("baseCertificateID" in this) + { + result.valueBlock.value.push(new asn1js.Constructed({ + idBlock: { + tagClass: 3, + tagNumber: 0 // [0] + }, + value: this.baseCertificateID.toSchema().valueBlock.value + })); + } + + if("objectDigestInfo" in this) + { + result.valueBlock.value.push(new asn1js.Constructed({ + idBlock: { + tagClass: 3, + tagNumber: 1 // [1] + }, + value: this.objectDigestInfo.toSchema().valueBlock.value + })); + } + + //region Construct and return new ASN.1 schema for this object + return result; + //endregion + } + //********************************************************************************** + /** + * Convertion for the class to JSON object + * @returns {Object} + */ + toJSON() + { + const result = {}; + + if("issuerName" in this) + result.issuerName = this.issuerName.toJSON(); + + if("baseCertificateID" in this) + result.baseCertificateID = this.baseCertificateID.toJSON(); + + if("objectDigestInfo" in this) + result.objectDigestInfo = this.objectDigestInfo.toJSON(); + + return result; + } + //********************************************************************************** +} +//************************************************************************************** +/** + * Class from RFC5755 + */ +export class Holder +{ + //********************************************************************************** + /** + * Constructor for Holder class + * @param {Object} [parameters={}] + * @param {Object} [parameters.schema] asn1js parsed value to initialize the class from + */ + constructor(parameters = {}) + { + //region Internal properties of the object + if("baseCertificateID" in parameters) + /** + * @type {IssuerSerial} + * @desc baseCertificateID + */ + this.baseCertificateID = getParametersValue(parameters, "baseCertificateID", Holder.defaultValues("baseCertificateID")); + + if("entityName" in parameters) + /** + * @type {GeneralNames} + * @desc entityName + */ + this.entityName = getParametersValue(parameters, "entityName", Holder.defaultValues("entityName")); + + if("objectDigestInfo" in parameters) + /** + * @type {ObjectDigestInfo} + * @desc objectDigestInfo + */ + this.objectDigestInfo = getParametersValue(parameters, "objectDigestInfo", Holder.defaultValues("objectDigestInfo")); + //endregion + + //region If input argument array contains "schema" for this object + if("schema" in parameters) + this.fromSchema(parameters.schema); + //endregion + } + //********************************************************************************** + /** + * Return default values for all class members + * @param {string} memberName String name for a class member + */ + static defaultValues(memberName) + { + switch(memberName) + { + case "baseCertificateID": + return new IssuerSerial(); + case "entityName": + return new GeneralNames(); + case "objectDigestInfo": + return new ObjectDigestInfo(); + default: + throw new Error(`Invalid member name for Holder class: ${memberName}`); + } + } + //********************************************************************************** + /** + * Return value of pre-defined ASN.1 schema for current class + * + * ASN.1 schema: + * ```asn1 + * Holder ::= SEQUENCE { + * baseCertificateID [0] IssuerSerial OPTIONAL, + * -- the issuer and serial number of + * -- the holder's Public Key Certificate + * entityName [1] GeneralNames OPTIONAL, + * -- the name of the claimant or role + * objectDigestInfo [2] ObjectDigestInfo OPTIONAL + * -- used to directly authenticate the holder, + * -- for example, an executable + * } + * ``` + * + * @param {Object} parameters Input parameters for the schema + * @returns {Object} asn1js schema object + */ + static schema(parameters = {}) + { + /** + * @type {Object} + * @property {string} [blockName] + * @property {string} [baseCertificateID] + * @property {string} [entityName] + * @property {string} [objectDigestInfo] + */ + const names = getParametersValue(parameters, "names", {}); + + return (new asn1js.Sequence({ + name: (names.blockName || ""), + value: [ + new asn1js.Constructed({ + optional: true, + name: (names.baseCertificateID || ""), + idBlock: { + tagClass: 3, + tagNumber: 0 // [0] + }, + value: IssuerSerial.schema().valueBlock.value + }), + new asn1js.Constructed({ + optional: true, + name: (names.entityName || ""), + idBlock: { + tagClass: 3, + tagNumber: 1 // [2] + }, + value: GeneralNames.schema().valueBlock.value + }), + new asn1js.Constructed({ + optional: true, + name: (names.objectDigestInfo || ""), + idBlock: { + tagClass: 3, + tagNumber: 2 // [2] + }, + value: ObjectDigestInfo.schema().valueBlock.value + }) + ] + })); + } + //********************************************************************************** + /** + * Convert parsed asn1js object into current class + * @param {!Object} schema + */ + fromSchema(schema) + { + //region Clear input data first + clearProps(schema, [ + "baseCertificateID", + "entityName", + "objectDigestInfo" + ]); + //endregion + + //region Check the schema is valid + const asn1 = asn1js.compareSchema(schema, + schema, + Holder.schema({ + names: { + baseCertificateID: "baseCertificateID", + entityName: "entityName", + objectDigestInfo: "objectDigestInfo" + } + }) + ); + + if(asn1.verified === false) + throw new Error("Object's schema was not verified against input data for Holder"); + //endregion + + //region Get internal properties from parsed schema + if("baseCertificateID" in asn1.result) + { + this.baseCertificateID = new IssuerSerial({ + schema: new asn1js.Sequence({ + value: asn1.result.baseCertificateID.valueBlock.value + }) + }); + } + + if("entityName" in asn1.result) + { + this.entityName = new GeneralNames({ + schema: new asn1js.Sequence({ + value: asn1.result.entityName.valueBlock.value + }) + }); + } + + if("objectDigestInfo" in asn1.result) + { + this.objectDigestInfo = new ObjectDigestInfo({ + schema: new asn1js.Sequence({ + value: asn1.result.objectDigestInfo.valueBlock.value + }) + }); + } + //endregion + } + //********************************************************************************** + /** + * Convert current object to asn1js object and set correct values + * @returns {Object} asn1js object + */ + toSchema() + { + const result = new asn1js.Sequence(); + + if("baseCertificateID" in this) + { + result.valueBlock.value.push(new asn1js.Constructed({ + idBlock: { + tagClass: 3, + tagNumber: 0 // [0] + }, + value: this.baseCertificateID.toSchema().valueBlock.value + })); + } + + if("entityName" in this) + { + result.valueBlock.value.push(new asn1js.Constructed({ + idBlock: { + tagClass: 3, + tagNumber: 1 // [1] + }, + value: this.entityName.toSchema().valueBlock.value + })); + } + + if("objectDigestInfo" in this) + { + result.valueBlock.value.push(new asn1js.Constructed({ + idBlock: { + tagClass: 3, + tagNumber: 2 // [2] + }, + value: this.objectDigestInfo.toSchema().valueBlock.value + })); + } + + return result; + } + //********************************************************************************** + /** + * Convertion for the class to JSON object + * @returns {Object} + */ + toJSON() + { + const result = {}; + + if("baseCertificateID" in this) + result.baseCertificateID = this.baseCertificateID.toJSON(); + + if("entityName" in this) + result.entityName = this.entityName.toJSON(); + + if("objectDigestInfo" in this) + result.objectDigestInfo = this.objectDigestInfo.toJSON(); + + return result; + } + //********************************************************************************** +} +//************************************************************************************** +/** + * Class from RFC5755 + */ +export class AttributeCertificateInfoV2 +{ + //********************************************************************************** + /** + * Constructor for AttributeCertificateInfoV2 class + * @param {Object} [parameters={}] + * @param {Object} [parameters.schema] asn1js parsed value to initialize the class from + */ + constructor(parameters = {}) + { + //region Internal properties of the object + /** + * @type {Number} + * @desc version + */ + this.version = getParametersValue(parameters, "version", AttributeCertificateInfoV2.defaultValues("version")); + /** + * @type {Holder} + * @desc holder + */ + this.holder = getParametersValue(parameters, "holder", AttributeCertificateInfoV2.defaultValues("holder")); + /** + * @type {GeneralNames|V2Form} + * @desc issuer + */ + this.issuer = getParametersValue(parameters, "issuer", AttributeCertificateInfoV2.defaultValues("issuer")); + /** + * @type {AlgorithmIdentifier} + * @desc signature + */ + this.signature = getParametersValue(parameters, "signature", AttributeCertificateInfoV2.defaultValues("signature")); + /** + * @type {Integer} + * @desc serialNumber + */ + this.serialNumber = getParametersValue(parameters, "serialNumber", AttributeCertificateInfoV2.defaultValues("serialNumber")); + /** + * @type {AttCertValidityPeriod} + * @desc attrCertValidityPeriod + */ + this.attrCertValidityPeriod = getParametersValue(parameters, "attrCertValidityPeriod", AttributeCertificateInfoV2.defaultValues("attrCertValidityPeriod")); + /** + * @type {Array.} + * @desc attributes + */ + this.attributes = getParametersValue(parameters, "attributes", AttributeCertificateInfoV2.defaultValues("attributes")); + + if("issuerUniqueID" in parameters) + /** + * @type {BitString} + * @desc issuerUniqueID + */ + this.issuerUniqueID = getParametersValue(parameters, "issuerUniqueID", AttributeCertificateInfoV2.defaultValues("issuerUniqueID")); + + if("extensions" in parameters) + /** + * @type {Extensions} + * @desc extensions + */ + this.extensions = getParametersValue(parameters, "extensions", AttributeCertificateInfoV2.defaultValues("extensions")); + //endregion + + //region If input argument array contains "schema" for this object + if("schema" in parameters) + this.fromSchema(parameters.schema); + //endregion + } + //********************************************************************************** + /** + * Return default values for all class members + * @param {string} memberName String name for a class member + */ + static defaultValues(memberName) + { + switch(memberName) + { + case "version": + return 1; + case "holder": + return new Holder(); + case "issuer": + return {}; + case "signature": + return new AlgorithmIdentifier(); + case "serialNumber": + return new asn1js.Integer(); + case "attrCertValidityPeriod": + return new AttCertValidityPeriod(); + case "attributes": + return []; + case "issuerUniqueID": + return new asn1js.BitString(); + case "extensions": + return new Extensions(); + default: + throw new Error(`Invalid member name for AttributeCertificateInfoV2 class: ${memberName}`); + } + } + //********************************************************************************** + /** + * Return value of pre-defined ASN.1 schema for current class + * + * ASN.1 schema: + * ```asn1 + * AttributeCertificateInfoV2 ::= SEQUENCE { + * version AttCertVersion, -- version is v2 + * holder Holder, + * issuer AttCertIssuer, + * signature AlgorithmIdentifier, + * serialNumber CertificateSerialNumber, + * attrCertValidityPeriod AttCertValidityPeriod, + * attributes SEQUENCE OF Attribute, + * issuerUniqueID UniqueIdentifier OPTIONAL, + * extensions Extensions OPTIONAL + * } + * ``` + * + * @param {Object} parameters Input parameters for the schema + * @returns {Object} asn1js schema object + */ + static schema(parameters = {}) + { + /** + * @type {Object} + * @property {string} [blockName] + * @property {string} [issuer] + * @property {string} [serialNumber] + */ + const names = getParametersValue(parameters, "names", {}); + + return (new asn1js.Sequence({ + name: (names.blockName || ""), + value: [ + new asn1js.Integer({ name: (names.version || "") }), + Holder.schema(names.holder || {}), + new asn1js.Choice({ + value: [ + GeneralNames.schema({ + names: { + blockName: (names.issuer || "") + } + }), + new asn1js.Constructed({ + name: (names.issuer || ""), + idBlock: { + tagClass: 3, // CONTEXT-SPECIFIC + tagNumber: 0 // [0] + }, + value: V2Form.schema().valueBlock.value + }) + ] + }), + AlgorithmIdentifier.schema(names.signature || {}), + new asn1js.Integer({ name: (names.serialNumber || "") }), + AttCertValidityPeriod.schema(names.attrCertValidityPeriod || {}), + new asn1js.Sequence({ + name: (names.attributes || ""), + value: [ + new asn1js.Repeated({ + value: Attribute.schema() + }) + ] + }), + new asn1js.BitString({ + optional: true, + name: (names.issuerUniqueID || "") + }), + Extensions.schema(names.extensions || {}, true) + ] + })); + } + //********************************************************************************** + /** + * Convert parsed asn1js object into current class + * @param {!Object} schema + */ + fromSchema(schema) + { + //region Clear input data first + clearProps(schema, [ + "version", + "holder", + "issuer", + "signature", + "serialNumber", + "attrCertValidityPeriod", + "attributes", + "issuerUniqueID", + "extensions" + ]); + //endregion + + //region Check the schema is valid + const asn1 = asn1js.compareSchema(schema, + schema, + AttributeCertificateInfoV2.schema({ + names: { + version: "version", + holder: { + names: { + blockName: "holder" + } + }, + issuer: "issuer", + signature: { + names: { + blockName: "signature" + } + }, + serialNumber: "serialNumber", + attrCertValidityPeriod: { + names: { + blockName: "attrCertValidityPeriod" + } + }, + attributes: "attributes", + issuerUniqueID: "issuerUniqueID", + extensions: { + names: { + blockName: "extensions" + } + } + } + }) + ); + + if(asn1.verified === false) + throw new Error("Object's schema was not verified against input data for AttributeCertificateInfoV2"); + //endregion + + //region Get internal properties from parsed schema + this.version = asn1.result.version.valueBlock.valueDec; + this.holder = new Holder({ schema: asn1.result.holder }); + + switch(asn1.result.issuer.idBlock.tagClass) + { + case 3: // V2Form + this.issuer = new V2Form({ + schema: new asn1js.Sequence({ + value: asn1.result.issuer.valueBlock.value + }) + }); + break; + case 1: // GeneralNames (should not be used) + default: + throw new Error("Incorect value for 'issuer' in AttributeCertificateInfoV2"); + } + + this.signature = new AlgorithmIdentifier({ schema: asn1.result.signature }); + this.serialNumber = asn1.result.serialNumber; + this.attrCertValidityPeriod = new AttCertValidityPeriod({ schema: asn1.result.attrCertValidityPeriod }); + this.attributes = Array.from(asn1.result.attributes.valueBlock.value, element => new Attribute({ schema: element })); + + if("issuerUniqueID" in asn1.result) + this.issuerUniqueID = asn1.result.issuerUniqueID; + + if("extensions" in asn1.result) + this.extensions = new Extensions({ schema: asn1.result.extensions }); + //endregion + } + //********************************************************************************** + /** + * Convert current object to asn1js object and set correct values + * @returns {Object} asn1js object + */ + toSchema() + { + const result = new asn1js.Sequence({ + value: [ + new asn1js.Integer({ value: this.version }), + this.holder.toSchema(), + new asn1js.Constructed({ + idBlock: { + tagClass: 3, // CONTEXT-SPECIFIC + tagNumber: 0 // [0] + }, + value: this.issuer.toSchema().valueBlock.value + }), + this.signature.toSchema(), + this.serialNumber, + this.attrCertValidityPeriod.toSchema(), + new asn1js.Sequence({ + value: Array.from(this.attributes, element => element.toSchema()) + }) + ] + }); + + if("issuerUniqueID" in this) + result.valueBlock.value.push(this.issuerUniqueID); + + if("extensions" in this) + result.valueBlock.value.push(this.extensions.toSchema()); + + return result; + } + //********************************************************************************** + /** + * Convertion for the class to JSON object + * @returns {Object} + */ + toJSON() + { + const result = { + version: this.version, + holder: this.holder.toJSON(), + issuer: this.issuer.toJSON(), + signature: this.signature.toJSON(), + serialNumber: this.serialNumber.toJSON(), + attrCertValidityPeriod: this.attrCertValidityPeriod.toJSON(), + attributes: Array.from(this.attributes, element => element.toJSON()) + }; + + if("issuerUniqueID" in this) + result.issuerUniqueID = this.issuerUniqueID.toJSON(); + + if("extensions" in this) + result.extensions = this.extensions.toJSON(); + + return result; + } + //********************************************************************************** +} +//************************************************************************************** +/** + * Class from RFC5755 + */ +export default class AttributeCertificateV2 +{ + //********************************************************************************** + /** + * Constructor for AttributeCertificateV2 class + * @param {Object} [parameters={}] + * @param {Object} [parameters.schema] asn1js parsed value to initialize the class from + */ + constructor(parameters = {}) + { + //region Internal properties of the object + /** + * @type {AttributeCertificateInfoV2} + * @desc acinfo + */ + this.acinfo = getParametersValue(parameters, "acinfo", AttributeCertificateV2.defaultValues("acinfo")); + /** + * @type {AlgorithmIdentifier} + * @desc signatureAlgorithm + */ + this.signatureAlgorithm = getParametersValue(parameters, "signatureAlgorithm", AttributeCertificateV2.defaultValues("signatureAlgorithm")); + /** + * @type {BitString} + * @desc signatureValue + */ + this.signatureValue = getParametersValue(parameters, "signatureValue", AttributeCertificateV2.defaultValues("signatureValue")); + //endregion + + //region If input argument array contains "schema" for this object + if("schema" in parameters) + this.fromSchema(parameters.schema); + //endregion + } + //********************************************************************************** + /** + * Return default values for all class members + * @param {string} memberName String name for a class member + */ + static defaultValues(memberName) + { + switch(memberName) + { + case "acinfo": + return new AttributeCertificateInfoV2(); + case "signatureAlgorithm": + return new AlgorithmIdentifier(); + case "signatureValue": + return new asn1js.BitString(); + default: + throw new Error(`Invalid member name for AttributeCertificateV2 class: ${memberName}`); + } + } + //********************************************************************************** + /** + * Return value of pre-defined ASN.1 schema for current class + * + * ASN.1 schema: + * ```asn1 + * AttributeCertificate ::= SEQUENCE { + * acinfo AttributeCertificateInfoV2, + * signatureAlgorithm AlgorithmIdentifier, + * signatureValue BIT STRING + * } + * ``` + * + * @param {Object} parameters Input parameters for the schema + * @returns {Object} asn1js schema object + */ + static schema(parameters = {}) + { + /** + * @type {Object} + * @property {string} [blockName] + * @property {Object} [acinfo] + * @property {Object} [signatureAlgorithm] + * @property {string} [signatureValue] + */ + const names = getParametersValue(parameters, "names", {}); + + return (new asn1js.Sequence({ + name: (names.blockName || ""), + value: [ + AttributeCertificateInfoV2.schema(names.acinfo || {}), + AlgorithmIdentifier.schema(names.signatureAlgorithm || {}), + new asn1js.BitString({ name: (names.signatureValue || "") }) + ] + })); + } + //********************************************************************************** + /** + * Convert parsed asn1js object into current class + * @param {!Object} schema + */ + fromSchema(schema) + { + //region Clear input data first + clearProps(schema, [ + "acinfo", + "signatureAlgorithm", + "signatureValue" + ]); + //endregion + + //region Check the schema is valid + const asn1 = asn1js.compareSchema(schema, + schema, + AttributeCertificateV2.schema({ + names: { + acinfo: { + names: { + blockName: "acinfo" + } + }, + signatureAlgorithm: { + names: { + blockName: "signatureAlgorithm" + } + }, + signatureValue: "signatureValue" + } + }) + ); + + if(asn1.verified === false) + throw new Error("Object's schema was not verified against input data for AttributeCertificateV2"); + //endregion + + //region Get internal properties from parsed schema + this.acinfo = new AttributeCertificateInfoV2({ schema: asn1.result.acinfo }); + this.signatureAlgorithm = new AlgorithmIdentifier({ schema: asn1.result.signatureAlgorithm }); + this.signatureValue = asn1.result.signatureValue; + //endregion + } + //********************************************************************************** + /** + * Convert current object to asn1js object and set correct values + * @returns {Object} asn1js object + */ + toSchema() + { + return (new asn1js.Sequence({ + value: [ + this.acinfo.toSchema(), + this.signatureAlgorithm.toSchema(), + this.signatureValue + ] + })); + } + //********************************************************************************** + /** + * Convertion for the class to JSON object + * @returns {Object} + */ + toJSON() + { + return { + acinfo: this.acinfo.toJSON(), + signatureAlgorithm: this.signatureAlgorithm.toJSON(), + signatureValue: this.signatureValue.toJSON() + }; + } + //********************************************************************************** +} +//************************************************************************************** diff --git a/core/third-party/pkijs/AttributeTypeAndValue.js b/core/third-party/pkijs/AttributeTypeAndValue.js new file mode 100644 index 0000000..a899567 --- /dev/null +++ b/core/third-party/pkijs/AttributeTypeAndValue.js @@ -0,0 +1,232 @@ +import * as asn1js from "./asn1.js"; +import { getParametersValue, isEqualBuffer, clearProps } from "./pvutils.js"; +import { stringPrep } from "./common.js"; +//************************************************************************************** +/** + * Class from RFC5280 + */ +export default class AttributeTypeAndValue +{ + //********************************************************************************** + /** + * Constructor for AttributeTypeAndValue class + * @param {Object} [parameters={}] + * @param {Object} [parameters.schema] asn1js parsed value to initialize the class from + */ + constructor(parameters = {}) + { + //region Internal properties of the object + /** + * @type {string} + * @desc type + */ + this.type = getParametersValue(parameters, "type", AttributeTypeAndValue.defaultValues("type")); + /** + * @type {Object} + * @desc Value of the AttributeTypeAndValue class + */ + this.value = getParametersValue(parameters, "value", AttributeTypeAndValue.defaultValues("value")); + //endregion + + //region If input argument array contains "schema" for this object + if("schema" in parameters) + this.fromSchema(parameters.schema); + //endregion + } + //********************************************************************************** + /** + * Return default values for all class members + * @param {string} memberName String name for a class member + */ + static defaultValues(memberName) + { + switch(memberName) + { + case "type": + return ""; + case "value": + return {}; + default: + throw new Error(`Invalid member name for AttributeTypeAndValue class: ${memberName}`); + } + } + //********************************************************************************** + /** + * Return value of pre-defined ASN.1 schema for current class + * + * ASN.1 schema: + * ```asn1 + * AttributeTypeAndValue ::= Sequence { + * type AttributeType, + * value AttributeValue } + * + * AttributeType ::= OBJECT IDENTIFIER + * + * AttributeValue ::= ANY -- DEFINED BY AttributeType + * ``` + * + * @param {Object} parameters Input parameters for the schema + * @returns {Object} asn1js schema object + */ + static schema(parameters = {}) + { + /** + * @type {Object} + * @property {string} [blockName] Name for entire block + * @property {string} [type] Name for "type" element + * @property {string} [value] Name for "value" element + */ + const names = getParametersValue(parameters, "names", {}); + + return (new asn1js.Sequence({ + name: (names.blockName || ""), + value: [ + new asn1js.ObjectIdentifier({ name: (names.type || "") }), + new asn1js.Any({ name: (names.value || "") }) + ] + })); + } + //********************************************************************************** + static blockName() + { + return "AttributeTypeAndValue"; + } + //********************************************************************************** + /** + * Convert parsed asn1js object into current class + * @param {!Object} schema + */ + fromSchema(schema) + { + //region Clear input data first + clearProps(schema, [ + "type", + "typeValue" + ]); + //endregion + + //region Check the schema is valid + const asn1 = asn1js.compareSchema(schema, + schema, + AttributeTypeAndValue.schema({ + names: { + type: "type", + value: "typeValue" + } + }) + ); + + if(asn1.verified === false) + throw new Error("Object's schema was not verified against input data for AttributeTypeAndValue"); + //endregion + + //region Get internal properties from parsed schema + this.type = asn1.result.type.valueBlock.toString(); + // noinspection JSUnresolvedVariable + this.value = asn1.result.typeValue; + //endregion + } + //********************************************************************************** + /** + * Convert current object to asn1js object and set correct values + * @returns {Object} asn1js object + */ + toSchema() + { + //region Construct and return new ASN.1 schema for this object + return (new asn1js.Sequence({ + value: [ + new asn1js.ObjectIdentifier({ value: this.type }), + this.value + ] + })); + //endregion + } + //********************************************************************************** + /** + * Convertion for the class to JSON object + * @returns {Object} + */ + toJSON() + { + const _object = { + type: this.type + }; + + if(Object.keys(this.value).length !== 0) + _object.value = this.value.toJSON(); + else + _object.value = this.value; + + return _object; + } + //********************************************************************************** + /** + * Compare two AttributeTypeAndValue values, or AttributeTypeAndValue with ArrayBuffer value + * @param {(AttributeTypeAndValue|ArrayBuffer)} compareTo The value compare to current + * @returns {boolean} + */ + isEqual(compareTo) + { + const stringBlockNames = [ + asn1js.Utf8String.blockName(), + asn1js.BmpString.blockName(), + asn1js.UniversalString.blockName(), + asn1js.NumericString.blockName(), + asn1js.PrintableString.blockName(), + asn1js.TeletexString.blockName(), + asn1js.VideotexString.blockName(), + asn1js.IA5String.blockName(), + asn1js.GraphicString.blockName(), + asn1js.VisibleString.blockName(), + asn1js.GeneralString.blockName(), + asn1js.CharacterString.blockName() + ]; + + if(compareTo.constructor.blockName() === AttributeTypeAndValue.blockName()) + { + if(this.type !== compareTo.type) + return false; + + //region Check we do have both strings + let isString = false; + const thisName = this.value.constructor.blockName(); + + if(thisName === compareTo.value.constructor.blockName()) + { + for(const name of stringBlockNames) + { + if(thisName === name) + { + isString = true; + break; + } + } + } + //endregion + + if(isString) + { + const value1 = stringPrep(this.value.valueBlock.value); + const value2 = stringPrep(compareTo.value.valueBlock.value); + + if(value1.localeCompare(value2) !== 0) + return false; + } + else // Comparing as two ArrayBuffers + { + if(isEqualBuffer(this.value.valueBeforeDecode, compareTo.value.valueBeforeDecode) === false) + return false; + } + + return true; + } + + if(compareTo instanceof ArrayBuffer) + return isEqualBuffer(this.value.valueBeforeDecode, compareTo); + + return false; + } + //********************************************************************************** +} +//************************************************************************************** diff --git a/core/third-party/pkijs/AuthenticatedSafe.js b/core/third-party/pkijs/AuthenticatedSafe.js new file mode 100644 index 0000000..ac08eb2 --- /dev/null +++ b/core/third-party/pkijs/AuthenticatedSafe.js @@ -0,0 +1,513 @@ +import * as asn1js from "./asn1.js"; +import { getParametersValue, utilConcatBuf, clearProps } from "./pvutils.js"; +import ContentInfo from "./ContentInfo.js"; +import SafeContents from "./SafeContents.js"; +import EnvelopedData from "./EnvelopedData.js"; +import EncryptedData from "./EncryptedData.js"; +//************************************************************************************** +/** + * Class from RFC7292 + */ +export default class AuthenticatedSafe +{ + //********************************************************************************** + /** + * Constructor for AuthenticatedSafe class + * @param {Object} [parameters={}] + * @param {Object} [parameters.schema] asn1js parsed value to initialize the class from + */ + constructor(parameters = {}) + { + //region Internal properties of the object + /** + * @type {Array.} + * @desc safeContents + */ + this.safeContents = getParametersValue(parameters, "safeContents", AuthenticatedSafe.defaultValues("safeContents")); + + if("parsedValue" in parameters) + /** + * @type {*} + * @desc parsedValue + */ + this.parsedValue = getParametersValue(parameters, "parsedValue", AuthenticatedSafe.defaultValues("parsedValue")); + //endregion + + //region If input argument array contains "schema" for this object + if("schema" in parameters) + this.fromSchema(parameters.schema); + //endregion + } + //********************************************************************************** + /** + * Return default values for all class members + * @param {string} memberName String name for a class member + */ + static defaultValues(memberName) + { + switch(memberName) + { + case "safeContents": + return []; + case "parsedValue": + return {}; + default: + throw new Error(`Invalid member name for AuthenticatedSafe class: ${memberName}`); + } + } + //********************************************************************************** + /** + * Compare values with default values for all class members + * @param {string} memberName String name for a class member + * @param {*} memberValue Value to compare with default value + */ + static compareWithDefault(memberName, memberValue) + { + switch(memberName) + { + case "safeContents": + return (memberValue.length === 0); + case "parsedValue": + return ((memberValue instanceof Object) && (Object.keys(memberValue).length === 0)); + default: + throw new Error(`Invalid member name for AuthenticatedSafe class: ${memberName}`); + } + } + //********************************************************************************** + /** + * Return value of pre-defined ASN.1 schema for current class + * + * ASN.1 schema: + * ```asn1 + * AuthenticatedSafe ::= SEQUENCE OF ContentInfo + * -- Data if unencrypted + * -- EncryptedData if password-encrypted + * -- EnvelopedData if public key-encrypted + * ``` + * + * @param {Object} parameters Input parameters for the schema + * @returns {Object} asn1js schema object + */ + static schema(parameters = {}) + { + /** + * @type {Object} + * @property {string} [blockName] + * @property {string} [contentInfos] + */ + const names = getParametersValue(parameters, "names", {}); + + return (new asn1js.Sequence({ + name: (names.blockName || ""), + value: [ + new asn1js.Repeated({ + name: (names.contentInfos || ""), + value: ContentInfo.schema() + }) + ] + })); + } + //********************************************************************************** + /** + * Convert parsed asn1js object into current class + * @param {!Object} schema + */ + fromSchema(schema) + { + //region Clear input data first + clearProps(schema, [ + "contentInfos" + ]); + //endregion + + //region Check the schema is valid + const asn1 = asn1js.compareSchema(schema, + schema, + AuthenticatedSafe.schema({ + names: { + contentInfos: "contentInfos" + } + }) + ); + + if(asn1.verified === false) + throw new Error("Object's schema was not verified against input data for AuthenticatedSafe"); + //endregion + + //region Get internal properties from parsed schema + this.safeContents = Array.from(asn1.result.contentInfos, element => new ContentInfo({ schema: element })); + //endregion + } + //********************************************************************************** + /** + * Convert current object to asn1js object and set correct values + * @returns {Object} asn1js object + */ + toSchema() + { + //region Construct and return new ASN.1 schema for this object + return (new asn1js.Sequence({ + value: Array.from(this.safeContents, element => element.toSchema()) + })); + //endregion + } + //********************************************************************************** + /** + * Convertion for the class to JSON object + * @returns {Object} + */ + toJSON() + { + return { + safeContents: Array.from(this.safeContents, element => element.toJSON()) + }; + } + //********************************************************************************** + parseInternalValues(parameters) + { + //region Check input data from "parameters" + if((parameters instanceof Object) === false) + return Promise.reject("The \"parameters\" must has \"Object\" type"); + + if(("safeContents" in parameters) === false) + return Promise.reject("Absent mandatory parameter \"safeContents\""); + + if((parameters.safeContents instanceof Array) === false) + return Promise.reject("The \"parameters.safeContents\" must has \"Array\" type"); + + if(parameters.safeContents.length !== this.safeContents.length) + return Promise.reject("Length of \"parameters.safeContents\" must be equal to \"this.safeContents.length\""); + //endregion + + //region Initial variables + let sequence = Promise.resolve(); + //endregion + + //region Create value for "this.parsedValue.authenticatedSafe" + this.parsedValue = { + safeContents: [] + }; + + for(const [index, content] of this.safeContents.entries()) + { + switch(content.contentType) + { + //region data + case "1.2.840.113549.1.7.1": + { + //region Check that we do have OCTETSTRING as "content" + if((content.content instanceof asn1js.OctetString) === false) + return Promise.reject("Wrong type of \"this.safeContents[j].content\""); + //endregion + + //region Check we have "constructive encoding" for AuthSafe content + let authSafeContent = new ArrayBuffer(0); + + if(content.content.valueBlock.isConstructed) + { + for(const contentValue of content.content.valueBlock.value) + authSafeContent = utilConcatBuf(authSafeContent, contentValue.valueBlock.valueHex); + } + else + authSafeContent = content.content.valueBlock.valueHex; + //endregion + + //region Parse internal ASN.1 data + const asn1 = asn1js.fromBER(authSafeContent); + if(asn1.offset === (-1)) + return Promise.reject("Error during parsing of ASN.1 data inside \"content.content\""); + //endregion + + //region Finilly initialize initial values of "SafeContents" type + this.parsedValue.safeContents.push({ + privacyMode: 0, // No privacy, clear data + value: new SafeContents({ schema: asn1.result }) + }); + //endregion + } + break; + //endregion + //region envelopedData + case "1.2.840.113549.1.7.3": + { + //region Initial variables + const cmsEnveloped = new EnvelopedData({ schema: content.content }); + //endregion + + //region Check mandatory parameters + if(("recipientCertificate" in parameters.safeContents[index]) === false) + return Promise.reject("Absent mandatory parameter \"recipientCertificate\" in \"parameters.safeContents[j]\""); + + const recipientCertificate = parameters.safeContents[index].recipientCertificate; + + if(("recipientKey" in parameters.safeContents[index]) === false) + return Promise.reject("Absent mandatory parameter \"recipientKey\" in \"parameters.safeContents[j]\""); + + // noinspection JSUnresolvedVariable + const recipientKey = parameters.safeContents[index].recipientKey; + //endregion + + //region Decrypt CMS EnvelopedData using first recipient information + sequence = sequence.then( + () => cmsEnveloped.decrypt(0, { + recipientCertificate, + recipientPrivateKey: recipientKey + }) + ); + + sequence = sequence.then( + /** + * @param {ArrayBuffer} result + */ + result => + { + const asn1 = asn1js.fromBER(result); + if(asn1.offset === (-1)) + return Promise.reject("Error during parsing of decrypted data"); + + this.parsedValue.safeContents.push({ + privacyMode: 2, // Public-key privacy mode + value: new SafeContents({ schema: asn1.result }) + }); + + return Promise.resolve(); + } + ); + //endregion + } + break; + //endregion + //region encryptedData + case "1.2.840.113549.1.7.6": + { + //region Initial variables + const cmsEncrypted = new EncryptedData({ schema: content.content }); + //endregion + + //region Check mandatory parameters + if(("password" in parameters.safeContents[index]) === false) + return Promise.reject("Absent mandatory parameter \"password\" in \"parameters.safeContents[j]\""); + + const password = parameters.safeContents[index].password; + //endregion + + //region Decrypt CMS EncryptedData using password + sequence = sequence.then( + () => cmsEncrypted.decrypt({ + password + }), + error => Promise.reject(error) + ); + //endregion + + //region Initialize internal data + sequence = sequence.then( + /** + * @param {ArrayBuffer} result + */ + result => + { + const asn1 = asn1js.fromBER(result); + if(asn1.offset === (-1)) + return Promise.reject("Error during parsing of decrypted data"); + + this.parsedValue.safeContents.push({ + privacyMode: 1, // Password-based privacy mode + value: new SafeContents({ schema: asn1.result }) + }); + + return Promise.resolve(); + }, + error => Promise.reject(error) + ); + //endregion + } + break; + //endregion + //region default + default: + throw new Error(`Unknown "contentType" for AuthenticatedSafe: " ${content.contentType}`); + //endregion + } + } + //endregion + + return sequence; + } + //********************************************************************************** + makeInternalValues(parameters) + { + //region Check data in "parsedValue" + if(("parsedValue" in this) === false) + return Promise.reject("Please run \"parseValues\" first or add \"parsedValue\" manually"); + + if((this.parsedValue instanceof Object) === false) + return Promise.reject("The \"this.parsedValue\" must has \"Object\" type"); + + if((this.parsedValue.safeContents instanceof Array) === false) + return Promise.reject("The \"this.parsedValue.safeContents\" must has \"Array\" type"); + //endregion + + //region Check input data from "parameters" + if((parameters instanceof Object) === false) + return Promise.reject("The \"parameters\" must has \"Object\" type"); + + if(("safeContents" in parameters) === false) + return Promise.reject("Absent mandatory parameter \"safeContents\""); + + if((parameters.safeContents instanceof Array) === false) + return Promise.reject("The \"parameters.safeContents\" must has \"Array\" type"); + + if(parameters.safeContents.length !== this.parsedValue.safeContents.length) + return Promise.reject("Length of \"parameters.safeContents\" must be equal to \"this.parsedValue.safeContents\""); + //endregion + + //region Initial variables + let sequence = Promise.resolve(); + //endregion + + //region Create internal values from already parsed values + this.safeContents = []; + + for(const [index, content] of this.parsedValue.safeContents.entries()) + { + //region Check current "content" value + if(("privacyMode" in content) === false) + return Promise.reject("The \"privacyMode\" is a mandatory parameter for \"content\""); + + if(("value" in content) === false) + return Promise.reject("The \"value\" is a mandatory parameter for \"content\""); + + if((content.value instanceof SafeContents) === false) + return Promise.reject("The \"content.value\" must has \"SafeContents\" type"); + //endregion + + switch(content.privacyMode) + { + //region No privacy + case 0: + { + const contentBuffer = content.value.toSchema().toBER(false); + + sequence = sequence.then( + () => + { + this.safeContents.push(new ContentInfo({ + contentType: "1.2.840.113549.1.7.1", + content: new asn1js.OctetString({ valueHex: contentBuffer }) + })); + }); + } + break; + //endregion + //region Privacy with password + case 1: + { + //region Initial variables + const cmsEncrypted = new EncryptedData(); + + const currentParameters = parameters.safeContents[index]; + currentParameters.contentToEncrypt = content.value.toSchema().toBER(false); + //endregion + + //region Encrypt CMS EncryptedData using password + sequence = sequence.then( + () => cmsEncrypted.encrypt(currentParameters), + error => Promise.reject(error) + ); + //endregion + + //region Store result content in CMS_CONTENT_INFO type + sequence = sequence.then( + () => + { + this.safeContents.push(new ContentInfo({ + contentType: "1.2.840.113549.1.7.6", + content: cmsEncrypted.toSchema() + })); + }, + error => Promise.reject(error) + ); + //endregion + } + break; + //endregion + //region Privacy with public key + case 2: + { + //region Initial variables + const cmsEnveloped = new EnvelopedData(); + const contentToEncrypt = content.value.toSchema().toBER(false); + //endregion + + //region Check mandatory parameters + if(("encryptingCertificate" in parameters.safeContents[index]) === false) + return Promise.reject("Absent mandatory parameter \"encryptingCertificate\" in \"parameters.safeContents[i]\""); + + if(("encryptionAlgorithm" in parameters.safeContents[index]) === false) + return Promise.reject("Absent mandatory parameter \"encryptionAlgorithm\" in \"parameters.safeContents[i]\""); + + switch(true) + { + case (parameters.safeContents[index].encryptionAlgorithm.name.toLowerCase() === "aes-cbc"): + case (parameters.safeContents[index].encryptionAlgorithm.name.toLowerCase() === "aes-gcm"): + break; + default: + return Promise.reject(`Incorrect parameter "encryptionAlgorithm" in "parameters.safeContents[i]": ${parameters.safeContents[index].encryptionAlgorithm}`); + } + + switch(true) + { + case (parameters.safeContents[index].encryptionAlgorithm.length === 128): + case (parameters.safeContents[index].encryptionAlgorithm.length === 192): + case (parameters.safeContents[index].encryptionAlgorithm.length === 256): + break; + default: + return Promise.reject(`Incorrect parameter "encryptionAlgorithm.length" in "parameters.safeContents[i]": ${parameters.safeContents[index].encryptionAlgorithm.length}`); + } + //endregion + + //region Making correct "encryptionAlgorithm" variable + const encryptionAlgorithm = parameters.safeContents[index].encryptionAlgorithm; + //endregion + + //region Append recipient for enveloped data + cmsEnveloped.addRecipientByCertificate(parameters.safeContents[index].encryptingCertificate); + //endregion + + //region Making encryption + sequence = sequence.then( + () => cmsEnveloped.encrypt(encryptionAlgorithm, contentToEncrypt) + ); + + sequence = sequence.then( + () => + { + this.safeContents.push(new ContentInfo({ + contentType: "1.2.840.113549.1.7.3", + content: cmsEnveloped.toSchema() + })); + } + ); + //endregion + } + break; + //endregion + //region default + default: + return Promise.reject(`Incorrect value for "content.privacyMode": ${content.privacyMode}`); + //endregion + } + } + //endregion + + //region Return result of the function + return sequence.then( + () => this, + error => Promise.reject(`Error during parsing: ${error}`) + ); + //endregion + } + //********************************************************************************** +} +//************************************************************************************** diff --git a/core/third-party/pkijs/AuthorityKeyIdentifier.js b/core/third-party/pkijs/AuthorityKeyIdentifier.js new file mode 100644 index 0000000..6f7bbe8 --- /dev/null +++ b/core/third-party/pkijs/AuthorityKeyIdentifier.js @@ -0,0 +1,244 @@ +import * as asn1js from "./asn1.js"; +import { getParametersValue, clearProps } from "./pvutils.js"; +import GeneralName from "./GeneralName.js"; +//************************************************************************************** +/** + * Class from RFC5280 + */ +export default class AuthorityKeyIdentifier +{ + //********************************************************************************** + /** + * Constructor for AuthorityKeyIdentifier class + * @param {Object} [parameters={}] + * @param {Object} [parameters.schema] asn1js parsed value to initialize the class from + */ + constructor(parameters = {}) + { + //region Internal properties of the object + if("keyIdentifier" in parameters) + /** + * @type {OctetString} + * @desc keyIdentifier + */ + this.keyIdentifier = getParametersValue(parameters, "keyIdentifier", AuthorityKeyIdentifier.defaultValues("keyIdentifier")); + + if("authorityCertIssuer" in parameters) + /** + * @type {Array.} + * @desc authorityCertIssuer + */ + this.authorityCertIssuer = getParametersValue(parameters, "authorityCertIssuer", AuthorityKeyIdentifier.defaultValues("authorityCertIssuer")); + + if("authorityCertSerialNumber" in parameters) + /** + * @type {Integer} + * @desc authorityCertIssuer + */ + this.authorityCertSerialNumber = getParametersValue(parameters, "authorityCertSerialNumber", AuthorityKeyIdentifier.defaultValues("authorityCertSerialNumber")); + //endregion + + //region If input argument array contains "schema" for this object + if("schema" in parameters) + this.fromSchema(parameters.schema); + //endregion + } + //********************************************************************************** + /** + * Return default values for all class members + * @param {string} memberName String name for a class member + */ + static defaultValues(memberName) + { + switch(memberName) + { + case "keyIdentifier": + return new asn1js.OctetString(); + case "authorityCertIssuer": + return []; + case "authorityCertSerialNumber": + return new asn1js.Integer(); + default: + throw new Error(`Invalid member name for AuthorityKeyIdentifier class: ${memberName}`); + } + } + //********************************************************************************** + /** + * Return value of pre-defined ASN.1 schema for current class + * + * ASN.1 schema: + * ```asn1 + * AuthorityKeyIdentifier OID ::= 2.5.29.35 + * + * AuthorityKeyIdentifier ::= SEQUENCE { + * keyIdentifier [0] KeyIdentifier OPTIONAL, + * authorityCertIssuer [1] GeneralNames OPTIONAL, + * authorityCertSerialNumber [2] CertificateSerialNumber OPTIONAL } + * + * KeyIdentifier ::= OCTET STRING + * ``` + * + * @param {Object} parameters Input parameters for the schema + * @returns {Object} asn1js schema object + */ + static schema(parameters = {}) + { + /** + * @type {Object} + * @property {string} [blockName] + * @property {string} [keyIdentifier] + * @property {string} [authorityCertIssuer] + * @property {string} [authorityCertSerialNumber] + */ + const names = getParametersValue(parameters, "names", {}); + + return (new asn1js.Sequence({ + name: (names.blockName || ""), + value: [ + new asn1js.Primitive({ + name: (names.keyIdentifier || ""), + optional: true, + idBlock: { + tagClass: 3, // CONTEXT-SPECIFIC + tagNumber: 0 // [0] + } + }), + new asn1js.Constructed({ + optional: true, + idBlock: { + tagClass: 3, // CONTEXT-SPECIFIC + tagNumber: 1 // [1] + }, + value: [ + new asn1js.Repeated({ + name: (names.authorityCertIssuer || ""), + value: GeneralName.schema() + }) + ] + }), + new asn1js.Primitive({ + name: (names.authorityCertSerialNumber || ""), + optional: true, + idBlock: { + tagClass: 3, // CONTEXT-SPECIFIC + tagNumber: 2 // [2] + } + }) + ] + })); + } + //********************************************************************************** + /** + * Convert parsed asn1js object into current class + * @param {!Object} schema + */ + fromSchema(schema) + { + //region Clear input data first + clearProps(schema, [ + "keyIdentifier", + "authorityCertIssuer", + "authorityCertSerialNumber" + ]); + //endregion + + //region Check the schema is valid + const asn1 = asn1js.compareSchema(schema, + schema, + AuthorityKeyIdentifier.schema({ + names: { + keyIdentifier: "keyIdentifier", + authorityCertIssuer: "authorityCertIssuer", + authorityCertSerialNumber: "authorityCertSerialNumber" + } + }) + ); + + if(asn1.verified === false) + throw new Error("Object's schema was not verified against input data for AuthorityKeyIdentifier"); + //endregion + + //region Get internal properties from parsed schema + if("keyIdentifier" in asn1.result) + this.keyIdentifier = new asn1js.OctetString({ valueHex: asn1.result.keyIdentifier.valueBlock.valueHex }); + + if("authorityCertIssuer" in asn1.result) + this.authorityCertIssuer = Array.from(asn1.result.authorityCertIssuer, element => new GeneralName({ schema: element })); + + if("authorityCertSerialNumber" in asn1.result) + this.authorityCertSerialNumber = new asn1js.Integer({ valueHex: asn1.result.authorityCertSerialNumber.valueBlock.valueHex }); + //endregion + } + //********************************************************************************** + /** + * Convert current object to asn1js object and set correct values + * @returns {Object} asn1js object + */ + toSchema() + { + //region Create array for output sequence + const outputArray = []; + + if("keyIdentifier" in this) + { + outputArray.push(new asn1js.Primitive({ + idBlock: { + tagClass: 3, // CONTEXT-SPECIFIC + tagNumber: 0 // [0] + }, + valueHex: this.keyIdentifier.valueBlock.valueHex + })); + } + + if("authorityCertIssuer" in this) + { + outputArray.push(new asn1js.Constructed({ + idBlock: { + tagClass: 3, // CONTEXT-SPECIFIC + tagNumber: 1 // [1] + }, + value: Array.from(this.authorityCertIssuer, element => element.toSchema()) + })); + } + + if("authorityCertSerialNumber" in this) + { + outputArray.push(new asn1js.Primitive({ + idBlock: { + tagClass: 3, // CONTEXT-SPECIFIC + tagNumber: 2 // [2] + }, + valueHex: this.authorityCertSerialNumber.valueBlock.valueHex + })); + } + //endregion + + //region Construct and return new ASN.1 schema for this object + return (new asn1js.Sequence({ + value: outputArray + })); + //endregion + } + //********************************************************************************** + /** + * Convertion for the class to JSON object + * @returns {Object} + */ + toJSON() + { + const object = {}; + + if("keyIdentifier" in this) + object.keyIdentifier = this.keyIdentifier.toJSON(); + + if("authorityCertIssuer" in this) + object.authorityCertIssuer = Array.from(this.authorityCertIssuer, element => element.toJSON()); + + if("authorityCertSerialNumber" in this) + object.authorityCertSerialNumber = this.authorityCertSerialNumber.toJSON(); + + return object; + } + //********************************************************************************** +} +//************************************************************************************** diff --git a/core/third-party/pkijs/BasicConstraints.js b/core/third-party/pkijs/BasicConstraints.js new file mode 100644 index 0000000..9581b3d --- /dev/null +++ b/core/third-party/pkijs/BasicConstraints.js @@ -0,0 +1,186 @@ +import * as asn1js from "./asn1.js"; +import { getParametersValue, clearProps } from "./pvutils.js"; +//************************************************************************************** +/** + * Class from RFC5280 + */ +export default class BasicConstraints +{ + //********************************************************************************** + /** + * Constructor for BasicConstraints class + * @param {Object} [parameters={}] + * @param {Object} [parameters.schema] asn1js parsed value to initialize the class from + * @property {Object} [cA] + * @property {Object} [pathLenConstraint] + */ + constructor(parameters = {}) + { + //region Internal properties of the object + /** + * @type {boolean} + * @desc cA + */ + this.cA = getParametersValue(parameters, "cA", false); + + if("pathLenConstraint" in parameters) + /** + * @type {number|Integer} + * @desc pathLenConstraint + */ + this.pathLenConstraint = getParametersValue(parameters, "pathLenConstraint", 0); + //endregion + + //region If input argument array contains "schema" for this object + if("schema" in parameters) + this.fromSchema(parameters.schema); + //endregion + } + //********************************************************************************** + /** + * Return default values for all class members + * @param {string} memberName String name for a class member + */ + static defaultValues(memberName) + { + switch(memberName) + { + case "cA": + return false; + default: + throw new Error(`Invalid member name for BasicConstraints class: ${memberName}`); + } + } + //********************************************************************************** + /** + * Return value of pre-defined ASN.1 schema for current class + * + * ASN.1 schema: + * ```asn1 + * BasicConstraints ::= SEQUENCE { + * cA BOOLEAN DEFAULT FALSE, + * pathLenConstraint INTEGER (0..MAX) OPTIONAL } + * ``` + * + * @param {Object} parameters Input parameters for the schema + * @returns {Object} asn1js schema object + */ + static schema(parameters = {}) + { + /** + * @type {Object} + * @property {string} [blockName] + * @property {string} [cA] + * @property {string} [pathLenConstraint] + */ + const names = getParametersValue(parameters, "names", {}); + + return (new asn1js.Sequence({ + name: (names.blockName || ""), + value: [ + new asn1js.Boolean({ + optional: true, + name: (names.cA || "") + }), + new asn1js.Integer({ + optional: true, + name: (names.pathLenConstraint || "") + }) + ] + })); + } + //********************************************************************************** + /** + * Convert parsed asn1js object into current class + * @param {!Object} schema + */ + fromSchema(schema) + { + //region Clear input data first + clearProps(schema, [ + "cA", + "pathLenConstraint" + ]); + //endregion + + //region Check the schema is valid + const asn1 = asn1js.compareSchema(schema, + schema, + BasicConstraints.schema({ + names: { + cA: "cA", + pathLenConstraint: "pathLenConstraint" + } + }) + ); + + if(asn1.verified === false) + throw new Error("Object's schema was not verified against input data for BasicConstraints"); + //endregion + + //region Get internal properties from parsed schema + if("cA" in asn1.result) + this.cA = asn1.result.cA.valueBlock.value; + + if("pathLenConstraint" in asn1.result) + { + if(asn1.result.pathLenConstraint.valueBlock.isHexOnly) + this.pathLenConstraint = asn1.result.pathLenConstraint; + else + this.pathLenConstraint = asn1.result.pathLenConstraint.valueBlock.valueDec; + } + //endregion + } + //********************************************************************************** + /** + * Convert current object to asn1js object and set correct values + * @returns {Object} asn1js object + */ + toSchema() + { + //region Create array for output sequence + const outputArray = []; + + if(this.cA !== BasicConstraints.defaultValues("cA")) + outputArray.push(new asn1js.Boolean({ value: this.cA })); + + if("pathLenConstraint" in this) + { + if(this.pathLenConstraint instanceof asn1js.Integer) + outputArray.push(this.pathLenConstraint); + else + outputArray.push(new asn1js.Integer({ value: this.pathLenConstraint })); + } + //endregion + + //region Construct and return new ASN.1 schema for this object + return (new asn1js.Sequence({ + value: outputArray + })); + //endregion + } + //********************************************************************************** + /** + * Convertion for the class to JSON object + * @returns {Object} + */ + toJSON() + { + const object = {}; + + if(this.cA !== BasicConstraints.defaultValues("cA")) + object.cA = this.cA; + + if("pathLenConstraint" in this) + { + if(this.pathLenConstraint instanceof asn1js.Integer) + object.pathLenConstraint = this.pathLenConstraint.toJSON(); + else + object.pathLenConstraint = this.pathLenConstraint; + } + + return object; + } + //********************************************************************************** +} +//************************************************************************************** diff --git a/core/third-party/pkijs/BasicOCSPResponse.js b/core/third-party/pkijs/BasicOCSPResponse.js new file mode 100644 index 0000000..3094dea --- /dev/null +++ b/core/third-party/pkijs/BasicOCSPResponse.js @@ -0,0 +1,562 @@ +import * as asn1js from "./asn1.js"; +import { getParametersValue, isEqualBuffer, clearProps } from "./pvutils.js"; +import { getAlgorithmByOID, getCrypto, getEngine } from "./common.js"; +import ResponseData from "./ResponseData.js"; +import AlgorithmIdentifier from "./AlgorithmIdentifier.js"; +import Certificate from "./Certificate.js"; +import CertID from "./CertID.js"; +import RelativeDistinguishedNames from "./RelativeDistinguishedNames.js"; +import CertificateChainValidationEngine from "./CertificateChainValidationEngine.js"; +//************************************************************************************** +/** + * Class from RFC6960 + */ +export default class BasicOCSPResponse +{ + //********************************************************************************** + /** + * Constructor for BasicOCSPResponse class + * @param {Object} [parameters={}] + * @param {Object} [parameters.schema] asn1js parsed value to initialize the class from + */ + constructor(parameters = {}) + { + //region Internal properties of the object + /** + * @type {ResponseData} + * @desc tbsResponseData + */ + this.tbsResponseData = getParametersValue(parameters, "tbsResponseData", BasicOCSPResponse.defaultValues("tbsResponseData")); + /** + * @type {AlgorithmIdentifier} + * @desc signatureAlgorithm + */ + this.signatureAlgorithm = getParametersValue(parameters, "signatureAlgorithm", BasicOCSPResponse.defaultValues("signatureAlgorithm")); + /** + * @type {BitString} + * @desc signature + */ + this.signature = getParametersValue(parameters, "signature", BasicOCSPResponse.defaultValues("signature")); + + if("certs" in parameters) + /** + * @type {Array.} + * @desc certs + */ + this.certs = getParametersValue(parameters, "certs", BasicOCSPResponse.defaultValues("certs")); + //endregion + + //region If input argument array contains "schema" for this object + if("schema" in parameters) + this.fromSchema(parameters.schema); + //endregion + } + //********************************************************************************** + /** + * Return default values for all class members + * @param {string} memberName String name for a class member + */ + static defaultValues(memberName) + { + switch(memberName) + { + case "tbsResponseData": + return new ResponseData(); + case "signatureAlgorithm": + return new AlgorithmIdentifier(); + case "signature": + return new asn1js.BitString(); + case "certs": + return []; + default: + throw new Error(`Invalid member name for BasicOCSPResponse class: ${memberName}`); + } + } + //********************************************************************************** + /** + * Compare values with default values for all class members + * @param {string} memberName String name for a class member + * @param {*} memberValue Value to compare with default value + */ + static compareWithDefault(memberName, memberValue) + { + switch(memberName) + { + case "type": + { + // noinspection OverlyComplexBooleanExpressionJS + let comparisonResult = ((ResponseData.compareWithDefault("tbs", memberValue.tbs)) && + (ResponseData.compareWithDefault("responderID", memberValue.responderID)) && + (ResponseData.compareWithDefault("producedAt", memberValue.producedAt)) && + (ResponseData.compareWithDefault("responses", memberValue.responses))); + + if("responseExtensions" in memberValue) + comparisonResult = comparisonResult && (ResponseData.compareWithDefault("responseExtensions", memberValue.responseExtensions)); + + return comparisonResult; + } + case "signatureAlgorithm": + return ((memberValue.algorithmId === "") && (("algorithmParams" in memberValue) === false)); + case "signature": + return (memberValue.isEqual(BasicOCSPResponse.defaultValues(memberName))); + case "certs": + return (memberValue.length === 0); + default: + throw new Error(`Invalid member name for BasicOCSPResponse class: ${memberName}`); + } + } + //********************************************************************************** + /** + * Return value of pre-defined ASN.1 schema for current class + * + * ASN.1 schema: + * ```asn1 + * BasicOCSPResponse ::= SEQUENCE { + * tbsResponseData ResponseData, + * signatureAlgorithm AlgorithmIdentifier, + * signature BIT STRING, + * certs [0] EXPLICIT SEQUENCE OF Certificate OPTIONAL } + * ``` + * + * @param {Object} parameters Input parameters for the schema + * @returns {Object} asn1js schema object + */ + static schema(parameters = {}) + { + /** + * @type {Object} + * @property {string} [blockName] + * @property {string} [tbsResponseData] + * @property {string} [signatureAlgorithm] + * @property {string} [signature] + * @property {string} [certs] + */ + const names = getParametersValue(parameters, "names", {}); + + return (new asn1js.Sequence({ + name: (names.blockName || "BasicOCSPResponse"), + value: [ + ResponseData.schema(names.tbsResponseData || { + names: { + blockName: "BasicOCSPResponse.tbsResponseData" + } + }), + AlgorithmIdentifier.schema(names.signatureAlgorithm || { + names: { + blockName: "BasicOCSPResponse.signatureAlgorithm" + } + }), + new asn1js.BitString({ name: (names.signature || "BasicOCSPResponse.signature") }), + new asn1js.Constructed({ + optional: true, + idBlock: { + tagClass: 3, // CONTEXT-SPECIFIC + tagNumber: 0 // [0] + }, + value: [ + new asn1js.Sequence({ + value: [new asn1js.Repeated({ + name: "BasicOCSPResponse.certs", + value: Certificate.schema(names.certs || {}) + })] + }) + ] + }) + ] + })); + } + //********************************************************************************** + /** + * Convert parsed asn1js object into current class + * @param {!Object} schema + */ + fromSchema(schema) + { + //region Clear input data first + clearProps(schema, [ + "BasicOCSPResponse.tbsResponseData", + "BasicOCSPResponse.signatureAlgorithm", + "BasicOCSPResponse.signature", + "BasicOCSPResponse.certs" + ]); + //endregion + + //region Check the schema is valid + const asn1 = asn1js.compareSchema(schema, + schema, + BasicOCSPResponse.schema() + ); + + if(asn1.verified === false) + throw new Error("Object's schema was not verified against input data for BasicOCSPResponse"); + //endregion + + //region Get internal properties from parsed schema + this.tbsResponseData = new ResponseData({ schema: asn1.result["BasicOCSPResponse.tbsResponseData"] }); + this.signatureAlgorithm = new AlgorithmIdentifier({ schema: asn1.result["BasicOCSPResponse.signatureAlgorithm"] }); + this.signature = asn1.result["BasicOCSPResponse.signature"]; + + if("BasicOCSPResponse.certs" in asn1.result) + this.certs = Array.from(asn1.result["BasicOCSPResponse.certs"], element => new Certificate({ schema: element })); + //endregion + } + //********************************************************************************** + /** + * Convert current object to asn1js object and set correct values + * @returns {Object} asn1js object + */ + toSchema() + { + //region Create array for output sequence + const outputArray = []; + + outputArray.push(this.tbsResponseData.toSchema()); + outputArray.push(this.signatureAlgorithm.toSchema()); + outputArray.push(this.signature); + + //region Create array of certificates + if("certs" in this) + { + outputArray.push(new asn1js.Constructed({ + idBlock: { + tagClass: 3, // CONTEXT-SPECIFIC + tagNumber: 0 // [0] + }, + value: [ + new asn1js.Sequence({ + value: Array.from(this.certs, element => element.toSchema()) + }) + ] + })); + } + //endregion + //endregion + + //region Construct and return new ASN.1 schema for this object + return (new asn1js.Sequence({ + value: outputArray + })); + //endregion + } + //********************************************************************************** + /** + * Convertion for the class to JSON object + * @returns {Object} + */ + toJSON() + { + const _object = { + tbsResponseData: this.tbsResponseData.toJSON(), + signatureAlgorithm: this.signatureAlgorithm.toJSON(), + signature: this.signature.toJSON() + }; + + if("certs" in this) + _object.certs = Array.from(this.certs, element => element.toJSON()); + + return _object; + } + //********************************************************************************** + /** + * Get OCSP response status for specific certificate + * @param {Certificate} certificate Certificate to be checked + * @param {Certificate} issuerCertificate Certificate of issuer for certificate to be checked + * @returns {Promise} + */ + getCertificateStatus(certificate, issuerCertificate) + { + //region Initial variables + let sequence = Promise.resolve(); + + const result = { + isForCertificate: false, + status: 2 // 0 = good, 1 = revoked, 2 = unknown + }; + + const hashesObject = {}; + + const certIDs = []; + const certIDPromises = []; + //endregion + + //region Create all "certIDs" for input certificates + for(const response of this.tbsResponseData.responses) + { + const hashAlgorithm = getAlgorithmByOID(response.certID.hashAlgorithm.algorithmId); + if(("name" in hashAlgorithm) === false) + return Promise.reject(`Wrong CertID hashing algorithm: ${response.certID.hashAlgorithm.algorithmId}`); + + if((hashAlgorithm.name in hashesObject) === false) + { + hashesObject[hashAlgorithm.name] = 1; + + const certID = new CertID(); + + certIDs.push(certID); + certIDPromises.push(certID.createForCertificate(certificate, { + hashAlgorithm: hashAlgorithm.name, + issuerCertificate + })); + } + } + + sequence = sequence.then(() => + Promise.all(certIDPromises) + ); + //endregion + + //region Compare all response's "certIDs" with identifiers for input certificate + sequence = sequence.then(() => + { + for(const response of this.tbsResponseData.responses) + { + for(const id of certIDs) + { + if(response.certID.isEqual(id)) + { + result.isForCertificate = true; + + try + { + switch(response.certStatus.idBlock.isConstructed) + { + case true: + if(response.certStatus.idBlock.tagNumber === 1) + result.status = 1; // revoked + + break; + case false: + switch(response.certStatus.idBlock.tagNumber) + { + case 0: // good + result.status = 0; + break; + case 2: // unknown + result.status = 2; + break; + default: + } + + break; + default: + } + } + catch(ex) + { + } + + return result; + } + } + } + + return result; + }); + //endregion + + return sequence; + } + //********************************************************************************** + /** + * Make signature for current OCSP Basic Response + * @param {Object} privateKey Private key for "subjectPublicKeyInfo" structure + * @param {string} [hashAlgorithm="SHA-1"] Hashing algorithm. Default SHA-1 + * @returns {Promise} + */ + sign(privateKey, hashAlgorithm = "SHA-1") + { + //region Initial checking + //region Get a private key from function parameter + if(typeof privateKey === "undefined") + return Promise.reject("Need to provide a private key for signing"); + //endregion + //endregion + + //region Initial variables + let sequence = Promise.resolve(); + let parameters; + + const engine = getEngine(); + //endregion + + //region Get a "default parameters" for current algorithm and set correct signature algorithm + sequence = sequence.then(() => engine.subtle.getSignatureParameters(privateKey, hashAlgorithm)); + + sequence = sequence.then(result => + { + parameters = result.parameters; + this.signatureAlgorithm = result.signatureAlgorithm; + }); + //endregion + + //region Create TBS data for signing + sequence = sequence.then(() => + { + this.tbsResponseData.tbs = this.tbsResponseData.toSchema(true).toBER(false); + }); + //endregion + + //region Signing TBS data on provided private key + sequence = sequence.then(() => engine.subtle.signWithPrivateKey(this.tbsResponseData.tbs, privateKey, parameters)); + + sequence = sequence.then(result => + { + this.signature = new asn1js.BitString({ valueHex: result }); + }); + //endregion + + return sequence; + } + //********************************************************************************** + /** + * Verify existing OCSP Basic Response + * @param {Object} parameters Additional parameters + * @returns {Promise} + */ + verify(parameters = {}) + { + //region Initial variables + let signerCert = null; + + let certIndex = -1; + + let sequence = Promise.resolve(); + + let trustedCerts = []; + + const _this = this; + + const engine = getEngine(); + //endregion + + //region Check amount of certificates + if(("certs" in this) === false) + return Promise.reject("No certificates attached to the BasicOCSPResponce"); + //endregion + + //region Get input values + if("trustedCerts" in parameters) + trustedCerts = parameters.trustedCerts; + //endregion + + //region Aux functions + /** + * Check CA flag for the certificate + * @param {Certificate} cert Certificate to find CA flag for + * @returns {*} + */ + function checkCA(cert) + { + //region Do not include signer's certificate + if((cert.issuer.isEqual(signerCert.issuer) === true) && (cert.serialNumber.isEqual(signerCert.serialNumber) === true)) + return null; + //endregion + + let isCA = false; + + for(const extension of cert.extensions) + { + if(extension.extnID === "2.5.29.19") // BasicConstraints + { + if("cA" in extension.parsedValue) + { + if(extension.parsedValue.cA === true) + isCA = true; + } + } + } + + if(isCA) + return cert; + + return null; + } + //endregion + + //region Get a "crypto" extension + const crypto = getCrypto(); + if(typeof crypto === "undefined") + return Promise.reject("Unable to create WebCrypto object"); + //endregion + + //region Find correct value for "responderID" + switch(true) + { + case (this.tbsResponseData.responderID instanceof RelativeDistinguishedNames): // [1] Name + sequence = sequence.then(() => + { + for(const [index, certificate] of _this.certs.entries()) + { + if(certificate.subject.isEqual(_this.tbsResponseData.responderID)) + { + certIndex = index; + break; + } + } + }); + break; + case (this.tbsResponseData.responderID instanceof asn1js.OctetString): // [2] KeyHash + sequence = sequence.then(() => Promise.all(Array.from(_this.certs, element => + crypto.digest({ name: "sha-1" }, new Uint8Array(element.subjectPublicKeyInfo.subjectPublicKey.valueBlock.valueHex)))).then(results => + { + for(const [index, ] of _this.certs.entries()) + { + if(isEqualBuffer(results[index], _this.tbsResponseData.responderID.valueBlock.valueHex)) + { + certIndex = index; + break; + } + } + })); + break; + default: + return Promise.reject("Wrong value for responderID"); + } + //endregion + + //region Make additional verification for signer's certificate + sequence = sequence.then(() => + { + if(certIndex === (-1)) + return Promise.reject("Correct certificate was not found in OCSP response"); + + signerCert = this.certs[certIndex]; + + return Promise.all(Array.from(_this.certs, element => checkCA(element))).then(promiseResults => + { + const additionalCerts = []; + additionalCerts.push(signerCert); + + for(const promiseResult of promiseResults) + { + if(promiseResult !== null) + additionalCerts.push(promiseResult); + } + + const certChain = new CertificateChainValidationEngine({ + certs: additionalCerts, + trustedCerts + }); + + return certChain.verify().then(verificationResult => + { + if(verificationResult.result === true) + return Promise.resolve(); + + return Promise.reject("Validation of signer's certificate failed"); + }, error => + Promise.reject(`Validation of signer's certificate failed with error: ${((error instanceof Object) ? error.resultMessage : error)}`) + ); + }, promiseError => + Promise.reject(`Error during checking certificates for CA flag: ${promiseError}`) + ); + }); + //endregion + + sequence = sequence.then(() => engine.subtle.verifyWithPublicKey(this.tbsResponseData.tbs, this.signature, this.certs[certIndex].subjectPublicKeyInfo, this.signatureAlgorithm)); + + return sequence; + } + //********************************************************************************** +} +//************************************************************************************** diff --git a/core/third-party/pkijs/CAVersion.js b/core/third-party/pkijs/CAVersion.js new file mode 100644 index 0000000..6cff338 --- /dev/null +++ b/core/third-party/pkijs/CAVersion.js @@ -0,0 +1,181 @@ +import * as asn1js from "./asn1.js"; +import { getParametersValue, utilConcatBuf } from "./pvutils.js"; +//************************************************************************************** +/** + * Class from https://docs.microsoft.com/en-us/windows/desktop/seccrypto/certification-authority-renewal + */ +export default class CAVersion +{ + //********************************************************************************** + /** + * Constructor for CAVersion class + * @param {Object} [parameters={}] + * @param {Object} [parameters.schema] asn1js parsed value to initialize the class from + */ + constructor(parameters = {}) + { + //region Internal properties of the object + /** + * @type {number} + * @desc certificateIndex + */ + this.certificateIndex = getParametersValue(parameters, "certificateIndex", CAVersion.defaultValues("certificateIndex")); + + /** + * @type {number} + * @desc keyIndex + */ + this.keyIndex = getParametersValue(parameters, "keyIndex", CAVersion.defaultValues("keyIndex")); + //endregion + + //region If input argument array contains "schema" for this object + if("schema" in parameters) + this.fromSchema(parameters.schema); + //endregion + } + //********************************************************************************** + /** + * Return default values for all class members + * @param {string} memberName String name for a class member + */ + static defaultValues(memberName) + { + switch(memberName) + { + case "certificateIndex": + case "keyIndex": + return 0; + default: + throw new Error(`Invalid member name for CAVersion class: ${memberName}`); + } + } + //********************************************************************************** + /** + * Return value of pre-defined ASN.1 schema for current class + * + * ASN.1 schema: + * ```asn1 + * CAVersion ::= INTEGER + * ``` + * + * @param {Object} parameters Input parameters for the schema + * @returns {Object} asn1js schema object + */ + static schema(parameters = {}) + { + return (new asn1js.Integer()); + } + //********************************************************************************** + /** + * Convert parsed asn1js object into current class + * @param {!Object} schema + */ + fromSchema(schema) + { + //region Check the schema is valid + if(schema.constructor.blockName() !== asn1js.Integer.blockName()) + throw new Error("Object's schema was not verified against input data for CAVersion"); + //endregion + + //region Check length of the input value and correct it if needed + let value = schema.valueBlock.valueHex.slice(0); + const valueView = new Uint8Array(value); + + switch(true) + { + case (value.byteLength < 4): + { + const tempValue = new ArrayBuffer(4); + const tempValueView = new Uint8Array(tempValue); + + tempValueView.set(valueView, 4 - value.byteLength); + + value = tempValue.slice(0); + } + break; + case (value.byteLength > 4): + { + const tempValue = new ArrayBuffer(4); + const tempValueView = new Uint8Array(tempValue); + + tempValueView.set(valueView.slice(0, 4)); + + value = tempValue.slice(0); + } + break; + default: + } + //endregion + + //region Get internal properties from parsed schema + const keyIndexBuffer = value.slice(0, 2); + const keyIndexView8 = new Uint8Array(keyIndexBuffer); + let temp = keyIndexView8[0]; + keyIndexView8[0] = keyIndexView8[1]; + keyIndexView8[1] = temp; + + const keyIndexView16 = new Uint16Array(keyIndexBuffer); + + this.keyIndex = keyIndexView16[0]; + + const certificateIndexBuffer = value.slice(2); + const certificateIndexView8 = new Uint8Array(certificateIndexBuffer); + temp = certificateIndexView8[0]; + certificateIndexView8[0] = certificateIndexView8[1]; + certificateIndexView8[1] = temp; + + const certificateIndexView16 = new Uint16Array(certificateIndexBuffer); + + this.certificateIndex = certificateIndexView16[0]; + //endregion + } + //********************************************************************************** + /** + * Convert current object to asn1js object and set correct values + * @returns {Object} asn1js object + */ + toSchema() + { + //region Create raw values + const certificateIndexBuffer = new ArrayBuffer(2); + const certificateIndexView = new Uint16Array(certificateIndexBuffer); + + certificateIndexView[0] = this.certificateIndex; + + const certificateIndexView8 = new Uint8Array(certificateIndexBuffer); + let temp = certificateIndexView8[0]; + certificateIndexView8[0] = certificateIndexView8[1]; + certificateIndexView8[1] = temp; + + const keyIndexBuffer = new ArrayBuffer(2); + const keyIndexView = new Uint16Array(keyIndexBuffer); + + keyIndexView[0] = this.keyIndex; + + const keyIndexView8 = new Uint8Array(keyIndexBuffer); + temp = keyIndexView8[0]; + keyIndexView8[0] = keyIndexView8[1]; + keyIndexView8[1] = temp; + //endregion + + //region Construct and return new ASN.1 schema for this object + return (new asn1js.Integer({ + valueHex: utilConcatBuf(keyIndexBuffer, certificateIndexBuffer) + })); + //endregion + } + //********************************************************************************** + /** + * Convertion for the class to JSON object + * @returns {Object} + */ + toJSON() + { + return { + certificateIndex: this.certificateIndex, + keyIndex: this.keyIndex + }; + } + //********************************************************************************** +} +//************************************************************************************** diff --git a/core/third-party/pkijs/CRLBag.js b/core/third-party/pkijs/CRLBag.js new file mode 100644 index 0000000..9c1318e --- /dev/null +++ b/core/third-party/pkijs/CRLBag.js @@ -0,0 +1,209 @@ +import * as asn1js from "./asn1.js"; +import { getParametersValue, clearProps } from "./pvutils.js"; +import CertificateRevocationList from "./CertificateRevocationList.js"; +//************************************************************************************** +/** + * Class from RFC7292 + */ +export default class CRLBag +{ + //********************************************************************************** + /** + * Constructor for CRLBag class + * @param {Object} [parameters={}] + * @param {Object} [parameters.schema] asn1js parsed value to initialize the class from + */ + constructor(parameters = {}) + { + //region Internal properties of the object + /** + * @type {string} + * @desc crlId + */ + this.crlId = getParametersValue(parameters, "crlId", CRLBag.defaultValues("crlId")); + /** + * @type {*} + * @desc crlValue + */ + this.crlValue = getParametersValue(parameters, "crlValue", CRLBag.defaultValues("crlValue")); + + if("parsedValue" in parameters) + /** + * @type {*} + * @desc parsedValue + */ + this.parsedValue = getParametersValue(parameters, "parsedValue", CRLBag.defaultValues("parsedValue")); + //endregion + + //region If input argument array contains "schema" for this object + if("schema" in parameters) + this.fromSchema(parameters.schema); + //endregion + } + //********************************************************************************** + /** + * Return default values for all class members + * @param {string} memberName String name for a class member + */ + static defaultValues(memberName) + { + switch(memberName) + { + case "crlId": + return ""; + case "crlValue": + return (new asn1js.Any()); + case "parsedValue": + return {}; + default: + throw new Error(`Invalid member name for CRLBag class: ${memberName}`); + } + } + //********************************************************************************** + /** + * Compare values with default values for all class members + * @param {string} memberName String name for a class member + * @param {*} memberValue Value to compare with default value + */ + static compareWithDefault(memberName, memberValue) + { + switch(memberName) + { + case "crlId": + return (memberValue === ""); + case "crlValue": + return (memberValue instanceof asn1js.Any); + case "parsedValue": + return ((memberValue instanceof Object) && (Object.keys(memberValue).length === 0)); + default: + throw new Error(`Invalid member name for CRLBag class: ${memberName}`); + } + } + //********************************************************************************** + /** + * Return value of pre-defined ASN.1 schema for current class + * + * ASN.1 schema: + * ```asn1 + * CRLBag ::= SEQUENCE { + * crlId BAG-TYPE.&id ({CRLTypes}), + * crlValue [0] EXPLICIT BAG-TYPE.&Type ({CRLTypes}{@crlId}) + *} + * ``` + * + * @param {Object} parameters Input parameters for the schema + * @returns {Object} asn1js schema object + */ + static schema(parameters = {}) + { + /** + * @type {Object} + * @property {string} [blockName] + * @property {string} [id] + * @property {string} [value] + */ + const names = getParametersValue(parameters, "names", {}); + + return (new asn1js.Sequence({ + name: (names.blockName || ""), + value: [ + new asn1js.ObjectIdentifier({ name: (names.id || "id") }), + new asn1js.Constructed({ + idBlock: { + tagClass: 3, // CONTEXT-SPECIFIC + tagNumber: 0 // [0] + }, + value: [new asn1js.Any({ name: (names.value || "value") })] // EXPLICIT ANY value + }) + ] + })); + } + //********************************************************************************** + /** + * Convert parsed asn1js object into current class + * @param {!Object} schema + */ + fromSchema(schema) + { + //region Clear input data first + clearProps(schema, [ + "crlId", + "crlValue" + ]); + //endregion + + //region Check the schema is valid + const asn1 = asn1js.compareSchema(schema, + schema, + CRLBag.schema({ + names: { + id: "crlId", + value: "crlValue" + } + }) + ); + + if(asn1.verified === false) + throw new Error("Object's schema was not verified against input data for CRLBag"); + //endregion + + //region Get internal properties from parsed schema + this.crlId = asn1.result.crlId.valueBlock.toString(); + this.crlValue = asn1.result.crlValue; + + switch(this.crlId) + { + case "1.2.840.113549.1.9.23.1": // x509CRL + { + const asn1Inner = asn1js.fromBER(this.certValue.valueBlock.valueHex); + this.parsedValue = new CertificateRevocationList({ schema: asn1Inner.result }); + } + break; + default: + throw new Error(`Incorrect "crlId" value in CRLBag: ${this.crlId}`); + } + //endregion + } + //********************************************************************************** + /** + * Convert current object to asn1js object and set correct values + * @returns {Object} asn1js object + */ + toSchema() + { + //region Construct and return new ASN.1 schema for this object + if("parsedValue" in this) + { + this.certId = "1.2.840.113549.1.9.23.1"; + this.certValue = new asn1js.OctetString({ valueHex: this.parsedValue.toSchema().toBER(false) }); + } + + return (new asn1js.Sequence({ + value: [ + new asn1js.ObjectIdentifier({ value: this.crlId }), + new asn1js.Constructed({ + idBlock: { + tagClass: 3, // CONTEXT-SPECIFIC + tagNumber: 0 // [0] + }, + value: [this.crlValue.toSchema()] + }) + ] + })); + //endregion + } + //********************************************************************************** + /** + * Convertion for the class to JSON object + * @returns {Object} + */ + toJSON() + { + return { + crlId: this.crlId, + crlValue: this.crlValue.toJSON() + }; + } + //********************************************************************************** +} +//************************************************************************************** diff --git a/core/third-party/pkijs/CRLDistributionPoints.js b/core/third-party/pkijs/CRLDistributionPoints.js new file mode 100644 index 0000000..38523c6 --- /dev/null +++ b/core/third-party/pkijs/CRLDistributionPoints.js @@ -0,0 +1,134 @@ +import * as asn1js from "./asn1.js"; +import { getParametersValue, clearProps } from "./pvutils.js"; +import DistributionPoint from "./DistributionPoint.js"; +//************************************************************************************** +/** + * Class from RFC5280 + */ +export default class CRLDistributionPoints +{ + //********************************************************************************** + /** + * Constructor for CRLDistributionPoints class + * @param {Object} [parameters={}] + * @param {Object} [parameters.schema] asn1js parsed value to initialize the class from + */ + constructor(parameters = {}) + { + //region Internal properties of the object + /** + * @type {Array.} + * @desc distributionPoints + */ + this.distributionPoints = getParametersValue(parameters, "distributionPoints", CRLDistributionPoints.defaultValues("distributionPoints")); + //endregion + + //region If input argument array contains "schema" for this object + if("schema" in parameters) + this.fromSchema(parameters.schema); + //endregion + } + //********************************************************************************** + /** + * Return default values for all class members + * @param {string} memberName String name for a class member + */ + static defaultValues(memberName) + { + switch(memberName) + { + case "distributionPoints": + return []; + default: + throw new Error(`Invalid member name for CRLDistributionPoints class: ${memberName}`); + } + } + //********************************************************************************** + /** + * Return value of pre-defined ASN.1 schema for current class + * + * ASN.1 schema: + * ```asn1 + * CRLDistributionPoints ::= SEQUENCE SIZE (1..MAX) OF DistributionPoint + * ``` + * + * @param {Object} parameters Input parameters for the schema + * @returns {Object} asn1js schema object + */ + static schema(parameters = {}) + { + /** + * @type {Object} + * @property {string} [blockName] + * @property {string} [distributionPoints] + */ + const names = getParametersValue(parameters, "names", {}); + + return (new asn1js.Sequence({ + name: (names.blockName || ""), + value: [ + new asn1js.Repeated({ + name: (names.distributionPoints || ""), + value: DistributionPoint.schema() + }) + ] + })); + } + //********************************************************************************** + /** + * Convert parsed asn1js object into current class + * @param {!Object} schema + */ + fromSchema(schema) + { + //region Clear input data first + clearProps(schema, [ + "distributionPoints" + ]); + //endregion + + //region Check the schema is valid + const asn1 = asn1js.compareSchema(schema, + schema, + CRLDistributionPoints.schema({ + names: { + distributionPoints: "distributionPoints" + } + }) + ); + + if(asn1.verified === false) + throw new Error("Object's schema was not verified against input data for CRLDistributionPoints"); + //endregion + + //region Get internal properties from parsed schema + this.distributionPoints = Array.from(asn1.result.distributionPoints, element => new DistributionPoint({ schema: element })); + //endregion + } + //********************************************************************************** + /** + * Convert current object to asn1js object and set correct values + * @returns {Object} asn1js object + */ + toSchema() + { + //region Construct and return new ASN.1 schema for this object + return (new asn1js.Sequence({ + value: Array.from(this.distributionPoints, element => element.toSchema()) + })); + //endregion + } + //********************************************************************************** + /** + * Convertion for the class to JSON object + * @returns {Object} + */ + toJSON() + { + return { + distributionPoints: Array.from(this.distributionPoints, element => element.toJSON()) + }; + } + //********************************************************************************** +} +//************************************************************************************** diff --git a/core/third-party/pkijs/CertBag.js b/core/third-party/pkijs/CertBag.js new file mode 100644 index 0000000..e02818e --- /dev/null +++ b/core/third-party/pkijs/CertBag.js @@ -0,0 +1,229 @@ +import * as asn1js from "./asn1.js"; +import { getParametersValue, clearProps } from "./pvutils.js"; +import Certificate from "./Certificate.js"; +import AttributeCertificateV2 from "./AttributeCertificateV2.js"; +//************************************************************************************** +/** + * Class from RFC7292 + */ +export default class CertBag +{ + //********************************************************************************** + /** + * Constructor for CertBag class + * @param {Object} [parameters={}] + * @param {Object} [parameters.schema] asn1js parsed value to initialize the class from + */ + constructor(parameters = {}) + { + //region Internal properties of the object + /** + * @type {string} + * @desc certId + */ + this.certId = getParametersValue(parameters, "certId", CertBag.defaultValues("certId")); + /** + * @type {*} + * @desc certValue + */ + this.certValue = getParametersValue(parameters, "certValue", CertBag.defaultValues("certValue")); + + if("parsedValue" in parameters) + /** + * @type {*} + * @desc parsedValue + */ + this.parsedValue = getParametersValue(parameters, "parsedValue", CertBag.defaultValues("parsedValue")); + //endregion + + //region If input argument array contains "schema" for this object + if("schema" in parameters) + this.fromSchema(parameters.schema); + //endregion + } + //********************************************************************************** + /** + * Return default values for all class members + * @param {string} memberName String name for a class member + */ + static defaultValues(memberName) + { + switch(memberName) + { + case "certId": + return ""; + case "certValue": + return (new asn1js.Any()); + case "parsedValue": + return {}; + default: + throw new Error(`Invalid member name for CertBag class: ${memberName}`); + } + } + //********************************************************************************** + /** + * Compare values with default values for all class members + * @param {string} memberName String name for a class member + * @param {*} memberValue Value to compare with default value + */ + static compareWithDefault(memberName, memberValue) + { + switch(memberName) + { + case "certId": + return (memberValue === ""); + case "certValue": + return (memberValue instanceof asn1js.Any); + case "parsedValue": + return ((memberValue instanceof Object) && (Object.keys(memberValue).length === 0)); + default: + throw new Error(`Invalid member name for CertBag class: ${memberName}`); + } + } + //********************************************************************************** + /** + * Return value of pre-defined ASN.1 schema for current class + * + * ASN.1 schema: + * ```asn1 + * CertBag ::= SEQUENCE { + * certId BAG-TYPE.&id ({CertTypes}), + * certValue [0] EXPLICIT BAG-TYPE.&Type ({CertTypes}{@certId}) + * } + * ``` + * + * @param {Object} parameters Input parameters for the schema + * @returns {Object} asn1js schema object + */ + static schema(parameters = {}) + { + /** + * @type {Object} + * @property {string} [blockName] + * @property {string} [id] + * @property {string} [value] + */ + const names = getParametersValue(parameters, "names", {}); + + return (new asn1js.Sequence({ + name: (names.blockName || ""), + value: [ + new asn1js.ObjectIdentifier({ name: (names.id || "id") }), + new asn1js.Constructed({ + idBlock: { + tagClass: 3, // CONTEXT-SPECIFIC + tagNumber: 0 // [0] + }, + value: [new asn1js.Any({ name: (names.value || "value") })] // EXPLICIT ANY value + }) + ] + })); + } + //********************************************************************************** + /** + * Convert parsed asn1js object into current class + * @param {!Object} schema + */ + fromSchema(schema) + { + //region Clear input data first + clearProps(schema, [ + "certId", + "certValue" + ]); + //endregion + + //region Check the schema is valid + const asn1 = asn1js.compareSchema(schema, + schema, + CertBag.schema({ + names: { + id: "certId", + value: "certValue" + } + }) + ); + + if(asn1.verified === false) + throw new Error("Object's schema was not verified against input data for CertBag"); + //endregion + + //region Get internal properties from parsed schema + this.certId = asn1.result.certId.valueBlock.toString(); + this.certValue = asn1.result.certValue; + + switch(this.certId) + { + case "1.2.840.113549.1.9.22.1": // x509Certificate + { + const asn1Inner = asn1js.fromBER(this.certValue.valueBlock.valueHex); + + try + { + this.parsedValue = new Certificate({ schema: asn1Inner.result }); + } + catch(ex) // In some realizations the same OID used for attribute certificates + { + this.parsedValue = new AttributeCertificateV2({ schema: asn1Inner.result }); + } + } + break; + case "1.2.840.113549.1.9.22.3": // attributeCertificate - (!!!) THIS OID IS SUBJECT FOR CHANGE IN FUTURE (!!!) + { + const asn1Inner = asn1js.fromBER(this.certValue.valueBlock.valueHex); + this.parsedValue = new AttributeCertificateV2({ schema: asn1Inner.result }); + } + break; + case "1.2.840.113549.1.9.22.2": // sdsiCertificate + default: + throw new Error(`Incorrect "certId" value in CertBag: ${this.certId}`); + } + //endregion + } + //********************************************************************************** + /** + * Convert current object to asn1js object and set correct values + * @returns {Object} asn1js object + */ + toSchema() + { + //region Construct and return new ASN.1 schema for this object + if("parsedValue" in this) + { + if("acinfo" in this.parsedValue) // attributeCertificate + this.certId = "1.2.840.113549.1.9.22.3"; + else // x509Certificate + this.certId = "1.2.840.113549.1.9.22.1"; + + this.certValue = new asn1js.OctetString({ valueHex: this.parsedValue.toSchema().toBER(false) }); + } + + return (new asn1js.Sequence({ + value: [ + new asn1js.ObjectIdentifier({ value: this.certId }), + new asn1js.Constructed({ + idBlock: { + tagClass: 3, // CONTEXT-SPECIFIC + tagNumber: 0 // [0] + }, + value: [(("toSchema" in this.certValue) ? this.certValue.toSchema() : this.certValue)] + }) + ] + })); + //endregion + } + //********************************************************************************** + /** + * Convertion for the class to JSON object + * @returns {Object} + */ + toJSON() + { + return { + certId: this.certId, + certValue: this.certValue.toJSON() + }; + } + //********************************************************************************** +} +//************************************************************************************** diff --git a/core/third-party/pkijs/CertID.js b/core/third-party/pkijs/CertID.js new file mode 100644 index 0000000..4a288f7 --- /dev/null +++ b/core/third-party/pkijs/CertID.js @@ -0,0 +1,306 @@ +import * as asn1js from "./asn1.js"; +import { getParametersValue, isEqualBuffer, clearProps } from "./pvutils.js"; +import { getCrypto, getOIDByAlgorithm } from "./common.js"; +import AlgorithmIdentifier from "./AlgorithmIdentifier.js"; +//************************************************************************************** +/** + * Class from RFC6960 + */ +export default class CertID +{ + //********************************************************************************** + /** + * Constructor for CertID class + * @param {Object} [parameters={}] + * @param {Object} [parameters.schema] asn1js parsed value to initialize the class from + */ + constructor(parameters = {}) + { + //region Internal properties of the object + /** + * @type {AlgorithmIdentifier} + * @desc hashAlgorithm + */ + this.hashAlgorithm = getParametersValue(parameters, "hashAlgorithm", CertID.defaultValues("hashAlgorithm")); + /** + * @type {OctetString} + * @desc issuerNameHash + */ + this.issuerNameHash = getParametersValue(parameters, "issuerNameHash", CertID.defaultValues("issuerNameHash")); + /** + * @type {OctetString} + * @desc issuerKeyHash + */ + this.issuerKeyHash = getParametersValue(parameters, "issuerKeyHash", CertID.defaultValues("issuerKeyHash")); + /** + * @type {Integer} + * @desc serialNumber + */ + this.serialNumber = getParametersValue(parameters, "serialNumber", CertID.defaultValues("serialNumber")); + //endregion + + //region If input argument array contains "schema" for this object + if("schema" in parameters) + this.fromSchema(parameters.schema); + //endregion + } + //********************************************************************************** + /** + * Return default values for all class members + * @param {string} memberName String name for a class member + */ + static defaultValues(memberName) + { + switch(memberName) + { + case "hashAlgorithm": + return new AlgorithmIdentifier(); + case "issuerNameHash": + case "issuerKeyHash": + return new asn1js.OctetString(); + case "serialNumber": + return new asn1js.Integer(); + default: + throw new Error(`Invalid member name for CertID class: ${memberName}`); + } + } + //********************************************************************************** + /** + * Compare values with default values for all class members + * @param {string} memberName String name for a class member + * @param {*} memberValue Value to compare with default value + */ + static compareWithDefault(memberName, memberValue) + { + switch(memberName) + { + case "hashAlgorithm": + return ((memberValue.algorithmId === "") && (("algorithmParams" in memberValue) === false)); + case "issuerNameHash": + case "issuerKeyHash": + case "serialNumber": + return (memberValue.isEqual(CertID.defaultValues(memberName))); + default: + throw new Error(`Invalid member name for CertID class: ${memberName}`); + } + } + //********************************************************************************** + /** + * Return value of pre-defined ASN.1 schema for current class + * + * ASN.1 schema: + * ```asn1 + * CertID ::= SEQUENCE { + * hashAlgorithm AlgorithmIdentifier, + * issuerNameHash OCTET STRING, -- Hash of issuer's DN + * issuerKeyHash OCTET STRING, -- Hash of issuer's public key + * serialNumber CertificateSerialNumber } + * ``` + * + * @param {Object} parameters Input parameters for the schema + * @returns {Object} asn1js schema object + */ + static schema(parameters = {}) + { + /** + * @type {Object} + * @property {string} [blockName] + * @property {string} [hashAlgorithm] + * @property {string} [hashAlgorithmObject] + * @property {string} [issuerNameHash] + * @property {string} [issuerKeyHash] + * @property {string} [serialNumber] + */ + const names = getParametersValue(parameters, "names", {}); + + return (new asn1js.Sequence({ + name: (names.blockName || ""), + value: [ + AlgorithmIdentifier.schema(names.hashAlgorithmObject || { + names: { + blockName: (names.hashAlgorithm || "") + } + }), + new asn1js.OctetString({ name: (names.issuerNameHash || "") }), + new asn1js.OctetString({ name: (names.issuerKeyHash || "") }), + new asn1js.Integer({ name: (names.serialNumber || "") }) + ] + })); + } + //********************************************************************************** + /** + * Convert parsed asn1js object into current class + * @param {!Object} schema + */ + fromSchema(schema) + { + //region Clear input data first + clearProps(schema, [ + "hashAlgorithm", + "issuerNameHash", + "issuerKeyHash", + "serialNumber" + ]); + //endregion + + //region Check the schema is valid + const asn1 = asn1js.compareSchema(schema, + schema, + CertID.schema({ + names: { + hashAlgorithm: "hashAlgorithm", + issuerNameHash: "issuerNameHash", + issuerKeyHash: "issuerKeyHash", + serialNumber: "serialNumber" + } + }) + ); + + if(asn1.verified === false) + throw new Error("Object's schema was not verified against input data for CertID"); + //endregion + + //region Get internal properties from parsed schema + this.hashAlgorithm = new AlgorithmIdentifier({ schema: asn1.result.hashAlgorithm }); + this.issuerNameHash = asn1.result.issuerNameHash; + this.issuerKeyHash = asn1.result.issuerKeyHash; + this.serialNumber = asn1.result.serialNumber; + //endregion + } + //********************************************************************************** + /** + * Convert current object to asn1js object and set correct values + * @returns {Object} asn1js object + */ + toSchema() + { + //region Construct and return new ASN.1 schema for this object + return (new asn1js.Sequence({ + value: [ + this.hashAlgorithm.toSchema(), + this.issuerNameHash, + this.issuerKeyHash, + this.serialNumber + ] + })); + //endregion + } + //********************************************************************************** + /** + * Convertion for the class to JSON object + * @returns {Object} + */ + toJSON() + { + return { + hashAlgorithm: this.hashAlgorithm.toJSON(), + issuerNameHash: this.issuerNameHash.toJSON(), + issuerKeyHash: this.issuerKeyHash.toJSON(), + serialNumber: this.serialNumber.toJSON() + }; + } + //********************************************************************************** + /** + * Check that two "CertIDs" are equal + * @param {CertID} certificateID Identifier of the certificate to be checked + * @returns {boolean} + */ + isEqual(certificateID) + { + //region Check "hashAlgorithm" + if(!this.hashAlgorithm.algorithmId === certificateID.hashAlgorithm.algorithmId) + return false; + //endregion + + //region Check "issuerNameHash" + if(isEqualBuffer(this.issuerNameHash.valueBlock.valueHex, certificateID.issuerNameHash.valueBlock.valueHex) === false) + return false; + //endregion + + //region Check "issuerKeyHash" + if(isEqualBuffer(this.issuerKeyHash.valueBlock.valueHex, certificateID.issuerKeyHash.valueBlock.valueHex) === false) + return false; + //endregion + + //region Check "serialNumber" + if(!this.serialNumber.isEqual(certificateID.serialNumber)) + return false; + //endregion + + return true; + } + //********************************************************************************** + /** + * Making OCSP certificate identifier for specific certificate + * @param {Certificate} certificate Certificate making OCSP Request for + * @param {Object} parameters Additional parameters + * @returns {Promise} + */ + createForCertificate(certificate, parameters) + { + //region Initial variables + let sequence = Promise.resolve(); + + let issuerCertificate; + //endregion + + //region Get a "crypto" extension + const crypto = getCrypto(); + if(typeof crypto === "undefined") + return Promise.reject("Unable to create WebCrypto object"); + //endregion + + //region Check input parameters + if(("hashAlgorithm" in parameters) === false) + return Promise.reject("Parameter \"hashAlgorithm\" is mandatory for \"OCSP_REQUEST.createForCertificate\""); + + const hashOID = getOIDByAlgorithm({ name: parameters.hashAlgorithm }); + if(hashOID === "") + return Promise.reject(`Incorrect "hashAlgorithm": ${this.hashAlgorithm}`); + + this.hashAlgorithm = new AlgorithmIdentifier({ + algorithmId: hashOID, + algorithmParams: new asn1js.Null() + }); + + if("issuerCertificate" in parameters) + issuerCertificate = parameters.issuerCertificate; + else + return Promise.reject("Parameter \"issuerCertificate\" is mandatory for \"OCSP_REQUEST.createForCertificate\""); + //endregion + + //region Initialize "serialNumber" field + this.serialNumber = certificate.serialNumber; + //endregion + + //region Create "issuerNameHash" + sequence = sequence.then(() => + crypto.digest({ name: parameters.hashAlgorithm }, issuerCertificate.subject.toSchema().toBER(false)), + error => + Promise.reject(error) + ); + //endregion + + //region Create "issuerKeyHash" + sequence = sequence.then(result => + { + this.issuerNameHash = new asn1js.OctetString({ valueHex: result }); + + const issuerKeyBuffer = issuerCertificate.subjectPublicKeyInfo.subjectPublicKey.valueBlock.valueHex; + + return crypto.digest({ name: parameters.hashAlgorithm }, issuerKeyBuffer); + }, error => + Promise.reject(error) + ).then(result => + { + this.issuerKeyHash = new asn1js.OctetString({ valueHex: result }); + }, error => + Promise.reject(error) + ); + //endregion + + return sequence; + } + //********************************************************************************** +} +//************************************************************************************** diff --git a/core/third-party/pkijs/Certificate.js b/core/third-party/pkijs/Certificate.js new file mode 100644 index 0000000..56ca40b --- /dev/null +++ b/core/third-party/pkijs/Certificate.js @@ -0,0 +1,625 @@ +import * as asn1js from "./asn1.js"; +import { getParametersValue, bufferToHexCodes, clearProps } from "./pvutils.js"; +import { getCrypto, getEngine } from "./common.js"; +import AlgorithmIdentifier from "./AlgorithmIdentifier.js"; +import RelativeDistinguishedNames from "./RelativeDistinguishedNames.js"; +import Time from "./Time.js"; +import PublicKeyInfo from "./PublicKeyInfo.js"; +import Extension from "./Extension.js"; +import Extensions from "./Extensions.js"; +//************************************************************************************** +function tbsCertificate(parameters = {}) +{ + //TBSCertificate ::= SEQUENCE { + // version [0] EXPLICIT Version DEFAULT v1, + // serialNumber CertificateSerialNumber, + // signature AlgorithmIdentifier, + // issuer Name, + // validity Validity, + // subject Name, + // subjectPublicKeyInfo SubjectPublicKeyInfo, + // issuerUniqueID [1] IMPLICIT UniqueIdentifier OPTIONAL, + // -- If present, version MUST be v2 or v3 + // subjectUniqueID [2] IMPLICIT UniqueIdentifier OPTIONAL, + // -- If present, version MUST be v2 or v3 + // extensions [3] EXPLICIT Extensions OPTIONAL + // -- If present, version MUST be v3 + //} + + /** + * @type {Object} + * @property {string} [blockName] + * @property {string} [tbsCertificateVersion] + * @property {string} [tbsCertificateSerialNumber] + * @property {string} [signature] + * @property {string} [issuer] + * @property {string} [tbsCertificateValidity] + * @property {string} [notBefore] + * @property {string} [notAfter] + * @property {string} [subject] + * @property {string} [subjectPublicKeyInfo] + * @property {string} [tbsCertificateIssuerUniqueID] + * @property {string} [tbsCertificateSubjectUniqueID] + * @property {string} [extensions] + */ + const names = getParametersValue(parameters, "names", {}); + + return (new asn1js.Sequence({ + name: (names.blockName || "tbsCertificate"), + value: [ + new asn1js.Constructed({ + optional: true, + idBlock: { + tagClass: 3, // CONTEXT-SPECIFIC + tagNumber: 0 // [0] + }, + value: [ + new asn1js.Integer({ name: (names.tbsCertificateVersion || "tbsCertificate.version") }) // EXPLICIT integer value + ] + }), + new asn1js.Integer({ name: (names.tbsCertificateSerialNumber || "tbsCertificate.serialNumber") }), + AlgorithmIdentifier.schema(names.signature || { + names: { + blockName: "tbsCertificate.signature" + } + }), + RelativeDistinguishedNames.schema(names.issuer || { + names: { + blockName: "tbsCertificate.issuer" + } + }), + new asn1js.Sequence({ + name: (names.tbsCertificateValidity || "tbsCertificate.validity"), + value: [ + Time.schema(names.notBefore || { + names: { + utcTimeName: "tbsCertificate.notBefore", + generalTimeName: "tbsCertificate.notBefore" + } + }), + Time.schema(names.notAfter || { + names: { + utcTimeName: "tbsCertificate.notAfter", + generalTimeName: "tbsCertificate.notAfter" + } + }) + ] + }), + RelativeDistinguishedNames.schema(names.subject || { + names: { + blockName: "tbsCertificate.subject" + } + }), + PublicKeyInfo.schema(names.subjectPublicKeyInfo || { + names: { + blockName: "tbsCertificate.subjectPublicKeyInfo" + } + }), + new asn1js.Primitive({ + name: (names.tbsCertificateIssuerUniqueID || "tbsCertificate.issuerUniqueID"), + optional: true, + idBlock: { + tagClass: 3, // CONTEXT-SPECIFIC + tagNumber: 1 // [1] + } + }), // IMPLICIT bistring value + new asn1js.Primitive({ + name: (names.tbsCertificateSubjectUniqueID || "tbsCertificate.subjectUniqueID"), + optional: true, + idBlock: { + tagClass: 3, // CONTEXT-SPECIFIC + tagNumber: 2 // [2] + } + }), // IMPLICIT bistring value + new asn1js.Constructed({ + optional: true, + idBlock: { + tagClass: 3, // CONTEXT-SPECIFIC + tagNumber: 3 // [3] + }, + value: [Extensions.schema(names.extensions || { + names: { + blockName: "tbsCertificate.extensions" + } + })] + }) // EXPLICIT SEQUENCE value + ] + })); +} +//************************************************************************************** +/** + * Class from RFC5280 + */ +export default class Certificate +{ + //********************************************************************************** + /** + * Constructor for Certificate class + * @param {Object} [parameters={}] + * @param {Object} [parameters.schema] asn1js parsed value to initialize the class from + */ + constructor(parameters = {}) + { + //region Internal properties of the object + /** + * @type {ArrayBuffer} + * @desc ToBeSigned (TBS) part of the certificate + */ + this.tbs = getParametersValue(parameters, "tbs", Certificate.defaultValues("tbs")); + /** + * @type {number} + * @desc Version number + */ + this.version = getParametersValue(parameters, "version", Certificate.defaultValues("version")); + /** + * @type {Integer} + * @desc Serial number of the certificate + */ + this.serialNumber = getParametersValue(parameters, "serialNumber", Certificate.defaultValues("serialNumber")); + /** + * @type {AlgorithmIdentifier} + * @desc This field contains the algorithm identifier for the algorithm used by the CA to sign the certificate + */ + this.signature = getParametersValue(parameters, "signature", Certificate.defaultValues("signature")); + /** + * @type {RelativeDistinguishedNames} + * @desc The issuer field identifies the entity that has signed and issued the certificate + */ + this.issuer = getParametersValue(parameters, "issuer", Certificate.defaultValues("issuer")); + /** + * @type {Time} + * @desc The date on which the certificate validity period begins + */ + this.notBefore = getParametersValue(parameters, "notBefore", Certificate.defaultValues("notBefore")); + /** + * @type {Time} + * @desc The date on which the certificate validity period ends + */ + this.notAfter = getParametersValue(parameters, "notAfter", Certificate.defaultValues("notAfter")); + /** + * @type {RelativeDistinguishedNames} + * @desc The subject field identifies the entity associated with the public key stored in the subject public key field + */ + this.subject = getParametersValue(parameters, "subject", Certificate.defaultValues("subject")); + /** + * @type {PublicKeyInfo} + * @desc This field is used to carry the public key and identify the algorithm with which the key is used + */ + this.subjectPublicKeyInfo = getParametersValue(parameters, "subjectPublicKeyInfo", Certificate.defaultValues("subjectPublicKeyInfo")); + + if("issuerUniqueID" in parameters) + /** + * @type {ArrayBuffer} + * @desc The subject and issuer unique identifiers are present in the certificate to handle the possibility of reuse of subject and/or issuer names over time + */ + this.issuerUniqueID = getParametersValue(parameters, "issuerUniqueID", Certificate.defaultValues("issuerUniqueID")); + + if("subjectUniqueID" in parameters) + /** + * @type {ArrayBuffer} + * @desc The subject and issuer unique identifiers are present in the certificate to handle the possibility of reuse of subject and/or issuer names over time + */ + this.subjectUniqueID = getParametersValue(parameters, "subjectUniqueID", Certificate.defaultValues("subjectUniqueID")); + + if("extensions" in parameters) + /** + * @type {Array} + * @desc If present, this field is a SEQUENCE of one or more certificate extensions + */ + this.extensions = getParametersValue(parameters, "extensions", Certificate.defaultValues("extensions")); + + /** + * @type {AlgorithmIdentifier} + * @desc The signatureAlgorithm field contains the identifier for the cryptographic algorithm used by the CA to sign this certificate + */ + this.signatureAlgorithm = getParametersValue(parameters, "signatureAlgorithm", Certificate.defaultValues("signatureAlgorithm")); + /** + * @type {BitString} + * @desc The signatureValue field contains a digital signature computed upon the ASN.1 DER encoded tbsCertificate + */ + this.signatureValue = getParametersValue(parameters, "signatureValue", Certificate.defaultValues("signatureValue")); + //endregion + + //region If input argument array contains "schema" for this object + if("schema" in parameters) + this.fromSchema(parameters.schema); + //endregion + } + //********************************************************************************** + /** + * Return default values for all class members + * @param {string} memberName String name for a class member + */ + static defaultValues(memberName) + { + switch(memberName) + { + case "tbs": + return new ArrayBuffer(0); + case "version": + return 0; + case "serialNumber": + return new asn1js.Integer(); + case "signature": + return new AlgorithmIdentifier(); + case "issuer": + return new RelativeDistinguishedNames(); + case "notBefore": + return new Time(); + case "notAfter": + return new Time(); + case "subject": + return new RelativeDistinguishedNames(); + case "subjectPublicKeyInfo": + return new PublicKeyInfo(); + case "issuerUniqueID": + return new ArrayBuffer(0); + case "subjectUniqueID": + return new ArrayBuffer(0); + case "extensions": + return []; + case "signatureAlgorithm": + return new AlgorithmIdentifier(); + case "signatureValue": + return new asn1js.BitString(); + default: + throw new Error(`Invalid member name for Certificate class: ${memberName}`); + } + } + //********************************************************************************** + /** + * Return value of pre-defined ASN.1 schema for current class + * + * ASN.1 schema: + * ```asn1 + * Certificate ::= SEQUENCE { + * tbsCertificate TBSCertificate, + * signatureAlgorithm AlgorithmIdentifier, + * signatureValue BIT STRING } + * ``` + * + * @param {Object} parameters Input parameters for the schema + * @returns {Object} asn1js schema object + */ + static schema(parameters = {}) + { + /** + * @type {Object} + * @property {string} [blockName] + * @property {string} [tbsCertificate] + * @property {string} [signatureAlgorithm] + * @property {string} [signatureValue] + */ + const names = getParametersValue(parameters, "names", {}); + + return (new asn1js.Sequence({ + name: (names.blockName || ""), + value: [ + tbsCertificate(names.tbsCertificate), + AlgorithmIdentifier.schema(names.signatureAlgorithm || { + names: { + blockName: "signatureAlgorithm" + } + }), + new asn1js.BitString({ name: (names.signatureValue || "signatureValue") }) + ] + })); + } + //********************************************************************************** + /** + * Convert parsed asn1js object into current class + * @param {!Object} schema + */ + fromSchema(schema) + { + //region Clear input data first + clearProps(schema, [ + "tbsCertificate", + "tbsCertificate.extensions", + "tbsCertificate.version", + "tbsCertificate.serialNumber", + "tbsCertificate.signature", + "tbsCertificate.issuer", + "tbsCertificate.notBefore", + "tbsCertificate.notAfter", + "tbsCertificate.subject", + "tbsCertificate.subjectPublicKeyInfo", + "tbsCertificate.issuerUniqueID", + "tbsCertificate.subjectUniqueID", + "signatureAlgorithm", + "signatureValue" + ]); + //endregion + + //region Check the schema is valid + const asn1 = asn1js.compareSchema(schema, + schema, + Certificate.schema({ + names: { + tbsCertificate: { + names: { + extensions: { + names: { + extensions: "tbsCertificate.extensions" + } + } + } + } + } + }) + ); + + if(asn1.verified === false) + throw new Error("Object's schema was not verified against input data for Certificate"); + //endregion + + //region Get internal properties from parsed schema + this.tbs = asn1.result.tbsCertificate.valueBeforeDecode; + + if("tbsCertificate.version" in asn1.result) + this.version = asn1.result["tbsCertificate.version"].valueBlock.valueDec; + this.serialNumber = asn1.result["tbsCertificate.serialNumber"]; + this.signature = new AlgorithmIdentifier({ schema: asn1.result["tbsCertificate.signature"] }); + this.issuer = new RelativeDistinguishedNames({ schema: asn1.result["tbsCertificate.issuer"] }); + this.notBefore = new Time({ schema: asn1.result["tbsCertificate.notBefore"] }); + this.notAfter = new Time({ schema: asn1.result["tbsCertificate.notAfter"] }); + this.subject = new RelativeDistinguishedNames({ schema: asn1.result["tbsCertificate.subject"] }); + this.subjectPublicKeyInfo = new PublicKeyInfo({ schema: asn1.result["tbsCertificate.subjectPublicKeyInfo"] }); + if("tbsCertificate.issuerUniqueID" in asn1.result) + this.issuerUniqueID = asn1.result["tbsCertificate.issuerUniqueID"].valueBlock.valueHex; + if("tbsCertificate.subjectUniqueID" in asn1.result) + this.subjectUniqueID = asn1.result["tbsCertificate.subjectUniqueID"].valueBlock.valueHex; + if("tbsCertificate.extensions" in asn1.result) + this.extensions = Array.from(asn1.result["tbsCertificate.extensions"], element => new Extension({ schema: element })); + + this.signatureAlgorithm = new AlgorithmIdentifier({ schema: asn1.result.signatureAlgorithm }); + this.signatureValue = asn1.result.signatureValue; + //endregion + } + //********************************************************************************** + /** + * Create ASN.1 schema for existing values of TBS part for the certificate + */ + encodeTBS() + { + //region Create array for output sequence + const outputArray = []; + + if(("version" in this) && (this.version !== Certificate.defaultValues("version"))) + { + outputArray.push(new asn1js.Constructed({ + optional: true, + idBlock: { + tagClass: 3, // CONTEXT-SPECIFIC + tagNumber: 0 // [0] + }, + value: [ + new asn1js.Integer({ value: this.version }) // EXPLICIT integer value + ] + })); + } + + outputArray.push(this.serialNumber); + outputArray.push(this.signature.toSchema()); + outputArray.push(this.issuer.toSchema()); + + outputArray.push(new asn1js.Sequence({ + value: [ + this.notBefore.toSchema(), + this.notAfter.toSchema() + ] + })); + + outputArray.push(this.subject.toSchema()); + outputArray.push(this.subjectPublicKeyInfo.toSchema()); + + if("issuerUniqueID" in this) + { + outputArray.push(new asn1js.Primitive({ + optional: true, + idBlock: { + tagClass: 3, // CONTEXT-SPECIFIC + tagNumber: 1 // [1] + }, + valueHex: this.issuerUniqueID + })); + } + if("subjectUniqueID" in this) + { + outputArray.push(new asn1js.Primitive({ + optional: true, + idBlock: { + tagClass: 3, // CONTEXT-SPECIFIC + tagNumber: 2 // [2] + }, + valueHex: this.subjectUniqueID + })); + } + + if("extensions" in this) + { + outputArray.push(new asn1js.Constructed({ + optional: true, + idBlock: { + tagClass: 3, // CONTEXT-SPECIFIC + tagNumber: 3 // [3] + }, + value: [new asn1js.Sequence({ + value: Array.from(this.extensions, element => element.toSchema()) + })] + })); + } + //endregion + + //region Create and return output sequence + return (new asn1js.Sequence({ + value: outputArray + })); + //endregion + } + //********************************************************************************** + /** + * Convert current object to asn1js object and set correct values + * @returns {Object} asn1js object + */ + toSchema(encodeFlag = false) + { + let tbsSchema = {}; + + //region Decode stored TBS value + if(encodeFlag === false) + { + if(this.tbs.length === 0) // No stored certificate TBS part + return Certificate.schema().value[0]; + + tbsSchema = asn1js.fromBER(this.tbs).result; + } + //endregion + //region Create TBS schema via assembling from TBS parts + else + tbsSchema = this.encodeTBS(); + //endregion + + //region Construct and return new ASN.1 schema for this object + return (new asn1js.Sequence({ + value: [ + tbsSchema, + this.signatureAlgorithm.toSchema(), + this.signatureValue + ] + })); + //endregion + } + //********************************************************************************** + /** + * Convertion for the class to JSON object + * @returns {Object} + */ + toJSON() + { + const object = { + tbs: bufferToHexCodes(this.tbs, 0, this.tbs.byteLength), + serialNumber: this.serialNumber.toJSON(), + signature: this.signature.toJSON(), + issuer: this.issuer.toJSON(), + notBefore: this.notBefore.toJSON(), + notAfter: this.notAfter.toJSON(), + subject: this.subject.toJSON(), + subjectPublicKeyInfo: this.subjectPublicKeyInfo.toJSON(), + signatureAlgorithm: this.signatureAlgorithm.toJSON(), + signatureValue: this.signatureValue.toJSON() + }; + + if(("version" in this) && (this.version !== Certificate.defaultValues("version"))) + object.version = this.version; + + if("issuerUniqueID" in this) + object.issuerUniqueID = bufferToHexCodes(this.issuerUniqueID, 0, this.issuerUniqueID.byteLength); + + if("subjectUniqueID" in this) + object.subjectUniqueID = bufferToHexCodes(this.subjectUniqueID, 0, this.subjectUniqueID.byteLength); + + if("extensions" in this) + object.extensions = Array.from(this.extensions, element => element.toJSON()); + + return object; + } + //********************************************************************************** + /** + * Importing public key for current certificate + */ + getPublicKey(parameters = null) + { + return getEngine().subtle.getPublicKey(this.subjectPublicKeyInfo, this.signatureAlgorithm, parameters); + } + //********************************************************************************** + /** + * Get hash value for subject public key (default SHA-1) + * @param {String} [hashAlgorithm=SHA-1] Hashing algorithm name + */ + getKeyHash(hashAlgorithm = "SHA-1") + { + //region Get a "crypto" extension + const crypto = getCrypto(); + if(typeof crypto === "undefined") + return Promise.reject("Unable to create WebCrypto object"); + //endregion + + return crypto.digest({ name: hashAlgorithm }, new Uint8Array(this.subjectPublicKeyInfo.subjectPublicKey.valueBlock.valueHex)); + } + //********************************************************************************** + /** + * Make a signature for current value from TBS section + * @param {Object} privateKey Private key for "subjectPublicKeyInfo" structure + * @param {string} [hashAlgorithm="SHA-1"] Hashing algorithm + */ + sign(privateKey, hashAlgorithm = "SHA-1") + { + //region Initial checking + //region Check private key + if(typeof privateKey === "undefined") + return Promise.reject("Need to provide a private key for signing"); + //endregion + //endregion + + //region Initial variables + let sequence = Promise.resolve(); + let parameters; + + const engine = getEngine(); + //endregion + + //region Get a "default parameters" for current algorithm and set correct signature algorithm + sequence = sequence.then(() => engine.subtle.getSignatureParameters(privateKey, hashAlgorithm)); + + sequence = sequence.then(result => + { + parameters = result.parameters; + this.signature = result.signatureAlgorithm; + this.signatureAlgorithm = result.signatureAlgorithm; + }); + //endregion + + //region Create TBS data for signing + sequence = sequence.then(() => + { + this.tbs = this.encodeTBS().toBER(false); + }); + //endregion + + //region Signing TBS data on provided private key + sequence = sequence.then(() => engine.subtle.signWithPrivateKey(this.tbs, privateKey, parameters)); + + sequence = sequence.then(result => + { + this.signatureValue = new asn1js.BitString({ valueHex: result }); + }); + //endregion + + return sequence; + } + //********************************************************************************** + verify(issuerCertificate = null) + { + //region Global variables + let subjectPublicKeyInfo = {}; + //endregion + + //region Set correct "subjectPublicKeyInfo" value + if(issuerCertificate !== null) + subjectPublicKeyInfo = issuerCertificate.subjectPublicKeyInfo; + else + { + if(this.issuer.isEqual(this.subject)) // Self-signed certificate + subjectPublicKeyInfo = this.subjectPublicKeyInfo; + } + + if((subjectPublicKeyInfo instanceof PublicKeyInfo) === false) + return Promise.reject("Please provide issuer certificate as a parameter"); + //endregion + + return getEngine().subtle.verifyWithPublicKey(this.tbs, this.signatureValue, subjectPublicKeyInfo, this.signatureAlgorithm); + } + //********************************************************************************** +} +//************************************************************************************** diff --git a/core/third-party/pkijs/CertificateChainValidationEngine.js b/core/third-party/pkijs/CertificateChainValidationEngine.js new file mode 100644 index 0000000..b2fc901 --- /dev/null +++ b/core/third-party/pkijs/CertificateChainValidationEngine.js @@ -0,0 +1,1910 @@ +import { getParametersValue, isEqualBuffer } from "./pvutils.js"; +import { getAlgorithmByOID, stringPrep } from "./common.js"; +//************************************************************************************** +export default class CertificateChainValidationEngine +{ + //********************************************************************************** + /** + * Constructor for CertificateChainValidationEngine class + * @param {Object} [parameters={}] + * @param {Object} [parameters.schema] asn1js parsed value to initialize the class from + */ + constructor(parameters = {}) + { + //region Internal properties of the object + /** + * @type {Array.} + * @desc Array of pre-defined trusted (by user) certificates + */ + this.trustedCerts = getParametersValue(parameters, "trustedCerts", this.defaultValues("trustedCerts")); + /** + * @type {Array.} + * @desc Array with certificate chain. Could be only one end-user certificate in there! + */ + this.certs = getParametersValue(parameters, "certs", this.defaultValues("certs")); + /** + * @type {Array.} + * @desc Array of all CRLs for all certificates from certificate chain + */ + this.crls = getParametersValue(parameters, "crls", this.defaultValues("crls")); + /** + * @type {Array} + * @desc Array of all OCSP responses + */ + this.ocsps = getParametersValue(parameters, "ocsps", this.defaultValues("ocsps")); + /** + * @type {Date} + * @desc The date at which the check would be + */ + this.checkDate = getParametersValue(parameters, "checkDate", this.defaultValues("checkDate")); + /** + * @type {Function} + * @desc The date at which the check would be + */ + this.findOrigin = getParametersValue(parameters, "findOrigin", this.defaultValues("findOrigin")); + /** + * @type {Function} + * @desc The date at which the check would be + */ + this.findIssuer = getParametersValue(parameters, "findIssuer", this.defaultValues("findIssuer")); + //endregion + } + //********************************************************************************** + static defaultFindOrigin(certificate, validationEngine) + { + //region Firstly encode TBS for certificate + if(certificate.tbs.byteLength === 0) + certificate.tbs = certificate.encodeTBS(); + //endregion + + //region Search in Intermediate Certificates + for(const localCert of validationEngine.certs) + { + //region Firstly encode TBS for certificate + if(localCert.tbs.byteLength === 0) + localCert.tbs = localCert.encodeTBS(); + //endregion + + if(isEqualBuffer(certificate.tbs, localCert.tbs)) + return "Intermediate Certificates"; + } + //endregion + + //region Search in Trusted Certificates + for(const trustedCert of validationEngine.trustedCerts) + { + //region Firstly encode TBS for certificate + if(trustedCert.tbs.byteLength === 0) + trustedCert.tbs = trustedCert.encodeTBS(); + //endregion + + if(isEqualBuffer(certificate.tbs, trustedCert.tbs)) + return "Trusted Certificates"; + } + //endregion + + return "Unknown"; + } + //********************************************************************************** + async defaultFindIssuer(certificate, validationEngine) + { + //region Initial variables + let result = []; + + let keyIdentifier = null; + + let authorityCertIssuer = null; + let authorityCertSerialNumber = null; + //endregion + + //region Speed-up searching in case of self-signed certificates + if(certificate.subject.isEqual(certificate.issuer)) + { + try + { + const verificationResult = await certificate.verify(); + if(verificationResult === true) + return [certificate]; + } + catch(ex) + { + } + } + //endregion + + //region Find values to speed-up search + if("extensions" in certificate) + { + for(const extension of certificate.extensions) + { + if(extension.extnID === "2.5.29.35") // AuthorityKeyIdentifier + { + if("keyIdentifier" in extension.parsedValue) + keyIdentifier = extension.parsedValue.keyIdentifier; + else + { + if("authorityCertIssuer" in extension.parsedValue) + authorityCertIssuer = extension.parsedValue.authorityCertIssuer; + + if("authorityCertSerialNumber" in extension.parsedValue) + authorityCertSerialNumber = extension.parsedValue.authorityCertSerialNumber; + } + + break; + } + } + } + //endregion + + //region Aux function + function checkCertificate(possibleIssuer) + { + //region Firstly search for appropriate extensions + if(keyIdentifier !== null) + { + if("extensions" in possibleIssuer) + { + let extensionFound = false; + + for(const extension of possibleIssuer.extensions) + { + if(extension.extnID === "2.5.29.14") // SubjectKeyIdentifier + { + extensionFound = true; + + if(isEqualBuffer(extension.parsedValue.valueBlock.valueHex, keyIdentifier.valueBlock.valueHex)) + result.push(possibleIssuer); + + break; + } + } + + if(extensionFound) + return; + } + } + //endregion + + //region Now search for authorityCertSerialNumber + let authorityCertSerialNumberEqual = false; + + if(authorityCertSerialNumber !== null) + authorityCertSerialNumberEqual = possibleIssuer.serialNumber.isEqual(authorityCertSerialNumber); + //endregion + + //region And at least search for Issuer data + if(authorityCertIssuer !== null) + { + if(possibleIssuer.subject.isEqual(authorityCertIssuer)) + { + if(authorityCertSerialNumberEqual) + result.push(possibleIssuer); + } + } + else + { + if(certificate.issuer.isEqual(possibleIssuer.subject)) + result.push(possibleIssuer); + } + //endregion + } + //endregion + + //region Search in Trusted Certificates + for(const trustedCert of validationEngine.trustedCerts) + checkCertificate(trustedCert); + //endregion + + //region Search in Intermediate Certificates + for(const intermediateCert of validationEngine.certs) + checkCertificate(intermediateCert); + //endregion + + //region Now perform certificate verification checking + for(let i = 0; i < result.length; i++) + { + try + { + const verificationResult = await certificate.verify(result[i]); + if(verificationResult === false) + result.splice(i, 1); + } + catch(ex) + { + result.splice(i, 1); // Something wrong, remove the certificate + } + } + //endregion + + return result; + } + //********************************************************************************** + /** + * Return default values for all class members + * @param {string} memberName String name for a class member + */ + defaultValues(memberName) + { + switch(memberName) + { + case "trustedCerts": + return []; + case "certs": + return []; + case "crls": + return []; + case "ocsps": + return []; + case "checkDate": + return new Date(); + case "findOrigin": + return CertificateChainValidationEngine.defaultFindOrigin; + case "findIssuer": + return this.defaultFindIssuer; + default: + throw new Error(`Invalid member name for CertificateChainValidationEngine class: ${memberName}`); + } + } + //********************************************************************************** + async sort(passedWhenNotRevValues = false) + { + //region Initial variables + const localCerts = []; + const _this = this; + //endregion + + //region Building certificate path + async function buildPath(certificate) + { + const result = []; + + //region Aux function checking array for unique elements + function checkUnique(array) + { + let unique = true; + + for(let i = 0; i < array.length; i++) + { + for(let j = 0; j < array.length; j++) + { + if(j === i) + continue; + + if(array[i] === array[j]) + { + unique = false; + break; + } + } + + if(!unique) + break; + } + + return unique; + } + + //endregion + + const findIssuerResult = await _this.findIssuer(certificate, _this); + if(findIssuerResult.length === 0) + throw new Error("No valid certificate paths found"); + + for(let i = 0; i < findIssuerResult.length; i++) + { + if(isEqualBuffer(findIssuerResult[i].tbs, certificate.tbs)) + { + result.push([findIssuerResult[i]]); + continue; + } + + const buildPathResult = await buildPath(findIssuerResult[i]); + + for(let j = 0; j < buildPathResult.length; j++) + { + const copy = buildPathResult[j].slice(); + copy.splice(0, 0, findIssuerResult[i]); + + if(checkUnique(copy)) + result.push(copy); + else + result.push(buildPathResult[j]); + } + } + + return result; + } + //endregion + + //region Find CRL for specific certificate + async function findCRL(certificate) + { + //region Initial variables + const issuerCertificates = []; + const crls = []; + const crlsAndCertificates = []; + //endregion + + //region Find all possible CRL issuers + issuerCertificates.push(...localCerts.filter(element => certificate.issuer.isEqual(element.subject))); + if(issuerCertificates.length === 0) + { + return { + status: 1, + statusMessage: "No certificate's issuers" + }; + } + //endregion + + //region Find all CRLs for certificate's issuer + crls.push(..._this.crls.filter(element => element.issuer.isEqual(certificate.issuer))); + if(crls.length === 0) + { + return { + status: 2, + statusMessage: "No CRLs for specific certificate issuer" + }; + } + //endregion + + //region Find specific certificate of issuer for each CRL + for(let i = 0; i < crls.length; i++) + { + //region Check "nextUpdate" for the CRL + // The "nextUpdate" is older than "checkDate". + // Thus we should do have another, updated CRL. + // Thus the CRL assumed to be invalid. + if(crls[i].nextUpdate.value < _this.checkDate) + continue; + //endregion + + for(let j = 0; j < issuerCertificates.length; j++) + { + try + { + const result = await crls[i].verify({ issuerCertificate: issuerCertificates[j] }); + if(result) + { + crlsAndCertificates.push({ + crl: crls[i], + certificate: issuerCertificates[j] + }); + + break; + } + } + catch(ex) + { + } + } + } + //endregion + + if(crlsAndCertificates.length) + { + return { + status: 0, + statusMessage: "", + result: crlsAndCertificates + }; + } + + return { + status: 3, + statusMessage: "No valid CRLs found" + }; + } + //endregion + + //region Find OCSP for specific certificate + async function findOCSP(certificate, issuerCertificate) + { + //region Get hash algorithm from certificate + const hashAlgorithm = getAlgorithmByOID(certificate.signatureAlgorithm.algorithmId); + if(("name" in hashAlgorithm) === false) + return 1; + if(("hash" in hashAlgorithm) === false) + return 1; + //endregion + + //region Search for OCSP response for the certificate + for(let i = 0; i < _this.ocsps.length; i++) + { + const result = await _this.ocsps[i].getCertificateStatus(certificate, issuerCertificate); + if(result.isForCertificate) + { + if(result.status === 0) + return 0; + + return 1; + } + } + //endregion + + return 2; + } + //endregion + + //region Check for certificate to be CA + async function checkForCA(certificate, needToCheckCRL = false) + { + //region Initial variables + let isCA = false; + let mustBeCA = false; + let keyUsagePresent = false; + let cRLSign = false; + //endregion + + if("extensions" in certificate) + { + for(let j = 0; j < certificate.extensions.length; j++) + { + if((certificate.extensions[j].critical === true) && + (("parsedValue" in certificate.extensions[j]) === false)) + { + return { + result: false, + resultCode: 6, + resultMessage: `Unable to parse critical certificate extension: ${certificate.extensions[j].extnID}` + }; + } + + if(certificate.extensions[j].extnID === "2.5.29.15") // KeyUsage + { + keyUsagePresent = true; + + const view = new Uint8Array(certificate.extensions[j].parsedValue.valueBlock.valueHex); + + if((view[0] & 0x04) === 0x04) // Set flag "keyCertSign" + mustBeCA = true; + + if((view[0] & 0x02) === 0x02) // Set flag "cRLSign" + cRLSign = true; + } + + if(certificate.extensions[j].extnID === "2.5.29.19") // BasicConstraints + { + if("cA" in certificate.extensions[j].parsedValue) + { + if(certificate.extensions[j].parsedValue.cA === true) + isCA = true; + } + } + } + + if((mustBeCA === true) && (isCA === false)) + { + return { + result: false, + resultCode: 3, + resultMessage: "Unable to build certificate chain - using \"keyCertSign\" flag set without BasicConstaints" + }; + } + + if((keyUsagePresent === true) && (isCA === true) && (mustBeCA === false)) + { + return { + result: false, + resultCode: 4, + resultMessage: "Unable to build certificate chain - \"keyCertSign\" flag was not set" + }; + } + + // noinspection OverlyComplexBooleanExpressionJS + if((isCA === true) && (keyUsagePresent === true) && ((needToCheckCRL) && (cRLSign === false))) + { + return { + result: false, + resultCode: 5, + resultMessage: "Unable to build certificate chain - intermediate certificate must have \"cRLSign\" key usage flag" + }; + } + } + + if(isCA === false) + { + return { + result: false, + resultCode: 7, + resultMessage: "Unable to build certificate chain - more than one possible end-user certificate" + }; + } + + return { + result: true, + resultCode: 0, + resultMessage: "" + }; + } + //endregion + + //region Basic check for certificate path + async function basicCheck(path, checkDate) + { + //region Check that all dates are valid + for(let i = 0; i < path.length; i++) + { + if((path[i].notBefore.value > checkDate) || + (path[i].notAfter.value < checkDate)) + { + return { + result: false, + resultCode: 8, + resultMessage: "The certificate is either not yet valid or expired" + }; + } + } + //endregion + + //region Check certificate name chain + + // We should have at least two certificates: end entity and trusted root + if(path.length < 2) + { + return { + result: false, + resultCode: 9, + resultMessage: "Too short certificate path" + }; + } + + for(let i = (path.length - 2); i >= 0; i--) + { + //region Check that we do not have a "self-signed" certificate + if(path[i].issuer.isEqual(path[i].subject) === false) + { + if(path[i].issuer.isEqual(path[i + 1].subject) === false) + { + return { + result: false, + resultCode: 10, + resultMessage: "Incorrect name chaining" + }; + } + } + //endregion + } + //endregion + + //region Check each certificate (except "trusted root") to be non-revoked + if((_this.crls.length !== 0) || (_this.ocsps.length !== 0)) // If CRLs and OCSPs are empty then we consider all certificates to be valid + { + for(let i = 0; i < (path.length - 1); i++) + { + //region Initial variables + let ocspResult = 2; + let crlResult = { + status: 0, + statusMessage: "" + }; + //endregion + + //region Check OCSPs first + if(_this.ocsps.length !== 0) + { + ocspResult = await findOCSP(path[i], path[i + 1]); + + switch(ocspResult) + { + case 0: + continue; + case 1: + return { + result: false, + resultCode: 12, + resultMessage: "One of certificates was revoked via OCSP response" + }; + case 2: // continue to check the certificate with CRL + break; + default: + } + } + //endregion + + //region Check CRLs + if(_this.crls.length !== 0) + { + crlResult = await findCRL(path[i]); + + if(crlResult.status === 0) + { + for(let j = 0; j < crlResult.result.length; j++) + { + //region Check that the CRL issuer certificate have not been revoked + const isCertificateRevoked = crlResult.result[j].crl.isCertificateRevoked(path[i]); + if(isCertificateRevoked) + { + return { + result: false, + resultCode: 12, + resultMessage: "One of certificates had been revoked" + }; + } + //endregion + + //region Check that the CRL issuer certificate is a CA certificate + const isCertificateCA = await checkForCA(crlResult.result[j].certificate, true); + if(isCertificateCA.result === false) + { + return { + result: false, + resultCode: 13, + resultMessage: "CRL issuer certificate is not a CA certificate or does not have crlSign flag" + }; + } + //endregion + } + } + else + { + if(passedWhenNotRevValues === false) + { + throw { + result: false, + resultCode: 11, + resultMessage: `No revocation values found for one of certificates: ${crlResult.statusMessage}` + }; + } + } + } + else + { + if(ocspResult === 2) + { + return { + result: false, + resultCode: 11, + resultMessage: "No revocation values found for one of certificates" + }; + } + } + //endregion + + //region Check we do have links to revocation values inside issuer's certificate + if((ocspResult === 2) && (crlResult.status === 2) && passedWhenNotRevValues) + { + const issuerCertificate = path[i + 1]; + let extensionFound = false; + + if("extensions" in issuerCertificate) + { + for(const extension of issuerCertificate.extensions) + { + switch(extension.extnID) + { + case "2.5.29.31": // CRLDistributionPoints + case "2.5.29.46": // FreshestCRL + case "1.3.6.1.5.5.7.1.1": // AuthorityInfoAccess + extensionFound = true; + break; + default: + } + } + } + + if(extensionFound) + { + throw { + result: false, + resultCode: 11, + resultMessage: `No revocation values found for one of certificates: ${crlResult.statusMessage}` + }; + } + } + //endregion + } + } + //endregion + + //region Check each certificate (except "end entity") in the path to be a CA certificate + for(let i = 1; i < path.length; i++) + { + const result = await checkForCA(path[i]); + if(result.result === false) + { + return { + result: false, + resultCode: 14, + resultMessage: "One of intermediate certificates is not a CA certificate" + }; + } + } + //endregion + + return { + result: true + }; + } + //endregion + + //region Do main work + //region Initialize "localCerts" by value of "_this.certs" + "_this.trustedCerts" arrays + localCerts.push(..._this.trustedCerts); + localCerts.push(..._this.certs); + //endregion + + //region Check all certificates for been unique + for(let i = 0; i < localCerts.length; i++) + { + for(let j = 0; j < localCerts.length; j++) + { + if(i === j) + continue; + + if(isEqualBuffer(localCerts[i].tbs, localCerts[j].tbs)) + { + localCerts.splice(j, 1); + i = 0; + break; + } + } + } + //endregion + + //region Initial variables + let result; + const certificatePath = [localCerts[localCerts.length - 1]]; // The "end entity" certificate must be the least in "certs" array + //endregion + + //region Build path for "end entity" certificate + result = await buildPath(localCerts[localCerts.length - 1]); + if(result.length === 0) + { + return { + result: false, + resultCode: 60, + resultMessage: "Unable to find certificate path" + }; + } + //endregion + + //region Exclude certificate paths not ended with "trusted roots" + for(let i = 0; i < result.length; i++) + { + let found = false; + + for(let j = 0; j < (result[i]).length; j++) + { + const certificate = (result[i])[j]; + + for(let k = 0; k < _this.trustedCerts.length; k++) + { + if(isEqualBuffer(certificate.tbs, _this.trustedCerts[k].tbs)) + { + found = true; + break; + } + } + + if(found) + break; + } + + if(!found) + { + result.splice(i, 1); + i = 0; + } + } + + if(result.length === 0) + { + throw { + result: false, + resultCode: 97, + resultMessage: "No valid certificate paths found" + }; + } + //endregion + + //region Find shortest certificate path (for the moment it is the only criteria) + let shortestLength = result[0].length; + let shortestIndex = 0; + + for(let i = 0; i < result.length; i++) + { + if(result[i].length < shortestLength) + { + shortestLength = result[i].length; + shortestIndex = i; + } + } + //endregion + + //region Create certificate path for basic check + for(let i = 0; i < result[shortestIndex].length; i++) + certificatePath.push((result[shortestIndex])[i]); + //endregion + + //region Perform basic checking for all certificates in the path + result = await basicCheck(certificatePath, _this.checkDate); + if(result.result === false) + throw result; + //endregion + + return certificatePath; + //endregion + } + //********************************************************************************** + /** + * Major verification function for certificate chain. + * @param {{initialPolicySet, initialExplicitPolicy, initialPolicyMappingInhibit, initialInhibitPolicy, initialPermittedSubtreesSet, initialExcludedSubtreesSet, initialRequiredNameForms}} [parameters] + * @returns {Promise} + */ + async verify(parameters = {}) + { + //region Auxiliary functions for name constraints checking + function compareDNSName(name, constraint) + { + /// Compare two dNSName values + /// DNS from name + /// Constraint for DNS from name + /// Boolean result - valid or invalid the "name" against the "constraint" + + //region Make a "string preparation" for both name and constrain + const namePrepared = stringPrep(name); + const constraintPrepared = stringPrep(constraint); + //endregion + + //region Make a "splitted" versions of "constraint" and "name" + const nameSplitted = namePrepared.split("."); + const constraintSplitted = constraintPrepared.split("."); + //endregion + + //region Length calculation and additional check + const nameLen = nameSplitted.length; + const constrLen = constraintSplitted.length; + + if((nameLen === 0) || (constrLen === 0) || (nameLen < constrLen)) + return false; + //endregion + + //region Check that no part of "name" has zero length + for(let i = 0; i < nameLen; i++) + { + if(nameSplitted[i].length === 0) + return false; + } + //endregion + + //region Check that no part of "constraint" has zero length + for(let i = 0; i < constrLen; i++) + { + if(constraintSplitted[i].length === 0) + { + if(i === 0) + { + if(constrLen === 1) + return false; + + continue; + } + + return false; + } + } + //endregion + + //region Check that "name" has a tail as "constraint" + + for(let i = 0; i < constrLen; i++) + { + if(constraintSplitted[constrLen - 1 - i].length === 0) + continue; + + if(nameSplitted[nameLen - 1 - i].localeCompare(constraintSplitted[constrLen - 1 - i]) !== 0) + return false; + } + //endregion + + return true; + } + + function compareRFC822Name(name, constraint) + { + /// Compare two rfc822Name values + /// E-mail address from name + /// Constraint for e-mail address from name + /// Boolean result - valid or invalid the "name" against the "constraint" + + //region Make a "string preparation" for both name and constrain + const namePrepared = stringPrep(name); + const constraintPrepared = stringPrep(constraint); + //endregion + + //region Make a "splitted" versions of "constraint" and "name" + const nameSplitted = namePrepared.split("@"); + const constraintSplitted = constraintPrepared.split("@"); + //endregion + + //region Splitted array length checking + if((nameSplitted.length === 0) || (constraintSplitted.length === 0) || (nameSplitted.length < constraintSplitted.length)) + return false; + //endregion + + if(constraintSplitted.length === 1) + { + const result = compareDNSName(nameSplitted[1], constraintSplitted[0]); + + if(result) + { + //region Make a "splitted" versions of domain name from "constraint" and "name" + const ns = nameSplitted[1].split("."); + const cs = constraintSplitted[0].split("."); + //endregion + + if(cs[0].length === 0) + return true; + + return ns.length === cs.length; + } + + return false; + } + + return (namePrepared.localeCompare(constraintPrepared) === 0); + } + + function compareUniformResourceIdentifier(name, constraint) + { + /// Compare two uniformResourceIdentifier values + /// uniformResourceIdentifier from name + /// Constraint for uniformResourceIdentifier from name + /// Boolean result - valid or invalid the "name" against the "constraint" + + //region Make a "string preparation" for both name and constrain + let namePrepared = stringPrep(name); + const constraintPrepared = stringPrep(constraint); + //endregion + + //region Find out a major URI part to compare with + const ns = namePrepared.split("/"); + const cs = constraintPrepared.split("/"); + + if(cs.length > 1) // Malformed constraint + return false; + + if(ns.length > 1) // Full URI string + { + for(let i = 0; i < ns.length; i++) + { + if((ns[i].length > 0) && (ns[i].charAt(ns[i].length - 1) !== ":")) + { + const nsPort = ns[i].split(":"); + namePrepared = nsPort[0]; + break; + } + } + } + //endregion + + const result = compareDNSName(namePrepared, constraintPrepared); + + if(result) + { + //region Make a "splitted" versions of "constraint" and "name" + const nameSplitted = namePrepared.split("."); + const constraintSplitted = constraintPrepared.split("."); + //endregion + + if(constraintSplitted[0].length === 0) + return true; + + return nameSplitted.length === constraintSplitted.length; + } + + return false; + } + + function compareIPAddress(name, constraint) + { + /// Compare two iPAddress values + /// iPAddress from name + /// Constraint for iPAddress from name + /// Boolean result - valid or invalid the "name" against the "constraint" + + //region Common variables + const nameView = new Uint8Array(name.valueBlock.valueHex); + const constraintView = new Uint8Array(constraint.valueBlock.valueHex); + //endregion + + //region Work with IPv4 addresses + if((nameView.length === 4) && (constraintView.length === 8)) + { + for(let i = 0; i < 4; i++) + { + if((nameView[i] ^ constraintView[i]) & constraintView[i + 4]) + return false; + } + + return true; + } + //endregion + + //region Work with IPv6 addresses + if((nameView.length === 16) && (constraintView.length === 32)) + { + for(let i = 0; i < 16; i++) + { + if((nameView[i] ^ constraintView[i]) & constraintView[i + 16]) + return false; + } + + return true; + } + //endregion + + return false; + } + + function compareDirectoryName(name, constraint) + { + /// Compare two directoryName values + /// directoryName from name + /// Constraint for directoryName from name + /// Boolean flag - should be comparision interrupted after first match or we need to match all "constraints" parts + /// Boolean result - valid or invalid the "name" against the "constraint" + + //region Initial check + if((name.typesAndValues.length === 0) || (constraint.typesAndValues.length === 0)) + return true; + + if(name.typesAndValues.length < constraint.typesAndValues.length) + return false; + //endregion + + //region Initial variables + let result = true; + let nameStart = 0; + //endregion + + for(let i = 0; i < constraint.typesAndValues.length; i++) + { + let localResult = false; + + for(let j = nameStart; j < name.typesAndValues.length; j++) + { + localResult = name.typesAndValues[j].isEqual(constraint.typesAndValues[i]); + + if(name.typesAndValues[j].type === constraint.typesAndValues[i].type) + result = result && localResult; + + if(localResult === true) + { + if((nameStart === 0) || (nameStart === j)) + { + nameStart = j + 1; + break; + } + else // Structure of "name" must be the same with "constraint" + return false; + } + } + + if(localResult === false) + return false; + } + + return (nameStart === 0) ? false : result; + } + //endregion + + try + { + //region Initial checks + if(this.certs.length === 0) + throw "Empty certificate array"; + //endregion + + //region Get input variables + let passedWhenNotRevValues = false; + + if("passedWhenNotRevValues" in parameters) + passedWhenNotRevValues = parameters.passedWhenNotRevValues; + + let initialPolicySet = []; + initialPolicySet.push("2.5.29.32.0"); // "anyPolicy" + + let initialExplicitPolicy = false; + let initialPolicyMappingInhibit = false; + let initialInhibitPolicy = false; + + let initialPermittedSubtreesSet = []; // Array of "simpl.x509.GeneralSubtree" + let initialExcludedSubtreesSet = []; // Array of "simpl.x509.GeneralSubtree" + let initialRequiredNameForms = []; // Array of "simpl.x509.GeneralSubtree" + + if("initialPolicySet" in parameters) + initialPolicySet = parameters.initialPolicySet; + + if("initialExplicitPolicy" in parameters) + initialExplicitPolicy = parameters.initialExplicitPolicy; + + if("initialPolicyMappingInhibit" in parameters) + initialPolicyMappingInhibit = parameters.initialPolicyMappingInhibit; + + if("initialInhibitPolicy" in parameters) + initialInhibitPolicy = parameters.initialInhibitPolicy; + + if("initialPermittedSubtreesSet" in parameters) + initialPermittedSubtreesSet = parameters.initialPermittedSubtreesSet; + + if("initialExcludedSubtreesSet" in parameters) + initialExcludedSubtreesSet = parameters.initialExcludedSubtreesSet; + + if("initialRequiredNameForms" in parameters) + initialRequiredNameForms = parameters.initialRequiredNameForms; + + let explicitPolicyIndicator = initialExplicitPolicy; + let policyMappingInhibitIndicator = initialPolicyMappingInhibit; + let inhibitAnyPolicyIndicator = initialInhibitPolicy; + + const pendingConstraints = new Array(3); + pendingConstraints[0] = false; // For "explicitPolicyPending" + pendingConstraints[1] = false; // For "policyMappingInhibitPending" + pendingConstraints[2] = false; // For "inhibitAnyPolicyPending" + + let explicitPolicyPending = 0; + let policyMappingInhibitPending = 0; + let inhibitAnyPolicyPending = 0; + + let permittedSubtrees = initialPermittedSubtreesSet; + let excludedSubtrees = initialExcludedSubtreesSet; + const requiredNameForms = initialRequiredNameForms; + + let pathDepth = 1; + //endregion + + //region Sorting certificates in the chain array + this.certs = await this.sort(passedWhenNotRevValues); + //endregion + + //region Work with policies + //region Support variables + const allPolicies = []; // Array of all policies (string values) + allPolicies.push("2.5.29.32.0"); // Put "anyPolicy" at first place + + const policiesAndCerts = []; // In fact "array of array" where rows are for each specific policy, column for each certificate and value is "true/false" + + const anyPolicyArray = new Array(this.certs.length - 1); // Minus "trusted anchor" + for(let ii = 0; ii < (this.certs.length - 1); ii++) + anyPolicyArray[ii] = true; + + policiesAndCerts.push(anyPolicyArray); + + const policyMappings = new Array(this.certs.length - 1); // Array of "PolicyMappings" for each certificate + const certPolicies = new Array(this.certs.length - 1); // Array of "CertificatePolicies" for each certificate + + let explicitPolicyStart = (explicitPolicyIndicator) ? (this.certs.length - 1) : (-1); + //endregion + + //region Gather all neccessary information from certificate chain + for(let i = (this.certs.length - 2); i >= 0; i--, pathDepth++) + { + if("extensions" in this.certs[i]) + { + //region Get information about certificate extensions + for(let j = 0; j < this.certs[i].extensions.length; j++) + { + //region CertificatePolicies + if(this.certs[i].extensions[j].extnID === "2.5.29.32") + { + certPolicies[i] = this.certs[i].extensions[j].parsedValue; + + //region Remove entry from "anyPolicies" for the certificate + for(let s = 0; s < allPolicies.length; s++) + { + if(allPolicies[s] === "2.5.29.32.0") + { + delete (policiesAndCerts[s])[i]; + break; + } + } + //endregion + + for(let k = 0; k < this.certs[i].extensions[j].parsedValue.certificatePolicies.length; k++) + { + let policyIndex = (-1); + + //region Try to find extension in "allPolicies" array + for(let s = 0; s < allPolicies.length; s++) + { + if(this.certs[i].extensions[j].parsedValue.certificatePolicies[k].policyIdentifier === allPolicies[s]) + { + policyIndex = s; + break; + } + } + //endregion + + if(policyIndex === (-1)) + { + allPolicies.push(this.certs[i].extensions[j].parsedValue.certificatePolicies[k].policyIdentifier); + + const certArray = new Array(this.certs.length - 1); + certArray[i] = true; + + policiesAndCerts.push(certArray); + } + else + (policiesAndCerts[policyIndex])[i] = true; + } + } + //endregion + + //region PolicyMappings + if(this.certs[i].extensions[j].extnID === "2.5.29.33") + { + if(policyMappingInhibitIndicator) + { + return { + result: false, + resultCode: 98, + resultMessage: "Policy mapping prohibited" + }; + } + + policyMappings[i] = this.certs[i].extensions[j].parsedValue; + } + //endregion + + //region PolicyConstraints + if(this.certs[i].extensions[j].extnID === "2.5.29.36") + { + if(explicitPolicyIndicator === false) + { + //region requireExplicitPolicy + if(this.certs[i].extensions[j].parsedValue.requireExplicitPolicy === 0) + { + explicitPolicyIndicator = true; + explicitPolicyStart = i; + } + else + { + if(pendingConstraints[0] === false) + { + pendingConstraints[0] = true; + explicitPolicyPending = this.certs[i].extensions[j].parsedValue.requireExplicitPolicy; + } + else + explicitPolicyPending = (explicitPolicyPending > this.certs[i].extensions[j].parsedValue.requireExplicitPolicy) ? this.certs[i].extensions[j].parsedValue.requireExplicitPolicy : explicitPolicyPending; + } + //endregion + + //region inhibitPolicyMapping + if(this.certs[i].extensions[j].parsedValue.inhibitPolicyMapping === 0) + policyMappingInhibitIndicator = true; + else + { + if(pendingConstraints[1] === false) + { + pendingConstraints[1] = true; + policyMappingInhibitPending = this.certs[i].extensions[j].parsedValue.inhibitPolicyMapping + 1; + } + else + policyMappingInhibitPending = (policyMappingInhibitPending > (this.certs[i].extensions[j].parsedValue.inhibitPolicyMapping + 1)) ? (this.certs[i].extensions[j].parsedValue.inhibitPolicyMapping + 1) : policyMappingInhibitPending; + } + //endregion + } + } + //endregion + + //region InhibitAnyPolicy + if(this.certs[i].extensions[j].extnID === "2.5.29.54") + { + if(inhibitAnyPolicyIndicator === false) + { + if(this.certs[i].extensions[j].parsedValue.valueBlock.valueDec === 0) + inhibitAnyPolicyIndicator = true; + else + { + if(pendingConstraints[2] === false) + { + pendingConstraints[2] = true; + inhibitAnyPolicyPending = this.certs[i].extensions[j].parsedValue.valueBlock.valueDec; + } + else + inhibitAnyPolicyPending = (inhibitAnyPolicyPending > this.certs[i].extensions[j].parsedValue.valueBlock.valueDec) ? this.certs[i].extensions[j].parsedValue.valueBlock.valueDec : inhibitAnyPolicyPending; + } + } + } + //endregion + } + //endregion + + //region Check "inhibitAnyPolicyIndicator" + if(inhibitAnyPolicyIndicator === true) + { + let policyIndex = (-1); + + //region Find "anyPolicy" index + for(let searchAnyPolicy = 0; searchAnyPolicy < allPolicies.length; searchAnyPolicy++) + { + if(allPolicies[searchAnyPolicy] === "2.5.29.32.0") + { + policyIndex = searchAnyPolicy; + break; + } + } + //endregion + + if(policyIndex !== (-1)) + delete (policiesAndCerts[0])[i]; // Unset value to "undefined" for "anyPolicies" value for current certificate + } + //endregion + + //region Process with "pending constraints" + if(explicitPolicyIndicator === false) + { + if(pendingConstraints[0] === true) + { + explicitPolicyPending--; + if(explicitPolicyPending === 0) + { + explicitPolicyIndicator = true; + explicitPolicyStart = i; + + pendingConstraints[0] = false; + } + } + } + + if(policyMappingInhibitIndicator === false) + { + if(pendingConstraints[1] === true) + { + policyMappingInhibitPending--; + if(policyMappingInhibitPending === 0) + { + policyMappingInhibitIndicator = true; + pendingConstraints[1] = false; + } + } + } + + if(inhibitAnyPolicyIndicator === false) + { + if(pendingConstraints[2] === true) + { + inhibitAnyPolicyPending--; + if(inhibitAnyPolicyPending === 0) + { + inhibitAnyPolicyIndicator = true; + pendingConstraints[2] = false; + } + } + } + //endregion + } + } + //endregion + + //region Working with policy mappings + for(let i = 0; i < (this.certs.length - 1); i++) + { + //region Check that there is "policy mapping" for level "i + 1" + if((i < (this.certs.length - 2)) && (typeof policyMappings[i + 1] !== "undefined")) + { + for(let k = 0; k < policyMappings[i + 1].mappings.length; k++) + { + //region Check that we do not have "anyPolicy" in current mapping + if((policyMappings[i + 1].mappings[k].issuerDomainPolicy === "2.5.29.32.0") || (policyMappings[i + 1].mappings[k].subjectDomainPolicy === "2.5.29.32.0")) + { + return { + result: false, + resultCode: 99, + resultMessage: "The \"anyPolicy\" should not be a part of policy mapping scheme" + }; + } + //endregion + + //region Initial variables + let issuerDomainPolicyIndex = (-1); + let subjectDomainPolicyIndex = (-1); + //endregion + + //region Search for index of policies indedes + for(let n = 0; n < allPolicies.length; n++) + { + if(allPolicies[n] === policyMappings[i + 1].mappings[k].issuerDomainPolicy) + issuerDomainPolicyIndex = n; + + if(allPolicies[n] === policyMappings[i + 1].mappings[k].subjectDomainPolicy) + subjectDomainPolicyIndex = n; + } + //endregion + + //region Delete existing "issuerDomainPolicy" because on the level we mapped the policy to another one + if(typeof (policiesAndCerts[issuerDomainPolicyIndex])[i] !== "undefined") + delete (policiesAndCerts[issuerDomainPolicyIndex])[i]; + //endregion + + //region Check all policies for the certificate + for(let j = 0; j < certPolicies[i].certificatePolicies.length; j++) + { + if(policyMappings[i + 1].mappings[k].subjectDomainPolicy === certPolicies[i].certificatePolicies[j].policyIdentifier) + { + //region Set mapped policy for current certificate + if((issuerDomainPolicyIndex !== (-1)) && (subjectDomainPolicyIndex !== (-1))) + { + for(let m = 0; m <= i; m++) + { + if(typeof (policiesAndCerts[subjectDomainPolicyIndex])[m] !== "undefined") + { + (policiesAndCerts[issuerDomainPolicyIndex])[m] = true; + delete (policiesAndCerts[subjectDomainPolicyIndex])[m]; + } + } + } + //endregion + } + } + //endregion + } + } + //endregion + } + //endregion + + //region Working with "explicitPolicyIndicator" and "anyPolicy" + for(let i = 0; i < allPolicies.length; i++) + { + if(allPolicies[i] === "2.5.29.32.0") + { + for(let j = 0; j < explicitPolicyStart; j++) + delete (policiesAndCerts[i])[j]; + } + } + //endregion + + //region Create "set of authorities-constrained policies" + const authConstrPolicies = []; + + for(let i = 0; i < policiesAndCerts.length; i++) + { + let found = true; + + for(let j = 0; j < (this.certs.length - 1); j++) + { + let anyPolicyFound = false; + + if((j < explicitPolicyStart) && (allPolicies[i] === "2.5.29.32.0") && (allPolicies.length > 1)) + { + found = false; + break; + } + + if(typeof (policiesAndCerts[i])[j] === "undefined") + { + if(j >= explicitPolicyStart) + { + //region Search for "anyPolicy" in the policy set + for(let k = 0; k < allPolicies.length; k++) + { + if(allPolicies[k] === "2.5.29.32.0") + { + if((policiesAndCerts[k])[j] === true) + anyPolicyFound = true; + + break; + } + } + //endregion + } + + if(!anyPolicyFound) + { + found = false; + break; + } + } + } + + if(found === true) + authConstrPolicies.push(allPolicies[i]); + } + //endregion + + //region Create "set of user-constrained policies" + let userConstrPolicies = []; + + if((initialPolicySet.length === 1) && (initialPolicySet[0] === "2.5.29.32.0") && (explicitPolicyIndicator === false)) + userConstrPolicies = initialPolicySet; + else + { + if((authConstrPolicies.length === 1) && (authConstrPolicies[0] === "2.5.29.32.0")) + userConstrPolicies = initialPolicySet; + else + { + for(let i = 0; i < authConstrPolicies.length; i++) + { + for(let j = 0; j < initialPolicySet.length; j++) + { + if((initialPolicySet[j] === authConstrPolicies[i]) || (initialPolicySet[j] === "2.5.29.32.0")) + { + userConstrPolicies.push(authConstrPolicies[i]); + break; + } + } + } + } + } + //endregion + + //region Combine output object + const policyResult = { + result: (userConstrPolicies.length > 0), + resultCode: 0, + resultMessage: (userConstrPolicies.length > 0) ? "" : "Zero \"userConstrPolicies\" array, no intersections with \"authConstrPolicies\"", + authConstrPolicies, + userConstrPolicies, + explicitPolicyIndicator, + policyMappings, + certificatePath: this.certs + }; + + if(userConstrPolicies.length === 0) + return policyResult; + //endregion + //endregion + + //region Work with name constraints + //region Check a result from "policy checking" part + if(policyResult.result === false) + return policyResult; + //endregion + + //region Check all certificates, excluding "trust anchor" + pathDepth = 1; + + for(let i = (this.certs.length - 2); i >= 0; i--, pathDepth++) + { + //region Support variables + let subjectAltNames = []; + + let certPermittedSubtrees = []; + let certExcludedSubtrees = []; + //endregion + + if("extensions" in this.certs[i]) + { + for(let j = 0; j < this.certs[i].extensions.length; j++) + { + //region NameConstraints + if(this.certs[i].extensions[j].extnID === "2.5.29.30") + { + if("permittedSubtrees" in this.certs[i].extensions[j].parsedValue) + certPermittedSubtrees = certPermittedSubtrees.concat(this.certs[i].extensions[j].parsedValue.permittedSubtrees); + + if("excludedSubtrees" in this.certs[i].extensions[j].parsedValue) + certExcludedSubtrees = certExcludedSubtrees.concat(this.certs[i].extensions[j].parsedValue.excludedSubtrees); + } + //endregion + + //region SubjectAltName + if(this.certs[i].extensions[j].extnID === "2.5.29.17") + subjectAltNames = subjectAltNames.concat(this.certs[i].extensions[j].parsedValue.altNames); + //endregion + } + } + + //region Checking for "required name forms" + let formFound = (requiredNameForms.length <= 0); + + for(let j = 0; j < requiredNameForms.length; j++) + { + switch(requiredNameForms[j].base.type) + { + case 4: // directoryName + { + if(requiredNameForms[j].base.value.typesAndValues.length !== this.certs[i].subject.typesAndValues.length) + continue; + + formFound = true; + + for(let k = 0; k < this.certs[i].subject.typesAndValues.length; k++) + { + if(this.certs[i].subject.typesAndValues[k].type !== requiredNameForms[j].base.value.typesAndValues[k].type) + { + formFound = false; + break; + } + } + + if(formFound === true) + break; + } + break; + default: // ??? Probably here we should reject the certificate ??? + } + } + + if(formFound === false) + { + policyResult.result = false; + policyResult.resultCode = 21; + policyResult.resultMessage = "No neccessary name form found"; + + throw policyResult; + } + //endregion + + //region Checking for "permited sub-trees" + //region Make groups for all types of constraints + const constrGroups = []; // Array of array for groupped constraints + constrGroups[0] = []; // rfc822Name + constrGroups[1] = []; // dNSName + constrGroups[2] = []; // directoryName + constrGroups[3] = []; // uniformResourceIdentifier + constrGroups[4] = []; // iPAddress + + for(let j = 0; j < permittedSubtrees.length; j++) + { + switch(permittedSubtrees[j].base.type) + { + //region rfc822Name + case 1: + constrGroups[0].push(permittedSubtrees[j]); + break; + //endregion + //region dNSName + case 2: + constrGroups[1].push(permittedSubtrees[j]); + break; + //endregion + //region directoryName + case 4: + constrGroups[2].push(permittedSubtrees[j]); + break; + //endregion + //region uniformResourceIdentifier + case 6: + constrGroups[3].push(permittedSubtrees[j]); + break; + //endregion + //region iPAddress + case 7: + constrGroups[4].push(permittedSubtrees[j]); + break; + //endregion + //region default + default: + //endregion + } + } + //endregion + + //region Check name constraints groupped by type, one-by-one + for(let p = 0; p < 5; p++) + { + let groupPermitted = false; + let valueExists = false; + const group = constrGroups[p]; + + for(let j = 0; j < group.length; j++) + { + switch(p) + { + //region rfc822Name + case 0: + if(subjectAltNames.length > 0) + { + for(let k = 0; k < subjectAltNames.length; k++) + { + if(subjectAltNames[k].type === 1) // rfc822Name + { + valueExists = true; + groupPermitted = groupPermitted || compareRFC822Name(subjectAltNames[k].value, group[j].base.value); + } + } + } + else // Try to find out "emailAddress" inside "subject" + { + for(let k = 0; k < this.certs[i].subject.typesAndValues.length; k++) + { + if((this.certs[i].subject.typesAndValues[k].type === "1.2.840.113549.1.9.1") || // PKCS#9 e-mail address + (this.certs[i].subject.typesAndValues[k].type === "0.9.2342.19200300.100.1.3")) // RFC1274 "rfc822Mailbox" e-mail address + { + valueExists = true; + groupPermitted = groupPermitted || compareRFC822Name(this.certs[i].subject.typesAndValues[k].value.valueBlock.value, group[j].base.value); + } + } + } + break; + //endregion + //region dNSName + case 1: + if(subjectAltNames.length > 0) + { + for(let k = 0; k < subjectAltNames.length; k++) + { + if(subjectAltNames[k].type === 2) // dNSName + { + valueExists = true; + groupPermitted = groupPermitted || compareDNSName(subjectAltNames[k].value, group[j].base.value); + } + } + } + break; + //endregion + //region directoryName + case 2: + valueExists = true; + groupPermitted = compareDirectoryName(this.certs[i].subject, group[j].base.value); + break; + //endregion + //region uniformResourceIdentifier + case 3: + if(subjectAltNames.length > 0) + { + for(let k = 0; k < subjectAltNames.length; k++) + { + if(subjectAltNames[k].type === 6) // uniformResourceIdentifier + { + valueExists = true; + groupPermitted = groupPermitted || compareUniformResourceIdentifier(subjectAltNames[k].value, group[j].base.value); + } + } + } + break; + //endregion + //region iPAddress + case 4: + if(subjectAltNames.length > 0) + { + for(let k = 0; k < subjectAltNames.length; k++) + { + if(subjectAltNames[k].type === 7) // iPAddress + { + valueExists = true; + groupPermitted = groupPermitted || compareIPAddress(subjectAltNames[k].value, group[j].base.value); + } + } + } + break; + //endregion + //region default + default: + //endregion + } + + if(groupPermitted) + break; + } + + if((groupPermitted === false) && (group.length > 0) && valueExists) + { + policyResult.result = false; + policyResult.resultCode = 41; + policyResult.resultMessage = "Failed to meet \"permitted sub-trees\" name constraint"; + + throw policyResult; + } + } + //endregion + //endregion + + //region Checking for "excluded sub-trees" + let excluded = false; + + for(let j = 0; j < excludedSubtrees.length; j++) + { + switch(excludedSubtrees[j].base.type) + { + //region rfc822Name + case 1: + if(subjectAltNames.length >= 0) + { + for(let k = 0; k < subjectAltNames.length; k++) + { + if(subjectAltNames[k].type === 1) // rfc822Name + excluded = excluded || compareRFC822Name(subjectAltNames[k].value, excludedSubtrees[j].base.value); + } + } + else // Try to find out "emailAddress" inside "subject" + { + for(let k = 0; k < this.certs[i].subject.typesAndValues.length; k++) + { + if((this.certs[i].subject.typesAndValues[k].type === "1.2.840.113549.1.9.1") || // PKCS#9 e-mail address + (this.certs[i].subject.typesAndValues[k].type === "0.9.2342.19200300.100.1.3")) // RFC1274 "rfc822Mailbox" e-mail address + excluded = excluded || compareRFC822Name(this.certs[i].subject.typesAndValues[k].value.valueBlock.value, excludedSubtrees[j].base.value); + } + } + break; + //endregion + //region dNSName + case 2: + if(subjectAltNames.length > 0) + { + for(let k = 0; k < subjectAltNames.length; k++) + { + if(subjectAltNames[k].type === 2) // dNSName + excluded = excluded || compareDNSName(subjectAltNames[k].value, excludedSubtrees[j].base.value); + } + } + break; + //endregion + //region directoryName + case 4: + excluded = excluded || compareDirectoryName(this.certs[i].subject, excludedSubtrees[j].base.value); + break; + //endregion + //region uniformResourceIdentifier + case 6: + if(subjectAltNames.length > 0) + { + for(let k = 0; k < subjectAltNames.length; k++) + { + if(subjectAltNames[k].type === 6) // uniformResourceIdentifier + excluded = excluded || compareUniformResourceIdentifier(subjectAltNames[k].value, excludedSubtrees[j].base.value); + } + } + break; + //endregion + //region iPAddress + case 7: + if(subjectAltNames.length > 0) + { + for(let k = 0; k < subjectAltNames.length; k++) + { + if(subjectAltNames[k].type === 7) // iPAddress + excluded = excluded || compareIPAddress(subjectAltNames[k].value, excludedSubtrees[j].base.value); + } + } + break; + //endregion + //region default + default: // No action, but probably here we need to create a warning for "malformed constraint" + //endregion + } + + if(excluded) + break; + } + + if(excluded === true) + { + policyResult.result = false; + policyResult.resultCode = 42; + policyResult.resultMessage = "Failed to meet \"excluded sub-trees\" name constraint"; + + throw policyResult; + } + //endregion + + //region Append "cert_..._subtrees" to "..._subtrees" + permittedSubtrees = permittedSubtrees.concat(certPermittedSubtrees); + excludedSubtrees = excludedSubtrees.concat(certExcludedSubtrees); + //endregion + } + //endregion + + return policyResult; + //endregion + } + catch(error) + { + if(error instanceof Object) + { + if("resultMessage" in error) + return error; + + if("message" in error) + { + return { + result: false, + resultCode: -1, + resultMessage: error.message + }; + } + } + + return { + result: false, + resultCode: -1, + resultMessage: error + }; + } + } + //********************************************************************************** +} +//************************************************************************************** diff --git a/core/third-party/pkijs/CertificatePolicies.js b/core/third-party/pkijs/CertificatePolicies.js new file mode 100644 index 0000000..07a55bf --- /dev/null +++ b/core/third-party/pkijs/CertificatePolicies.js @@ -0,0 +1,134 @@ +import * as asn1js from "./asn1.js"; +import { getParametersValue, clearProps } from "./pvutils.js"; +import PolicyInformation from "./PolicyInformation.js"; +//************************************************************************************** +/** + * Class from RFC5280 + */ +export default class CertificatePolicies +{ + //********************************************************************************** + /** + * Constructor for CertificatePolicies class + * @param {Object} [parameters={}] + * @param {Object} [parameters.schema] asn1js parsed value to initialize the class from + */ + constructor(parameters = {}) + { + //region Internal properties of the object + /** + * @type {Array.} + * @desc certificatePolicies + */ + this.certificatePolicies = getParametersValue(parameters, "certificatePolicies", CertificatePolicies.defaultValues("certificatePolicies")); + //endregion + + //region If input argument array contains "schema" for this object + if("schema" in parameters) + this.fromSchema(parameters.schema); + //endregion + } + //********************************************************************************** + /** + * Return default values for all class members + * @param {string} memberName String name for a class member + */ + static defaultValues(memberName) + { + switch(memberName) + { + case "certificatePolicies": + return []; + default: + throw new Error(`Invalid member name for CertificatePolicies class: ${memberName}`); + } + } + //********************************************************************************** + /** + * Return value of pre-defined ASN.1 schema for current class + * + * ASN.1 schema: + * ```asn1 + * certificatePolicies ::= SEQUENCE SIZE (1..MAX) OF PolicyInformation + * ``` + * + * @param {Object} parameters Input parameters for the schema + * @returns {Object} asn1js schema object + */ + static schema(parameters = {}) + { + /** + * @type {Object} + * @property {string} [blockName] + * @property {string} [certificatePolicies] + */ + const names = getParametersValue(parameters, "names", {}); + + return (new asn1js.Sequence({ + name: (names.blockName || ""), + value: [ + new asn1js.Repeated({ + name: (names.certificatePolicies || ""), + value: PolicyInformation.schema() + }) + ] + })); + } + //********************************************************************************** + /** + * Convert parsed asn1js object into current class + * @param {!Object} schema + */ + fromSchema(schema) + { + //region Clear input data first + clearProps(schema, [ + "certificatePolicies" + ]); + //endregion + + //region Check the schema is valid + const asn1 = asn1js.compareSchema(schema, + schema, + CertificatePolicies.schema({ + names: { + certificatePolicies: "certificatePolicies" + } + }) + ); + + if(asn1.verified === false) + throw new Error("Object's schema was not verified against input data for CertificatePolicies"); + //endregion + + //region Get internal properties from parsed schema + this.certificatePolicies = Array.from(asn1.result.certificatePolicies, element => new PolicyInformation({ schema: element })); + //endregion + } + //********************************************************************************** + /** + * Convert current object to asn1js object and set correct values + * @returns {Object} asn1js object + */ + toSchema() + { + //region Construct and return new ASN.1 schema for this object + return (new asn1js.Sequence({ + value: Array.from(this.certificatePolicies, element => element.toSchema()) + })); + //endregion + } + //********************************************************************************** + /** + * Convertion for the class to JSON object + * @returns {Object} + */ + toJSON() + { + return { + certificatePolicies: Array.from(this.certificatePolicies, element => element.toJSON()) + }; + } + //********************************************************************************** +} +//************************************************************************************** diff --git a/core/third-party/pkijs/CertificateRevocationList.js b/core/third-party/pkijs/CertificateRevocationList.js new file mode 100644 index 0000000..c9ec5ed --- /dev/null +++ b/core/third-party/pkijs/CertificateRevocationList.js @@ -0,0 +1,538 @@ +import * as asn1js from "./asn1.js"; +import { getParametersValue, bufferToHexCodes, clearProps } from "./pvutils.js"; +import { getEngine } from "./common.js"; +import AlgorithmIdentifier from "./AlgorithmIdentifier.js"; +import RelativeDistinguishedNames from "./RelativeDistinguishedNames.js"; +import Time from "./Time.js"; +import RevokedCertificate from "./RevokedCertificate.js"; +import Extensions from "./Extensions.js"; +//************************************************************************************** +function tbsCertList(parameters = {}) +{ + //TBSCertList ::= SEQUENCE { + // version Version OPTIONAL, + // -- if present, MUST be v2 + // signature AlgorithmIdentifier, + // issuer Name, + // thisUpdate Time, + // nextUpdate Time OPTIONAL, + // revokedCertificates SEQUENCE OF SEQUENCE { + // userCertificate CertificateSerialNumber, + // revocationDate Time, + // crlEntryExtensions Extensions OPTIONAL + // -- if present, version MUST be v2 + // } OPTIONAL, + // crlExtensions [0] EXPLICIT Extensions OPTIONAL + // -- if present, version MUST be v2 + //} + + /** + * @type {Object} + * @property {string} [blockName] + * @property {string} [tbsCertListVersion] + * @property {string} [signature] + * @property {string} [issuer] + * @property {string} [tbsCertListThisUpdate] + * @property {string} [tbsCertListNextUpdate] + * @property {string} [tbsCertListRevokedCertificates] + * @property {string} [crlExtensions] + */ + const names = getParametersValue(parameters, "names", {}); + + return (new asn1js.Sequence({ + name: (names.blockName || "tbsCertList"), + value: [ + new asn1js.Integer({ + optional: true, + name: (names.tbsCertListVersion || "tbsCertList.version"), + value: 2 + }), // EXPLICIT integer value (v2) + AlgorithmIdentifier.schema(names.signature || { + names: { + blockName: "tbsCertList.signature" + } + }), + RelativeDistinguishedNames.schema(names.issuer || { + names: { + blockName: "tbsCertList.issuer" + } + }), + Time.schema(names.tbsCertListThisUpdate || { + names: { + utcTimeName: "tbsCertList.thisUpdate", + generalTimeName: "tbsCertList.thisUpdate" + } + }), + Time.schema(names.tbsCertListNextUpdate || { + names: { + utcTimeName: "tbsCertList.nextUpdate", + generalTimeName: "tbsCertList.nextUpdate" + } + }, true), + new asn1js.Sequence({ + optional: true, + value: [ + new asn1js.Repeated({ + name: (names.tbsCertListRevokedCertificates || "tbsCertList.revokedCertificates"), + value: new asn1js.Sequence({ + value: [ + new asn1js.Integer(), + Time.schema(), + Extensions.schema({}, true) + ] + }) + }) + ] + }), + new asn1js.Constructed({ + optional: true, + idBlock: { + tagClass: 3, // CONTEXT-SPECIFIC + tagNumber: 0 // [0] + }, + value: [Extensions.schema(names.crlExtensions || { + names: { + blockName: "tbsCertList.extensions" + } + })] + }) // EXPLICIT SEQUENCE value + ] + })); +} +//************************************************************************************** +/** + * Class from RFC5280 + */ +export default class CertificateRevocationList { + //********************************************************************************** + /** + * Constructor for Attribute class + * @param {Object} [parameters={}] + * @param {Object} [parameters.schema] asn1js parsed value to initialize the class from + */ + constructor(parameters = {}) + { + //region Internal properties of the object + /** + * @type {ArrayBuffer} + * @desc tbs + */ + this.tbs = getParametersValue(parameters, "tbs", CertificateRevocationList.defaultValues("tbs")); + /** + * @type {number} + * @desc version + */ + this.version = getParametersValue(parameters, "version", CertificateRevocationList.defaultValues("version")); + /** + * @type {AlgorithmIdentifier} + * @desc signature + */ + this.signature = getParametersValue(parameters, "signature", CertificateRevocationList.defaultValues("signature")); + /** + * @type {RelativeDistinguishedNames} + * @desc issuer + */ + this.issuer = getParametersValue(parameters, "issuer", CertificateRevocationList.defaultValues("issuer")); + /** + * @type {Time} + * @desc thisUpdate + */ + this.thisUpdate = getParametersValue(parameters, "thisUpdate", CertificateRevocationList.defaultValues("thisUpdate")); + + if("nextUpdate" in parameters) + /** + * @type {Time} + * @desc nextUpdate + */ + this.nextUpdate = getParametersValue(parameters, "nextUpdate", CertificateRevocationList.defaultValues("nextUpdate")); + + if("revokedCertificates" in parameters) + /** + * @type {Array.} + * @desc revokedCertificates + */ + this.revokedCertificates = getParametersValue(parameters, "revokedCertificates", CertificateRevocationList.defaultValues("revokedCertificates")); + + if("crlExtensions" in parameters) + /** + * @type {Extensions} + * @desc crlExtensions + */ + this.crlExtensions = getParametersValue(parameters, "crlExtensions", CertificateRevocationList.defaultValues("crlExtensions")); + + /** + * @type {AlgorithmIdentifier} + * @desc signatureAlgorithm + */ + this.signatureAlgorithm = getParametersValue(parameters, "signatureAlgorithm", CertificateRevocationList.defaultValues("signatureAlgorithm")); + /** + * @type {BitString} + * @desc signatureValue + */ + this.signatureValue = getParametersValue(parameters, "signatureValue", CertificateRevocationList.defaultValues("signatureValue")); + //endregion + + //region If input argument array contains "schema" for this object + if("schema" in parameters) + this.fromSchema(parameters.schema); + //endregion + } + //********************************************************************************** + /** + * Return default values for all class members + * @param {string} memberName String name for a class member + */ + static defaultValues(memberName) + { + switch(memberName) + { + case "tbs": + return new ArrayBuffer(0); + case "version": + return 1; + case "signature": + return new AlgorithmIdentifier(); + case "issuer": + return new RelativeDistinguishedNames(); + case "thisUpdate": + return new Time(); + case "nextUpdate": + return new Time(); + case "revokedCertificates": + return []; + case "crlExtensions": + return new Extensions(); + case "signatureAlgorithm": + return new AlgorithmIdentifier(); + case "signatureValue": + return new asn1js.BitString(); + default: + throw new Error(`Invalid member name for CertificateRevocationList class: ${memberName}`); + } + } + //********************************************************************************** + /** + * Return value of pre-defined ASN.1 schema for current class + * + * ASN.1 schema: + * ```asn1 + * CertificateList ::= SEQUENCE { + * tbsCertList TBSCertList, + * signatureAlgorithm AlgorithmIdentifier, + * signatureValue BIT STRING } + * ``` + * + * @param {Object} parameters Input parameters for the schema + * @returns {Object} asn1js schema object + */ + static schema(parameters = {}) + { + /** + * @type {Object} + * @property {string} [blockName] + * @property {string} [signatureAlgorithm] + * @property {string} [signatureValue] + */ + const names = getParametersValue(parameters, "names", {}); + + return (new asn1js.Sequence({ + name: (names.blockName || "CertificateList"), + value: [ + tbsCertList(parameters), + AlgorithmIdentifier.schema(names.signatureAlgorithm || { + names: { + blockName: "signatureAlgorithm" + } + }), + new asn1js.BitString({ name: (names.signatureValue || "signatureValue") }) + ] + })); + } + //********************************************************************************** + /** + * Convert parsed asn1js object into current class + * @param {!Object} schema + */ + fromSchema(schema) + { + //region Clear input data first + clearProps(schema, [ + "tbsCertList", + "tbsCertList.version", + "tbsCertList.signature", + "tbsCertList.issuer", + "tbsCertList.thisUpdate", + "tbsCertList.nextUpdate", + "tbsCertList.revokedCertificates", + "tbsCertList.extensions", + "signatureAlgorithm", + "signatureValue" + ]); + //endregion + + //region Check the schema is valid + const asn1 = asn1js.compareSchema(schema, + schema, + CertificateRevocationList.schema() + ); + + if(asn1.verified === false) + throw new Error("Object's schema was not verified against input data for CertificateRevocationList"); + //endregion + + //region Get internal properties from parsed schema + // noinspection JSUnresolvedVariable + this.tbs = asn1.result.tbsCertList.valueBeforeDecode; + + if("tbsCertList.version" in asn1.result) + this.version = asn1.result["tbsCertList.version"].valueBlock.valueDec; + this.signature = new AlgorithmIdentifier({ schema: asn1.result["tbsCertList.signature"] }); + this.issuer = new RelativeDistinguishedNames({ schema: asn1.result["tbsCertList.issuer"] }); + this.thisUpdate = new Time({ schema: asn1.result["tbsCertList.thisUpdate"] }); + if("tbsCertList.nextUpdate" in asn1.result) + this.nextUpdate = new Time({ schema: asn1.result["tbsCertList.nextUpdate"] }); + if("tbsCertList.revokedCertificates" in asn1.result) + this.revokedCertificates = Array.from(asn1.result["tbsCertList.revokedCertificates"], element => new RevokedCertificate({ schema: element })); + if("tbsCertList.extensions" in asn1.result) + this.crlExtensions = new Extensions({ schema: asn1.result["tbsCertList.extensions"] }); + + this.signatureAlgorithm = new AlgorithmIdentifier({ schema: asn1.result.signatureAlgorithm }); + this.signatureValue = asn1.result.signatureValue; + //endregion + } + //********************************************************************************** + encodeTBS() + { + //region Create array for output sequence + const outputArray = []; + + if(this.version !== CertificateRevocationList.defaultValues("version")) + outputArray.push(new asn1js.Integer({ value: this.version })); + + outputArray.push(this.signature.toSchema()); + outputArray.push(this.issuer.toSchema()); + outputArray.push(this.thisUpdate.toSchema()); + + if("nextUpdate" in this) + outputArray.push(this.nextUpdate.toSchema()); + + if("revokedCertificates" in this) + { + outputArray.push(new asn1js.Sequence({ + value: Array.from(this.revokedCertificates, element => element.toSchema()) + })); + } + + if("crlExtensions" in this) + { + outputArray.push(new asn1js.Constructed({ + optional: true, + idBlock: { + tagClass: 3, // CONTEXT-SPECIFIC + tagNumber: 0 // [0] + }, + value: [ + this.crlExtensions.toSchema() + ] + })); + } + //endregion + + return (new asn1js.Sequence({ + value: outputArray + })); + } + //********************************************************************************** + /** + * Convert current object to asn1js object and set correct values + * @returns {Object} asn1js object + */ + toSchema(encodeFlag = false) + { + //region Decode stored TBS value + let tbsSchema; + + if(encodeFlag === false) + { + if(this.tbs.length === 0) // No stored TBS part + return CertificateRevocationList.schema(); + + tbsSchema = asn1js.fromBER(this.tbs).result; + } + //endregion + //region Create TBS schema via assembling from TBS parts + else + tbsSchema = this.encodeTBS(); + //endregion + + //region Construct and return new ASN.1 schema for this object + return (new asn1js.Sequence({ + value: [ + tbsSchema, + this.signatureAlgorithm.toSchema(), + this.signatureValue + ] + })); + //endregion + } + //********************************************************************************** + /** + * Convertion for the class to JSON object + * @returns {Object} + */ + toJSON() + { + const object = { + tbs: bufferToHexCodes(this.tbs, 0, this.tbs.byteLength), + signature: this.signature.toJSON(), + issuer: this.issuer.toJSON(), + thisUpdate: this.thisUpdate.toJSON(), + signatureAlgorithm: this.signatureAlgorithm.toJSON(), + signatureValue: this.signatureValue.toJSON() + }; + + if(this.version !== CertificateRevocationList.defaultValues("version")) + object.version = this.version; + + if("nextUpdate" in this) + object.nextUpdate = this.nextUpdate.toJSON(); + + if("revokedCertificates" in this) + object.revokedCertificates = Array.from(this.revokedCertificates, element => element.toJSON()); + + if("crlExtensions" in this) + object.crlExtensions = this.crlExtensions.toJSON(); + + return object; + } + //********************************************************************************** + isCertificateRevoked(certificate) + { + //region Check that issuer of the input certificate is the same with issuer of this CRL + if(this.issuer.isEqual(certificate.issuer) === false) + return false; + //endregion + + //region Check that there are revoked certificates in this CRL + if(("revokedCertificates" in this) === false) + return false; + //endregion + + //region Search for input certificate in revoked certificates array + for(const revokedCertificate of this.revokedCertificates) + { + if(revokedCertificate.userCertificate.isEqual(certificate.serialNumber)) + return true; + } + //endregion + + return false; + } + //********************************************************************************** + /** + * Make a signature for existing CRL data + * @param {Object} privateKey Private key for "subjectPublicKeyInfo" structure + * @param {string} [hashAlgorithm] Hashing algorithm. Default SHA-1 + */ + sign(privateKey, hashAlgorithm = "SHA-1") + { + //region Initial checking + //region Get a private key from function parameter + if(typeof privateKey === "undefined") + return Promise.reject("Need to provide a private key for signing"); + //endregion + //endregion + + //region Initial variables + let sequence = Promise.resolve(); + let parameters; + + const engine = getEngine(); + //endregion + + //region Get a "default parameters" for current algorithm and set correct signature algorithm + sequence = sequence.then(() => engine.subtle.getSignatureParameters(privateKey, hashAlgorithm)); + + sequence = sequence.then(result => + { + parameters = result.parameters; + this.signature = result.signatureAlgorithm; + this.signatureAlgorithm = result.signatureAlgorithm; + }); + //endregion + + //region Create TBS data for signing + sequence = sequence.then(() => + { + this.tbs = this.encodeTBS().toBER(false); + }); + //endregion + + //region Signing TBS data on provided private key + sequence = sequence.then(() => engine.subtle.signWithPrivateKey(this.tbs, privateKey, parameters)); + + sequence = sequence.then(result => + { + this.signatureValue = new asn1js.BitString({ valueHex: result }); + }); + //endregion + + return sequence; + } + //********************************************************************************** + /** + * Verify existing signature + * @param {{[issuerCertificate]: Object, [publicKeyInfo]: Object}} parameters + * @returns {*} + */ + verify(parameters = {}) + { + //region Global variables + let sequence = Promise.resolve(); + + let subjectPublicKeyInfo = -1; + + const engine = getEngine(); + //endregion + + //region Get information about CRL issuer certificate + if("issuerCertificate" in parameters) // "issuerCertificate" must be of type "Certificate" + { + subjectPublicKeyInfo = parameters.issuerCertificate.subjectPublicKeyInfo; + + // The CRL issuer name and "issuerCertificate" subject name are not equal + if(this.issuer.isEqual(parameters.issuerCertificate.subject) === false) + return Promise.resolve(false); + } + + //region In case if there is only public key during verification + if("publicKeyInfo" in parameters) + subjectPublicKeyInfo = parameters.publicKeyInfo; // Must be of type "PublicKeyInfo" + //endregion + + if(("subjectPublicKey" in subjectPublicKeyInfo) === false) + return Promise.reject("Issuer's certificate must be provided as an input parameter"); + //endregion + + //region Check the CRL for unknown critical extensions + if("crlExtensions" in this) + { + for(const extension of this.crlExtensions.extensions) + { + if(extension.critical) + { + // We can not be sure that unknown extension has no value for CRL signature + if(("parsedValue" in extension) === false) + return Promise.resolve(false); + } + } + } + //endregion + + sequence = sequence.then(() => engine.subtle.verifyWithPublicKey(this.tbs, this.signatureValue, subjectPublicKeyInfo, this.signatureAlgorithm)); + + return sequence; + } + //********************************************************************************** +} +//************************************************************************************** diff --git a/core/third-party/pkijs/CertificateSet.js b/core/third-party/pkijs/CertificateSet.js new file mode 100644 index 0000000..35c7adc --- /dev/null +++ b/core/third-party/pkijs/CertificateSet.js @@ -0,0 +1,235 @@ +import * as asn1js from "./asn1.js"; +import { getParametersValue, clearProps } from "./pvutils.js"; +import Certificate from "./Certificate.js"; +import AttributeCertificateV1 from "./AttributeCertificateV1.js"; +import AttributeCertificateV2 from "./AttributeCertificateV2.js"; +import OtherCertificateFormat from "./OtherCertificateFormat.js"; +//************************************************************************************** +/** + * Class from RFC5652 + */ +export default class CertificateSet +{ + //********************************************************************************** + /** + * Constructor for CertificateSet class + * @param {Object} [parameters={}] + * @param {Object} [parameters.schema] asn1js parsed value to initialize the class from + */ + constructor(parameters = {}) + { + //region Internal properties of the object + /** + * @type {Array} + * @desc certificates + */ + this.certificates = getParametersValue(parameters, "certificates", CertificateSet.defaultValues("certificates")); + //endregion + + //region If input argument array contains "schema" for this object + if("schema" in parameters) + this.fromSchema(parameters.schema); + //endregion + } + //********************************************************************************** + /** + * Return default values for all class members + * @param {string} memberName String name for a class member + */ + static defaultValues(memberName) + { + switch(memberName) + { + case "certificates": + return []; + default: + throw new Error(`Invalid member name for Attribute class: ${memberName}`); + } + } + //********************************************************************************** + /** + * Return value of pre-defined ASN.1 schema for current class + * + * ASN.1 schema: + * ```asn1 + * CertificateSet ::= SET OF CertificateChoices + * + * CertificateChoices ::= CHOICE { + * certificate Certificate, + * extendedCertificate [0] IMPLICIT ExtendedCertificate, -- Obsolete + * v1AttrCert [1] IMPLICIT AttributeCertificateV1, -- Obsolete + * v2AttrCert [2] IMPLICIT AttributeCertificateV2, + * other [3] IMPLICIT OtherCertificateFormat } + * ``` + * + * @param {Object} parameters Input parameters for the schema + * @returns {Object} asn1js schema object + */ + static schema(parameters = {}) + { + /** + * @type {Object} + * @property {string} [blockName] + */ + const names = getParametersValue(parameters, "names", {}); + + return ( + new asn1js.Set({ + name: (names.blockName || ""), + value: [ + new asn1js.Repeated({ + name: (names.certificates || "certificates"), + value: new asn1js.Choice({ + value: [ + Certificate.schema(), + new asn1js.Constructed({ + idBlock: { + tagClass: 3, // CONTEXT-SPECIFIC + tagNumber: 0 // [0] + }, + value: [ + new asn1js.Any() + ] + }), // JUST A STUB + new asn1js.Constructed({ + idBlock: { + tagClass: 3, // CONTEXT-SPECIFIC + tagNumber: 1 // [1] + }, + value: AttributeCertificateV1.schema().valueBlock.value + }), + new asn1js.Constructed({ + idBlock: { + tagClass: 3, // CONTEXT-SPECIFIC + tagNumber: 2 // [2] + }, + value: AttributeCertificateV2.schema().valueBlock.value + }), + new asn1js.Constructed({ + idBlock: { + tagClass: 3, // CONTEXT-SPECIFIC + tagNumber: 3 // [3] + }, + value: OtherCertificateFormat.schema().valueBlock.value + }) + ] + }) + }) + ] + }) + ); + } + //********************************************************************************** + /** + * Convert parsed asn1js object into current class + * @param {!Object} schema + */ + fromSchema(schema) + { + //region Clear input data first + clearProps(schema, [ + "certificates" + ]); + //endregion + + //region Check the schema is valid + const asn1 = asn1js.compareSchema(schema, + schema, + CertificateSet.schema() + ); + + if(asn1.verified === false) + throw new Error("Object's schema was not verified against input data for CertificateSet"); + //endregion + + //region Get internal properties from parsed schema + this.certificates = Array.from(asn1.result.certificates || [], element => + { + const initialTagNumber = element.idBlock.tagNumber; + + if(element.idBlock.tagClass === 1) + return new Certificate({ schema: element }); + + //region Making "Sequence" from "Constructed" value + const elementSequence = new asn1js.Sequence({ + value: element.valueBlock.value + }); + //endregion + + switch(initialTagNumber) + { + case 1: + return new AttributeCertificateV1({ schema: elementSequence }); + case 2: + return new AttributeCertificateV2({ schema: elementSequence }); + case 3: + return new OtherCertificateFormat({ schema: elementSequence }); + case 0: + default: + } + + return element; + }); + //endregion + } + //********************************************************************************** + /** + * Convert current object to asn1js object and set correct values + * @returns {Object} asn1js object + */ + toSchema() + { + //region Construct and return new ASN.1 schema for this object + return (new asn1js.Set({ + value: Array.from(this.certificates, element => + { + switch(true) + { + case (element instanceof Certificate): + return element.toSchema(); + case (element instanceof AttributeCertificateV1): + return new asn1js.Constructed({ + idBlock: { + tagClass: 3, + tagNumber: 1 // [1] + }, + value: element.toSchema().valueBlock.value + }); + case (element instanceof AttributeCertificateV2): + return new asn1js.Constructed({ + idBlock: { + tagClass: 3, + tagNumber: 2 // [2] + }, + value: element.toSchema().valueBlock.value + }); + case (element instanceof OtherCertificateFormat): + return new asn1js.Constructed({ + idBlock: { + tagClass: 3, + tagNumber: 3 // [3] + }, + value: element.toSchema().valueBlock.value + }); + default: + } + + return element; + }) + })); + //endregion + } + //********************************************************************************** + /** + * Convertion for the class to JSON object + * @returns {Object} + */ + toJSON() + { + return { + certificates: Array.from(this.certificates, element => element.toJSON()) + }; + } + //********************************************************************************** +} +//************************************************************************************** diff --git a/core/third-party/pkijs/CertificateTemplate.js b/core/third-party/pkijs/CertificateTemplate.js new file mode 100644 index 0000000..f18378e --- /dev/null +++ b/core/third-party/pkijs/CertificateTemplate.js @@ -0,0 +1,191 @@ +import * as asn1js from "./asn1.js"; +import { getParametersValue, clearProps } from "./pvutils.js"; +//************************************************************************************** +/** + * Class from "[MS-WCCE]: Windows Client Certificate Enrollment Protocol" + */ +export default class CertificateTemplate +{ + //********************************************************************************** + /** + * Constructor for CertificateTemplate class + * @param {Object} [parameters={}] + * @param {Object} [parameters.schema] asn1js parsed value to initialize the class from + */ + constructor(parameters = {}) + { + //region Internal properties of the object + /** + * @type {string} + * @desc templateID + */ + this.templateID = getParametersValue(parameters, "templateID", CertificateTemplate.defaultValues("templateID")); + + if("templateMajorVersion" in parameters) + /** + * @type {number} + * @desc templateMajorVersion + */ + this.templateMajorVersion = getParametersValue(parameters, "templateMajorVersion", CertificateTemplate.defaultValues("templateMajorVersion")); + + if("templateMinorVersion" in parameters) + /** + * @type {number} + * @desc templateMinorVersion + */ + this.templateMinorVersion = getParametersValue(parameters, "templateMinorVersion", CertificateTemplate.defaultValues("templateMinorVersion")); + //endregion + + //region If input argument array contains "schema" for this object + if("schema" in parameters) + this.fromSchema(parameters.schema); + //endregion + } + //********************************************************************************** + /** + * Return default values for all class members + * @param {string} memberName String name for a class member + */ + static defaultValues(memberName) + { + switch(memberName) + { + case "templateID": + return ""; + case "templateMajorVersion": + case "templateMinorVersion": + return 0; + default: + throw new Error(`Invalid member name for CertificateTemplate class: ${memberName}`); + } + } + //********************************************************************************** + /** + * Return value of pre-defined ASN.1 schema for current class + * + * ASN.1 schema: + * ```asn1 + * CertificateTemplateOID ::= SEQUENCE { + * templateID OBJECT IDENTIFIER, + * templateMajorVersion INTEGER (0..4294967295) OPTIONAL, + * templateMinorVersion INTEGER (0..4294967295) OPTIONAL + * } + * ``` + * + * @param {Object} parameters Input parameters for the schema + * @returns {Object} asn1js schema object + */ + static schema(parameters = {}) + { + /** + * @type {Object} + * @property {string} [blockName] + * @property {string} [templateID] + * @property {string} [templateMajorVersion] + * @property {string} [templateMinorVersion] + */ + const names = getParametersValue(parameters, "names", {}); + + return (new asn1js.Sequence({ + name: (names.blockName || ""), + value: [ + new asn1js.ObjectIdentifier({ name: (names.templateID || "") }), + new asn1js.Integer({ + name: (names.templateMajorVersion || ""), + optional: true + }), + new asn1js.Integer({ + name: (names.templateMinorVersion || ""), + optional: true + }), + ] + })); + } + //********************************************************************************** + /** + * Convert parsed asn1js object into current class + * @param {!Object} schema + */ + fromSchema(schema) + { + //region Clear input data first + clearProps(schema, [ + "templateID", + "templateMajorVersion", + "templateMinorVersion" + ]); + //endregion + + //region Check the schema is valid + let asn1 = asn1js.compareSchema(schema, + schema, + CertificateTemplate.schema({ + names: { + templateID: "templateID", + templateMajorVersion: "templateMajorVersion", + templateMinorVersion: "templateMinorVersion" + } + }) + ); + + if(asn1.verified === false) + throw new Error("Object's schema was not verified against input data for CertificateTemplate"); + //endregion + + //region Get internal properties from parsed schema + this.templateID = asn1.result.templateID.valueBlock.toString(); + + if("templateMajorVersion" in asn1.result) + this.templateMajorVersion = asn1.result.templateMajorVersion.valueBlock.valueDec; + + if("templateMinorVersion" in asn1.result) + this.templateMinorVersion = asn1.result.templateMinorVersion.valueBlock.valueDec; + //endregion + } + //********************************************************************************** + /** + * Convert current object to asn1js object and set correct values + * @returns {Object} asn1js object + */ + toSchema() + { + //region Create array for output sequence + const outputArray = []; + + outputArray.push(new asn1js.ObjectIdentifier({ value: this.templateID })); + + if("templateMajorVersion" in this) + outputArray.push(new asn1js.Integer({ value: this.templateMajorVersion })); + + if("templateMinorVersion" in this) + outputArray.push(new asn1js.Integer({ value: this.templateMinorVersion })); + //endregion + + //region Construct and return new ASN.1 schema for this object + return (new asn1js.Sequence({ + value: outputArray + })); + //endregion + } + //********************************************************************************** + /** + * Convertion for the class to JSON object + * @returns {Object} + */ + toJSON() + { + const object = { + extnID: this.templateID + }; + + if("templateMajorVersion" in this) + object.templateMajorVersion = this.templateMajorVersion; + + if("templateMinorVersion" in this) + object.templateMinorVersion = this.templateMinorVersion; + + return object; + } + //********************************************************************************** +} +//************************************************************************************** diff --git a/core/third-party/pkijs/CertificationRequest.js b/core/third-party/pkijs/CertificationRequest.js new file mode 100644 index 0000000..bbbc9fa --- /dev/null +++ b/core/third-party/pkijs/CertificationRequest.js @@ -0,0 +1,383 @@ +import * as asn1js from "./asn1.js"; +import { getParametersValue, bufferToHexCodes, clearProps } from "./pvutils.js"; +import { getEngine } from "./common.js"; +import PublicKeyInfo from "./PublicKeyInfo.js"; +import RelativeDistinguishedNames from "./RelativeDistinguishedNames.js"; +import AlgorithmIdentifier from "./AlgorithmIdentifier.js"; +import Attribute from "./Attribute.js"; +//************************************************************************************** +function CertificationRequestInfo(parameters = {}) +{ + //CertificationRequestInfo ::= SEQUENCE { + // version INTEGER { v1(0) } (v1,...), + // subject Name, + // subjectPKInfo SubjectPublicKeyInfo{{ PKInfoAlgorithms }}, + // attributes [0] Attributes{{ CRIAttributes }} + //} + + /** + * @type {Object} + * @property {string} [blockName] + * @property {string} [CertificationRequestInfo] + * @property {string} [CertificationRequestInfoVersion] + * @property {string} [subject] + * @property {string} [CertificationRequestInfoAttributes] + * @property {string} [attributes] + */ + const names = getParametersValue(parameters, "names", {}); + + return (new asn1js.Sequence({ + name: (names.CertificationRequestInfo || "CertificationRequestInfo"), + value: [ + new asn1js.Integer({ name: (names.CertificationRequestInfoVersion || "CertificationRequestInfo.version") }), + RelativeDistinguishedNames.schema(names.subject || { + names: { + blockName: "CertificationRequestInfo.subject" + } + }), + PublicKeyInfo.schema({ + names: { + blockName: "CertificationRequestInfo.subjectPublicKeyInfo" + } + }), + new asn1js.Constructed({ + optional: true, + idBlock: { + tagClass: 3, // CONTEXT-SPECIFIC + tagNumber: 0 // [0] + }, + value: [ + new asn1js.Repeated({ + optional: true, // Because OpenSSL makes wrong "attributes" field + name: (names.CertificationRequestInfoAttributes || "CertificationRequestInfo.attributes"), + value: Attribute.schema(names.attributes || {}) + }) + ] + }) + ] + })); +} +//************************************************************************************** +/** + * Class from RFC2986 + */ +export default class CertificationRequest +{ + //********************************************************************************** + /** + * Constructor for Attribute class + * @param {Object} [parameters={}] + * @param {Object} [parameters.schema] asn1js parsed value to initialize the class from + */ + constructor(parameters = {}) + { + //region Internal properties of the object + /** + * @type {ArrayBuffer} + * @desc tbs + */ + this.tbs = getParametersValue(parameters, "tbs", CertificationRequest.defaultValues("tbs")); + /** + * @type {number} + * @desc version + */ + this.version = getParametersValue(parameters, "version", CertificationRequest.defaultValues("version")); + /** + * @type {RelativeDistinguishedNames} + * @desc subject + */ + this.subject = getParametersValue(parameters, "subject", CertificationRequest.defaultValues("subject")); + /** + * @type {PublicKeyInfo} + * @desc subjectPublicKeyInfo + */ + this.subjectPublicKeyInfo = getParametersValue(parameters, "subjectPublicKeyInfo", CertificationRequest.defaultValues("subjectPublicKeyInfo")); + + if("attributes" in parameters) + /** + * @type {Array.} + * @desc attributes + */ + this.attributes = getParametersValue(parameters, "attributes", CertificationRequest.defaultValues("attributes")); + + /** + * @type {AlgorithmIdentifier} + * @desc signatureAlgorithm + */ + this.signatureAlgorithm = getParametersValue(parameters, "signatureAlgorithm", CertificationRequest.defaultValues("signatureAlgorithm")); + /** + * @type {BitString} + * @desc signatureAlgorithm + */ + this.signatureValue = getParametersValue(parameters, "signatureValue", CertificationRequest.defaultValues("signatureValue")); + //endregion + + //region If input argument array contains "schema" for this object + if("schema" in parameters) + this.fromSchema(parameters.schema); + //endregion + } + //********************************************************************************** + /** + * Return default values for all class members + * @param {string} memberName String name for a class member + */ + static defaultValues(memberName) + { + switch(memberName) + { + case "tbs": + return new ArrayBuffer(0); + case "version": + return 0; + case "subject": + return new RelativeDistinguishedNames(); + case "subjectPublicKeyInfo": + return new PublicKeyInfo(); + case "attributes": + return []; + case "signatureAlgorithm": + return new AlgorithmIdentifier(); + case "signatureValue": + return new asn1js.BitString(); + default: + throw new Error(`Invalid member name for CertificationRequest class: ${memberName}`); + } + } + //********************************************************************************** + /** + * Return value of pre-defined ASN.1 schema for current class + * + * ASN.1 schema: + * ```asn1 + * CertificationRequest ::= SEQUENCE { + * certificationRequestInfo CertificationRequestInfo, + * signatureAlgorithm AlgorithmIdentifier{{ SignatureAlgorithms }}, + * signature BIT STRING + * } + * ``` + * + * @param {Object} parameters Input parameters for the schema + * @returns {Object} asn1js schema object + */ + static schema(parameters = {}) + { + /** + * @type {Object} + * @property {string} [blockName] + * @property {string} [certificationRequestInfo] + * @property {string} [signatureAlgorithm] + * @property {string} [signatureValue] + */ + const names = getParametersValue(parameters, "names", {}); + + return (new asn1js.Sequence({ + value: [ + CertificationRequestInfo(names.certificationRequestInfo || {}), + new asn1js.Sequence({ + name: (names.signatureAlgorithm || "signatureAlgorithm"), + value: [ + new asn1js.ObjectIdentifier(), + new asn1js.Any({ optional: true }) + ] + }), + new asn1js.BitString({ name: (names.signatureValue || "signatureValue") }) + ] + })); + } + //********************************************************************************** + /** + * Convert parsed asn1js object into current class + * @param {!Object} schema + */ + fromSchema(schema) + { + //region Clear input data first + clearProps(schema, [ + "CertificationRequestInfo", + "CertificationRequestInfo.version", + "CertificationRequestInfo.subject", + "CertificationRequestInfo.subjectPublicKeyInfo", + "CertificationRequestInfo.attributes", + "signatureAlgorithm", + "signatureValue" + ]); + //endregion + + //region Check the schema is valid + const asn1 = asn1js.compareSchema(schema, + schema, + CertificationRequest.schema() + ); + + if(asn1.verified === false) + throw new Error("Object's schema was not verified against input data for CertificationRequest"); + //endregion + + //region Get internal properties from parsed schema + this.tbs = asn1.result.CertificationRequestInfo.valueBeforeDecode; + + this.version = asn1.result["CertificationRequestInfo.version"].valueBlock.valueDec; + this.subject = new RelativeDistinguishedNames({ schema: asn1.result["CertificationRequestInfo.subject"] }); + this.subjectPublicKeyInfo = new PublicKeyInfo({ schema: asn1.result["CertificationRequestInfo.subjectPublicKeyInfo"] }); + if("CertificationRequestInfo.attributes" in asn1.result) + this.attributes = Array.from(asn1.result["CertificationRequestInfo.attributes"], element => new Attribute({ schema: element })); + + this.signatureAlgorithm = new AlgorithmIdentifier({ schema: asn1.result.signatureAlgorithm }); + this.signatureValue = asn1.result.signatureValue; + //endregion + } + //********************************************************************************** + /** + * Aux function making ASN1js Sequence from current TBS + * @returns {Sequence} + */ + encodeTBS() + { + //region Create array for output sequence + const outputArray = [ + new asn1js.Integer({ value: this.version }), + this.subject.toSchema(), + this.subjectPublicKeyInfo.toSchema() + ]; + + if("attributes" in this) + { + outputArray.push(new asn1js.Constructed({ + idBlock: { + tagClass: 3, // CONTEXT-SPECIFIC + tagNumber: 0 // [0] + }, + value: Array.from(this.attributes, element => element.toSchema()) + })); + } + //endregion + + return (new asn1js.Sequence({ + value: outputArray + })); + } + //********************************************************************************** + /** + * Convert current object to asn1js object and set correct values + * @returns {Object} asn1js object + */ + toSchema(encodeFlag = false) + { + //region Decode stored TBS value + let tbsSchema; + + if(encodeFlag === false) + { + if(this.tbs.byteLength === 0) // No stored TBS part + return CertificationRequest.schema(); + + tbsSchema = asn1js.fromBER(this.tbs).result; + } + //endregion + //region Create TBS schema via assembling from TBS parts + else + tbsSchema = this.encodeTBS(); + //endregion + + //region Construct and return new ASN.1 schema for this object + return (new asn1js.Sequence({ + value: [ + tbsSchema, + this.signatureAlgorithm.toSchema(), + this.signatureValue + ] + })); + //endregion + } + //********************************************************************************** + /** + * Convertion for the class to JSON object + * @returns {Object} + */ + toJSON() + { + const object = { + tbs: bufferToHexCodes(this.tbs, 0, this.tbs.byteLength), + version: this.version, + subject: this.subject.toJSON(), + subjectPublicKeyInfo: this.subjectPublicKeyInfo.toJSON(), + signatureAlgorithm: this.signatureAlgorithm.toJSON(), + signatureValue: this.signatureValue.toJSON() + }; + + if("attributes" in this) + object.attributes = Array.from(this.attributes, element => element.toJSON()); + + return object; + } + //********************************************************************************** + /** + * Makes signature for currect certification request + * @param {Object} privateKey WebCrypto private key + * @param {string} [hashAlgorithm=SHA-1] String representing current hashing algorithm + */ + sign(privateKey, hashAlgorithm = "SHA-1") + { + //region Initial checking + //region Get a private key from function parameter + if(typeof privateKey === "undefined") + return Promise.reject("Need to provide a private key for signing"); + //endregion + //endregion + + //region Initial variables + let sequence = Promise.resolve(); + let parameters; + + const engine = getEngine(); + //endregion + + //region Get a "default parameters" for current algorithm and set correct signature algorithm + sequence = sequence.then(() => engine.subtle.getSignatureParameters(privateKey, hashAlgorithm)); + + sequence = sequence.then(result => + { + parameters = result.parameters; + this.signatureAlgorithm = result.signatureAlgorithm; + }); + //endregion + + //region Create TBS data for signing + sequence = sequence.then(() => + { + this.tbs = this.encodeTBS().toBER(false); + }); + //endregion + + //region Signing TBS data on provided private key + sequence = sequence.then(() => engine.subtle.signWithPrivateKey(this.tbs, privateKey, parameters)); + + sequence = sequence.then(result => + { + this.signatureValue = new asn1js.BitString({ valueHex: result }); + }); + //endregion + + return sequence; + } + //********************************************************************************** + /** + * Verify existing certification request signature + * @returns {*} + */ + verify() + { + return getEngine().subtle.verifyWithPublicKey(this.tbs, this.signatureValue, this.subjectPublicKeyInfo, this.signatureAlgorithm); + } + //********************************************************************************** + /** + * Importing public key for current certificate request + */ + getPublicKey(parameters = null) + { + return getEngine().getPublicKey(this.subjectPublicKeyInfo, this.signatureAlgorithm, parameters); + } + //********************************************************************************** +} +//************************************************************************************** diff --git a/core/third-party/pkijs/ContentInfo.js b/core/third-party/pkijs/ContentInfo.js new file mode 100644 index 0000000..c370678 --- /dev/null +++ b/core/third-party/pkijs/ContentInfo.js @@ -0,0 +1,181 @@ +import * as asn1js from "./asn1.js"; +import { getParametersValue, clearProps } from "./pvutils.js"; +//************************************************************************************** +/** + * Class from RFC5652 + */ +export default class ContentInfo +{ + //********************************************************************************** + /** + * Constructor for ContentInfo class + * @param {Object} [parameters={}] + * @param {Object} [parameters.schema] asn1js parsed value to initialize the class from + */ + constructor(parameters = {}) + { + //region Internal properties of the object + /** + * @type {string} + * @desc contentType + */ + this.contentType = getParametersValue(parameters, "contentType", ContentInfo.defaultValues("contentType")); + /** + * @type {Any} + * @desc content + */ + this.content = getParametersValue(parameters, "content", ContentInfo.defaultValues("content")); + //endregion + + //region If input argument array contains "schema" for this object + if("schema" in parameters) + this.fromSchema(parameters.schema); + //endregion + } + //********************************************************************************** + /** + * Return default values for all class members + * @param {string} memberName String name for a class member + */ + static defaultValues(memberName) + { + switch(memberName) + { + case "contentType": + return ""; + case "content": + return new asn1js.Any(); + default: + throw new Error(`Invalid member name for ContentInfo class: ${memberName}`); + } + } + //********************************************************************************** + /** + * Compare values with default values for all class members + * @param {string} memberName String name for a class member + * @param {*} memberValue Value to compare with default value + */ + static compareWithDefault(memberName, memberValue) + { + switch(memberName) + { + case "contentType": + return (memberValue === ""); + case "content": + return (memberValue instanceof asn1js.Any); + default: + throw new Error(`Invalid member name for ContentInfo class: ${memberName}`); + } + } + //********************************************************************************** + /** + * Return value of pre-defined ASN.1 schema for current class + * + * ASN.1 schema: + * ```asn1 + * ContentInfo ::= SEQUENCE { + * contentType ContentType, + * content [0] EXPLICIT ANY DEFINED BY contentType } + * ``` + * + * @param {Object} parameters Input parameters for the schema + * @returns {Object} asn1js schema object + */ + static schema(parameters = {}) + { + /** + * @type {Object} + * @property {string} [blockName] + * @property {string} [contentType] + * @property {string} [content] + */ + const names = getParametersValue(parameters, "names", {}); + + if(("optional" in names) === false) + names.optional = false; + + return (new asn1js.Sequence({ + name: (names.blockName || "ContentInfo"), + optional: names.optional, + value: [ + new asn1js.ObjectIdentifier({ name: (names.contentType || "contentType") }), + new asn1js.Constructed({ + idBlock: { + tagClass: 3, // CONTEXT-SPECIFIC + tagNumber: 0 // [0] + }, + value: [new asn1js.Any({ name: (names.content || "content") })] // EXPLICIT ANY value + }) + ] + })); + } + //********************************************************************************** + /** + * Convert parsed asn1js object into current class + * @param {!Object} schema + */ + fromSchema(schema) + { + //region Clear input data first + clearProps(schema, [ + "contentType", + "content" + ]); + //endregion + + //region Check the schema is valid + const asn1 = asn1js.compareSchema(schema, + schema, + ContentInfo.schema() + ); + + if(asn1.verified === false) + throw new Error("Object's schema was not verified against input data for ContentInfo"); + //endregion + + //region Get internal properties from parsed schema + this.contentType = asn1.result.contentType.valueBlock.toString(); + this.content = asn1.result.content; + //endregion + } + //********************************************************************************** + /** + * Convert current object to asn1js object and set correct values + * @returns {Object} asn1js object + */ + toSchema() + { + //region Construct and return new ASN.1 schema for this object + return (new asn1js.Sequence({ + value: [ + new asn1js.ObjectIdentifier({ value: this.contentType }), + new asn1js.Constructed({ + idBlock: { + tagClass: 3, // CONTEXT-SPECIFIC + tagNumber: 0 // [0] + }, + value: [this.content] // EXPLICIT ANY value + }) + ] + })); + //endregion + } + //********************************************************************************** + /** + * Convertion for the class to JSON object + * @returns {Object} + */ + toJSON() + { + const object = { + contentType: this.contentType + }; + + if(!(this.content instanceof asn1js.Any)) + object.content = this.content.toJSON(); + + return object; + } + //********************************************************************************** +} +//************************************************************************************** diff --git a/core/third-party/pkijs/CryptoEngine.js b/core/third-party/pkijs/CryptoEngine.js new file mode 100644 index 0000000..d9c8f50 --- /dev/null +++ b/core/third-party/pkijs/CryptoEngine.js @@ -0,0 +1,2565 @@ +import * as asn1js from "./asn1.js"; +import { getParametersValue, stringToArrayBuffer, arrayBufferToString, utilConcatBuf } from "./pvutils.js"; +import { createCMSECDSASignature, createECDSASignatureFromCMS } from "./common.js"; +import PublicKeyInfo from "./PublicKeyInfo.js"; +import PrivateKeyInfo from "./PrivateKeyInfo.js"; +import AlgorithmIdentifier from "./AlgorithmIdentifier.js"; +import EncryptedContentInfo from "./EncryptedContentInfo.js"; +import RSASSAPSSParams from "./RSASSAPSSParams.js"; +import PBKDF2Params from "./PBKDF2Params.js"; +import PBES2Params from "./PBES2Params.js"; +//************************************************************************************** +/** + * Making MAC key using algorithm described in B.2 of PKCS#12 standard. + */ +function makePKCS12B2Key(cryptoEngine, hashAlgorithm, keyLength, password, salt, iterationCount) +{ + //region Initial variables + let u; + let v; + + const result = []; + //endregion + + //region Get "u" and "v" values + switch(hashAlgorithm.toUpperCase()) + { + case "SHA-1": + u = 20; // 160 + v = 64; // 512 + break; + case "SHA-256": + u = 32; // 256 + v = 64; // 512 + break; + case "SHA-384": + u = 48; // 384 + v = 128; // 1024 + break; + case "SHA-512": + u = 64; // 512 + v = 128; // 1024 + break; + default: + throw new Error("Unsupported hashing algorithm"); + } + //endregion + + //region Main algorithm making key + //region Transform password to UTF-8 like string + const passwordViewInitial = new Uint8Array(password); + + const passwordTransformed = new ArrayBuffer((password.byteLength * 2) + 2); + const passwordTransformedView = new Uint8Array(passwordTransformed); + + for(let i = 0; i < passwordViewInitial.length; i++) + { + passwordTransformedView[i * 2] = 0x00; + passwordTransformedView[i * 2 + 1] = passwordViewInitial[i]; + } + + passwordTransformedView[passwordTransformedView.length - 2] = 0x00; + passwordTransformedView[passwordTransformedView.length - 1] = 0x00; + + password = passwordTransformed.slice(0); + //endregion + + //region Construct a string D (the "diversifier") by concatenating v/8 copies of ID + const D = new ArrayBuffer(v); + const dView = new Uint8Array(D); + + for(let i = 0; i < D.byteLength; i++) + dView[i] = 3; // The ID value equal to "3" for MACing (see B.3 of standard) + //endregion + + //region Concatenate copies of the salt together to create a string S of length v * ceil(s / v) bytes (the final copy of the salt may be trunacted to create S) + const saltLength = salt.byteLength; + + const sLen = v * Math.ceil(saltLength / v); + const S = new ArrayBuffer(sLen); + const sView = new Uint8Array(S); + + const saltView = new Uint8Array(salt); + + for(let i = 0; i < sLen; i++) + sView[i] = saltView[i % saltLength]; + //endregion + + //region Concatenate copies of the password together to create a string P of length v * ceil(p / v) bytes (the final copy of the password may be truncated to create P) + const passwordLength = password.byteLength; + + const pLen = v * Math.ceil(passwordLength / v); + const P = new ArrayBuffer(pLen); + const pView = new Uint8Array(P); + + const passwordView = new Uint8Array(password); + + for(let i = 0; i < pLen; i++) + pView[i] = passwordView[i % passwordLength]; + //endregion + + //region Set I=S||P to be the concatenation of S and P + const sPlusPLength = S.byteLength + P.byteLength; + + let I = new ArrayBuffer(sPlusPLength); + let iView = new Uint8Array(I); + + iView.set(sView); + iView.set(pView, sView.length); + //endregion + + //region Set c=ceil(n / u) + const c = Math.ceil((keyLength >> 3) / u); + //endregion + + //region Initial variables + let internalSequence = Promise.resolve(I); + //endregion + + //region For i=1, 2, ..., c, do the following: + for(let i = 0; i <= c; i++) + { + internalSequence = internalSequence.then(_I => + { + //region Create contecanetion of D and I + const dAndI = new ArrayBuffer(D.byteLength + _I.byteLength); + const dAndIView = new Uint8Array(dAndI); + + dAndIView.set(dView); + dAndIView.set(iView, dView.length); + //endregion + + return dAndI; + }); + + //region Make "iterationCount" rounds of hashing + for(let j = 0; j < iterationCount; j++) + internalSequence = internalSequence.then(roundBuffer => cryptoEngine.digest({ name: hashAlgorithm }, new Uint8Array(roundBuffer))); + //endregion + + internalSequence = internalSequence.then(roundBuffer => + { + //region Concatenate copies of Ai to create a string B of length v bits (the final copy of Ai may be truncated to create B) + const B = new ArrayBuffer(v); + const bView = new Uint8Array(B); + + for(let j = 0; j < B.byteLength; j++) + bView[j] = roundBuffer[j % roundBuffer.length]; + //endregion + + //region Make new I value + const k = Math.ceil(saltLength / v) + Math.ceil(passwordLength / v); + const iRound = []; + + let sliceStart = 0; + let sliceLength = v; + + for(let j = 0; j < k; j++) + { + const chunk = Array.from(new Uint8Array(I.slice(sliceStart, sliceStart + sliceLength))); + sliceStart += v; + if((sliceStart + v) > I.byteLength) + sliceLength = I.byteLength - sliceStart; + + let x = 0x1ff; + + for(let l = (B.byteLength - 1); l >= 0; l--) + { + x >>= 8; + x += bView[l] + chunk[l]; + chunk[l] = (x & 0xff); + } + + iRound.push(...chunk); + } + + I = new ArrayBuffer(iRound.length); + iView = new Uint8Array(I); + + iView.set(iRound); + //endregion + + result.push(...(new Uint8Array(roundBuffer))); + + return I; + }); + } + //endregion + + //region Initialize final key + internalSequence = internalSequence.then(() => + { + const resultBuffer = new ArrayBuffer(keyLength >> 3); + const resultView = new Uint8Array(resultBuffer); + + resultView.set((new Uint8Array(result)).slice(0, keyLength >> 3)); + + return resultBuffer; + }); + //endregion + //endregion + + return internalSequence; +} +//************************************************************************************** +/** + * Default cryptographic engine for Web Cryptography API + */ +export default class CryptoEngine +{ + //********************************************************************************** + /** + * Constructor for CryptoEngine class + * @param {Object} [parameters={}] + * @param {Object} [parameters.schema] asn1js parsed value to initialize the class from + */ + constructor(parameters = {}) + { + //region Internal properties of the object + /** + * @type {Object} + * @desc Usually here we are expecting "window.crypto" or an equivalent from custom "crypto engine" + */ + this.crypto = getParametersValue(parameters, "crypto", {}); + /** + * @type {Object} + * @desc Usually here we are expecting "window.crypto.subtle" or an equivalent from custom "crypto engine" + */ + this.subtle = getParametersValue(parameters, "subtle", {}); + /** + * @type {string} + * @desc Name of the "crypto engine" + */ + this.name = getParametersValue(parameters, "name", ""); + //endregion + } + //********************************************************************************** + /** + * Import WebCrypto keys from different formats + * @param {string} format + * @param {ArrayBuffer|Uint8Array} keyData + * @param {Object} algorithm + * @param {boolean} extractable + * @param {Array} keyUsages + * @returns {Promise} + */ + importKey(format, keyData, algorithm, extractable, keyUsages) + { + //region Initial variables + let jwk = {}; + //endregion + + //region Change "keyData" type if needed + if(keyData instanceof Uint8Array) + keyData = keyData.buffer; + //endregion + + switch(format.toLowerCase()) + { + case "raw": + return this.subtle.importKey("raw", keyData, algorithm, extractable, keyUsages); + case "spki": + { + const asn1 = asn1js.fromBER(keyData); + if(asn1.offset === (-1)) + return Promise.reject("Incorrect keyData"); + + const publicKeyInfo = new PublicKeyInfo(); + try + { + publicKeyInfo.fromSchema(asn1.result); + } + catch(ex) + { + return Promise.reject("Incorrect keyData"); + } + + + // noinspection FallThroughInSwitchStatementJS + switch(algorithm.name.toUpperCase()) + { + case "RSA-PSS": + { + //region Get information about used hash function + switch(algorithm.hash.name.toUpperCase()) + { + case "SHA-1": + jwk.alg = "PS1"; + break; + case "SHA-256": + jwk.alg = "PS256"; + break; + case "SHA-384": + jwk.alg = "PS384"; + break; + case "SHA-512": + jwk.alg = "PS512"; + break; + default: + return Promise.reject(`Incorrect hash algorithm: ${algorithm.hash.name.toUpperCase()}`); + } + //endregion + } + // break omitted + case "RSASSA-PKCS1-V1_5": + { + keyUsages = ["verify"]; // Override existing keyUsages value since the key is a public key + + jwk.kty = "RSA"; + jwk.ext = extractable; + jwk.key_ops = keyUsages; + + if(publicKeyInfo.algorithm.algorithmId !== "1.2.840.113549.1.1.1") + return Promise.reject(`Incorrect public key algorithm: ${publicKeyInfo.algorithm.algorithmId}`); + + //region Get information about used hash function + if(("alg" in jwk) === false) + { + switch(algorithm.hash.name.toUpperCase()) + { + case "SHA-1": + jwk.alg = "RS1"; + break; + case "SHA-256": + jwk.alg = "RS256"; + break; + case "SHA-384": + jwk.alg = "RS384"; + break; + case "SHA-512": + jwk.alg = "RS512"; + break; + default: + return Promise.reject(`Incorrect hash algorithm: ${algorithm.hash.name.toUpperCase()}`); + } + } + //endregion + + //region Create RSA Public Key elements + const publicKeyJSON = publicKeyInfo.toJSON(); + + for(const key of Object.keys(publicKeyJSON)) + jwk[key] = publicKeyJSON[key]; + //endregion + } + break; + case "ECDSA": + keyUsages = ["verify"]; // Override existing keyUsages value since the key is a public key + // break omitted + case "ECDH": + { + //region Initial variables + jwk = { + kty: "EC", + ext: extractable, + key_ops: keyUsages + }; + //endregion + + //region Get information about algorithm + if(publicKeyInfo.algorithm.algorithmId !== "1.2.840.10045.2.1") + return Promise.reject(`Incorrect public key algorithm: ${publicKeyInfo.algorithm.algorithmId}`); + //endregion + + //region Create ECDSA Public Key elements + const publicKeyJSON = publicKeyInfo.toJSON(); + + for(const key of Object.keys(publicKeyJSON)) + jwk[key] = publicKeyJSON[key]; + //endregion + } + break; + case "RSA-OAEP": + { + jwk.kty = "RSA"; + jwk.ext = extractable; + jwk.key_ops = keyUsages; + + if(this.name.toLowerCase() === "safari") + jwk.alg = "RSA-OAEP"; + else + { + switch(algorithm.hash.name.toUpperCase()) + { + case "SHA-1": + jwk.alg = "RSA-OAEP"; + break; + case "SHA-256": + jwk.alg = "RSA-OAEP-256"; + break; + case "SHA-384": + jwk.alg = "RSA-OAEP-384"; + break; + case "SHA-512": + jwk.alg = "RSA-OAEP-512"; + break; + default: + return Promise.reject(`Incorrect hash algorithm: ${algorithm.hash.name.toUpperCase()}`); + } + } + + //region Create ECDSA Public Key elements + const publicKeyJSON = publicKeyInfo.toJSON(); + + for(const key of Object.keys(publicKeyJSON)) + jwk[key] = publicKeyJSON[key]; + //endregion + } + break; + default: + return Promise.reject(`Incorrect algorithm name: ${algorithm.name.toUpperCase()}`); + } + } + break; + case "pkcs8": + { + const privateKeyInfo = new PrivateKeyInfo(); + + //region Parse "PrivateKeyInfo" object + const asn1 = asn1js.fromBER(keyData); + if(asn1.offset === (-1)) + return Promise.reject("Incorrect keyData"); + + try + { + privateKeyInfo.fromSchema(asn1.result); + } + catch(ex) + { + return Promise.reject("Incorrect keyData"); + } + + if(("parsedKey" in privateKeyInfo) === false) + return Promise.reject("Incorrect keyData"); + //endregion + + // noinspection FallThroughInSwitchStatementJS + // noinspection FallThroughInSwitchStatementJS + switch(algorithm.name.toUpperCase()) + { + case "RSA-PSS": + { + //region Get information about used hash function + switch(algorithm.hash.name.toUpperCase()) + { + case "SHA-1": + jwk.alg = "PS1"; + break; + case "SHA-256": + jwk.alg = "PS256"; + break; + case "SHA-384": + jwk.alg = "PS384"; + break; + case "SHA-512": + jwk.alg = "PS512"; + break; + default: + return Promise.reject(`Incorrect hash algorithm: ${algorithm.hash.name.toUpperCase()}`); + } + //endregion + } + // break omitted + case "RSASSA-PKCS1-V1_5": + { + keyUsages = ["sign"]; // Override existing keyUsages value since the key is a private key + + jwk.kty = "RSA"; + jwk.ext = extractable; + jwk.key_ops = keyUsages; + + //region Get information about used hash function + if(privateKeyInfo.privateKeyAlgorithm.algorithmId !== "1.2.840.113549.1.1.1") + return Promise.reject(`Incorrect private key algorithm: ${privateKeyInfo.privateKeyAlgorithm.algorithmId}`); + //endregion + + //region Get information about used hash function + if(("alg" in jwk) === false) + { + switch(algorithm.hash.name.toUpperCase()) + { + case "SHA-1": + jwk.alg = "RS1"; + break; + case "SHA-256": + jwk.alg = "RS256"; + break; + case "SHA-384": + jwk.alg = "RS384"; + break; + case "SHA-512": + jwk.alg = "RS512"; + break; + default: + return Promise.reject(`Incorrect hash algorithm: ${algorithm.hash.name.toUpperCase()}`); + } + } + //endregion + + //region Create RSA Private Key elements + const privateKeyJSON = privateKeyInfo.toJSON(); + + for(const key of Object.keys(privateKeyJSON)) + jwk[key] = privateKeyJSON[key]; + //endregion + } + break; + case "ECDSA": + keyUsages = ["sign"]; // Override existing keyUsages value since the key is a private key + // break omitted + case "ECDH": + { + //region Initial variables + jwk = { + kty: "EC", + ext: extractable, + key_ops: keyUsages + }; + //endregion + + //region Get information about used hash function + if(privateKeyInfo.privateKeyAlgorithm.algorithmId !== "1.2.840.10045.2.1") + return Promise.reject(`Incorrect algorithm: ${privateKeyInfo.privateKeyAlgorithm.algorithmId}`); + //endregion + + //region Create ECDSA Private Key elements + const privateKeyJSON = privateKeyInfo.toJSON(); + + for(const key of Object.keys(privateKeyJSON)) + jwk[key] = privateKeyJSON[key]; + //endregion + } + break; + case "RSA-OAEP": + { + jwk.kty = "RSA"; + jwk.ext = extractable; + jwk.key_ops = keyUsages; + + //region Get information about used hash function + if(this.name.toLowerCase() === "safari") + jwk.alg = "RSA-OAEP"; + else + { + switch(algorithm.hash.name.toUpperCase()) + { + case "SHA-1": + jwk.alg = "RSA-OAEP"; + break; + case "SHA-256": + jwk.alg = "RSA-OAEP-256"; + break; + case "SHA-384": + jwk.alg = "RSA-OAEP-384"; + break; + case "SHA-512": + jwk.alg = "RSA-OAEP-512"; + break; + default: + return Promise.reject(`Incorrect hash algorithm: ${algorithm.hash.name.toUpperCase()}`); + } + } + //endregion + + //region Create RSA Private Key elements + const privateKeyJSON = privateKeyInfo.toJSON(); + + for(const key of Object.keys(privateKeyJSON)) + jwk[key] = privateKeyJSON[key]; + //endregion + } + break; + default: + return Promise.reject(`Incorrect algorithm name: ${algorithm.name.toUpperCase()}`); + } + } + break; + case "jwk": + jwk = keyData; + break; + default: + return Promise.reject(`Incorrect format: ${format}`); + } + + //region Special case for Safari browser (since its acting not as WebCrypto standard describes) + if(this.name.toLowerCase() === "safari") + { + // Try to use both ways - import using ArrayBuffer and pure JWK (for Safari Technology Preview) + return Promise.resolve().then(() => this.subtle.importKey("jwk", stringToArrayBuffer(JSON.stringify(jwk)), algorithm, extractable, keyUsages)) + .then(result => result, () => this.subtle.importKey("jwk", jwk, algorithm, extractable, keyUsages)); + } + //endregion + + return this.subtle.importKey("jwk", jwk, algorithm, extractable, keyUsages); + } + //********************************************************************************** + /** + * Export WebCrypto keys to different formats + * @param {string} format + * @param {Object} key + * @returns {Promise} + */ + exportKey(format, key) + { + let sequence = this.subtle.exportKey("jwk", key); + + //region Currently Safari returns ArrayBuffer as JWK thus we need an additional transformation + if(this.name.toLowerCase() === "safari") + { + sequence = sequence.then(result => + { + // Some additional checks for Safari Technology Preview + if(result instanceof ArrayBuffer) + return JSON.parse(arrayBufferToString(result)); + + return result; + }); + } + //endregion + + switch(format.toLowerCase()) + { + case "raw": + return this.subtle.exportKey("raw", key); + case "spki": + sequence = sequence.then(result => + { + const publicKeyInfo = new PublicKeyInfo(); + + try + { + publicKeyInfo.fromJSON(result); + } + catch(ex) + { + return Promise.reject("Incorrect key data"); + } + + return publicKeyInfo.toSchema().toBER(false); + }); + break; + case "pkcs8": + sequence = sequence.then(result => + { + const privateKeyInfo = new PrivateKeyInfo(); + + try + { + privateKeyInfo.fromJSON(result); + } + catch(ex) + { + return Promise.reject("Incorrect key data"); + } + + return privateKeyInfo.toSchema().toBER(false); + }); + break; + case "jwk": + break; + default: + return Promise.reject(`Incorrect format: ${format}`); + } + + return sequence; + } + //********************************************************************************** + /** + * Convert WebCrypto keys between different export formats + * @param {string} inputFormat + * @param {string} outputFormat + * @param {ArrayBuffer|Object} keyData + * @param {Object} algorithm + * @param {boolean} extractable + * @param {Array} keyUsages + * @returns {Promise} + */ + convert(inputFormat, outputFormat, keyData, algorithm, extractable, keyUsages) + { + switch(inputFormat.toLowerCase()) + { + case "raw": + switch(outputFormat.toLowerCase()) + { + case "raw": + return Promise.resolve(keyData); + case "spki": + return Promise.resolve() + .then(() => this.importKey("raw", keyData, algorithm, extractable, keyUsages)) + .then(result => this.exportKey("spki", result)); + case "pkcs8": + return Promise.resolve() + .then(() => this.importKey("raw", keyData, algorithm, extractable, keyUsages)) + .then(result => this.exportKey("pkcs8", result)); + case "jwk": + return Promise.resolve() + .then(() => this.importKey("raw", keyData, algorithm, extractable, keyUsages)) + .then(result => this.exportKey("jwk", result)); + default: + return Promise.reject(`Incorrect outputFormat: ${outputFormat}`); + } + case "spki": + switch(outputFormat.toLowerCase()) + { + case "raw": + return Promise.resolve() + .then(() => this.importKey("spki", keyData, algorithm, extractable, keyUsages)) + .then(result => this.exportKey("raw", result)); + case "spki": + return Promise.resolve(keyData); + case "pkcs8": + return Promise.reject("Impossible to convert between SPKI/PKCS8"); + case "jwk": + return Promise.resolve() + .then(() => this.importKey("spki", keyData, algorithm, extractable, keyUsages)) + .then(result => this.exportKey("jwk", result)); + default: + return Promise.reject(`Incorrect outputFormat: ${outputFormat}`); + } + case "pkcs8": + switch(outputFormat.toLowerCase()) + { + case "raw": + return Promise.resolve() + .then(() => this.importKey("pkcs8", keyData, algorithm, extractable, keyUsages)) + .then(result => this.exportKey("raw", result)); + case "spki": + return Promise.reject("Impossible to convert between SPKI/PKCS8"); + case "pkcs8": + return Promise.resolve(keyData); + case "jwk": + return Promise.resolve() + .then(() => this.importKey("pkcs8", keyData, algorithm, extractable, keyUsages)) + .then(result => this.exportKey("jwk", result)); + default: + return Promise.reject(`Incorrect outputFormat: ${outputFormat}`); + } + case "jwk": + switch(outputFormat.toLowerCase()) + { + case "raw": + return Promise.resolve() + .then(() => this.importKey("jwk", keyData, algorithm, extractable, keyUsages)) + .then(result => this.exportKey("raw", result)); + case "spki": + return Promise.resolve() + .then(() => this.importKey("jwk", keyData, algorithm, extractable, keyUsages)) + .then(result => this.exportKey("spki", result)); + case "pkcs8": + return Promise.resolve() + .then(() => this.importKey("jwk", keyData, algorithm, extractable, keyUsages)) + .then(result => this.exportKey("pkcs8", result)); + case "jwk": + return Promise.resolve(keyData); + default: + return Promise.reject(`Incorrect outputFormat: ${outputFormat}`); + } + default: + return Promise.reject(`Incorrect inputFormat: ${inputFormat}`); + } + } + //********************************************************************************** + /** + * Wrapper for standard function "encrypt" + * @param args + * @returns {Promise} + */ + encrypt(...args) + { + return this.subtle.encrypt(...args); + } + //********************************************************************************** + /** + * Wrapper for standard function "decrypt" + * @param args + * @returns {Promise} + */ + decrypt(...args) + { + return this.subtle.decrypt(...args); + } + //********************************************************************************** + /** + * Wrapper for standard function "sign" + * @param args + * @returns {Promise} + */ + sign(...args) + { + return this.subtle.sign(...args); + } + //********************************************************************************** + /** + * Wrapper for standard function "verify" + * @param args + * @returns {Promise} + */ + verify(...args) + { + return this.subtle.verify(...args); + } + //********************************************************************************** + /** + * Wrapper for standard function "digest" + * @param args + * @returns {Promise} + */ + digest(...args) + { + return this.subtle.digest(...args); + } + //********************************************************************************** + /** + * Wrapper for standard function "generateKey" + * @param args + * @returns {Promise} + */ + generateKey(...args) + { + return this.subtle.generateKey(...args); + } + //********************************************************************************** + /** + * Wrapper for standard function "deriveKey" + * @param args + * @returns {Promise} + */ + deriveKey(...args) + { + return this.subtle.deriveKey(...args); + } + //********************************************************************************** + /** + * Wrapper for standard function "deriveBits" + * @param args + * @returns {Promise} + */ + deriveBits(...args) + { + return this.subtle.deriveBits(...args); + } + //********************************************************************************** + /** + * Wrapper for standard function "wrapKey" + * @param args + * @returns {Promise} + */ + wrapKey(...args) + { + return this.subtle.wrapKey(...args); + } + //********************************************************************************** + /** + * Wrapper for standard function "unwrapKey" + * @param args + * @returns {Promise} + */ + unwrapKey(...args) + { + return this.subtle.unwrapKey(...args); + } + //********************************************************************************** + /** + * Initialize input Uint8Array by random values (with help from current "crypto engine") + * @param {!Uint8Array} view + * @returns {*} + */ + getRandomValues(view) + { + if(("getRandomValues" in this.crypto) === false) + throw new Error("No support for getRandomValues"); + + return this.crypto.getRandomValues(view); + } + //********************************************************************************** + /** + * Get WebCrypto algorithm by wel-known OID + * @param {string} oid well-known OID to search for + * @returns {Object} + */ + getAlgorithmByOID(oid) + { + switch(oid) + { + case "1.2.840.113549.1.1.1": + case "1.2.840.113549.1.1.5": + return { + name: "RSASSA-PKCS1-v1_5", + hash: { + name: "SHA-1" + } + }; + case "1.2.840.113549.1.1.11": + return { + name: "RSASSA-PKCS1-v1_5", + hash: { + name: "SHA-256" + } + }; + case "1.2.840.113549.1.1.12": + return { + name: "RSASSA-PKCS1-v1_5", + hash: { + name: "SHA-384" + } + }; + case "1.2.840.113549.1.1.13": + return { + name: "RSASSA-PKCS1-v1_5", + hash: { + name: "SHA-512" + } + }; + case "1.2.840.113549.1.1.10": + return { + name: "RSA-PSS" + }; + case "1.2.840.113549.1.1.7": + return { + name: "RSA-OAEP" + }; + case "1.2.840.10045.2.1": + case "1.2.840.10045.4.1": + return { + name: "ECDSA", + hash: { + name: "SHA-1" + } + }; + case "1.2.840.10045.4.3.2": + return { + name: "ECDSA", + hash: { + name: "SHA-256" + } + }; + case "1.2.840.10045.4.3.3": + return { + name: "ECDSA", + hash: { + name: "SHA-384" + } + }; + case "1.2.840.10045.4.3.4": + return { + name: "ECDSA", + hash: { + name: "SHA-512" + } + }; + case "1.3.133.16.840.63.0.2": + return { + name: "ECDH", + kdf: "SHA-1" + }; + case "1.3.132.1.11.1": + return { + name: "ECDH", + kdf: "SHA-256" + }; + case "1.3.132.1.11.2": + return { + name: "ECDH", + kdf: "SHA-384" + }; + case "1.3.132.1.11.3": + return { + name: "ECDH", + kdf: "SHA-512" + }; + case "2.16.840.1.101.3.4.1.2": + return { + name: "AES-CBC", + length: 128 + }; + case "2.16.840.1.101.3.4.1.22": + return { + name: "AES-CBC", + length: 192 + }; + case "2.16.840.1.101.3.4.1.42": + return { + name: "AES-CBC", + length: 256 + }; + case "2.16.840.1.101.3.4.1.6": + return { + name: "AES-GCM", + length: 128 + }; + case "2.16.840.1.101.3.4.1.26": + return { + name: "AES-GCM", + length: 192 + }; + case "2.16.840.1.101.3.4.1.46": + return { + name: "AES-GCM", + length: 256 + }; + case "2.16.840.1.101.3.4.1.4": + return { + name: "AES-CFB", + length: 128 + }; + case "2.16.840.1.101.3.4.1.24": + return { + name: "AES-CFB", + length: 192 + }; + case "2.16.840.1.101.3.4.1.44": + return { + name: "AES-CFB", + length: 256 + }; + case "2.16.840.1.101.3.4.1.5": + return { + name: "AES-KW", + length: 128 + }; + case "2.16.840.1.101.3.4.1.25": + return { + name: "AES-KW", + length: 192 + }; + case "2.16.840.1.101.3.4.1.45": + return { + name: "AES-KW", + length: 256 + }; + case "1.2.840.113549.2.7": + return { + name: "HMAC", + hash: { + name: "SHA-1" + } + }; + case "1.2.840.113549.2.9": + return { + name: "HMAC", + hash: { + name: "SHA-256" + } + }; + case "1.2.840.113549.2.10": + return { + name: "HMAC", + hash: { + name: "SHA-384" + } + }; + case "1.2.840.113549.2.11": + return { + name: "HMAC", + hash: { + name: "SHA-512" + } + }; + case "1.2.840.113549.1.9.16.3.5": + return { + name: "DH" + }; + case "1.3.14.3.2.26": + return { + name: "SHA-1" + }; + case "2.16.840.1.101.3.4.2.1": + return { + name: "SHA-256" + }; + case "2.16.840.1.101.3.4.2.2": + return { + name: "SHA-384" + }; + case "2.16.840.1.101.3.4.2.3": + return { + name: "SHA-512" + }; + case "1.2.840.113549.1.5.12": + return { + name: "PBKDF2" + }; + //region Special case - OIDs for ECC curves + case "1.2.840.10045.3.1.7": + return { + name: "P-256" + }; + case "1.3.132.0.34": + return { + name: "P-384" + }; + case "1.3.132.0.35": + return { + name: "P-521" + }; + //endregion + default: + } + + return {}; + } + //********************************************************************************** + /** + * Get OID for each specific algorithm + * @param {Object} algorithm + * @returns {string} + */ + getOIDByAlgorithm(algorithm) + { + let result = ""; + + switch(algorithm.name.toUpperCase()) + { + case "RSASSA-PKCS1-V1_5": + switch(algorithm.hash.name.toUpperCase()) + { + case "SHA-1": + result = "1.2.840.113549.1.1.5"; + break; + case "SHA-256": + result = "1.2.840.113549.1.1.11"; + break; + case "SHA-384": + result = "1.2.840.113549.1.1.12"; + break; + case "SHA-512": + result = "1.2.840.113549.1.1.13"; + break; + default: + } + break; + case "RSA-PSS": + result = "1.2.840.113549.1.1.10"; + break; + case "RSA-OAEP": + result = "1.2.840.113549.1.1.7"; + break; + case "ECDSA": + switch(algorithm.hash.name.toUpperCase()) + { + case "SHA-1": + result = "1.2.840.10045.4.1"; + break; + case "SHA-256": + result = "1.2.840.10045.4.3.2"; + break; + case "SHA-384": + result = "1.2.840.10045.4.3.3"; + break; + case "SHA-512": + result = "1.2.840.10045.4.3.4"; + break; + default: + } + break; + case "ECDH": + switch(algorithm.kdf.toUpperCase()) // Non-standard addition - hash algorithm of KDF function + { + case "SHA-1": + result = "1.3.133.16.840.63.0.2"; // dhSinglePass-stdDH-sha1kdf-scheme + break; + case "SHA-256": + result = "1.3.132.1.11.1"; // dhSinglePass-stdDH-sha256kdf-scheme + break; + case "SHA-384": + result = "1.3.132.1.11.2"; // dhSinglePass-stdDH-sha384kdf-scheme + break; + case "SHA-512": + result = "1.3.132.1.11.3"; // dhSinglePass-stdDH-sha512kdf-scheme + break; + default: + } + break; + case "AES-CTR": + break; + case "AES-CBC": + switch(algorithm.length) + { + case 128: + result = "2.16.840.1.101.3.4.1.2"; + break; + case 192: + result = "2.16.840.1.101.3.4.1.22"; + break; + case 256: + result = "2.16.840.1.101.3.4.1.42"; + break; + default: + } + break; + case "AES-CMAC": + break; + case "AES-GCM": + switch(algorithm.length) + { + case 128: + result = "2.16.840.1.101.3.4.1.6"; + break; + case 192: + result = "2.16.840.1.101.3.4.1.26"; + break; + case 256: + result = "2.16.840.1.101.3.4.1.46"; + break; + default: + } + break; + case "AES-CFB": + switch(algorithm.length) + { + case 128: + result = "2.16.840.1.101.3.4.1.4"; + break; + case 192: + result = "2.16.840.1.101.3.4.1.24"; + break; + case 256: + result = "2.16.840.1.101.3.4.1.44"; + break; + default: + } + break; + case "AES-KW": + switch(algorithm.length) + { + case 128: + result = "2.16.840.1.101.3.4.1.5"; + break; + case 192: + result = "2.16.840.1.101.3.4.1.25"; + break; + case 256: + result = "2.16.840.1.101.3.4.1.45"; + break; + default: + } + break; + case "HMAC": + switch(algorithm.hash.name.toUpperCase()) + { + case "SHA-1": + result = "1.2.840.113549.2.7"; + break; + case "SHA-256": + result = "1.2.840.113549.2.9"; + break; + case "SHA-384": + result = "1.2.840.113549.2.10"; + break; + case "SHA-512": + result = "1.2.840.113549.2.11"; + break; + default: + } + break; + case "DH": + result = "1.2.840.113549.1.9.16.3.5"; + break; + case "SHA-1": + result = "1.3.14.3.2.26"; + break; + case "SHA-256": + result = "2.16.840.1.101.3.4.2.1"; + break; + case "SHA-384": + result = "2.16.840.1.101.3.4.2.2"; + break; + case "SHA-512": + result = "2.16.840.1.101.3.4.2.3"; + break; + case "CONCAT": + break; + case "HKDF": + break; + case "PBKDF2": + result = "1.2.840.113549.1.5.12"; + break; + //region Special case - OIDs for ECC curves + case "P-256": + result = "1.2.840.10045.3.1.7"; + break; + case "P-384": + result = "1.3.132.0.34"; + break; + case "P-521": + result = "1.3.132.0.35"; + break; + //endregion + default: + } + + return result; + } + //********************************************************************************** + /** + * Get default algorithm parameters for each kind of operation + * @param {string} algorithmName Algorithm name to get common parameters for + * @param {string} operation Kind of operation: "sign", "encrypt", "generatekey", "importkey", "exportkey", "verify" + * @returns {*} + */ + getAlgorithmParameters(algorithmName, operation) + { + let result = { + algorithm: {}, + usages: [] + }; + + switch(algorithmName.toUpperCase()) + { + case "RSASSA-PKCS1-V1_5": + switch(operation.toLowerCase()) + { + case "generatekey": + result = { + algorithm: { + name: "RSASSA-PKCS1-v1_5", + modulusLength: 2048, + publicExponent: new Uint8Array([0x01, 0x00, 0x01]), + hash: { + name: "SHA-256" + } + }, + usages: ["sign", "verify"] + }; + break; + case "verify": + case "sign": + case "importkey": + result = { + algorithm: { + name: "RSASSA-PKCS1-v1_5", + hash: { + name: "SHA-256" + } + }, + usages: ["verify"] // For importKey("pkcs8") usage must be "sign" only + }; + break; + case "exportkey": + default: + return { + algorithm: { + name: "RSASSA-PKCS1-v1_5" + }, + usages: [] + }; + } + break; + case "RSA-PSS": + switch(operation.toLowerCase()) + { + case "sign": + case "verify": + result = { + algorithm: { + name: "RSA-PSS", + hash: { + name: "SHA-1" + }, + saltLength: 20 + }, + usages: ["sign", "verify"] + }; + break; + case "generatekey": + result = { + algorithm: { + name: "RSA-PSS", + modulusLength: 2048, + publicExponent: new Uint8Array([0x01, 0x00, 0x01]), + hash: { + name: "SHA-1" + } + }, + usages: ["sign", "verify"] + }; + break; + case "importkey": + result = { + algorithm: { + name: "RSA-PSS", + hash: { + name: "SHA-1" + } + }, + usages: ["verify"] // For importKey("pkcs8") usage must be "sign" only + }; + break; + case "exportkey": + default: + return { + algorithm: { + name: "RSA-PSS" + }, + usages: [] + }; + } + break; + case "RSA-OAEP": + switch(operation.toLowerCase()) + { + case "encrypt": + case "decrypt": + result = { + algorithm: { + name: "RSA-OAEP" + }, + usages: ["encrypt", "decrypt"] + }; + break; + case "generatekey": + result = { + algorithm: { + name: "RSA-OAEP", + modulusLength: 2048, + publicExponent: new Uint8Array([0x01, 0x00, 0x01]), + hash: { + name: "SHA-256" + } + }, + usages: ["encrypt", "decrypt", "wrapKey", "unwrapKey"] + }; + break; + case "importkey": + result = { + algorithm: { + name: "RSA-OAEP", + hash: { + name: "SHA-256" + } + }, + usages: ["encrypt"] // encrypt for "spki" and decrypt for "pkcs8" + }; + break; + case "exportkey": + default: + return { + algorithm: { + name: "RSA-OAEP" + }, + usages: [] + }; + } + break; + case "ECDSA": + switch(operation.toLowerCase()) + { + case "generatekey": + result = { + algorithm: { + name: "ECDSA", + namedCurve: "P-256" + }, + usages: ["sign", "verify"] + }; + break; + case "importkey": + result = { + algorithm: { + name: "ECDSA", + namedCurve: "P-256" + }, + usages: ["verify"] // "sign" for "pkcs8" + }; + break; + case "verify": + case "sign": + result = { + algorithm: { + name: "ECDSA", + hash: { + name: "SHA-256" + } + }, + usages: ["sign"] + }; + break; + default: + return { + algorithm: { + name: "ECDSA" + }, + usages: [] + }; + } + break; + case "ECDH": + switch(operation.toLowerCase()) + { + case "exportkey": + case "importkey": + case "generatekey": + result = { + algorithm: { + name: "ECDH", + namedCurve: "P-256" + }, + usages: ["deriveKey", "deriveBits"] + }; + break; + case "derivekey": + case "derivebits": + result = { + algorithm: { + name: "ECDH", + namedCurve: "P-256", + public: [] // Must be a "publicKey" + }, + usages: ["encrypt", "decrypt"] + }; + break; + default: + return { + algorithm: { + name: "ECDH" + }, + usages: [] + }; + } + break; + case "AES-CTR": + switch(operation.toLowerCase()) + { + case "importkey": + case "exportkey": + case "generatekey": + result = { + algorithm: { + name: "AES-CTR", + length: 256 + }, + usages: ["encrypt", "decrypt", "wrapKey", "unwrapKey"] + }; + break; + case "decrypt": + case "encrypt": + result = { + algorithm: { + name: "AES-CTR", + counter: new Uint8Array(16), + length: 10 + }, + usages: ["encrypt", "decrypt", "wrapKey", "unwrapKey"] + }; + break; + default: + return { + algorithm: { + name: "AES-CTR" + }, + usages: [] + }; + } + break; + case "AES-CBC": + switch(operation.toLowerCase()) + { + case "importkey": + case "exportkey": + case "generatekey": + result = { + algorithm: { + name: "AES-CBC", + length: 256 + }, + usages: ["encrypt", "decrypt", "wrapKey", "unwrapKey"] + }; + break; + case "decrypt": + case "encrypt": + result = { + algorithm: { + name: "AES-CBC", + iv: this.getRandomValues(new Uint8Array(16)) // For "decrypt" the value should be replaced with value got on "encrypt" step + }, + usages: ["encrypt", "decrypt", "wrapKey", "unwrapKey"] + }; + break; + default: + return { + algorithm: { + name: "AES-CBC" + }, + usages: [] + }; + } + break; + case "AES-GCM": + switch(operation.toLowerCase()) + { + case "importkey": + case "exportkey": + case "generatekey": + result = { + algorithm: { + name: "AES-GCM", + length: 256 + }, + usages: ["encrypt", "decrypt", "wrapKey", "unwrapKey"] + }; + break; + case "decrypt": + case "encrypt": + result = { + algorithm: { + name: "AES-GCM", + iv: this.getRandomValues(new Uint8Array(16)) // For "decrypt" the value should be replaced with value got on "encrypt" step + }, + usages: ["encrypt", "decrypt", "wrapKey", "unwrapKey"] + }; + break; + default: + return { + algorithm: { + name: "AES-GCM" + }, + usages: [] + }; + } + break; + case "AES-KW": + switch(operation.toLowerCase()) + { + case "importkey": + case "exportkey": + case "generatekey": + case "wrapkey": + case "unwrapkey": + result = { + algorithm: { + name: "AES-KW", + length: 256 + }, + usages: ["wrapKey", "unwrapKey"] + }; + break; + default: + return { + algorithm: { + name: "AES-KW" + }, + usages: [] + }; + } + break; + case "HMAC": + switch(operation.toLowerCase()) + { + case "sign": + case "verify": + result = { + algorithm: { + name: "HMAC" + }, + usages: ["sign", "verify"] + }; + break; + case "importkey": + case "exportkey": + case "generatekey": + result = { + algorithm: { + name: "HMAC", + length: 32, + hash: { + name: "SHA-256" + } + }, + usages: ["sign", "verify"] + }; + break; + default: + return { + algorithm: { + name: "HMAC" + }, + usages: [] + }; + } + break; + case "HKDF": + switch(operation.toLowerCase()) + { + case "derivekey": + result = { + algorithm: { + name: "HKDF", + hash: "SHA-256", + salt: new Uint8Array([]), + info: new Uint8Array([]) + }, + usages: ["encrypt", "decrypt"] + }; + break; + default: + return { + algorithm: { + name: "HKDF" + }, + usages: [] + }; + } + break; + case "PBKDF2": + switch(operation.toLowerCase()) + { + case "derivekey": + result = { + algorithm: { + name: "PBKDF2", + hash: { name: "SHA-256" }, + salt: new Uint8Array([]), + iterations: 10000 + }, + usages: ["encrypt", "decrypt"] + }; + break; + default: + return { + algorithm: { + name: "PBKDF2" + }, + usages: [] + }; + } + break; + default: + } + + return result; + } + //********************************************************************************** + /** + * Getting hash algorithm by signature algorithm + * @param {AlgorithmIdentifier} signatureAlgorithm Signature algorithm + * @returns {string} + */ + getHashAlgorithm(signatureAlgorithm) + { + let result = ""; + + switch(signatureAlgorithm.algorithmId) + { + case "1.2.840.10045.4.1": // ecdsa-with-SHA1 + case "1.2.840.113549.1.1.5": + result = "SHA-1"; + break; + case "1.2.840.10045.4.3.2": // ecdsa-with-SHA256 + case "1.2.840.113549.1.1.11": + result = "SHA-256"; + break; + case "1.2.840.10045.4.3.3": // ecdsa-with-SHA384 + case "1.2.840.113549.1.1.12": + result = "SHA-384"; + break; + case "1.2.840.10045.4.3.4": // ecdsa-with-SHA512 + case "1.2.840.113549.1.1.13": + result = "SHA-512"; + break; + case "1.2.840.113549.1.1.10": // RSA-PSS + { + try + { + const params = new RSASSAPSSParams({ schema: signatureAlgorithm.algorithmParams }); + if("hashAlgorithm" in params) + { + const algorithm = this.getAlgorithmByOID(params.hashAlgorithm.algorithmId); + if(("name" in algorithm) === false) + return ""; + + result = algorithm.name; + } + else + result = "SHA-1"; + } + catch(ex) + { + } + } + break; + default: + } + + return result; + } + //********************************************************************************** + /** + * Specialized function encrypting "EncryptedContentInfo" object using parameters + * @param {Object} parameters + * @returns {Promise} + */ + encryptEncryptedContentInfo(parameters) + { + //region Check for input parameters + if((parameters instanceof Object) === false) + return Promise.reject("Parameters must have type \"Object\""); + + if(("password" in parameters) === false) + return Promise.reject("Absent mandatory parameter \"password\""); + + if(("contentEncryptionAlgorithm" in parameters) === false) + return Promise.reject("Absent mandatory parameter \"contentEncryptionAlgorithm\""); + + if(("hmacHashAlgorithm" in parameters) === false) + return Promise.reject("Absent mandatory parameter \"hmacHashAlgorithm\""); + + if(("iterationCount" in parameters) === false) + return Promise.reject("Absent mandatory parameter \"iterationCount\""); + + if(("contentToEncrypt" in parameters) === false) + return Promise.reject("Absent mandatory parameter \"contentToEncrypt\""); + + if(("contentType" in parameters) === false) + return Promise.reject("Absent mandatory parameter \"contentType\""); + + const contentEncryptionOID = this.getOIDByAlgorithm(parameters.contentEncryptionAlgorithm); + if(contentEncryptionOID === "") + return Promise.reject("Wrong \"contentEncryptionAlgorithm\" value"); + + const pbkdf2OID = this.getOIDByAlgorithm({ + name: "PBKDF2" + }); + if(pbkdf2OID === "") + return Promise.reject("Can not find OID for PBKDF2"); + + const hmacOID = this.getOIDByAlgorithm({ + name: "HMAC", + hash: { + name: parameters.hmacHashAlgorithm + } + }); + if(hmacOID === "") + return Promise.reject(`Incorrect value for "hmacHashAlgorithm": ${parameters.hmacHashAlgorithm}`); + //endregion + + //region Initial variables + let sequence = Promise.resolve(); + + const ivBuffer = new ArrayBuffer(16); // For AES we need IV 16 bytes long + const ivView = new Uint8Array(ivBuffer); + this.getRandomValues(ivView); + + const saltBuffer = new ArrayBuffer(64); + const saltView = new Uint8Array(saltBuffer); + this.getRandomValues(saltView); + + const contentView = new Uint8Array(parameters.contentToEncrypt); + + const pbkdf2Params = new PBKDF2Params({ + salt: new asn1js.OctetString({ valueHex: saltBuffer }), + iterationCount: parameters.iterationCount, + prf: new AlgorithmIdentifier({ + algorithmId: hmacOID, + algorithmParams: new asn1js.Null() + }) + }); + //endregion + + //region Derive PBKDF2 key from "password" buffer + sequence = sequence.then(() => + { + const passwordView = new Uint8Array(parameters.password); + + return this.importKey("raw", + passwordView, + "PBKDF2", + false, + ["deriveKey"]); + }, error => + Promise.reject(error) + ); + //endregion + + //region Derive key for "contentEncryptionAlgorithm" + sequence = sequence.then(result => + this.deriveKey({ + name: "PBKDF2", + hash: { + name: parameters.hmacHashAlgorithm + }, + salt: saltView, + iterations: parameters.iterationCount + }, + result, + parameters.contentEncryptionAlgorithm, + false, + ["encrypt"]), + error => + Promise.reject(error) + ); + //endregion + + //region Encrypt content + sequence = sequence.then(result => + this.encrypt({ + name: parameters.contentEncryptionAlgorithm.name, + iv: ivView + }, + result, + contentView), + error => + Promise.reject(error) + ); + //endregion + + //region Store all parameters in EncryptedData object + sequence = sequence.then(result => + { + const pbes2Parameters = new PBES2Params({ + keyDerivationFunc: new AlgorithmIdentifier({ + algorithmId: pbkdf2OID, + algorithmParams: pbkdf2Params.toSchema() + }), + encryptionScheme: new AlgorithmIdentifier({ + algorithmId: contentEncryptionOID, + algorithmParams: new asn1js.OctetString({ valueHex: ivBuffer }) + }) + }); + + return new EncryptedContentInfo({ + contentType: parameters.contentType, + contentEncryptionAlgorithm: new AlgorithmIdentifier({ + algorithmId: "1.2.840.113549.1.5.13", // pkcs5PBES2 + algorithmParams: pbes2Parameters.toSchema() + }), + encryptedContent: new asn1js.OctetString({ valueHex: result }) + }); + }, error => + Promise.reject(error) + ); + //endregion + + return sequence; + } + //********************************************************************************** + /** + * Decrypt data stored in "EncryptedContentInfo" object using parameters + * @param parameters + * @return {Promise} + */ + decryptEncryptedContentInfo(parameters) + { + //region Check for input parameters + if((parameters instanceof Object) === false) + return Promise.reject("Parameters must have type \"Object\""); + + if(("password" in parameters) === false) + return Promise.reject("Absent mandatory parameter \"password\""); + + if(("encryptedContentInfo" in parameters) === false) + return Promise.reject("Absent mandatory parameter \"encryptedContentInfo\""); + + if(parameters.encryptedContentInfo.contentEncryptionAlgorithm.algorithmId !== "1.2.840.113549.1.5.13") // pkcs5PBES2 + return Promise.reject(`Unknown "contentEncryptionAlgorithm": ${parameters.encryptedContentInfo.contentEncryptionAlgorithm.algorithmId}`); + //endregion + + //region Initial variables + let sequence = Promise.resolve(); + + let pbes2Parameters; + + try + { + pbes2Parameters = new PBES2Params({ schema: parameters.encryptedContentInfo.contentEncryptionAlgorithm.algorithmParams }); + } + catch(ex) + { + return Promise.reject("Incorrectly encoded \"pbes2Parameters\""); + } + + let pbkdf2Params; + + try + { + pbkdf2Params = new PBKDF2Params({ schema: pbes2Parameters.keyDerivationFunc.algorithmParams }); + } + catch(ex) + { + return Promise.reject("Incorrectly encoded \"pbkdf2Params\""); + } + + const contentEncryptionAlgorithm = this.getAlgorithmByOID(pbes2Parameters.encryptionScheme.algorithmId); + if(("name" in contentEncryptionAlgorithm) === false) + return Promise.reject(`Incorrect OID for "contentEncryptionAlgorithm": ${pbes2Parameters.encryptionScheme.algorithmId}`); + + const ivBuffer = pbes2Parameters.encryptionScheme.algorithmParams.valueBlock.valueHex; + const ivView = new Uint8Array(ivBuffer); + + const saltBuffer = pbkdf2Params.salt.valueBlock.valueHex; + const saltView = new Uint8Array(saltBuffer); + + const iterationCount = pbkdf2Params.iterationCount; + + let hmacHashAlgorithm = "SHA-1"; + + if("prf" in pbkdf2Params) + { + const algorithm = this.getAlgorithmByOID(pbkdf2Params.prf.algorithmId); + if(("name" in algorithm) === false) + return Promise.reject("Incorrect OID for HMAC hash algorithm"); + + hmacHashAlgorithm = algorithm.hash.name; + } + //endregion + + //region Derive PBKDF2 key from "password" buffer + sequence = sequence.then(() => + this.importKey("raw", + parameters.password, + "PBKDF2", + false, + ["deriveKey"]), + error => + Promise.reject(error) + ); + //endregion + + //region Derive key for "contentEncryptionAlgorithm" + sequence = sequence.then(result => + this.deriveKey({ + name: "PBKDF2", + hash: { + name: hmacHashAlgorithm + }, + salt: saltView, + iterations: iterationCount + }, + result, + contentEncryptionAlgorithm, + false, + ["decrypt"]), + error => + Promise.reject(error) + ); + //endregion + + //region Decrypt internal content using derived key + sequence = sequence.then(result => + { + //region Create correct data block for decryption + let dataBuffer = new ArrayBuffer(0); + + if(parameters.encryptedContentInfo.encryptedContent.idBlock.isConstructed === false) + dataBuffer = parameters.encryptedContentInfo.encryptedContent.valueBlock.valueHex; + else + { + for(const content of parameters.encryptedContentInfo.encryptedContent.valueBlock.value) + dataBuffer = utilConcatBuf(dataBuffer, content.valueBlock.valueHex); + } + //endregion + + return this.decrypt({ + name: contentEncryptionAlgorithm.name, + iv: ivView + }, + result, + dataBuffer); + }, error => + Promise.reject(error) + ); + //endregion + + return sequence; + } + //********************************************************************************** + /** + * Stamping (signing) data using algorithm simular to HMAC + * @param {Object} parameters + * @return {Promise.|Promise} + */ + stampDataWithPassword(parameters) + { + //region Check for input parameters + if((parameters instanceof Object) === false) + return Promise.reject("Parameters must have type \"Object\""); + + if(("password" in parameters) === false) + return Promise.reject("Absent mandatory parameter \"password\""); + + if(("hashAlgorithm" in parameters) === false) + return Promise.reject("Absent mandatory parameter \"hashAlgorithm\""); + + if(("salt" in parameters) === false) + return Promise.reject("Absent mandatory parameter \"iterationCount\""); + + if(("iterationCount" in parameters) === false) + return Promise.reject("Absent mandatory parameter \"salt\""); + + if(("contentToStamp" in parameters) === false) + return Promise.reject("Absent mandatory parameter \"contentToStamp\""); + //endregion + + //region Choose correct length for HMAC key + let length; + + switch(parameters.hashAlgorithm.toLowerCase()) + { + case "sha-1": + length = 160; + break; + case "sha-256": + length = 256; + break; + case "sha-384": + length = 384; + break; + case "sha-512": + length = 512; + break; + default: + return Promise.reject(`Incorrect "parameters.hashAlgorithm" parameter: ${parameters.hashAlgorithm}`); + } + //endregion + + //region Initial variables + let sequence = Promise.resolve(); + + const hmacAlgorithm = { + name: "HMAC", + length, + hash: { + name: parameters.hashAlgorithm + } + }; + //endregion + + //region Create PKCS#12 key for integrity checking + sequence = sequence.then(() => makePKCS12B2Key(this, parameters.hashAlgorithm, length, parameters.password, parameters.salt, parameters.iterationCount)); + //endregion + + //region Import HMAC key + // noinspection JSCheckFunctionSignatures + sequence = sequence.then( + result => + this.importKey("raw", + new Uint8Array(result), + hmacAlgorithm, + false, + ["sign"]) + ); + //endregion + + //region Make signed HMAC value + sequence = sequence.then( + result => + this.sign(hmacAlgorithm, result, new Uint8Array(parameters.contentToStamp)), + error => Promise.reject(error) + ); + //endregion + + return sequence; + } + //********************************************************************************** + verifyDataStampedWithPassword(parameters) + { + //region Check for input parameters + if((parameters instanceof Object) === false) + return Promise.reject("Parameters must have type \"Object\""); + + if(("password" in parameters) === false) + return Promise.reject("Absent mandatory parameter \"password\""); + + if(("hashAlgorithm" in parameters) === false) + return Promise.reject("Absent mandatory parameter \"hashAlgorithm\""); + + if(("salt" in parameters) === false) + return Promise.reject("Absent mandatory parameter \"iterationCount\""); + + if(("iterationCount" in parameters) === false) + return Promise.reject("Absent mandatory parameter \"salt\""); + + if(("contentToVerify" in parameters) === false) + return Promise.reject("Absent mandatory parameter \"contentToVerify\""); + + if(("signatureToVerify" in parameters) === false) + return Promise.reject("Absent mandatory parameter \"signatureToVerify\""); + //endregion + + //region Choose correct length for HMAC key + let length; + + switch(parameters.hashAlgorithm.toLowerCase()) + { + case "sha-1": + length = 160; + break; + case "sha-256": + length = 256; + break; + case "sha-384": + length = 384; + break; + case "sha-512": + length = 512; + break; + default: + return Promise.reject(`Incorrect "parameters.hashAlgorithm" parameter: ${parameters.hashAlgorithm}`); + } + //endregion + + //region Initial variables + let sequence = Promise.resolve(); + + const hmacAlgorithm = { + name: "HMAC", + length, + hash: { + name: parameters.hashAlgorithm + } + }; + //endregion + + //region Create PKCS#12 key for integrity checking + sequence = sequence.then(() => makePKCS12B2Key(this, parameters.hashAlgorithm, length, parameters.password, parameters.salt, parameters.iterationCount)); + //endregion + + //region Import HMAC key + // noinspection JSCheckFunctionSignatures + sequence = sequence.then(result => + this.importKey("raw", + new Uint8Array(result), + hmacAlgorithm, + false, + ["verify"]) + ); + //endregion + + //region Make signed HMAC value + sequence = sequence.then( + result => + this.verify(hmacAlgorithm, result, new Uint8Array(parameters.signatureToVerify), new Uint8Array(parameters.contentToVerify)), + error => Promise.reject(error) + ); + //endregion + + return sequence; + } + //********************************************************************************** + /** + * Get signature parameters by analyzing private key algorithm + * @param {Object} privateKey The private key user would like to use + * @param {string} [hashAlgorithm="SHA-1"] Hash algorithm user would like to use + * @return {Promise.|Promise} + */ + getSignatureParameters(privateKey, hashAlgorithm = "SHA-1") + { + //region Check hashing algorithm + const oid = this.getOIDByAlgorithm({ name: hashAlgorithm }); + if(oid === "") + return Promise.reject(`Unsupported hash algorithm: ${hashAlgorithm}`); + //endregion + + //region Initial variables + const signatureAlgorithm = new AlgorithmIdentifier(); + //endregion + + //region Get a "default parameters" for current algorithm + const parameters = this.getAlgorithmParameters(privateKey.algorithm.name, "sign"); + parameters.algorithm.hash.name = hashAlgorithm; + //endregion + + //region Fill internal structures base on "privateKey" and "hashAlgorithm" + switch(privateKey.algorithm.name.toUpperCase()) + { + case "RSASSA-PKCS1-V1_5": + case "ECDSA": + signatureAlgorithm.algorithmId = this.getOIDByAlgorithm(parameters.algorithm); + break; + case "RSA-PSS": + { + //region Set "saltLength" as a length (in octets) of hash function result + switch(hashAlgorithm.toUpperCase()) + { + case "SHA-256": + parameters.algorithm.saltLength = 32; + break; + case "SHA-384": + parameters.algorithm.saltLength = 48; + break; + case "SHA-512": + parameters.algorithm.saltLength = 64; + break; + default: + } + //endregion + + //region Fill "RSASSA_PSS_params" object + const paramsObject = {}; + + if(hashAlgorithm.toUpperCase() !== "SHA-1") + { + const hashAlgorithmOID = this.getOIDByAlgorithm({ name: hashAlgorithm }); + if(hashAlgorithmOID === "") + return Promise.reject(`Unsupported hash algorithm: ${hashAlgorithm}`); + + paramsObject.hashAlgorithm = new AlgorithmIdentifier({ + algorithmId: hashAlgorithmOID, + algorithmParams: new asn1js.Null() + }); + + paramsObject.maskGenAlgorithm = new AlgorithmIdentifier({ + algorithmId: "1.2.840.113549.1.1.8", // MGF1 + algorithmParams: paramsObject.hashAlgorithm.toSchema() + }); + } + + if(parameters.algorithm.saltLength !== 20) + paramsObject.saltLength = parameters.algorithm.saltLength; + + const pssParameters = new RSASSAPSSParams(paramsObject); + //endregion + + //region Automatically set signature algorithm + signatureAlgorithm.algorithmId = "1.2.840.113549.1.1.10"; + signatureAlgorithm.algorithmParams = pssParameters.toSchema(); + //endregion + } + break; + default: + return Promise.reject(`Unsupported signature algorithm: ${privateKey.algorithm.name}`); + } + //endregion + + return Promise.resolve().then(() => ({ + signatureAlgorithm, + parameters + })); + } + //********************************************************************************** + /** + * Sign data with pre-defined private key + * @param {ArrayBuffer} data Data to be signed + * @param {Object} privateKey Private key to use + * @param {Object} parameters Parameters for used algorithm + * @return {Promise.|Promise} + */ + signWithPrivateKey(data, privateKey, parameters) + { + return this.sign(parameters.algorithm, + privateKey, + new Uint8Array(data)) + .then(result => + { + //region Special case for ECDSA algorithm + if(parameters.algorithm.name === "ECDSA") + result = createCMSECDSASignature(result); + //endregion + + return result; + }, error => + Promise.reject(`Signing error: ${error}`) + ); + } + //********************************************************************************** + fillPublicKeyParameters(publicKeyInfo, signatureAlgorithm) + { + const parameters = {}; + + //region Find signer's hashing algorithm + const shaAlgorithm = this.getHashAlgorithm(signatureAlgorithm); + if(shaAlgorithm === "") + return Promise.reject(`Unsupported signature algorithm: ${signatureAlgorithm.algorithmId}`); + //endregion + + //region Get information about public key algorithm and default parameters for import + let algorithmId; + if(signatureAlgorithm.algorithmId === "1.2.840.113549.1.1.10") + algorithmId = signatureAlgorithm.algorithmId; + else + algorithmId = publicKeyInfo.algorithm.algorithmId; + + const algorithmObject = this.getAlgorithmByOID(algorithmId); + if(("name" in algorithmObject) === "") + return Promise.reject(`Unsupported public key algorithm: ${signatureAlgorithm.algorithmId}`); + + parameters.algorithm = this.getAlgorithmParameters(algorithmObject.name, "importkey"); + if("hash" in parameters.algorithm.algorithm) + parameters.algorithm.algorithm.hash.name = shaAlgorithm; + + //region Special case for ECDSA + if(algorithmObject.name === "ECDSA") + { + //region Get information about named curve + let algorithmParamsChecked = false; + + if(("algorithmParams" in publicKeyInfo.algorithm) === true) + { + if("idBlock" in publicKeyInfo.algorithm.algorithmParams) + { + if((publicKeyInfo.algorithm.algorithmParams.idBlock.tagClass === 1) && (publicKeyInfo.algorithm.algorithmParams.idBlock.tagNumber === 6)) + algorithmParamsChecked = true; + } + } + + if(algorithmParamsChecked === false) + return Promise.reject("Incorrect type for ECDSA public key parameters"); + + const curveObject = this.getAlgorithmByOID(publicKeyInfo.algorithm.algorithmParams.valueBlock.toString()); + if(("name" in curveObject) === false) + return Promise.reject(`Unsupported named curve algorithm: ${publicKeyInfo.algorithm.algorithmParams.valueBlock.toString()}`); + //endregion + + parameters.algorithm.algorithm.namedCurve = curveObject.name; + } + //endregion + //endregion + + return parameters; + } + //********************************************************************************** + getPublicKey(publicKeyInfo, signatureAlgorithm, parameters = null) + { + if(parameters === null) + parameters = this.fillPublicKeyParameters(publicKeyInfo, signatureAlgorithm); + + const publicKeyInfoSchema = publicKeyInfo.toSchema(); + const publicKeyInfoBuffer = publicKeyInfoSchema.toBER(false); + const publicKeyInfoView = new Uint8Array(publicKeyInfoBuffer); + + return this.importKey("spki", + publicKeyInfoView, + parameters.algorithm.algorithm, + true, + parameters.algorithm.usages + ); + } + //********************************************************************************** + verifyWithPublicKey(data, signature, publicKeyInfo, signatureAlgorithm, shaAlgorithm = null) + { + //region Initial variables + let sequence = Promise.resolve(); + //endregion + + //region Find signer's hashing algorithm + if(shaAlgorithm === null) + { + shaAlgorithm = this.getHashAlgorithm(signatureAlgorithm); + if(shaAlgorithm === "") + return Promise.reject(`Unsupported signature algorithm: ${signatureAlgorithm.algorithmId}`); + + //region Import public key + sequence = sequence.then(() => + this.getPublicKey(publicKeyInfo, signatureAlgorithm)); + //endregion + } + else + { + const parameters = {}; + + //region Get information about public key algorithm and default parameters for import + let algorithmId; + if(signatureAlgorithm.algorithmId === "1.2.840.113549.1.1.10") + algorithmId = signatureAlgorithm.algorithmId; + else + algorithmId = publicKeyInfo.algorithm.algorithmId; + + const algorithmObject = this.getAlgorithmByOID(algorithmId); + if(("name" in algorithmObject) === "") + return Promise.reject(`Unsupported public key algorithm: ${signatureAlgorithm.algorithmId}`); + + parameters.algorithm = this.getAlgorithmParameters(algorithmObject.name, "importkey"); + if("hash" in parameters.algorithm.algorithm) + parameters.algorithm.algorithm.hash.name = shaAlgorithm; + + //region Special case for ECDSA + if(algorithmObject.name === "ECDSA") + { + //region Get information about named curve + let algorithmParamsChecked = false; + + if(("algorithmParams" in publicKeyInfo.algorithm) === true) + { + if("idBlock" in publicKeyInfo.algorithm.algorithmParams) + { + if((publicKeyInfo.algorithm.algorithmParams.idBlock.tagClass === 1) && (publicKeyInfo.algorithm.algorithmParams.idBlock.tagNumber === 6)) + algorithmParamsChecked = true; + } + } + + if(algorithmParamsChecked === false) + return Promise.reject("Incorrect type for ECDSA public key parameters"); + + const curveObject = this.getAlgorithmByOID(publicKeyInfo.algorithm.algorithmParams.valueBlock.toString()); + if(("name" in curveObject) === false) + return Promise.reject(`Unsupported named curve algorithm: ${publicKeyInfo.algorithm.algorithmParams.valueBlock.toString()}`); + //endregion + + parameters.algorithm.algorithm.namedCurve = curveObject.name; + } + //endregion + //endregion + + //region Import public key + sequence = sequence.then(() => + this.getPublicKey(publicKeyInfo, null, parameters)); + //endregion + } + //endregion + + //region Verify signature + sequence = sequence.then(publicKey => + { + //region Get default algorithm parameters for verification + const algorithm = this.getAlgorithmParameters(publicKey.algorithm.name, "verify"); + if("hash" in algorithm.algorithm) + algorithm.algorithm.hash.name = shaAlgorithm; + //endregion + + //region Special case for ECDSA signatures + let signatureValue = signature.valueBlock.valueHex; + + if(publicKey.algorithm.name === "ECDSA") + { + const asn1 = asn1js.fromBER(signatureValue); + // noinspection JSCheckFunctionSignatures + signatureValue = createECDSASignatureFromCMS(asn1.result); + } + //endregion + + //region Special case for RSA-PSS + if(publicKey.algorithm.name === "RSA-PSS") + { + let pssParameters; + + try + { + pssParameters = new RSASSAPSSParams({ schema: signatureAlgorithm.algorithmParams }); + } + catch(ex) + { + return Promise.reject(ex); + } + + if("saltLength" in pssParameters) + algorithm.algorithm.saltLength = pssParameters.saltLength; + else + algorithm.algorithm.saltLength = 20; + + let hashAlgo = "SHA-1"; + + if("hashAlgorithm" in pssParameters) + { + const hashAlgorithm = this.getAlgorithmByOID(pssParameters.hashAlgorithm.algorithmId); + if(("name" in hashAlgorithm) === false) + return Promise.reject(`Unrecognized hash algorithm: ${pssParameters.hashAlgorithm.algorithmId}`); + + hashAlgo = hashAlgorithm.name; + } + + algorithm.algorithm.hash.name = hashAlgo; + } + //endregion + + return this.verify(algorithm.algorithm, + publicKey, + new Uint8Array(signatureValue), + new Uint8Array(data) + ); + }); + //endregion + + return sequence; + } + //********************************************************************************** +} +//************************************************************************************** diff --git a/core/third-party/pkijs/DigestInfo.js b/core/third-party/pkijs/DigestInfo.js new file mode 100644 index 0000000..59ea8d5 --- /dev/null +++ b/core/third-party/pkijs/DigestInfo.js @@ -0,0 +1,179 @@ +import * as asn1js from "./asn1.js"; +import { getParametersValue, clearProps } from "./pvutils.js"; +import AlgorithmIdentifier from "./AlgorithmIdentifier.js"; +//************************************************************************************** +/** + * Class from RFC3447 + */ +export default class DigestInfo +{ + //********************************************************************************** + /** + * Constructor for DigestInfo class + * @param {Object} [parameters={}] + * @param {Object} [parameters.schema] asn1js parsed value to initialize the class from + */ + constructor(parameters = {}) + { + //region Internal properties of the object + /** + * @type {AlgorithmIdentifier} + * @desc digestAlgorithm + */ + this.digestAlgorithm = getParametersValue(parameters, "digestAlgorithm", DigestInfo.defaultValues("digestAlgorithm")); + /** + * @type {OctetString} + * @desc digest + */ + this.digest = getParametersValue(parameters, "digest", DigestInfo.defaultValues("digest")); + //endregion + + //region If input argument array contains "schema" for this object + if("schema" in parameters) + this.fromSchema(parameters.schema); + //endregion + } + //********************************************************************************** + /** + * Return default values for all class members + * @param {string} memberName String name for a class member + */ + static defaultValues(memberName) + { + switch(memberName) + { + case "digestAlgorithm": + return new AlgorithmIdentifier(); + case "digest": + return new asn1js.OctetString(); + default: + throw new Error(`Invalid member name for DigestInfo class: ${memberName}`); + } + } + //********************************************************************************** + /** + * Compare values with default values for all class members + * @param {string} memberName String name for a class member + * @param {*} memberValue Value to compare with default value + */ + static compareWithDefault(memberName, memberValue) + { + switch(memberName) + { + case "digestAlgorithm": + return ((AlgorithmIdentifier.compareWithDefault("algorithmId", memberValue.algorithmId)) && + (("algorithmParams" in memberValue) === false)); + case "digest": + return (memberValue.isEqual(DigestInfo.defaultValues(memberName))); + default: + throw new Error(`Invalid member name for DigestInfo class: ${memberName}`); + } + } + //********************************************************************************** + /** + * Return value of pre-defined ASN.1 schema for current class + * + * ASN.1 schema: + * ```asn1 + * DigestInfo ::= SEQUENCE { + * digestAlgorithm DigestAlgorithmIdentifier, + * digest Digest } + * + * Digest ::= OCTET STRING + * ``` + * + * @param {Object} parameters Input parameters for the schema + * @returns {Object} asn1js schema object + */ + static schema(parameters = {}) + { + /** + * @type {Object} + * @property {string} [blockName] + * @property {string} [type] + * @property {string} [setName] + * @property {string} [values] + */ + const names = getParametersValue(parameters, "names", {}); + + return (new asn1js.Sequence({ + name: (names.blockName || ""), + value: [ + AlgorithmIdentifier.schema(names.digestAlgorithm || { + names: { + blockName: "digestAlgorithm" + } + }), + new asn1js.OctetString({ name: (names.digest || "digest") }) + ] + })); + } + //********************************************************************************** + /** + * Convert parsed asn1js object into current class + * @param {!Object} schema + */ + fromSchema(schema) + { + //region Clear input data first + clearProps(schema, [ + "digestAlgorithm", + "digest" + ]); + //endregion + + //region Check the schema is valid + const asn1 = asn1js.compareSchema(schema, + schema, + DigestInfo.schema({ + names: { + digestAlgorithm: { + names: { + blockName: "digestAlgorithm" + } + }, + digest: "digest" + } + }) + ); + + if(asn1.verified === false) + throw new Error("Object's schema was not verified against input data for DigestInfo"); + //endregion + + //region Get internal properties from parsed schema + this.digestAlgorithm = new AlgorithmIdentifier({ schema: asn1.result.digestAlgorithm }); + this.digest = asn1.result.digest; + //endregion + } + //********************************************************************************** + /** + * Convert current object to asn1js object and set correct values + * @returns {Object} asn1js object + */ + toSchema() + { + //region Construct and return new ASN.1 schema for this object + return (new asn1js.Sequence({ + value: [ + this.digestAlgorithm.toSchema(), + this.digest + ] + })); + //endregion + } + //********************************************************************************** + /** + * Convertion for the class to JSON object + * @returns {Object} + */ + toJSON() + { + return { + digestAlgorithm: this.digestAlgorithm.toJSON(), + digest: this.digest.toJSON() + }; + } + //********************************************************************************** +} +//************************************************************************************** diff --git a/core/third-party/pkijs/DistributionPoint.js b/core/third-party/pkijs/DistributionPoint.js new file mode 100644 index 0000000..8a893e9 --- /dev/null +++ b/core/third-party/pkijs/DistributionPoint.js @@ -0,0 +1,334 @@ +import * as asn1js from "./asn1.js"; +import { getParametersValue, clearProps } from "./pvutils.js"; +import GeneralName from "./GeneralName.js"; +import RelativeDistinguishedNames from "./RelativeDistinguishedNames.js"; +//************************************************************************************** +/** + * Class from RFC5280 + */ +export default class DistributionPoint +{ + //********************************************************************************** + /** + * Constructor for DistributionPoint class + * @param {Object} [parameters={}] + * @param {Object} [parameters.schema] asn1js parsed value to initialize the class from + * @property {Object} [distributionPoint] + * @property {Object} [reasons] + * @property {Object} [cRLIssuer] + */ + constructor(parameters = {}) + { + //region Internal properties of the object + if("distributionPoint" in parameters) + /** + * @type {Array.} + * @desc distributionPoint + */ + this.distributionPoint = getParametersValue(parameters, "distributionPoint", DistributionPoint.defaultValues("distributionPoint")); + + if("reasons" in parameters) + /** + * @type {BitString} + * @desc values + */ + this.reasons = getParametersValue(parameters, "reasons", DistributionPoint.defaultValues("reasons")); + + if("cRLIssuer" in parameters) + /** + * @type {Array.} + * @desc cRLIssuer + */ + this.cRLIssuer = getParametersValue(parameters, "cRLIssuer", DistributionPoint.defaultValues("cRLIssuer")); + //endregion + + //region If input argument array contains "schema" for this object + if("schema" in parameters) + this.fromSchema(parameters.schema); + //endregion + } + //********************************************************************************** + /** + * Return default values for all class members + * @param {string} memberName String name for a class member + */ + static defaultValues(memberName) + { + switch(memberName) + { + case "distributionPoint": + return []; + case "reasons": + return new asn1js.BitString(); + case "cRLIssuer": + return []; + default: + throw new Error(`Invalid member name for DistributionPoint class: ${memberName}`); + } + } + //********************************************************************************** + /** + * Return value of pre-defined ASN.1 schema for current class + * + * ASN.1 schema: + * ```asn1 + * DistributionPoint ::= SEQUENCE { + * distributionPoint [0] DistributionPointName OPTIONAL, + * reasons [1] ReasonFlags OPTIONAL, + * cRLIssuer [2] GeneralNames OPTIONAL } + * + * DistributionPointName ::= CHOICE { + * fullName [0] GeneralNames, + * nameRelativeToCRLIssuer [1] RelativeDistinguishedName } + * + * ReasonFlags ::= BIT STRING { + * unused (0), + * keyCompromise (1), + * cACompromise (2), + * affiliationChanged (3), + * superseded (4), + * cessationOfOperation (5), + * certificateHold (6), + * privilegeWithdrawn (7), + * aACompromise (8) } + * ``` + * + * @param {Object} parameters Input parameters for the schema + * @returns {Object} asn1js schema object + */ + static schema(parameters = {}) + { + /** + * @type {Object} + * @property {string} [blockName] + * @property {string} [distributionPoint] + * @property {string} [distributionPointNames] + * @property {string} [reasons] + * @property {string} [cRLIssuer] + * @property {string} [cRLIssuerNames] + */ + const names = getParametersValue(parameters, "names", {}); + + return (new asn1js.Sequence({ + name: (names.blockName || ""), + value: [ + new asn1js.Constructed({ + optional: true, + idBlock: { + tagClass: 3, // CONTEXT-SPECIFIC + tagNumber: 0 // [0] + }, + value: [ + new asn1js.Choice({ + value: [ + new asn1js.Constructed({ + name: (names.distributionPoint || ""), + optional: true, + idBlock: { + tagClass: 3, // CONTEXT-SPECIFIC + tagNumber: 0 // [0] + }, + value: [ + new asn1js.Repeated({ + name: (names.distributionPointNames || ""), + value: GeneralName.schema() + }) + ] + }), + new asn1js.Constructed({ + name: (names.distributionPoint || ""), + optional: true, + idBlock: { + tagClass: 3, // CONTEXT-SPECIFIC + tagNumber: 1 // [1] + }, + value: RelativeDistinguishedNames.schema().valueBlock.value + }) + ] + }) + ] + }), + new asn1js.Primitive({ + name: (names.reasons || ""), + optional: true, + idBlock: { + tagClass: 3, // CONTEXT-SPECIFIC + tagNumber: 1 // [1] + } + }), // IMPLICIT bitstring value + new asn1js.Constructed({ + name: (names.cRLIssuer || ""), + optional: true, + idBlock: { + tagClass: 3, // CONTEXT-SPECIFIC + tagNumber: 2 // [2] + }, + value: [ + new asn1js.Repeated({ + name: (names.cRLIssuerNames || ""), + value: GeneralName.schema() + }) + ] + }) // IMPLICIT bitstring value + ] + })); + } + //********************************************************************************** + /** + * Convert parsed asn1js object into current class + * @param {!Object} schema + */ + fromSchema(schema) + { + //region Clear input data first + clearProps(schema, [ + "distributionPoint", + "distributionPointNames", + "reasons", + "cRLIssuer", + "cRLIssuerNames" + ]); + //endregion + + //region Check the schema is valid + const asn1 = asn1js.compareSchema(schema, + schema, + DistributionPoint.schema({ + names: { + distributionPoint: "distributionPoint", + distributionPointNames: "distributionPointNames", + reasons: "reasons", + cRLIssuer: "cRLIssuer", + cRLIssuerNames: "cRLIssuerNames" + } + }) + ); + + if(asn1.verified === false) + throw new Error("Object's schema was not verified against input data for DistributionPoint"); + //endregion + + //region Get internal properties from parsed schema + if("distributionPoint" in asn1.result) + { + if(asn1.result.distributionPoint.idBlock.tagNumber === 0) // GENERAL_NAMES variant + this.distributionPoint = Array.from(asn1.result.distributionPointNames, element => new GeneralName({ schema: element })); + + if(asn1.result.distributionPoint.idBlock.tagNumber === 1) // RDN variant + { + this.distributionPoint = new RelativeDistinguishedNames({ + schema: new asn1js.Sequence({ + value: asn1.result.distributionPoint.valueBlock.value + }) + }); + } + } + + if("reasons" in asn1.result) + this.reasons = new asn1js.BitString({ valueHex: asn1.result.reasons.valueBlock.valueHex }); + + if("cRLIssuer" in asn1.result) + this.cRLIssuer = Array.from(asn1.result.cRLIssuerNames, element => new GeneralName({ schema: element })); + //endregion + } + //********************************************************************************** + /** + * Convert current object to asn1js object and set correct values + * @returns {Object} asn1js object + */ + toSchema() + { + //region Create array for output sequence + const outputArray = []; + + if("distributionPoint" in this) + { + let internalValue; + + if(this.distributionPoint instanceof Array) + { + internalValue = new asn1js.Constructed({ + idBlock: { + tagClass: 3, // CONTEXT-SPECIFIC + tagNumber: 0 // [0] + }, + value: Array.from(this.distributionPoint, element => element.toSchema()) + }); + } + else + { + internalValue = new asn1js.Constructed({ + idBlock: { + tagClass: 3, // CONTEXT-SPECIFIC + tagNumber: 1 // [1] + }, + value: [this.distributionPoint.toSchema()] + }); + } + + outputArray.push(new asn1js.Constructed({ + idBlock: { + tagClass: 3, // CONTEXT-SPECIFIC + tagNumber: 0 // [0] + }, + value: [internalValue] + })); + } + + if("reasons" in this) + { + outputArray.push(new asn1js.Primitive({ + idBlock: { + tagClass: 3, // CONTEXT-SPECIFIC + tagNumber: 1 // [1] + }, + valueHex: this.reasons.valueBlock.valueHex + })); + } + + if("cRLIssuer" in this) + { + outputArray.push(new asn1js.Constructed({ + idBlock: { + tagClass: 3, // CONTEXT-SPECIFIC + tagNumber: 2 // [2] + }, + value: Array.from(this.cRLIssuer, element => element.toSchema()) + })); + } + //endregion + + //region Construct and return new ASN.1 schema for this object + return (new asn1js.Sequence({ + value: outputArray + })); + //endregion + } + //********************************************************************************** + /** + * Convertion for the class to JSON object + * @returns {Object} + */ + toJSON() + { + const object = {}; + + if("distributionPoint" in this) + { + if(this.distributionPoint instanceof Array) + object.distributionPoint = Array.from(this.distributionPoint, element => element.toJSON()); + else + object.distributionPoint = this.distributionPoint.toJSON(); + } + + if("reasons" in this) + object.reasons = this.reasons.toJSON(); + + if("cRLIssuer" in this) + object.cRLIssuer = Array.from(this.cRLIssuer, element => element.toJSON()); + + return object; + } + //********************************************************************************** +} +//************************************************************************************** diff --git a/core/third-party/pkijs/ECCCMSSharedInfo.js b/core/third-party/pkijs/ECCCMSSharedInfo.js new file mode 100644 index 0000000..af4ec2c --- /dev/null +++ b/core/third-party/pkijs/ECCCMSSharedInfo.js @@ -0,0 +1,233 @@ +import * as asn1js from "./asn1.js"; +import { getParametersValue, clearProps } from "./pvutils.js"; +import AlgorithmIdentifier from "./AlgorithmIdentifier.js"; +//************************************************************************************** +/** + * Class from RFC6318 + */ +export default class ECCCMSSharedInfo +{ + //********************************************************************************** + /** + * Constructor for ECCCMSSharedInfo class + * @param {Object} [parameters={}] + * @param {Object} [parameters.schema] asn1js parsed value to initialize the class from + */ + constructor(parameters = {}) + { + //region Internal properties of the object + /** + * @type {AlgorithmIdentifier} + * @desc keyInfo + */ + this.keyInfo = getParametersValue(parameters, "keyInfo", ECCCMSSharedInfo.defaultValues("keyInfo")); + + if("entityUInfo" in parameters) + /** + * @type {OctetString} + * @desc entityUInfo + */ + this.entityUInfo = getParametersValue(parameters, "entityUInfo", ECCCMSSharedInfo.defaultValues("entityUInfo")); + + /** + * @type {OctetString} + * @desc suppPubInfo + */ + this.suppPubInfo = getParametersValue(parameters, "suppPubInfo", ECCCMSSharedInfo.defaultValues("suppPubInfo")); + //endregion + + //region If input argument array contains "schema" for this object + if("schema" in parameters) + this.fromSchema(parameters.schema); + //endregion + } + //********************************************************************************** + /** + * Return default values for all class members + * @param {string} memberName String name for a class member + */ + static defaultValues(memberName) + { + switch(memberName) + { + case "keyInfo": + return new AlgorithmIdentifier(); + case "entityUInfo": + return new asn1js.OctetString(); + case "suppPubInfo": + return new asn1js.OctetString(); + default: + throw new Error(`Invalid member name for ECCCMSSharedInfo class: ${memberName}`); + } + } + //********************************************************************************** + /** + * Compare values with default values for all class members + * @param {string} memberName String name for a class member + * @param {*} memberValue Value to compare with default value + */ + static compareWithDefault(memberName, memberValue) + { + switch(memberName) + { + case "keyInfo": + case "entityUInfo": + case "suppPubInfo": + return (memberValue.isEqual(ECCCMSSharedInfo.defaultValues(memberName))); + default: + throw new Error(`Invalid member name for ECCCMSSharedInfo class: ${memberName}`); + } + } + //********************************************************************************** + /** + * Return value of pre-defined ASN.1 schema for current class + * + * ASN.1 schema: + * ```asn1 + * ECC-CMS-SharedInfo ::= SEQUENCE { + * keyInfo AlgorithmIdentifier, + * entityUInfo [0] EXPLICIT OCTET STRING OPTIONAL, + * suppPubInfo [2] EXPLICIT OCTET STRING } + * ``` + * + * @param {Object} parameters Input parameters for the schema + * @returns {Object} asn1js schema object + */ + static schema(parameters = {}) + { + /** + * @type {Object} + * @property {string} [blockName] + * @property {string} [keyInfo] + * @property {string} [entityUInfo] + * @property {string} [suppPubInfo] + */ + const names = getParametersValue(parameters, "names", {}); + + return (new asn1js.Sequence({ + name: (names.blockName || ""), + value: [ + AlgorithmIdentifier.schema(names.keyInfo || {}), + new asn1js.Constructed({ + name: (names.entityUInfo || ""), + idBlock: { + tagClass: 3, // CONTEXT-SPECIFIC + tagNumber: 0 // [0] + }, + optional: true, + value: [new asn1js.OctetString()] + }), + new asn1js.Constructed({ + name: (names.suppPubInfo || ""), + idBlock: { + tagClass: 3, // CONTEXT-SPECIFIC + tagNumber: 2 // [2] + }, + value: [new asn1js.OctetString()] + }) + ] + })); + } + //********************************************************************************** + /** + * Convert parsed asn1js object into current class + * @param {!Object} schema + */ + fromSchema(schema) + { + //region Clear input data first + clearProps(schema, [ + "keyInfo", + "entityUInfo", + "suppPubInfo" + ]); + //endregion + + //region Check the schema is valid + const asn1 = asn1js.compareSchema(schema, + schema, + ECCCMSSharedInfo.schema({ + names: { + keyInfo: { + names: { + blockName: "keyInfo" + } + }, + entityUInfo: "entityUInfo", + suppPubInfo: "suppPubInfo" + } + }) + ); + + if(asn1.verified === false) + throw new Error("Object's schema was not verified against input data for ECCCMSSharedInfo"); + //endregion + + //region Get internal properties from parsed schema + this.keyInfo = new AlgorithmIdentifier({ schema: asn1.result.keyInfo }); + + if("entityUInfo" in asn1.result) + this.entityUInfo = asn1.result.entityUInfo.valueBlock.value[0]; + + this.suppPubInfo = asn1.result.suppPubInfo.valueBlock.value[0]; + //endregion + } + //********************************************************************************** + /** + * Convert current object to asn1js object and set correct values + * @returns {Object} asn1js object + */ + toSchema() + { + //region Create output array for sequence + const outputArray = []; + + outputArray.push(this.keyInfo.toSchema()); + + if("entityUInfo" in this) + { + outputArray.push(new asn1js.Constructed({ + idBlock: { + tagClass: 3, // CONTEXT-SPECIFIC + tagNumber: 0 // [0] + }, + value: [this.entityUInfo] + })); + } + + outputArray.push(new asn1js.Constructed({ + idBlock: { + tagClass: 3, // CONTEXT-SPECIFIC + tagNumber: 2 // [2] + }, + value: [this.suppPubInfo] + })); + //endregion + + //region Construct and return new ASN.1 schema for this object + return new asn1js.Sequence({ + value: outputArray + }); + //endregion + } + //********************************************************************************** + /** + * Convertion for the class to JSON object + * @returns {Object} + */ + toJSON() + { + const _object = { + keyInfo: this.keyInfo.toJSON() + }; + + if("entityUInfo" in this) + _object.entityUInfo = this.entityUInfo.toJSON(); + + _object.suppPubInfo = this.suppPubInfo.toJSON(); + + return _object; + } + //********************************************************************************** +} +//************************************************************************************** diff --git a/core/third-party/pkijs/ECPrivateKey.js b/core/third-party/pkijs/ECPrivateKey.js new file mode 100644 index 0000000..43b4798 --- /dev/null +++ b/core/third-party/pkijs/ECPrivateKey.js @@ -0,0 +1,344 @@ +import * as asn1js from "./asn1.js"; +import { getParametersValue, toBase64, arrayBufferToString, stringToArrayBuffer, fromBase64, clearProps } from "./pvutils.js"; +import ECPublicKey from "./ECPublicKey.js"; +//************************************************************************************** +/** + * Class from RFC5915 + */ +export default class ECPrivateKey +{ + //********************************************************************************** + /** + * Constructor for ECPrivateKey class + * @param {Object} [parameters={}] + * @param {Object} [parameters.schema] asn1js parsed value to initialize the class from + */ + constructor(parameters = {}) + { + //region Internal properties of the object + /** + * @type {number} + * @desc version + */ + this.version = getParametersValue(parameters, "version", ECPrivateKey.defaultValues("version")); + /** + * @type {OctetString} + * @desc privateKey + */ + this.privateKey = getParametersValue(parameters, "privateKey", ECPrivateKey.defaultValues("privateKey")); + + if("namedCurve" in parameters) + /** + * @type {string} + * @desc namedCurve + */ + this.namedCurve = getParametersValue(parameters, "namedCurve", ECPrivateKey.defaultValues("namedCurve")); + + if("publicKey" in parameters) + /** + * @type {ECPublicKey} + * @desc publicKey + */ + this.publicKey = getParametersValue(parameters, "publicKey", ECPrivateKey.defaultValues("publicKey")); + //endregion + + //region If input argument array contains "schema" for this object + if("schema" in parameters) + this.fromSchema(parameters.schema); + //endregion + //region If input argument array contains "json" for this object + if("json" in parameters) + this.fromJSON(parameters.json); + //endregion + } + //********************************************************************************** + /** + * Return default values for all class members + * @param {string} memberName String name for a class member + */ + static defaultValues(memberName) + { + switch(memberName) + { + case "version": + return 1; + case "privateKey": + return new asn1js.OctetString(); + case "namedCurve": + return ""; + case "publicKey": + return new ECPublicKey(); + default: + throw new Error(`Invalid member name for ECCPrivateKey class: ${memberName}`); + } + } + //********************************************************************************** + /** + * Compare values with default values for all class members + * @param {string} memberName String name for a class member + * @param {*} memberValue Value to compare with default value + */ + static compareWithDefault(memberName, memberValue) + { + switch(memberName) + { + case "version": + return (memberValue === ECPrivateKey.defaultValues(memberName)); + case "privateKey": + return (memberValue.isEqual(ECPrivateKey.defaultValues(memberName))); + case "namedCurve": + return (memberValue === ""); + case "publicKey": + return ((ECPublicKey.compareWithDefault("namedCurve", memberValue.namedCurve)) && + (ECPublicKey.compareWithDefault("x", memberValue.x)) && + (ECPublicKey.compareWithDefault("y", memberValue.y))); + default: + throw new Error(`Invalid member name for ECCPrivateKey class: ${memberName}`); + } + } + //********************************************************************************** + /** + * Return value of pre-defined ASN.1 schema for current class + * + * ASN.1 schema: + * ```asn1 + * ECPrivateKey ::= SEQUENCE { + * version INTEGER { ecPrivkeyVer1(1) } (ecPrivkeyVer1), + * privateKey OCTET STRING, + * parameters [0] ECParameters {{ NamedCurve }} OPTIONAL, + * publicKey [1] BIT STRING OPTIONAL + * } + * ``` + * + * @param {Object} parameters Input parameters for the schema + * @returns {Object} asn1js schema object + */ + static schema(parameters = {}) + { + /** + * @type {Object} + * @property {string} [blockName] + * @property {string} [version] + * @property {string} [privateKey] + * @property {string} [namedCurve] + * @property {string} [publicKey] + */ + const names = getParametersValue(parameters, "names", {}); + + return (new asn1js.Sequence({ + name: (names.blockName || ""), + value: [ + new asn1js.Integer({ name: (names.version || "") }), + new asn1js.OctetString({ name: (names.privateKey || "") }), + new asn1js.Constructed({ + optional: true, + idBlock: { + tagClass: 3, // CONTEXT-SPECIFIC + tagNumber: 0 // [0] + }, + value: [ + new asn1js.ObjectIdentifier({ name: (names.namedCurve || "") }) + ] + }), + new asn1js.Constructed({ + optional: true, + idBlock: { + tagClass: 3, // CONTEXT-SPECIFIC + tagNumber: 1 // [1] + }, + value: [ + new asn1js.BitString({ name: (names.publicKey || "") }) + ] + }) + ] + })); + } + //********************************************************************************** + /** + * Convert parsed asn1js object into current class + * @param {!Object} schema + */ + fromSchema(schema) + { + //region Clear input data first + clearProps(schema, [ + "version", + "privateKey", + "namedCurve", + "publicKey" + ]); + //endregion + + //region Check the schema is valid + const asn1 = asn1js.compareSchema(schema, + schema, + ECPrivateKey.schema({ + names: { + version: "version", + privateKey: "privateKey", + namedCurve: "namedCurve", + publicKey: "publicKey" + } + }) + ); + + if(asn1.verified === false) + throw new Error("Object's schema was not verified against input data for ECPrivateKey"); + //endregion + + //region Get internal properties from parsed schema + this.version = asn1.result.version.valueBlock.valueDec; + this.privateKey = asn1.result.privateKey; + + if("namedCurve" in asn1.result) + this.namedCurve = asn1.result.namedCurve.valueBlock.toString(); + + if("publicKey" in asn1.result) + { + const publicKeyData = { schema: asn1.result.publicKey.valueBlock.valueHex }; + if("namedCurve" in this) + publicKeyData.namedCurve = this.namedCurve; + + this.publicKey = new ECPublicKey(publicKeyData); + } + //endregion + } + //********************************************************************************** + /** + * Convert current object to asn1js object and set correct values + * @returns {Object} asn1js object + */ + toSchema() + { + const outputArray = [ + new asn1js.Integer({ value: this.version }), + this.privateKey + ]; + + if("namedCurve" in this) + { + outputArray.push(new asn1js.Constructed({ + idBlock: { + tagClass: 3, // CONTEXT-SPECIFIC + tagNumber: 0 // [0] + }, + value: [ + new asn1js.ObjectIdentifier({ value: this.namedCurve }) + ] + })); + } + + if("publicKey" in this) + { + outputArray.push(new asn1js.Constructed({ + idBlock: { + tagClass: 3, // CONTEXT-SPECIFIC + tagNumber: 1 // [1] + }, + value: [ + new asn1js.BitString({ valueHex: this.publicKey.toSchema().toBER(false) }) + ] + })); + } + + return new asn1js.Sequence({ + value: outputArray + }); + } + //********************************************************************************** + /** + * Convertion for the class to JSON object + * @returns {Object} + */ + toJSON() + { + if((("namedCurve" in this) === false) || (ECPrivateKey.compareWithDefault("namedCurve", this.namedCurve))) + throw new Error("Not enough information for making JSON: absent \"namedCurve\" value"); + + let crvName = ""; + + switch(this.namedCurve) + { + case "1.2.840.10045.3.1.7": // P-256 + crvName = "P-256"; + break; + case "1.3.132.0.34": // P-384 + crvName = "P-384"; + break; + case "1.3.132.0.35": // P-521 + crvName = "P-521"; + break; + default: + } + + const privateKeyJSON = { + crv: crvName, + d: toBase64(arrayBufferToString(this.privateKey.valueBlock.valueHex), true, true, false) + }; + + if("publicKey" in this) + { + const publicKeyJSON = this.publicKey.toJSON(); + + privateKeyJSON.x = publicKeyJSON.x; + privateKeyJSON.y = publicKeyJSON.y; + } + + return privateKeyJSON; + } + //********************************************************************************** + /** + * Convert JSON value into current object + * @param {Object} json + */ + fromJSON(json) + { + let coodinateLength = 0; + + if("crv" in json) + { + switch(json.crv.toUpperCase()) + { + case "P-256": + this.namedCurve = "1.2.840.10045.3.1.7"; + coodinateLength = 32; + break; + case "P-384": + this.namedCurve = "1.3.132.0.34"; + coodinateLength = 48; + break; + case "P-521": + this.namedCurve = "1.3.132.0.35"; + coodinateLength = 66; + break; + default: + } + } + else + throw new Error("Absent mandatory parameter \"crv\""); + + if("d" in json) + { + const convertBuffer = stringToArrayBuffer(fromBase64(json.d, true)); + + if(convertBuffer.byteLength < coodinateLength) + { + const buffer = new ArrayBuffer(coodinateLength); + const view = new Uint8Array(buffer); + const convertBufferView = new Uint8Array(convertBuffer); + view.set(convertBufferView, 1); + + this.privateKey = new asn1js.OctetString({ valueHex: buffer }); + } + else + this.privateKey = new asn1js.OctetString({ valueHex: convertBuffer.slice(0, coodinateLength) }); + } + else + throw new Error("Absent mandatory parameter \"d\""); + + if(("x" in json) && ("y" in json)) + this.publicKey = new ECPublicKey({ json }); + } + //********************************************************************************** +} +//************************************************************************************** diff --git a/core/third-party/pkijs/ECPublicKey.js b/core/third-party/pkijs/ECPublicKey.js new file mode 100644 index 0000000..18e0059 --- /dev/null +++ b/core/third-party/pkijs/ECPublicKey.js @@ -0,0 +1,242 @@ +import * as asn1js from "./asn1.js"; +import { getParametersValue, utilConcatBuf, isEqualBuffer, toBase64, fromBase64, arrayBufferToString, stringToArrayBuffer } from "./pvutils.js"; +//************************************************************************************** +/** + * Class from RFC5480 + */ +export default class ECPublicKey +{ + //********************************************************************************** + /** + * Constructor for ECCPublicKey class + * @param {Object} [parameters={}] + * @param {Object} [parameters.schema] asn1js parsed value to initialize the class from + */ + constructor(parameters = {}) + { + //region Internal properties of the object + /** + * @type {ArrayBuffer} + * @desc type + */ + this.x = getParametersValue(parameters, "x", ECPublicKey.defaultValues("x")); + /** + * @type {ArrayBuffer} + * @desc values + */ + this.y = getParametersValue(parameters, "y", ECPublicKey.defaultValues("y")); + /** + * @type {string} + * @desc namedCurve + */ + this.namedCurve = getParametersValue(parameters, "namedCurve", ECPublicKey.defaultValues("namedCurve")); + //endregion + + //region If input argument array contains "schema" for this object + if("schema" in parameters) + this.fromSchema(parameters.schema); + //endregion + //region If input argument array contains "json" for this object + if("json" in parameters) + this.fromJSON(parameters.json); + //endregion + } + //********************************************************************************** + /** + * Return default values for all class members + * @param {string} memberName String name for a class member + */ + static defaultValues(memberName) + { + switch(memberName) + { + case "x": + case "y": + return new ArrayBuffer(0); + case "namedCurve": + return ""; + default: + throw new Error(`Invalid member name for ECCPublicKey class: ${memberName}`); + } + } + //********************************************************************************** + /** + * Compare values with default values for all class members + * @param {string} memberName String name for a class member + * @param {*} memberValue Value to compare with default value + */ + static compareWithDefault(memberName, memberValue) + { + switch(memberName) + { + case "x": + case "y": + return (isEqualBuffer(memberValue, ECPublicKey.defaultValues(memberName))); + case "namedCurve": + return (memberValue === ""); + default: + throw new Error(`Invalid member name for ECCPublicKey class: ${memberName}`); + } + } + //********************************************************************************** + /** + * Return value of pre-defined ASN.1 schema for current class + * @param {Object} parameters Input parameters for the schema + * @returns {Object} asn1js schema object + */ + static schema(parameters = {}) + { + return new asn1js.RawData(); + } + //********************************************************************************** + /** + * Convert ArrayBuffer into current class + * @param {!ArrayBuffer} schema Special case: schema is an ArrayBuffer + */ + fromSchema(schema) + { + //region Check the schema is valid + if((schema instanceof ArrayBuffer) === false) + throw new Error("Object's schema was not verified against input data for ECPublicKey"); + + const view = new Uint8Array(schema); + if(view[0] !== 0x04) + throw new Error("Object's schema was not verified against input data for ECPublicKey"); + //endregion + + //region Get internal properties from parsed schema + let coordinateLength; + + switch(this.namedCurve) + { + case "1.2.840.10045.3.1.7": // P-256 + coordinateLength = 32; + break; + case "1.3.132.0.34": // P-384 + coordinateLength = 48; + break; + case "1.3.132.0.35": // P-521 + coordinateLength = 66; + break; + default: + throw new Error(`Incorrect curve OID: ${this.namedCurve}`); + } + + if(schema.byteLength !== (coordinateLength * 2 + 1)) + throw new Error("Object's schema was not verified against input data for ECPublicKey"); + + this.x = schema.slice(1, coordinateLength + 1); + this.y = schema.slice(1 + coordinateLength, coordinateLength * 2 + 1); + //endregion + } + //********************************************************************************** + /** + * Convert current object to asn1js object and set correct values + * @returns {Object} asn1js object + */ + toSchema() + { + return new asn1js.RawData({ data: utilConcatBuf( + (new Uint8Array([0x04])).buffer, + this.x, + this.y + ) + }); + } + //********************************************************************************** + /** + * Convertion for the class to JSON object + * @returns {Object} + */ + toJSON() + { + let crvName = ""; + + switch(this.namedCurve) + { + case "1.2.840.10045.3.1.7": // P-256 + crvName = "P-256"; + break; + case "1.3.132.0.34": // P-384 + crvName = "P-384"; + break; + case "1.3.132.0.35": // P-521 + crvName = "P-521"; + break; + default: + } + + return { + crv: crvName, + x: toBase64(arrayBufferToString(this.x), true, true, false), + y: toBase64(arrayBufferToString(this.y), true, true, false) + }; + } + //********************************************************************************** + /** + * Convert JSON value into current object + * @param {Object} json + */ + fromJSON(json) + { + let coodinateLength = 0; + + if("crv" in json) + { + switch(json.crv.toUpperCase()) + { + case "P-256": + this.namedCurve = "1.2.840.10045.3.1.7"; + coodinateLength = 32; + break; + case "P-384": + this.namedCurve = "1.3.132.0.34"; + coodinateLength = 48; + break; + case "P-521": + this.namedCurve = "1.3.132.0.35"; + coodinateLength = 66; + break; + default: + } + } + else + throw new Error("Absent mandatory parameter \"crv\""); + + if("x" in json) + { + const convertBuffer = stringToArrayBuffer(fromBase64(json.x, true)); + + if(convertBuffer.byteLength < coodinateLength) + { + this.x = new ArrayBuffer(coodinateLength); + const view = new Uint8Array(this.x); + const convertBufferView = new Uint8Array(convertBuffer); + view.set(convertBufferView, 1); + } + else + this.x = convertBuffer.slice(0, coodinateLength); + } + else + throw new Error("Absent mandatory parameter \"x\""); + + if("y" in json) + { + const convertBuffer = stringToArrayBuffer(fromBase64(json.y, true)); + + if(convertBuffer.byteLength < coodinateLength) + { + this.y = new ArrayBuffer(coodinateLength); + const view = new Uint8Array(this.y); + const convertBufferView = new Uint8Array(convertBuffer); + view.set(convertBufferView, 1); + } + else + this.y = convertBuffer.slice(0, coodinateLength); + } + else + throw new Error("Absent mandatory parameter \"y\""); + } + //********************************************************************************** +} +//************************************************************************************** diff --git a/core/third-party/pkijs/EncapsulatedContentInfo.js b/core/third-party/pkijs/EncapsulatedContentInfo.js new file mode 100644 index 0000000..3d43184 --- /dev/null +++ b/core/third-party/pkijs/EncapsulatedContentInfo.js @@ -0,0 +1,243 @@ +import * as asn1js from "./asn1.js"; +import { getParametersValue, clearProps } from "./pvutils.js"; +//************************************************************************************** +/** + * Class from RFC5652 + */ +export default class EncapsulatedContentInfo +{ + //********************************************************************************** + /** + * Constructor for EncapsulatedContentInfo class + * @param {Object} [parameters={}] + * @param {Object} [parameters.schema] asn1js parsed value to initialize the class from + */ + constructor(parameters = {}) + { + //region Internal properties of the object + /** + * @type {string} + * @desc eContentType + */ + this.eContentType = getParametersValue(parameters, "eContentType", EncapsulatedContentInfo.defaultValues("eContentType")); + + if("eContent" in parameters) + { + /** + * @type {OctetString} + * @desc eContent + */ + this.eContent = getParametersValue(parameters, "eContent", EncapsulatedContentInfo.defaultValues("eContent")); + if((this.eContent.idBlock.tagClass === 1) && + (this.eContent.idBlock.tagNumber === 4)) + { + //region Divide OCTETSTRING value down to small pieces + if(this.eContent.idBlock.isConstructed === false) + { + const constrString = new asn1js.OctetString({ + idBlock: { isConstructed: true }, + isConstructed: true + }); + + let offset = 0; + let length = this.eContent.valueBlock.valueHex.byteLength; + + while(length > 0) + { + const pieceView = new Uint8Array(this.eContent.valueBlock.valueHex, offset, ((offset + 65536) > this.eContent.valueBlock.valueHex.byteLength) ? (this.eContent.valueBlock.valueHex.byteLength - offset) : 65536); + const _array = new ArrayBuffer(pieceView.length); + const _view = new Uint8Array(_array); + + for(let i = 0; i < _view.length; i++) + _view[i] = pieceView[i]; + + constrString.valueBlock.value.push(new asn1js.OctetString({ valueHex: _array })); + + length -= pieceView.length; + offset += pieceView.length; + } + + this.eContent = constrString; + } + //endregion + } + } + //endregion + + //region If input argument array contains "schema" for this object + if("schema" in parameters) + this.fromSchema(parameters.schema); + //endregion + } + //********************************************************************************** + /** + * Return default values for all class members + * @param {string} memberName String name for a class member + */ + static defaultValues(memberName) + { + switch(memberName) + { + case "eContentType": + return ""; + case "eContent": + return new asn1js.OctetString(); + default: + throw new Error(`Invalid member name for EncapsulatedContentInfo class: ${memberName}`); + } + } + //********************************************************************************** + /** + * Compare values with default values for all class members + * @param {string} memberName String name for a class member + * @param {*} memberValue Value to compare with default value + */ + static compareWithDefault(memberName, memberValue) + { + switch(memberName) + { + case "eContentType": + return (memberValue === ""); + case "eContent": + { + if((memberValue.idBlock.tagClass === 1) && (memberValue.idBlock.tagNumber === 4)) + return (memberValue.isEqual(EncapsulatedContentInfo.defaultValues("eContent"))); + + return false; + } + default: + throw new Error(`Invalid member name for EncapsulatedContentInfo class: ${memberName}`); + } + } + //********************************************************************************** + /** + * Return value of pre-defined ASN.1 schema for current class + * + * ASN.1 schema: + * ```asn1 + * EncapsulatedContentInfo ::= SEQUENCE { + * eContentType ContentType, + * eContent [0] EXPLICIT OCTET STRING OPTIONAL } * Changed it to ANY, as in PKCS#7 + * ``` + * + * @param {Object} parameters Input parameters for the schema + * @returns {Object} asn1js schema object + */ + static schema(parameters = {}) + { + /** + * @type {Object} + * @property {string} [blockName] + * @property {string} [type] + * @property {string} [setName] + * @property {string} [values] + */ + const names = getParametersValue(parameters, "names", {}); + + return (new asn1js.Sequence({ + name: (names.blockName || ""), + value: [ + new asn1js.ObjectIdentifier({ name: (names.eContentType || "") }), + new asn1js.Constructed({ + optional: true, + idBlock: { + tagClass: 3, // CONTEXT-SPECIFIC + tagNumber: 0 // [0] + }, + value: [ + new asn1js.Any({ name: (names.eContent || "") }) // In order to aling this with PKCS#7 and CMS as well + ] + }) + ] + })); + } + //********************************************************************************** + /** + * Convert parsed asn1js object into current class + * @param {!Object} schema + */ + fromSchema(schema) + { + //region Clear input data first + clearProps(schema, [ + "eContentType", + "eContent" + ]); + //endregion + + //region Check the schema is valid + const asn1 = asn1js.compareSchema(schema, + schema, + EncapsulatedContentInfo.schema({ + names: { + eContentType: "eContentType", + eContent: "eContent" + } + }) + ); + + if(asn1.verified === false) + throw new Error("Object's schema was not verified against input data for EncapsulatedContentInfo"); + //endregion + + //region Get internal properties from parsed schema + this.eContentType = asn1.result.eContentType.valueBlock.toString(); + if("eContent" in asn1.result) + this.eContent = asn1.result.eContent; + //endregion + } + //********************************************************************************** + /** + * Convert current object to asn1js object and set correct values + * @returns {Object} asn1js object + */ + toSchema() + { + //region Create array for output sequence + const outputArray = []; + + outputArray.push(new asn1js.ObjectIdentifier({ value: this.eContentType })); + if("eContent" in this) + { + if(EncapsulatedContentInfo.compareWithDefault("eContent", this.eContent) === false) + { + outputArray.push(new asn1js.Constructed({ + optional: true, + idBlock: { + tagClass: 3, // CONTEXT-SPECIFIC + tagNumber: 0 // [0] + }, + value: [this.eContent] + })); + } + } + //endregion + + //region Construct and return new ASN.1 schema for this object + return (new asn1js.Sequence({ + value: outputArray + })); + //endregion + } + //********************************************************************************** + /** + * Convertion for the class to JSON object + * @returns {Object} + */ + toJSON() + { + const _object = { + eContentType: this.eContentType + }; + + if("eContent" in this) + { + if(EncapsulatedContentInfo.compareWithDefault("eContent", this.eContent) === false) + _object.eContent = this.eContent.toJSON(); + } + + return _object; + } + //********************************************************************************** +} +//************************************************************************************** diff --git a/core/third-party/pkijs/EncryptedContentInfo.js b/core/third-party/pkijs/EncryptedContentInfo.js new file mode 100644 index 0000000..fb6a1cd --- /dev/null +++ b/core/third-party/pkijs/EncryptedContentInfo.js @@ -0,0 +1,287 @@ +import * as asn1js from "./asn1.js"; +import { getParametersValue, clearProps } from "./pvutils.js"; +import AlgorithmIdentifier from "./AlgorithmIdentifier.js"; +//************************************************************************************** +/** + * Class from RFC5652 + */ +export default class EncryptedContentInfo +{ + //********************************************************************************** + /** + * Constructor for EncryptedContentInfo class + * @param {Object} [parameters={}] + * @param {Object} [parameters.schema] asn1js parsed value to initialize the class from + */ + constructor(parameters = {}) + { + //region Internal properties of the object + /** + * @type {string} + * @desc contentType + */ + this.contentType = getParametersValue(parameters, "contentType", EncryptedContentInfo.defaultValues("contentType")); + /** + * @type {AlgorithmIdentifier} + * @desc contentEncryptionAlgorithm + */ + this.contentEncryptionAlgorithm = getParametersValue(parameters, "contentEncryptionAlgorithm", EncryptedContentInfo.defaultValues("contentEncryptionAlgorithm")); + + if("encryptedContent" in parameters) + { + /** + * @type {OctetString} + * @desc encryptedContent (!!!) could be contructive or primitive value (!!!) + */ + this.encryptedContent = parameters.encryptedContent; + + if((this.encryptedContent.idBlock.tagClass === 1) && + (this.encryptedContent.idBlock.tagNumber === 4)) + { + //region Divide OCTETSTRING value down to small pieces + if(this.encryptedContent.idBlock.isConstructed === false) + { + const constrString = new asn1js.OctetString({ + idBlock: { isConstructed: true }, + isConstructed: true + }); + + let offset = 0; + let length = this.encryptedContent.valueBlock.valueHex.byteLength; + + while(length > 0) + { + const pieceView = new Uint8Array(this.encryptedContent.valueBlock.valueHex, offset, ((offset + 1024) > this.encryptedContent.valueBlock.valueHex.byteLength) ? (this.encryptedContent.valueBlock.valueHex.byteLength - offset) : 1024); + const _array = new ArrayBuffer(pieceView.length); + const _view = new Uint8Array(_array); + + for(let i = 0; i < _view.length; i++) + _view[i] = pieceView[i]; + + constrString.valueBlock.value.push(new asn1js.OctetString({ valueHex: _array })); + + length -= pieceView.length; + offset += pieceView.length; + } + + this.encryptedContent = constrString; + } + //endregion + } + } + //endregion + + //region If input argument array contains "schema" for this object + if("schema" in parameters) + this.fromSchema(parameters.schema); + //endregion + } + //********************************************************************************** + /** + * Return default values for all class members + * @param {string} memberName String name for a class member + */ + static defaultValues(memberName) + { + switch(memberName) + { + case "contentType": + return ""; + case "contentEncryptionAlgorithm": + return new AlgorithmIdentifier(); + case "encryptedContent": + return new asn1js.OctetString(); + default: + throw new Error(`Invalid member name for EncryptedContentInfo class: ${memberName}`); + } + } + //********************************************************************************** + /** + * Compare values with default values for all class members + * @param {string} memberName String name for a class member + * @param {*} memberValue Value to compare with default value + */ + static compareWithDefault(memberName, memberValue) + { + switch(memberName) + { + case "contentType": + return (memberValue === ""); + case "contentEncryptionAlgorithm": + return ((memberValue.algorithmId === "") && (("algorithmParams" in memberValue) === false)); + case "encryptedContent": + return (memberValue.isEqual(EncryptedContentInfo.defaultValues(memberName))); + default: + throw new Error(`Invalid member name for EncryptedContentInfo class: ${memberName}`); + } + } + //********************************************************************************** + /** + * Return value of pre-defined ASN.1 schema for current class + * + * ASN.1 schema: + * ```asn1 + * EncryptedContentInfo ::= SEQUENCE { + * contentType ContentType, + * contentEncryptionAlgorithm ContentEncryptionAlgorithmIdentifier, + * encryptedContent [0] IMPLICIT EncryptedContent OPTIONAL } + * + * Comment: Strange, but modern crypto engines create "encryptedContent" as "[0] EXPLICIT EncryptedContent" + * + * EncryptedContent ::= OCTET STRING + * ``` + * + * @param {Object} parameters Input parameters for the schema + * @returns {Object} asn1js schema object + */ + static schema(parameters = {}) + { + /** + * @type {Object} + * @property {string} [blockName] + * @property {string} [contentType] + * @property {string} [contentEncryptionAlgorithm] + * @property {string} [encryptedContent] + */ + const names = getParametersValue(parameters, "names", {}); + + return (new asn1js.Sequence({ + name: (names.blockName || ""), + value: [ + new asn1js.ObjectIdentifier({ name: (names.contentType || "") }), + AlgorithmIdentifier.schema(names.contentEncryptionAlgorithm || {}), + // The CHOICE we need because "EncryptedContent" could have either "constructive" + // or "primitive" form of encoding and we need to handle both variants + new asn1js.Choice({ + value: [ + new asn1js.Constructed({ + name: (names.encryptedContent || ""), + idBlock: { + tagClass: 3, // CONTEXT-SPECIFIC + tagNumber: 0 // [0] + }, + value: [ + new asn1js.Repeated({ + value: new asn1js.OctetString() + }) + ] + }), + new asn1js.Primitive({ + name: (names.encryptedContent || ""), + idBlock: { + tagClass: 3, // CONTEXT-SPECIFIC + tagNumber: 0 // [0] + } + }) + ] + }) + ] + })); + } + //********************************************************************************** + /** + * Convert parsed asn1js object into current class + * @param {!Object} schema + */ + fromSchema(schema) + { + //region Clear input data first + clearProps(schema, [ + "contentType", + "contentEncryptionAlgorithm", + "encryptedContent" + ]); + //endregion + + //region Check the schema is valid + const asn1 = asn1js.compareSchema(schema, + schema, + EncryptedContentInfo.schema({ + names: { + contentType: "contentType", + contentEncryptionAlgorithm: { + names: { + blockName: "contentEncryptionAlgorithm" + } + }, + encryptedContent: "encryptedContent" + } + }) + ); + + if(asn1.verified === false) + throw new Error("Object's schema was not verified against input data for EncryptedContentInfo"); + //endregion + + //region Get internal properties from parsed schema + this.contentType = asn1.result.contentType.valueBlock.toString(); + this.contentEncryptionAlgorithm = new AlgorithmIdentifier({ schema: asn1.result.contentEncryptionAlgorithm }); + + if("encryptedContent" in asn1.result) + { + this.encryptedContent = asn1.result.encryptedContent; + + this.encryptedContent.idBlock.tagClass = 1; // UNIVERSAL + this.encryptedContent.idBlock.tagNumber = 4; // OCTETSTRING (!!!) The value still has instance of "in_window.org.pkijs.asn1.ASN1_CONSTRUCTED / ASN1_PRIMITIVE" + } + //endregion + } + //********************************************************************************** + /** + * Convert current object to asn1js object and set correct values + * @returns {Object} asn1js object + */ + toSchema() + { + //region Create array for output sequence + const sequenceLengthBlock = { + isIndefiniteForm: false + }; + + const outputArray = []; + + outputArray.push(new asn1js.ObjectIdentifier({ value: this.contentType })); + outputArray.push(this.contentEncryptionAlgorithm.toSchema()); + + if("encryptedContent" in this) + { + sequenceLengthBlock.isIndefiniteForm = this.encryptedContent.idBlock.isConstructed; + + const encryptedValue = this.encryptedContent; + + encryptedValue.idBlock.tagClass = 3; // CONTEXT-SPECIFIC + encryptedValue.idBlock.tagNumber = 0; // [0] + + encryptedValue.lenBlock.isIndefiniteForm = this.encryptedContent.idBlock.isConstructed; + + outputArray.push(encryptedValue); + } + //endregion + + //region Construct and return new ASN.1 schema for this object + return (new asn1js.Sequence({ + lenBlock: sequenceLengthBlock, + value: outputArray + })); + //endregion + } + //********************************************************************************** + /** + * Convertion for the class to JSON object + * @returns {Object} + */ + toJSON() + { + const _object = { + contentType: this.contentType, + contentEncryptionAlgorithm: this.contentEncryptionAlgorithm.toJSON() + }; + + if("encryptedContent" in this) + _object.encryptedContent = this.encryptedContent.toJSON(); + + return _object; + } + //********************************************************************************** +} +//************************************************************************************** diff --git a/core/third-party/pkijs/EncryptedData.js b/core/third-party/pkijs/EncryptedData.js new file mode 100644 index 0000000..75aa30b --- /dev/null +++ b/core/third-party/pkijs/EncryptedData.js @@ -0,0 +1,287 @@ +import * as asn1js from "./asn1.js"; +import { getParametersValue, clearProps } from "./pvutils.js"; +import { getEngine } from "./common.js"; +import EncryptedContentInfo from "./EncryptedContentInfo.js"; +import Attribute from "./Attribute.js"; +//************************************************************************************** +/** + * Class from RFC5652 + */ +export default class EncryptedData +{ + //********************************************************************************** + /** + * Constructor for EncryptedData class + * @param {Object} [parameters={}] + * @param {Object} [parameters.schema] asn1js parsed value to initialize the class from + */ + constructor(parameters = {}) + { + //region Internal properties of the object + /** + * @type {number} + * @desc version + */ + this.version = getParametersValue(parameters, "version", EncryptedData.defaultValues("version")); + /** + * @type {EncryptedContentInfo} + * @desc encryptedContentInfo + */ + this.encryptedContentInfo = getParametersValue(parameters, "encryptedContentInfo", EncryptedData.defaultValues("encryptedContentInfo")); + + if("unprotectedAttrs" in parameters) + /** + * @type {Array.} + * @desc unprotectedAttrs + */ + this.unprotectedAttrs = getParametersValue(parameters, "unprotectedAttrs", EncryptedData.defaultValues("unprotectedAttrs")); + //endregion + + //region If input argument array contains "schema" for this object + if("schema" in parameters) + this.fromSchema(parameters.schema); + //endregion + } + //********************************************************************************** + /** + * Return default values for all class members + * @param {string} memberName String name for a class member + */ + static defaultValues(memberName) + { + switch(memberName) + { + case "version": + return 0; + case "encryptedContentInfo": + return new EncryptedContentInfo(); + case "unprotectedAttrs": + return []; + default: + throw new Error(`Invalid member name for EncryptedData class: ${memberName}`); + } + } + //********************************************************************************** + /** + * Compare values with default values for all class members + * @param {string} memberName String name for a class member + * @param {*} memberValue Value to compare with default value + */ + static compareWithDefault(memberName, memberValue) + { + switch(memberName) + { + case "version": + return (memberValue === 0); + case "encryptedContentInfo": + return ((EncryptedContentInfo.compareWithDefault("contentType", memberValue.contentType)) && + (EncryptedContentInfo.compareWithDefault("contentEncryptionAlgorithm", memberValue.contentEncryptionAlgorithm)) && + (EncryptedContentInfo.compareWithDefault("encryptedContent", memberValue.encryptedContent))); + case "unprotectedAttrs": + return (memberValue.length === 0); + default: + throw new Error(`Invalid member name for EncryptedData class: ${memberName}`); + } + } + //********************************************************************************** + /** + * Return value of pre-defined ASN.1 schema for current class + * + * ASN.1 schema: + * ```asn1 + * EncryptedData ::= SEQUENCE { + * version CMSVersion, + * encryptedContentInfo EncryptedContentInfo, + * unprotectedAttrs [1] IMPLICIT UnprotectedAttributes OPTIONAL } + * ``` + * + * @param {Object} parameters Input parameters for the schema + * @returns {Object} asn1js schema object + */ + static schema(parameters = {}) + { + /** + * @type {Object} + * @property {string} [blockName] + * @property {string} [version] + * @property {string} [encryptedContentInfo] + * @property {string} [unprotectedAttrs] + */ + const names = getParametersValue(parameters, "names", {}); + + return (new asn1js.Sequence({ + name: (names.blockName || ""), + value: [ + new asn1js.Integer({ name: (names.version || "") }), + EncryptedContentInfo.schema(names.encryptedContentInfo || {}), + new asn1js.Constructed({ + optional: true, + idBlock: { + tagClass: 3, // CONTEXT-SPECIFIC + tagNumber: 1 // [1] + }, + value: [ + new asn1js.Repeated({ + name: (names.unprotectedAttrs || ""), + value: Attribute.schema() + }) + ] + }) + ] + })); + } + //********************************************************************************** + /** + * Convert parsed asn1js object into current class + * @param {!Object} schema + */ + fromSchema(schema) + { + //region Clear input data first + clearProps(schema, [ + "version", + "encryptedContentInfo", + "unprotectedAttrs" + ]); + //endregion + + //region Check the schema is valid + const asn1 = asn1js.compareSchema(schema, + schema, + EncryptedData.schema({ + names: { + version: "version", + encryptedContentInfo: { + names: { + blockName: "encryptedContentInfo" + } + }, + unprotectedAttrs: "unprotectedAttrs" + } + }) + ); + + if(asn1.verified === false) + throw new Error("Object's schema was not verified against input data for EncryptedData"); + //endregion + + //region Get internal properties from parsed schema + this.version = asn1.result.version.valueBlock.valueDec; + this.encryptedContentInfo = new EncryptedContentInfo({ schema: asn1.result.encryptedContentInfo }); + + if("unprotectedAttrs" in asn1.result) + this.unprotectedAttrs = Array.from(asn1.result.unprotectedAttrs, element => new Attribute({ schema: element })); + //endregion + } + //********************************************************************************** + /** + * Convert current object to asn1js object and set correct values + * @returns {Object} asn1js object + */ + toSchema() + { + //region Create array for output sequence + const outputArray = []; + + outputArray.push(new asn1js.Integer({ value: this.version })); + outputArray.push(this.encryptedContentInfo.toSchema()); + + if("unprotectedAttrs" in this) + { + outputArray.push(new asn1js.Constructed({ + optional: true, + idBlock: { + tagClass: 3, // CONTEXT-SPECIFIC + tagNumber: 1 // [1] + }, + value: Array.from(this.unprotectedAttrs, element => element.toSchema()) + })); + } + //endregion + + //region Construct and return new ASN.1 schema for this object + return (new asn1js.Sequence({ + value: outputArray + })); + //endregion + } + //********************************************************************************** + /** + * Convertion for the class to JSON object + * @returns {Object} + */ + toJSON() + { + const _object = { + version: this.version, + encryptedContentInfo: this.encryptedContentInfo.toJSON() + }; + + if("unprotectedAttrs" in this) + _object.unprotectedAttrs = Array.from(this.unprotectedAttrs, element => element.toJSON()); + + return _object; + } + //********************************************************************************** + /** + * Create a new CMS Encrypted Data content + * @param {Object} parameters Parameters neccessary for encryption + * @returns {Promise} + */ + encrypt(parameters) + { + //region Check for input parameters + if((parameters instanceof Object) === false) + return Promise.reject("Parameters must have type \"Object\""); + //endregion + + //region Get cryptographic engine + const engine = getEngine(); + if(typeof engine === "undefined") + return Promise.reject("Unable to initialize cryptographic engine"); + //endregion + + //region Set "contentType" parameter + parameters.contentType = "1.2.840.113549.1.7.1"; // "data" + //endregion + + if("encryptEncryptedContentInfo" in engine.subtle) + { + return engine.subtle.encryptEncryptedContentInfo(parameters).then(result => + { + this.encryptedContentInfo = result; + }); + } + + return Promise.reject(`No support for "encryptEncryptedContentInfo" in current crypto engine ${engine.name}`); + } + //********************************************************************************** + /** + * Create a new CMS Encrypted Data content + * @param {Object} parameters Parameters neccessary for encryption + */ + decrypt(parameters) + { + //region Check for input parameters + if((parameters instanceof Object) === false) + return Promise.reject("Parameters must have type \"Object\""); + //endregion + + //region Get cryptographic engine + const engine = getEngine(); + if(typeof engine === "undefined") + return Promise.reject("Unable to initialize cryptographic engine"); + //endregion + + //region Set "encryptedContentInfo" value + parameters.encryptedContentInfo = this.encryptedContentInfo; + //endregion + + if("decryptEncryptedContentInfo" in engine.subtle) + return engine.subtle.decryptEncryptedContentInfo(parameters); + + return Promise.reject(`No support for "decryptEncryptedContentInfo" in current crypto engine ${engine.name}`); + } + //********************************************************************************** +} +//************************************************************************************** diff --git a/core/third-party/pkijs/EnvelopedData.js b/core/third-party/pkijs/EnvelopedData.js new file mode 100644 index 0000000..4b2a6eb --- /dev/null +++ b/core/third-party/pkijs/EnvelopedData.js @@ -0,0 +1,1729 @@ +import * as asn1js from "./asn1.js"; +import { getParametersValue, utilConcatBuf, clearProps } from "./pvutils.js"; +import { getOIDByAlgorithm, getRandomValues, getCrypto, getAlgorithmByOID, kdf } from "./common.js"; +import OriginatorInfo from "./OriginatorInfo.js"; +import RecipientInfo from "./RecipientInfo.js"; +import EncryptedContentInfo from "./EncryptedContentInfo.js"; +import Attribute from "./Attribute.js"; +import AlgorithmIdentifier from "./AlgorithmIdentifier.js"; +import RSAESOAEPParams from "./RSAESOAEPParams.js"; +import KeyTransRecipientInfo from "./KeyTransRecipientInfo.js"; +import IssuerAndSerialNumber from "./IssuerAndSerialNumber.js"; +import RecipientEncryptedKey from "./RecipientEncryptedKey.js"; +import KeyAgreeRecipientIdentifier from "./KeyAgreeRecipientIdentifier.js"; +import KeyAgreeRecipientInfo from "./KeyAgreeRecipientInfo.js"; +import RecipientEncryptedKeys from "./RecipientEncryptedKeys.js"; +import KEKRecipientInfo from "./KEKRecipientInfo.js"; +import KEKIdentifier from "./KEKIdentifier.js"; +import PBKDF2Params from "./PBKDF2Params.js"; +import PasswordRecipientinfo from "./PasswordRecipientinfo.js"; +import ECCCMSSharedInfo from "./ECCCMSSharedInfo.js"; +import OriginatorIdentifierOrKey from "./OriginatorIdentifierOrKey.js"; +import OriginatorPublicKey from "./OriginatorPublicKey.js"; +//************************************************************************************** +/** + * Class from RFC5652 + */ +export default class EnvelopedData +{ + //********************************************************************************** + /** + * Constructor for EnvelopedData class + * @param {Object} [parameters={}] + * @param {Object} [parameters.schema] asn1js parsed value to initialize the class from + */ + constructor(parameters = {}) + { + //region Internal properties of the object + /** + * @type {number} + * @desc version + */ + this.version = getParametersValue(parameters, "version", EnvelopedData.defaultValues("version")); + + if("originatorInfo" in parameters) + /** + * @type {OriginatorInfo} + * @desc originatorInfo + */ + this.originatorInfo = getParametersValue(parameters, "originatorInfo", EnvelopedData.defaultValues("originatorInfo")); + + /** + * @type {Array.} + * @desc recipientInfos + */ + this.recipientInfos = getParametersValue(parameters, "recipientInfos", EnvelopedData.defaultValues("recipientInfos")); + /** + * @type {EncryptedContentInfo} + * @desc encryptedContentInfo + */ + this.encryptedContentInfo = getParametersValue(parameters, "encryptedContentInfo", EnvelopedData.defaultValues("encryptedContentInfo")); + + if("unprotectedAttrs" in parameters) + /** + * @type {Array.} + * @desc unprotectedAttrs + */ + this.unprotectedAttrs = getParametersValue(parameters, "unprotectedAttrs", EnvelopedData.defaultValues("unprotectedAttrs")); + //endregion + + //region If input argument array contains "schema" for this object + if("schema" in parameters) + this.fromSchema(parameters.schema); + //endregion + } + //********************************************************************************** + /** + * Return default values for all class members + * @param {string} memberName String name for a class member + */ + static defaultValues(memberName) + { + switch(memberName) + { + case "version": + return 0; + case "originatorInfo": + return new OriginatorInfo(); + case "recipientInfos": + return []; + case "encryptedContentInfo": + return new EncryptedContentInfo(); + case "unprotectedAttrs": + return []; + default: + throw new Error(`Invalid member name for EnvelopedData class: ${memberName}`); + } + } + //********************************************************************************** + /** + * Compare values with default values for all class members + * @param {string} memberName String name for a class member + * @param {*} memberValue Value to compare with default value + */ + static compareWithDefault(memberName, memberValue) + { + switch(memberName) + { + case "version": + return (memberValue === EnvelopedData.defaultValues(memberName)); + case "originatorInfo": + return ((memberValue.certs.certificates.length === 0) && (memberValue.crls.crls.length === 0)); + case "recipientInfos": + case "unprotectedAttrs": + return (memberValue.length === 0); + case "encryptedContentInfo": + return ((EncryptedContentInfo.compareWithDefault("contentType", memberValue.contentType)) && + (EncryptedContentInfo.compareWithDefault("contentEncryptionAlgorithm", memberValue.contentEncryptionAlgorithm) && + (EncryptedContentInfo.compareWithDefault("encryptedContent", memberValue.encryptedContent)))); + default: + throw new Error(`Invalid member name for EnvelopedData class: ${memberName}`); + } + } + //********************************************************************************** + /** + * Return value of pre-defined ASN.1 schema for current class + * + * ASN.1 schema: + * ```asn1 + * EnvelopedData ::= SEQUENCE { + * version CMSVersion, + * originatorInfo [0] IMPLICIT OriginatorInfo OPTIONAL, + * recipientInfos RecipientInfos, + * encryptedContentInfo EncryptedContentInfo, + * unprotectedAttrs [1] IMPLICIT UnprotectedAttributes OPTIONAL } + * ``` + * + * @param {Object} parameters Input parameters for the schema + * @returns {Object} asn1js schema object + */ + static schema(parameters = {}) + { + /** + * @type {Object} + * @property {string} [blockName] + * @property {string} [version] + * @property {string} [originatorInfo] + * @property {string} [recipientInfos] + * @property {string} [encryptedContentInfo] + * @property {string} [unprotectedAttrs] + */ + const names = getParametersValue(parameters, "names", {}); + + return (new asn1js.Sequence({ + name: (names.blockName || ""), + value: [ + new asn1js.Integer({ name: (names.version || "") }), + new asn1js.Constructed({ + name: (names.originatorInfo || ""), + optional: true, + idBlock: { + tagClass: 3, // CONTEXT-SPECIFIC + tagNumber: 0 // [0] + }, + value: OriginatorInfo.schema().valueBlock.value + }), + new asn1js.Set({ + value: [ + new asn1js.Repeated({ + name: (names.recipientInfos || ""), + value: RecipientInfo.schema() + }) + ] + }), + EncryptedContentInfo.schema(names.encryptedContentInfo || {}), + new asn1js.Constructed({ + optional: true, + idBlock: { + tagClass: 3, // CONTEXT-SPECIFIC + tagNumber: 1 // [1] + }, + value: [ + new asn1js.Repeated({ + name: (names.unprotectedAttrs || ""), + value: Attribute.schema() + }) + ] + }) + ] + })); + } + //********************************************************************************** + /** + * Convert parsed asn1js object into current class + * @param {!Object} schema + */ + fromSchema(schema) + { + //region Clear input data first + clearProps(schema, [ + "version", + "originatorInfo", + "recipientInfos", + "encryptedContentInfo", + "unprotectedAttrs" + ]); + //endregion + + //region Check the schema is valid + const asn1 = asn1js.compareSchema(schema, + schema, + EnvelopedData.schema({ + names: { + version: "version", + originatorInfo: "originatorInfo", + recipientInfos: "recipientInfos", + encryptedContentInfo: { + names: { + blockName: "encryptedContentInfo" + } + }, + unprotectedAttrs: "unprotectedAttrs" + } + }) + ); + + if(asn1.verified === false) + throw new Error("Object's schema was not verified against input data for EnvelopedData"); + //endregion + + //region Get internal properties from parsed schema + this.version = asn1.result.version.valueBlock.valueDec; + + if("originatorInfo" in asn1.result) + { + this.originatorInfo = new OriginatorInfo({ + schema: new asn1js.Sequence({ + value: asn1.result.originatorInfo.valueBlock.value + }) + }); + } + + this.recipientInfos = Array.from(asn1.result.recipientInfos, element => new RecipientInfo({ schema: element })); + this.encryptedContentInfo = new EncryptedContentInfo({ schema: asn1.result.encryptedContentInfo }); + + if("unprotectedAttrs" in asn1.result) + this.unprotectedAttrs = Array.from(asn1.result.unprotectedAttrs, element => new Attribute({ schema: element })); + //endregion + } + //********************************************************************************** + /** + * Convert current object to asn1js object and set correct values + * @returns {Object} asn1js object + */ + toSchema() + { + //region Create array for output sequence + const outputArray = []; + + outputArray.push(new asn1js.Integer({ value: this.version })); + + if("originatorInfo" in this) + { + outputArray.push(new asn1js.Constructed({ + optional: true, + idBlock: { + tagClass: 3, // CONTEXT-SPECIFIC + tagNumber: 0 // [0] + }, + value: this.originatorInfo.toSchema().valueBlock.value + })); + } + + outputArray.push(new asn1js.Set({ + value: Array.from(this.recipientInfos, element => element.toSchema()) + })); + + outputArray.push(this.encryptedContentInfo.toSchema()); + + if("unprotectedAttrs" in this) + { + outputArray.push(new asn1js.Constructed({ + optional: true, + idBlock: { + tagClass: 3, // CONTEXT-SPECIFIC + tagNumber: 1 // [1] + }, + value: Array.from(this.unprotectedAttrs, element => element.toSchema()) + })); + } + //endregion + + //region Construct and return new ASN.1 schema for this object + return (new asn1js.Sequence({ + value: outputArray + })); + //endregion + } + //********************************************************************************** + /** + * Convertion for the class to JSON object + * @returns {Object} + */ + toJSON() + { + const _object = { + version: this.version + }; + + if("originatorInfo" in this) + _object.originatorInfo = this.originatorInfo.toJSON(); + + _object.recipientInfos = Array.from(this.recipientInfos, element => element.toJSON()); + _object.encryptedContentInfo = this.encryptedContentInfo.toJSON(); + + if("unprotectedAttrs" in this) + _object.unprotectedAttrs = Array.from(this.unprotectedAttrs, element => element.toJSON()); + + return _object; + } + //********************************************************************************** + /** + * Helpers function for filling "RecipientInfo" based on recipient's certificate. + * Problem with WebCrypto is that for RSA certificates we have only one option - "key transport" and + * for ECC certificates we also have one option - "key agreement". As soon as Google will implement + * DH algorithm it would be possible to use "key agreement" also for RSA certificates. + * @param {Certificate} [certificate] Recipient's certificate + * @param {Object} [parameters] Additional parameters neccessary for "fine tunning" of encryption process + * @param {number} [variant] Variant = 1 is for "key transport", variant = 2 is for "key agreement". In fact the "variant" is unneccessary now because Google has no DH algorithm implementation. Thus key encryption scheme would be choosen by certificate type only: "key transport" for RSA and "key agreement" for ECC certificates. + */ + addRecipientByCertificate(certificate, parameters, variant) + { + //region Initial variables + const encryptionParameters = parameters || {}; + //endregion + + //region Check type of certificate + if(certificate.subjectPublicKeyInfo.algorithm.algorithmId.indexOf("1.2.840.113549") !== (-1)) + variant = 1; // For the moment it is the only variant for RSA-based certificates + else + { + if(certificate.subjectPublicKeyInfo.algorithm.algorithmId.indexOf("1.2.840.10045") !== (-1)) + variant = 2; // For the moment it is the only variant for ECC-based certificates + else + throw new Error(`Unknown type of certificate's public key: ${certificate.subjectPublicKeyInfo.algorithm.algorithmId}`); + } + //endregion + + //region Initialize encryption parameters + if(("oaepHashAlgorithm" in encryptionParameters) === false) + encryptionParameters.oaepHashAlgorithm = "SHA-512"; + + if(("kdfAlgorithm" in encryptionParameters) === false) + encryptionParameters.kdfAlgorithm = "SHA-512"; + + if(("kekEncryptionLength" in encryptionParameters) === false) + encryptionParameters.kekEncryptionLength = 256; + //endregion + + //region Add new "recipient" depends on "variant" and certificate type + switch(variant) + { + case 1: // Key transport scheme + { + //region keyEncryptionAlgorithm + const oaepOID = getOIDByAlgorithm({ + name: "RSA-OAEP" + }); + if(oaepOID === "") + throw new Error("Can not find OID for OAEP"); + //endregion + + //region RSAES-OAEP-params + const hashOID = getOIDByAlgorithm({ + name: encryptionParameters.oaepHashAlgorithm + }); + if(hashOID === "") + throw new Error(`Unknown OAEP hash algorithm: ${encryptionParameters.oaepHashAlgorithm}`); + + const hashAlgorithm = new AlgorithmIdentifier({ + algorithmId: hashOID, + algorithmParams: new asn1js.Null() + }); + + const rsaOAEPParams = new RSAESOAEPParams({ + hashAlgorithm, + maskGenAlgorithm: new AlgorithmIdentifier({ + algorithmId: "1.2.840.113549.1.1.8", // id-mgf1 + algorithmParams: hashAlgorithm.toSchema() + }) + }); + //endregion + + //region KeyTransRecipientInfo + const keyInfo = new KeyTransRecipientInfo({ + version: 0, + rid: new IssuerAndSerialNumber({ + issuer: certificate.issuer, + serialNumber: certificate.serialNumber + }), + keyEncryptionAlgorithm: new AlgorithmIdentifier({ + algorithmId: oaepOID, + algorithmParams: rsaOAEPParams.toSchema() + }), + recipientCertificate: certificate + // "encryptedKey" will be calculated in "encrypt" function + }); + //endregion + + //region Final values for "CMS_ENVELOPED_DATA" + this.recipientInfos.push(new RecipientInfo({ + variant: 1, + value: keyInfo + })); + //endregion + } + break; + case 2: // Key agreement scheme + { + //region RecipientEncryptedKey + const encryptedKey = new RecipientEncryptedKey({ + rid: new KeyAgreeRecipientIdentifier({ + variant: 1, + value: new IssuerAndSerialNumber({ + issuer: certificate.issuer, + serialNumber: certificate.serialNumber + }) + }) + // "encryptedKey" will be calculated in "encrypt" function + }); + //endregion + + //region keyEncryptionAlgorithm + const aesKWoid = getOIDByAlgorithm({ + name: "AES-KW", + length: encryptionParameters.kekEncryptionLength + }); + if(aesKWoid === "") + throw new Error(`Unknown length for key encryption algorithm: ${encryptionParameters.kekEncryptionLength}`); + + const aesKW = new AlgorithmIdentifier({ + algorithmId: aesKWoid, + algorithmParams: new asn1js.Null() + }); + //endregion + + //region KeyAgreeRecipientInfo + const ecdhOID = getOIDByAlgorithm({ + name: "ECDH", + kdf: encryptionParameters.kdfAlgorithm + }); + if(ecdhOID === "") + throw new Error(`Unknown KDF algorithm: ${encryptionParameters.kdfAlgorithm}`); + + // In fact there is no need in so long UKM, but RFC2631 + // has requirement that "UserKeyMaterial" must be 512 bits long + const ukmBuffer = new ArrayBuffer(64); + const ukmView = new Uint8Array(ukmBuffer); + getRandomValues(ukmView); // Generate random values in 64 bytes long buffer + + const keyInfo = new KeyAgreeRecipientInfo({ + version: 3, + // "originator" will be calculated in "encrypt" function because ephemeral key would be generated there + ukm: new asn1js.OctetString({ valueHex: ukmBuffer }), + keyEncryptionAlgorithm: new AlgorithmIdentifier({ + algorithmId: ecdhOID, + algorithmParams: aesKW.toSchema() + }), + recipientEncryptedKeys: new RecipientEncryptedKeys({ + encryptedKeys: [encryptedKey] + }), + recipientCertificate: certificate + }); + //endregion + + //region Final values for "CMS_ENVELOPED_DATA" + this.recipientInfos.push(new RecipientInfo({ + variant: 2, + value: keyInfo + })); + //endregion + } + break; + default: + throw new Error(`Unknown "variant" value: ${variant}`); + } + //endregion + + return true; + } + //********************************************************************************** + /** + * Add recipient based on pre-defined data like password or KEK + * @param {ArrayBuffer} preDefinedData ArrayBuffer with pre-defined data + * @param {Object} parameters Additional parameters neccessary for "fine tunning" of encryption process + * @param {number} variant Variant = 1 for pre-defined "key encryption key" (KEK). Variant = 2 for password-based encryption. + */ + addRecipientByPreDefinedData(preDefinedData, parameters, variant) + { + //region Initial variables + const encryptionParameters = parameters || {}; + //endregion + + //region Check initial parameters + if((preDefinedData instanceof ArrayBuffer) === false) + throw new Error("Please pass \"preDefinedData\" in ArrayBuffer type"); + + if(preDefinedData.byteLength === 0) + throw new Error("Pre-defined data could have zero length"); + //endregion + + //region Initialize encryption parameters + if(("keyIdentifier" in encryptionParameters) === false) + { + const keyIdentifierBuffer = new ArrayBuffer(16); + const keyIdentifierView = new Uint8Array(keyIdentifierBuffer); + getRandomValues(keyIdentifierView); + + encryptionParameters.keyIdentifier = keyIdentifierBuffer; + } + + if(("hmacHashAlgorithm" in encryptionParameters) === false) + encryptionParameters.hmacHashAlgorithm = "SHA-512"; + + if(("iterationCount" in encryptionParameters) === false) + encryptionParameters.iterationCount = 2048; + + if(("keyEncryptionAlgorithm" in encryptionParameters) === false) + { + encryptionParameters.keyEncryptionAlgorithm = { + name: "AES-KW", + length: 256 + }; + } + + if(("keyEncryptionAlgorithmParams" in encryptionParameters) === false) + encryptionParameters.keyEncryptionAlgorithmParams = new asn1js.Null(); + //endregion + + //region Add new recipient based on passed variant + switch(variant) + { + case 1: // KEKRecipientInfo + { + //region keyEncryptionAlgorithm + const kekOID = getOIDByAlgorithm(encryptionParameters.keyEncryptionAlgorithm); + if(kekOID === "") + throw new Error("Incorrect value for \"keyEncryptionAlgorithm\""); + //endregion + + //region KEKRecipientInfo + const keyInfo = new KEKRecipientInfo({ + version: 4, + kekid: new KEKIdentifier({ + keyIdentifier: new asn1js.OctetString({ valueHex: encryptionParameters.keyIdentifier }) + }), + keyEncryptionAlgorithm: new AlgorithmIdentifier({ + algorithmId: kekOID, + /* + For AES-KW params are NULL, but for other algorithm could another situation. + */ + algorithmParams: encryptionParameters.keyEncryptionAlgorithmParams + }), + preDefinedKEK: preDefinedData + // "encryptedKey" would be set in "ecrypt" function + }); + //endregion + + //region Final values for "CMS_ENVELOPED_DATA" + this.recipientInfos.push(new RecipientInfo({ + variant: 3, + value: keyInfo + })); + //endregion + } + break; + case 2: // PasswordRecipientinfo + { + //region keyDerivationAlgorithm + const pbkdf2OID = getOIDByAlgorithm({ + name: "PBKDF2" + }); + if(pbkdf2OID === "") + throw new Error("Can not find OID for PBKDF2"); + //endregion + + //region Salt + const saltBuffer = new ArrayBuffer(64); + const saltView = new Uint8Array(saltBuffer); + getRandomValues(saltView); + //endregion + + //region HMAC-based algorithm + const hmacOID = getOIDByAlgorithm({ + name: "HMAC", + hash: { + name: encryptionParameters.hmacHashAlgorithm + } + }); + if(hmacOID === "") + throw new Error(`Incorrect value for "hmacHashAlgorithm": ${encryptionParameters.hmacHashAlgorithm}`); + //endregion + + //region PBKDF2-params + const pbkdf2Params = new PBKDF2Params({ + salt: new asn1js.OctetString({ valueHex: saltBuffer }), + iterationCount: encryptionParameters.iterationCount, + prf: new AlgorithmIdentifier({ + algorithmId: hmacOID, + algorithmParams: new asn1js.Null() + }) + }); + //endregion + + //region keyEncryptionAlgorithm + const kekOID = getOIDByAlgorithm(encryptionParameters.keyEncryptionAlgorithm); + if(kekOID === "") + throw new Error("Incorrect value for \"keyEncryptionAlgorithm\""); + //endregion + + //region PasswordRecipientinfo + const keyInfo = new PasswordRecipientinfo({ + version: 0, + keyDerivationAlgorithm: new AlgorithmIdentifier({ + algorithmId: pbkdf2OID, + algorithmParams: pbkdf2Params.toSchema() + }), + keyEncryptionAlgorithm: new AlgorithmIdentifier({ + algorithmId: kekOID, + /* + For AES-KW params are NULL, but for other algorithm could be another situation. + */ + algorithmParams: encryptionParameters.keyEncryptionAlgorithmParams + }), + password: preDefinedData + // "encryptedKey" would be set in "ecrypt" function + }); + //endregion + + //region Final values for "CMS_ENVELOPED_DATA" + this.recipientInfos.push(new RecipientInfo({ + variant: 4, + value: keyInfo + })); + //endregion + } + break; + default: + throw new Error(`Unknown value for "variant": ${variant}`); + } + //endregion + } + //********************************************************************************** + /** + * Create a new CMS Enveloped Data content with encrypted data + * @param {Object} contentEncryptionAlgorithm WebCrypto algorithm. For the moment here could be only "AES-CBC" or "AES-GCM" algorithms. + * @param {ArrayBuffer} contentToEncrypt Content to encrypt + * @returns {Promise} + */ + encrypt(contentEncryptionAlgorithm, contentToEncrypt) + { + //region Initial variables + let sequence = Promise.resolve(); + + const ivBuffer = new ArrayBuffer(16); // For AES we need IV 16 bytes long + const ivView = new Uint8Array(ivBuffer); + getRandomValues(ivView); + + const contentView = new Uint8Array(contentToEncrypt); + + let sessionKey; + let encryptedContent; + let exportedSessionKey; + + const recipientsPromises = []; + + const _this = this; + //endregion + + //region Check for input parameters + const contentEncryptionOID = getOIDByAlgorithm(contentEncryptionAlgorithm); + if(contentEncryptionOID === "") + return Promise.reject("Wrong \"contentEncryptionAlgorithm\" value"); + //endregion + + //region Get a "crypto" extension + const crypto = getCrypto(); + if(typeof crypto === "undefined") + return Promise.reject("Unable to create WebCrypto object"); + //endregion + + //region Generate new content encryption key + sequence = sequence.then(() => + crypto.generateKey(contentEncryptionAlgorithm, true, ["encrypt"])); + //endregion + //region Encrypt content + sequence = sequence.then(result => + { + sessionKey = result; + + return crypto.encrypt({ + name: contentEncryptionAlgorithm.name, + iv: ivView + }, + sessionKey, + contentView); + }, error => + Promise.reject(error)); + //endregion + //region Export raw content of content encryption key + sequence = sequence.then(result => + { + //region Create output OCTETSTRING with encrypted content + encryptedContent = result; + //endregion + + return crypto.exportKey("raw", sessionKey); + }, error => + Promise.reject(error) + ).then(result => + { + exportedSessionKey = result; + + return true; + }, error => + Promise.reject(error)); + //endregion + //region Append common information to CMS_ENVELOPED_DATA + sequence = sequence.then(() => + { + this.version = 2; + this.encryptedContentInfo = new EncryptedContentInfo({ + contentType: "1.2.840.113549.1.7.1", // "data" + contentEncryptionAlgorithm: new AlgorithmIdentifier({ + algorithmId: contentEncryptionOID, + algorithmParams: new asn1js.OctetString({ valueHex: ivBuffer }) + }), + encryptedContent: new asn1js.OctetString({ valueHex: encryptedContent }) + }); + }, error => + Promise.reject(error)); + //endregion + + //region Special sub-functions to work with each recipient's type + function SubKeyAgreeRecipientInfo(index) + { + //region Initial variables + let currentSequence = Promise.resolve(); + + let ecdhPublicKey; + let ecdhPrivateKey; + + let recipientCurve; + let recipientCurveLength; + + let exportedECDHPublicKey; + //endregion + + //region Get "namedCurve" parameter from recipient's certificate + currentSequence = currentSequence.then(() => + { + const curveObject = _this.recipientInfos[index].value.recipientCertificate.subjectPublicKeyInfo.algorithm.algorithmParams; + + if(curveObject.constructor.blockName() !== asn1js.ObjectIdentifier.blockName()) + return Promise.reject(`Incorrect "recipientCertificate" for index ${index}`); + + const curveOID = curveObject.valueBlock.toString(); + + switch(curveOID) + { + case "1.2.840.10045.3.1.7": + recipientCurve = "P-256"; + recipientCurveLength = 256; + break; + case "1.3.132.0.34": + recipientCurve = "P-384"; + recipientCurveLength = 384; + break; + case "1.3.132.0.35": + recipientCurve = "P-521"; + recipientCurveLength = 528; + break; + default: + return Promise.reject(`Incorrect curve OID for index ${index}`); + } + + return recipientCurve; + }, error => + Promise.reject(error)); + //endregion + + //region Generate ephemeral ECDH key + currentSequence = currentSequence.then(result => + crypto.generateKey({ + name: "ECDH", + namedCurve: result + }, + true, + ["deriveBits"]), + error => + Promise.reject(error) + ); + //endregion + //region Export public key of ephemeral ECDH key pair + currentSequence = currentSequence.then(result => + { + ecdhPublicKey = result.publicKey; + ecdhPrivateKey = result.privateKey; + + return crypto.exportKey("spki", ecdhPublicKey); + }, + error => + Promise.reject(error)); + //endregion + + //region Import recipient's public key + currentSequence = currentSequence.then(result => + { + exportedECDHPublicKey = result; + + return _this.recipientInfos[index].value.recipientCertificate.getPublicKey({ + algorithm: { + algorithm: { + name: "ECDH", + namedCurve: recipientCurve + }, + usages: [] + } + }); + }, error => + Promise.reject(error)); + //endregion + //region Create shared secret + currentSequence = currentSequence.then(result => crypto.deriveBits({ + name: "ECDH", + public: result + }, + ecdhPrivateKey, + recipientCurveLength), + error => + Promise.reject(error)); + //endregion + + //region Apply KDF function to shared secret + currentSequence = currentSequence.then( + /** + * @param {ArrayBuffer} result + */ + result => + { + //region Get length of used AES-KW algorithm + const aesKWAlgorithm = new AlgorithmIdentifier({ schema: _this.recipientInfos[index].value.keyEncryptionAlgorithm.algorithmParams }); + + const KWalgorithm = getAlgorithmByOID(aesKWAlgorithm.algorithmId); + if(("name" in KWalgorithm) === false) + return Promise.reject(`Incorrect OID for key encryption algorithm: ${aesKWAlgorithm.algorithmId}`); + //endregion + + //region Translate AES-KW length to ArrayBuffer + let kwLength = KWalgorithm.length; + + const kwLengthBuffer = new ArrayBuffer(4); + const kwLengthView = new Uint8Array(kwLengthBuffer); + + for(let j = 3; j >= 0; j--) + { + kwLengthView[j] = kwLength; + kwLength >>= 8; + } + //endregion + + //region Create and encode "ECC-CMS-SharedInfo" structure + const eccInfo = new ECCCMSSharedInfo({ + keyInfo: new AlgorithmIdentifier({ + algorithmId: aesKWAlgorithm.algorithmId, + /* + Initially RFC5753 says that AES algorithms have absent parameters. + But since early implementations all put NULL here. Thus, in order to be + "backward compatible", index also put NULL here. + */ + algorithmParams: new asn1js.Null() + }), + entityUInfo: _this.recipientInfos[index].value.ukm, + suppPubInfo: new asn1js.OctetString({ valueHex: kwLengthBuffer }) + }); + + const encodedInfo = eccInfo.toSchema().toBER(false); + //endregion + + //region Get SHA algorithm used together with ECDH + const ecdhAlgorithm = getAlgorithmByOID(_this.recipientInfos[index].value.keyEncryptionAlgorithm.algorithmId); + if(("name" in ecdhAlgorithm) === false) + return Promise.reject(`Incorrect OID for key encryption algorithm: ${_this.recipientInfos[index].value.keyEncryptionAlgorithm.algorithmId}`); + //endregion + + return kdf(ecdhAlgorithm.kdf, result, KWalgorithm.length, encodedInfo); + }, + error => + Promise.reject(error)); + //endregion + //region Import AES-KW key from result of KDF function + currentSequence = currentSequence.then(result => + crypto.importKey("raw", result, { name: "AES-KW" }, true, ["wrapKey"]), + error => + Promise.reject(error) + ); + //endregion + //region Finally wrap session key by using AES-KW algorithm + currentSequence = currentSequence.then(result => crypto.wrapKey("raw", sessionKey, result, { name: "AES-KW" }), + error => + Promise.reject(error) + ); + //endregion + //region Append all neccessary data to current CMS_RECIPIENT_INFO object + currentSequence = currentSequence.then(result => + { + //region OriginatorIdentifierOrKey + const asn1 = asn1js.fromBER(exportedECDHPublicKey); + + const originator = new OriginatorIdentifierOrKey(); + originator.variant = 3; + originator.value = new OriginatorPublicKey({ schema: asn1.result }); + // There is option when we can stay with ECParameters, but here index prefer to avoid the params + if("algorithmParams" in originator.value.algorithm) + delete originator.value.algorithm.algorithmParams; + + _this.recipientInfos[index].value.originator = originator; + //endregion + + //region RecipientEncryptedKey + /* + We will not support using of same ephemeral key for many recipients + */ + _this.recipientInfos[index].value.recipientEncryptedKeys.encryptedKeys[0].encryptedKey = new asn1js.OctetString({ valueHex: result }); + //endregion + + return {ecdhPrivateKey}; + }, error => + Promise.reject(error) + ); + //endregion + + return currentSequence; + } + + function SubKeyTransRecipientInfo(index) + { + //region Initial variables + let currentSequence = Promise.resolve(); + //endregion + + //region Get recipient's public key + currentSequence = currentSequence.then(() => + { + //region Check we have a correct algorithm here + const oaepOID = getOIDByAlgorithm({ + name: "RSA-OAEP" + }); + if(oaepOID === "") + throw new Error("Can not find OID for OAEP"); + + if(_this.recipientInfos[index].value.keyEncryptionAlgorithm.algorithmId !== oaepOID) + throw new Error("Not supported encryption scheme, only RSA-OAEP is supported for key transport encryption scheme"); + //endregion + + //region Get current used SHA algorithm + const schema = _this.recipientInfos[index].value.keyEncryptionAlgorithm.algorithmParams; + const rsaOAEPParams = new RSAESOAEPParams({ schema }); + + const hashAlgorithm = getAlgorithmByOID(rsaOAEPParams.hashAlgorithm.algorithmId); + if(("name" in hashAlgorithm) === false) + return Promise.reject(`Incorrect OID for hash algorithm: ${rsaOAEPParams.hashAlgorithm.algorithmId}`); + //endregion + + return _this.recipientInfos[index].value.recipientCertificate.getPublicKey({ + algorithm: { + algorithm: { + name: "RSA-OAEP", + hash: { + name: hashAlgorithm.name + } + }, + usages: ["encrypt", "wrapKey"] + } + }); + }, error => + Promise.reject(error)); + //endregion + //region Encrypt early exported session key on recipient's public key + currentSequence = currentSequence.then(result => + crypto.encrypt(result.algorithm, result, exportedSessionKey), + error => + Promise.reject(error) + ); + //endregion + + //region Append all neccessary data to current CMS_RECIPIENT_INFO object + currentSequence = currentSequence.then(result => + { + //region RecipientEncryptedKey + _this.recipientInfos[index].value.encryptedKey = new asn1js.OctetString({ valueHex: result }); + //endregion + }, error => + Promise.reject(error) + ); + //endregion + + return currentSequence; + } + + function SubKEKRecipientInfo(index) + { + //region Initial variables + let currentSequence = Promise.resolve(); + let kekAlgorithm; + //endregion + + //region Import KEK from pre-defined data + currentSequence = currentSequence.then(() => + { + //region Get WebCrypto form of "keyEncryptionAlgorithm" + kekAlgorithm = getAlgorithmByOID(_this.recipientInfos[index].value.keyEncryptionAlgorithm.algorithmId); + if(("name" in kekAlgorithm) === false) + return Promise.reject(`Incorrect OID for "keyEncryptionAlgorithm": ${_this.recipientInfos[index].value.keyEncryptionAlgorithm.algorithmId}`); + //endregion + + return crypto.importKey("raw", + new Uint8Array(_this.recipientInfos[index].value.preDefinedKEK), + kekAlgorithm, + true, + ["wrapKey"]); // Too specific for AES-KW + }, error => + Promise.reject(error) + ); + //endregion + + //region Wrap previously exported session key + currentSequence = currentSequence.then(result => + crypto.wrapKey("raw", sessionKey, result, kekAlgorithm), + error => + Promise.reject(error) + ); + //endregion + //region Append all neccessary data to current CMS_RECIPIENT_INFO object + currentSequence = currentSequence.then(result => + { + //region RecipientEncryptedKey + _this.recipientInfos[index].value.encryptedKey = new asn1js.OctetString({ valueHex: result }); + //endregion + }, error => + Promise.reject(error) + ); + //endregion + + return currentSequence; + } + + function SubPasswordRecipientinfo(index) + { + //region Initial variables + let currentSequence = Promise.resolve(); + let pbkdf2Params; + let kekAlgorithm; + //endregion + + //region Check that we have encoded "keyDerivationAlgorithm" plus "PBKDF2_params" in there + currentSequence = currentSequence.then(() => + { + if(("keyDerivationAlgorithm" in _this.recipientInfos[index].value) === false) + return Promise.reject("Please append encoded \"keyDerivationAlgorithm\""); + + if(("algorithmParams" in _this.recipientInfos[index].value.keyDerivationAlgorithm) === false) + return Promise.reject("Incorrectly encoded \"keyDerivationAlgorithm\""); + + try + { + pbkdf2Params = new PBKDF2Params({ schema: _this.recipientInfos[index].value.keyDerivationAlgorithm.algorithmParams }); + } + catch(ex) + { + return Promise.reject("Incorrectly encoded \"keyDerivationAlgorithm\""); + } + + return Promise.resolve(); + }, error => + Promise.reject(error) + ); + //endregion + //region Derive PBKDF2 key from "password" buffer + currentSequence = currentSequence.then(() => + { + const passwordView = new Uint8Array(_this.recipientInfos[index].value.password); + + return crypto.importKey("raw", + passwordView, + "PBKDF2", + false, + ["deriveKey"]); + }, error => + Promise.reject(error) + ); + //endregion + //region Derive key for "keyEncryptionAlgorithm" + currentSequence = currentSequence.then(result => + { + //region Get WebCrypto form of "keyEncryptionAlgorithm" + kekAlgorithm = getAlgorithmByOID(_this.recipientInfos[index].value.keyEncryptionAlgorithm.algorithmId); + if(("name" in kekAlgorithm) === false) + return Promise.reject(`Incorrect OID for "keyEncryptionAlgorithm": ${_this.recipientInfos[index].value.keyEncryptionAlgorithm.algorithmId}`); + //endregion + + //region Get HMAC hash algorithm + let hmacHashAlgorithm = "SHA-1"; + + if("prf" in pbkdf2Params) + { + const algorithm = getAlgorithmByOID(pbkdf2Params.prf.algorithmId); + if(("name" in algorithm) === false) + return Promise.reject("Incorrect OID for HMAC hash algorithm"); + + hmacHashAlgorithm = algorithm.hash.name; + } + //endregion + + //region Get PBKDF2 "salt" value + const saltView = new Uint8Array(pbkdf2Params.salt.valueBlock.valueHex); + //endregion + + //region Get PBKDF2 iterations count + const iterations = pbkdf2Params.iterationCount; + //endregion + + return crypto.deriveKey({ + name: "PBKDF2", + hash: { + name: hmacHashAlgorithm + }, + salt: saltView, + iterations + }, + result, + kekAlgorithm, + true, + ["wrapKey"]); // Usages are too specific for KEK algorithm + }, error => + Promise.reject(error) + ); + //endregion + //region Wrap previously exported session key (Also too specific for KEK algorithm) + currentSequence = currentSequence.then(result => + crypto.wrapKey("raw", sessionKey, result, kekAlgorithm), + error => + Promise.reject(error) + ); + //endregion + //region Append all neccessary data to current CMS_RECIPIENT_INFO object + currentSequence = currentSequence.then(result => + { + //region RecipientEncryptedKey + _this.recipientInfos[index].value.encryptedKey = new asn1js.OctetString({ valueHex: result }); + //endregion + }, error => + Promise.reject(error) + ); + //endregion + + return currentSequence; + } + + //endregion + + //region Create special routines for each "recipient" + sequence = sequence.then(() => + { + for(let i = 0; i < this.recipientInfos.length; i++) + { + //region Initial variables + let currentSequence = Promise.resolve(); + //endregion + + switch(this.recipientInfos[i].variant) + { + case 1: // KeyTransRecipientInfo + currentSequence = SubKeyTransRecipientInfo(i); + break; + case 2: // KeyAgreeRecipientInfo + currentSequence = SubKeyAgreeRecipientInfo(i); + break; + case 3: // KEKRecipientInfo + currentSequence = SubKEKRecipientInfo(i); + break; + case 4: // PasswordRecipientinfo + currentSequence = SubPasswordRecipientinfo(i); + break; + default: + return Promise.reject(`Uknown recipient type in array with index ${i}`); + } + + recipientsPromises.push(currentSequence); + } + + return Promise.all(recipientsPromises); + }, error => + Promise.reject(error) + ); + //endregion + + return sequence; + } + //********************************************************************************** + /** + * Decrypt existing CMS Enveloped Data content + * @param {number} recipientIndex Index of recipient + * @param {Object} parameters Additional parameters + * @returns {Promise} + */ + decrypt(recipientIndex, parameters) + { + //region Initial variables + let sequence = Promise.resolve(); + + const decryptionParameters = parameters || {}; + + const _this = this; + //endregion + + //region Check for input parameters + if((recipientIndex + 1) > this.recipientInfos.length) + return Promise.reject(`Maximum value for "index" is: ${this.recipientInfos.length - 1}`); + //endregion + + //region Get a "crypto" extension + const crypto = getCrypto(); + if(typeof crypto === "undefined") + return Promise.reject("Unable to create WebCrypto object"); + //endregion + + //region Special sub-functions to work with each recipient's type + function SubKeyAgreeRecipientInfo(index) + { + //region Initial variables + let currentSequence = Promise.resolve(); + + let recipientCurve; + let recipientCurveLength; + + let curveOID; + + let ecdhPrivateKey; + //endregion + + //region Get "namedCurve" parameter from recipient's certificate + currentSequence = currentSequence.then(() => + { + if(("recipientCertificate" in decryptionParameters) === false) + return Promise.reject("Parameter \"recipientCertificate\" is mandatory for \"KeyAgreeRecipientInfo\""); + + if(("recipientPrivateKey" in decryptionParameters) === false) + return Promise.reject("Parameter \"recipientPrivateKey\" is mandatory for \"KeyAgreeRecipientInfo\""); + + const curveObject = decryptionParameters.recipientCertificate.subjectPublicKeyInfo.algorithm.algorithmParams; + + + if(curveObject.constructor.blockName() !== asn1js.ObjectIdentifier.blockName()) + return Promise.reject(`Incorrect "recipientCertificate" for index ${index}`); + curveOID = curveObject.valueBlock.toString(); + + switch(curveOID) + { + case "1.2.840.10045.3.1.7": + recipientCurve = "P-256"; + recipientCurveLength = 256; + break; + case "1.3.132.0.34": + recipientCurve = "P-384"; + recipientCurveLength = 384; + break; + case "1.3.132.0.35": + recipientCurve = "P-521"; + recipientCurveLength = 528; + break; + default: + return Promise.reject(`Incorrect curve OID for index ${index}`); + } + + return crypto.importKey("pkcs8", + decryptionParameters.recipientPrivateKey, + { + name: "ECDH", + namedCurve: recipientCurve + }, + true, + ["deriveBits"] + ); + }, error => + Promise.reject(error) + ); + //endregion + //region Import sender's ephemeral public key + currentSequence = currentSequence.then(result => + { + ecdhPrivateKey = result; + + //region Change "OriginatorPublicKey" if "curve" parameter absent + if(("algorithmParams" in _this.recipientInfos[index].value.originator.value.algorithm) === false) + _this.recipientInfos[index].value.originator.value.algorithm.algorithmParams = new asn1js.ObjectIdentifier({ value: curveOID }); + //endregion + + //region Create ArrayBuffer with sender's public key + const buffer = _this.recipientInfos[index].value.originator.value.toSchema().toBER(false); + //endregion + + return crypto.importKey("spki", + buffer, + { + name: "ECDH", + namedCurve: recipientCurve + }, + true, + []); + }, error => + Promise.reject(error) + ); + //endregion + //region Create shared secret + currentSequence = currentSequence.then(result => + crypto.deriveBits({ + name: "ECDH", + public: result + }, + ecdhPrivateKey, + recipientCurveLength), + error => + Promise.reject(error) + ); + //endregion + //region Apply KDF function to shared secret + currentSequence = currentSequence.then( + /** + * @param {ArrayBuffer} result + */ + result => + { + //region Get length of used AES-KW algorithm + const aesKWAlgorithm = new AlgorithmIdentifier({ schema: _this.recipientInfos[index].value.keyEncryptionAlgorithm.algorithmParams }); + + const KWalgorithm = getAlgorithmByOID(aesKWAlgorithm.algorithmId); + if(("name" in KWalgorithm) === false) + return Promise.reject(`Incorrect OID for key encryption algorithm: ${aesKWAlgorithm.algorithmId}`); + //endregion + + //region Translate AES-KW length to ArrayBuffer + let kwLength = KWalgorithm.length; + + const kwLengthBuffer = new ArrayBuffer(4); + const kwLengthView = new Uint8Array(kwLengthBuffer); + + for(let j = 3; j >= 0; j--) + { + kwLengthView[j] = kwLength; + kwLength >>= 8; + } + //endregion + + //region Create and encode "ECC-CMS-SharedInfo" structure + const eccInfo = new ECCCMSSharedInfo({ + keyInfo: new AlgorithmIdentifier({ + algorithmId: aesKWAlgorithm.algorithmId, + /* + Initially RFC5753 says that AES algorithms have absent parameters. + But since early implementations all put NULL here. Thus, in order to be + "backward compatible", index also put NULL here. + */ + algorithmParams: new asn1js.Null() + }), + entityUInfo: _this.recipientInfos[index].value.ukm, + suppPubInfo: new asn1js.OctetString({ valueHex: kwLengthBuffer }) + }); + + const encodedInfo = eccInfo.toSchema().toBER(false); + //endregion + + //region Get SHA algorithm used together with ECDH + const ecdhAlgorithm = getAlgorithmByOID(_this.recipientInfos[index].value.keyEncryptionAlgorithm.algorithmId); + if(("name" in ecdhAlgorithm) === false) + return Promise.reject(`Incorrect OID for key encryption algorithm: ${_this.recipientInfos[index].value.keyEncryptionAlgorithm.algorithmId}`); + //endregion + + return kdf(ecdhAlgorithm.kdf, result, KWalgorithm.length, encodedInfo); + }, + error => + Promise.reject(error) + ); + //endregion + //region Import AES-KW key from result of KDF function + currentSequence = currentSequence.then(result => + crypto.importKey("raw", + result, + { name: "AES-KW" }, + true, + ["unwrapKey"]), + error => Promise.reject(error) + ); + //endregion + //region Finally unwrap session key + currentSequence = currentSequence.then(result => + { + //region Get WebCrypto form of content encryption algorithm + const contentEncryptionAlgorithm = getAlgorithmByOID(_this.encryptedContentInfo.contentEncryptionAlgorithm.algorithmId); + if(("name" in contentEncryptionAlgorithm) === false) + return Promise.reject(`Incorrect "contentEncryptionAlgorithm": ${_this.encryptedContentInfo.contentEncryptionAlgorithm.algorithmId}`); + //endregion + + return crypto.unwrapKey("raw", + _this.recipientInfos[index].value.recipientEncryptedKeys.encryptedKeys[0].encryptedKey.valueBlock.valueHex, + result, + { name: "AES-KW" }, + contentEncryptionAlgorithm, + true, + ["decrypt"]); + }, error => + Promise.reject(error) + ); + //endregion + + return currentSequence; + } + + function SubKeyTransRecipientInfo(index) + { + //region Initial variables + let currentSequence = Promise.resolve(); + //endregion + + //region Import recipient's private key + currentSequence = currentSequence.then(() => + { + if(("recipientPrivateKey" in decryptionParameters) === false) + return Promise.reject("Parameter \"recipientPrivateKey\" is mandatory for \"KeyTransRecipientInfo\""); + + //region Get current used SHA algorithm + const schema = _this.recipientInfos[index].value.keyEncryptionAlgorithm.algorithmParams; + const rsaOAEPParams = new RSAESOAEPParams({ schema }); + + const hashAlgorithm = getAlgorithmByOID(rsaOAEPParams.hashAlgorithm.algorithmId); + if(("name" in hashAlgorithm) === false) + return Promise.reject(`Incorrect OID for hash algorithm: ${rsaOAEPParams.hashAlgorithm.algorithmId}`); + //endregion + + return crypto.importKey("pkcs8", + decryptionParameters.recipientPrivateKey, + { + name: "RSA-OAEP", + hash: { + name: hashAlgorithm.name + } + }, + true, + ["decrypt"]); + }, error => + Promise.reject(error) + ); + //endregion + //region Decrypt encrypted session key + currentSequence = currentSequence.then(result => + crypto.decrypt(result.algorithm, + result, + _this.recipientInfos[index].value.encryptedKey.valueBlock.valueHex + ), error => + Promise.reject(error) + ); + //endregion + //region Import decrypted session key + currentSequence = currentSequence.then(result => + { + //region Get WebCrypto form of content encryption algorithm + const contentEncryptionAlgorithm = getAlgorithmByOID(_this.encryptedContentInfo.contentEncryptionAlgorithm.algorithmId); + if(("name" in contentEncryptionAlgorithm) === false) + return Promise.reject(`Incorrect "contentEncryptionAlgorithm": ${_this.encryptedContentInfo.contentEncryptionAlgorithm.algorithmId}`); + //endregion + + return crypto.importKey("raw", + result, + contentEncryptionAlgorithm, + true, + ["decrypt"] + ); + }, error => + Promise.reject(error) + ); + //endregion + + return currentSequence; + } + + function SubKEKRecipientInfo(index) + { + //region Initial variables + let currentSequence = Promise.resolve(); + let kekAlgorithm; + //endregion + + //region Import KEK from pre-defined data + currentSequence = currentSequence.then(() => + { + if(("preDefinedData" in decryptionParameters) === false) + return Promise.reject("Parameter \"preDefinedData\" is mandatory for \"KEKRecipientInfo\""); + + //region Get WebCrypto form of "keyEncryptionAlgorithm" + kekAlgorithm = getAlgorithmByOID(_this.recipientInfos[index].value.keyEncryptionAlgorithm.algorithmId); + if(("name" in kekAlgorithm) === false) + return Promise.reject(`Incorrect OID for "keyEncryptionAlgorithm": ${_this.recipientInfos[index].value.keyEncryptionAlgorithm.algorithmId}`); + //endregion + + return crypto.importKey("raw", + decryptionParameters.preDefinedData, + kekAlgorithm, + true, + ["unwrapKey"]); // Too specific for AES-KW + }, error => + Promise.reject(error) + ); + //endregion + //region Unwrap previously exported session key + currentSequence = currentSequence.then(result => + { + //region Get WebCrypto form of content encryption algorithm + const contentEncryptionAlgorithm = getAlgorithmByOID(_this.encryptedContentInfo.contentEncryptionAlgorithm.algorithmId); + if(("name" in contentEncryptionAlgorithm) === false) + return Promise.reject(`Incorrect "contentEncryptionAlgorithm": ${_this.encryptedContentInfo.contentEncryptionAlgorithm.algorithmId}`); + //endregion + + return crypto.unwrapKey("raw", + _this.recipientInfos[index].value.encryptedKey.valueBlock.valueHex, + result, + kekAlgorithm, + contentEncryptionAlgorithm, + true, + ["decrypt"]); + }, error => + Promise.reject(error) + ); + //endregion + + return currentSequence; + } + + function SubPasswordRecipientinfo(index) + { + //region Initial variables + let currentSequence = Promise.resolve(); + let pbkdf2Params; + let kekAlgorithm; + //endregion + + //region Derive PBKDF2 key from "password" buffer + currentSequence = currentSequence.then(() => + { + if(("preDefinedData" in decryptionParameters) === false) + return Promise.reject("Parameter \"preDefinedData\" is mandatory for \"KEKRecipientInfo\""); + + if(("keyDerivationAlgorithm" in _this.recipientInfos[index].value) === false) + return Promise.reject("Please append encoded \"keyDerivationAlgorithm\""); + + if(("algorithmParams" in _this.recipientInfos[index].value.keyDerivationAlgorithm) === false) + return Promise.reject("Incorrectly encoded \"keyDerivationAlgorithm\""); + + try + { + pbkdf2Params = new PBKDF2Params({ schema: _this.recipientInfos[index].value.keyDerivationAlgorithm.algorithmParams }); + } + catch(ex) + { + return Promise.reject("Incorrectly encoded \"keyDerivationAlgorithm\""); + } + + return crypto.importKey("raw", + decryptionParameters.preDefinedData, + "PBKDF2", + false, + ["deriveKey"]); + }, error => + Promise.reject(error) + ); + //endregion + //region Derive key for "keyEncryptionAlgorithm" + currentSequence = currentSequence.then(result => + { + //region Get WebCrypto form of "keyEncryptionAlgorithm" + kekAlgorithm = getAlgorithmByOID(_this.recipientInfos[index].value.keyEncryptionAlgorithm.algorithmId); + if(("name" in kekAlgorithm) === false) + return Promise.reject(`Incorrect OID for "keyEncryptionAlgorithm": ${_this.recipientInfos[index].value.keyEncryptionAlgorithm.algorithmId}`); + //endregion + + //region Get HMAC hash algorithm + let hmacHashAlgorithm = "SHA-1"; + + if("prf" in pbkdf2Params) + { + const algorithm = getAlgorithmByOID(pbkdf2Params.prf.algorithmId); + if(("name" in algorithm) === false) + return Promise.reject("Incorrect OID for HMAC hash algorithm"); + + hmacHashAlgorithm = algorithm.hash.name; + } + //endregion + + //region Get PBKDF2 "salt" value + const saltView = new Uint8Array(pbkdf2Params.salt.valueBlock.valueHex); + //endregion + + //region Get PBKDF2 iterations count + const iterations = pbkdf2Params.iterationCount; + //endregion + + return crypto.deriveKey({ + name: "PBKDF2", + hash: { + name: hmacHashAlgorithm + }, + salt: saltView, + iterations + }, + result, + kekAlgorithm, + true, + ["unwrapKey"]); // Usages are too specific for KEK algorithm + }, error => + Promise.reject(error) + ); + //endregion + //region Unwrap previously exported session key + currentSequence = currentSequence.then(result => + { + //region Get WebCrypto form of content encryption algorithm + const contentEncryptionAlgorithm = getAlgorithmByOID(_this.encryptedContentInfo.contentEncryptionAlgorithm.algorithmId); + if(("name" in contentEncryptionAlgorithm) === false) + return Promise.reject(`Incorrect "contentEncryptionAlgorithm": ${_this.encryptedContentInfo.contentEncryptionAlgorithm.algorithmId}`); + //endregion + + return crypto.unwrapKey("raw", + _this.recipientInfos[index].value.encryptedKey.valueBlock.valueHex, + result, + kekAlgorithm, + contentEncryptionAlgorithm, + true, + ["decrypt"]); + }, error => + Promise.reject(error) + ); + //endregion + + return currentSequence; + } + + //endregion + + //region Perform steps, specific to each type of session key encryption + sequence = sequence.then(() => + { + //region Initial variables + let currentSequence = Promise.resolve(); + //endregion + + switch(this.recipientInfos[recipientIndex].variant) + { + case 1: // KeyTransRecipientInfo + currentSequence = SubKeyTransRecipientInfo(recipientIndex); + break; + case 2: // KeyAgreeRecipientInfo + currentSequence = SubKeyAgreeRecipientInfo(recipientIndex); + break; + case 3: // KEKRecipientInfo + currentSequence = SubKEKRecipientInfo(recipientIndex); + break; + case 4: // PasswordRecipientinfo + currentSequence = SubPasswordRecipientinfo(recipientIndex); + break; + default: + return Promise.reject(`Uknown recipient type in array with index ${recipientIndex}`); + } + + return currentSequence; + }, error => + Promise.reject(error) + ); + //endregion + + //region Finally decrypt data by session key + sequence = sequence.then(result => + { + //region Get WebCrypto form of content encryption algorithm + const contentEncryptionAlgorithm = getAlgorithmByOID(this.encryptedContentInfo.contentEncryptionAlgorithm.algorithmId); + if(("name" in contentEncryptionAlgorithm) === false) + return Promise.reject(`Incorrect "contentEncryptionAlgorithm": ${this.encryptedContentInfo.contentEncryptionAlgorithm.algorithmId}`); + //endregion + + //region Get "intialization vector" for content encryption algorithm + const ivBuffer = this.encryptedContentInfo.contentEncryptionAlgorithm.algorithmParams.valueBlock.valueHex; + const ivView = new Uint8Array(ivBuffer); + //endregion + + //region Create correct data block for decryption + let dataBuffer = new ArrayBuffer(0); + + if(this.encryptedContentInfo.encryptedContent.idBlock.isConstructed === false) + dataBuffer = this.encryptedContentInfo.encryptedContent.valueBlock.valueHex; + else + { + for(const content of this.encryptedContentInfo.encryptedContent.valueBlock.value) + dataBuffer = utilConcatBuf(dataBuffer, content.valueBlock.valueHex); + } + //endregion + + return crypto.decrypt({ + name: contentEncryptionAlgorithm.name, + iv: ivView + }, + result, + dataBuffer); + }, error => + Promise.reject(error) + ); + //endregion + + return sequence; + } + //********************************************************************************** +} +//************************************************************************************** diff --git a/core/third-party/pkijs/ExtKeyUsage.js b/core/third-party/pkijs/ExtKeyUsage.js new file mode 100644 index 0000000..e5ec1ff --- /dev/null +++ b/core/third-party/pkijs/ExtKeyUsage.js @@ -0,0 +1,135 @@ +import * as asn1js from "./asn1.js"; +import { getParametersValue, clearProps } from "./pvutils.js"; +//************************************************************************************** +/** + * Class from RFC5280 + */ +export default class ExtKeyUsage +{ + //********************************************************************************** + /** + * Constructor for ExtKeyUsage class + * @param {Object} [parameters={}] + * @param {Object} [parameters.schema] asn1js parsed value to initialize the class from + */ + constructor(parameters = {}) + { + //region Internal properties of the object + /** + * @type {Array.} + * @desc keyPurposes + */ + this.keyPurposes = getParametersValue(parameters, "keyPurposes", ExtKeyUsage.defaultValues("keyPurposes")); + //endregion + + //region If input argument array contains "schema" for this object + if("schema" in parameters) + this.fromSchema(parameters.schema); + //endregion + } + //********************************************************************************** + /** + * Return default values for all class members + * @param {string} memberName String name for a class member + */ + static defaultValues(memberName) + { + switch(memberName) + { + case "keyPurposes": + return []; + default: + throw new Error(`Invalid member name for ExtKeyUsage class: ${memberName}`); + } + } + //********************************************************************************** + /** + * Return value of pre-defined ASN.1 schema for current class + * + * ASN.1 schema: + * ```asn1 + * ExtKeyUsage ::= SEQUENCE SIZE (1..MAX) OF KeyPurposeId + * + * KeyPurposeId ::= OBJECT IDENTIFIER + * ``` + * + * @param {Object} parameters Input parameters for the schema + * @returns {Object} asn1js schema object + */ + static schema(parameters = {}) + { + /** + * @type {Object} + * @property {string} [blockName] + * @property {string} [keyPurposes] + */ + const names = getParametersValue(parameters, "names", {}); + + return (new asn1js.Sequence({ + name: (names.blockName || ""), + value: [ + new asn1js.Repeated({ + name: (names.keyPurposes || ""), + value: new asn1js.ObjectIdentifier() + }) + ] + })); + } + //********************************************************************************** + /** + * Convert parsed asn1js object into current class + * @param {!Object} schema + */ + fromSchema(schema) + { + //region Clear input data first + clearProps(schema, [ + "keyPurposes" + ]); + //endregion + + //region Check the schema is valid + const asn1 = asn1js.compareSchema(schema, + schema, + ExtKeyUsage.schema({ + names: { + keyPurposes: "keyPurposes" + } + }) + ); + + if(asn1.verified === false) + throw new Error("Object's schema was not verified against input data for ExtKeyUsage"); + //endregion + + //region Get internal properties from parsed schema + this.keyPurposes = Array.from(asn1.result.keyPurposes, element => element.valueBlock.toString()); + //endregion + } + //********************************************************************************** + /** + * Convert current object to asn1js object and set correct values + * @returns {Object} asn1js object + */ + toSchema() + { + //region Construct and return new ASN.1 schema for this object + return (new asn1js.Sequence({ + value: Array.from(this.keyPurposes, element => new asn1js.ObjectIdentifier({ value: element })) + })); + //endregion + } + //********************************************************************************** + /** + * Convertion for the class to JSON object + * @returns {Object} + */ + toJSON() + { + return { + keyPurposes: Array.from(this.keyPurposes) + }; + } + //********************************************************************************** +} +//************************************************************************************** diff --git a/core/third-party/pkijs/Extension.js b/core/third-party/pkijs/Extension.js new file mode 100644 index 0000000..85a2303 --- /dev/null +++ b/core/third-party/pkijs/Extension.js @@ -0,0 +1,453 @@ +import * as asn1js from "./asn1.js"; +import { getParametersValue, clearProps } from "./pvutils.js"; +import SubjectDirectoryAttributes from "./SubjectDirectoryAttributes.js"; +import PrivateKeyUsagePeriod from "./PrivateKeyUsagePeriod.js"; +import AltName from "./AltName.js"; +import BasicConstraints from "./BasicConstraints.js"; +import IssuingDistributionPoint from "./IssuingDistributionPoint.js"; +import GeneralNames from "./GeneralNames.js"; +import NameConstraints from "./NameConstraints.js"; +import CRLDistributionPoints from "./CRLDistributionPoints.js"; +import CertificatePolicies from "./CertificatePolicies.js"; +import PolicyMappings from "./PolicyMappings.js"; +import AuthorityKeyIdentifier from "./AuthorityKeyIdentifier.js"; +import PolicyConstraints from "./PolicyConstraints.js"; +import ExtKeyUsage from "./ExtKeyUsage.js"; +import InfoAccess from "./InfoAccess.js"; +import SignedCertificateTimestampList from "./SignedCertificateTimestampList.js"; +import CertificateTemplate from "./CertificateTemplate.js"; +import CAVersion from "./CAVersion.js"; +import QCStatements from "./QCStatements.js"; +//************************************************************************************** +/** + * Class from RFC5280 + */ +export default class Extension +{ + //********************************************************************************** + /** + * Constructor for Extension class + * @param {Object} [parameters={}] + * @param {Object} [parameters.schema] asn1js parsed value to initialize the class from + */ + constructor(parameters = {}) + { + //region Internal properties of the object + /** + * @type {string} + * @desc extnID + */ + this.extnID = getParametersValue(parameters, "extnID", Extension.defaultValues("extnID")); + /** + * @type {boolean} + * @desc critical + */ + this.critical = getParametersValue(parameters, "critical", Extension.defaultValues("critical")); + /** + * @type {OctetString} + * @desc extnValue + */ + if("extnValue" in parameters) + this.extnValue = new asn1js.OctetString({ valueHex: parameters.extnValue }); + else + this.extnValue = Extension.defaultValues("extnValue"); + + if("parsedValue" in parameters) + /** + * @type {Object} + * @desc parsedValue + */ + this.parsedValue = getParametersValue(parameters, "parsedValue", Extension.defaultValues("parsedValue")); + //endregion + + //region If input argument array contains "schema" for this object + if("schema" in parameters) + this.fromSchema(parameters.schema); + //endregion + } + //********************************************************************************** + /** + * Return default values for all class members + * @param {string} memberName String name for a class member + */ + static defaultValues(memberName) + { + switch(memberName) + { + case "extnID": + return ""; + case "critical": + return false; + case "extnValue": + return new asn1js.OctetString(); + case "parsedValue": + return {}; + default: + throw new Error(`Invalid member name for Extension class: ${memberName}`); + } + } + //********************************************************************************** + /** + * Return value of pre-defined ASN.1 schema for current class + * + * ASN.1 schema: + * ```asn1 + * Extension ::= SEQUENCE { + * extnID OBJECT IDENTIFIER, + * critical BOOLEAN DEFAULT FALSE, + * extnValue OCTET STRING + * } + * ``` + * + * @param {Object} parameters Input parameters for the schema + * @returns {Object} asn1js schema object + */ + static schema(parameters = {}) + { + /** + * @type {Object} + * @property {string} [blockName] + * @property {string} [extnID] + * @property {string} [critical] + * @property {string} [extnValue] + */ + const names = getParametersValue(parameters, "names", {}); + + return (new asn1js.Sequence({ + name: (names.blockName || ""), + value: [ + new asn1js.ObjectIdentifier({ name: (names.extnID || "") }), + new asn1js.Boolean({ + name: (names.critical || ""), + optional: true + }), + new asn1js.OctetString({ name: (names.extnValue || "") }) + ] + })); + } + //********************************************************************************** + /** + * Convert parsed asn1js object into current class + * @param {!Object} schema + */ + fromSchema(schema) + { + //region Clear input data first + clearProps(schema, [ + "extnID", + "critical", + "extnValue" + ]); + //endregion + + //region Check the schema is valid + let asn1 = asn1js.compareSchema(schema, + schema, + Extension.schema({ + names: { + extnID: "extnID", + critical: "critical", + extnValue: "extnValue" + } + }) + ); + + if(asn1.verified === false) + throw new Error("Object's schema was not verified against input data for Extension"); + //endregion + + //region Get internal properties from parsed schema + this.extnID = asn1.result.extnID.valueBlock.toString(); + if("critical" in asn1.result) + this.critical = asn1.result.critical.valueBlock.value; + this.extnValue = asn1.result.extnValue; + + //region Get "parsedValue" for well-known extensions + asn1 = asn1js.fromBER(this.extnValue.valueBlock.valueHex); + if(asn1.offset === (-1)) + return; + + switch(this.extnID) + { + case "2.5.29.9": // SubjectDirectoryAttributes + try + { + this.parsedValue = new SubjectDirectoryAttributes({ schema: asn1.result }); + } + catch(ex) + { + this.parsedValue = new SubjectDirectoryAttributes(); + this.parsedValue.parsingError = "Incorrectly formated SubjectDirectoryAttributes"; + } + break; + case "2.5.29.14": // SubjectKeyIdentifier + this.parsedValue = asn1.result; // Should be just a simple OCTETSTRING + break; + case "2.5.29.15": // KeyUsage + this.parsedValue = asn1.result; // Should be just a simple BITSTRING + break; + case "2.5.29.16": // PrivateKeyUsagePeriod + try + { + this.parsedValue = new PrivateKeyUsagePeriod({ schema: asn1.result }); + } + catch(ex) + { + this.parsedValue = new PrivateKeyUsagePeriod(); + this.parsedValue.parsingError = "Incorrectly formated PrivateKeyUsagePeriod"; + } + break; + case "2.5.29.17": // SubjectAltName + case "2.5.29.18": // IssuerAltName + try + { + this.parsedValue = new AltName({ schema: asn1.result }); + } + catch(ex) + { + this.parsedValue = new AltName(); + this.parsedValue.parsingError = "Incorrectly formated AltName"; + } + break; + case "2.5.29.19": // BasicConstraints + try + { + this.parsedValue = new BasicConstraints({ schema: asn1.result }); + } + catch(ex) + { + this.parsedValue = new BasicConstraints(); + this.parsedValue.parsingError = "Incorrectly formated BasicConstraints"; + } + break; + case "2.5.29.20": // CRLNumber + case "2.5.29.27": // BaseCRLNumber (delta CRL indicator) + this.parsedValue = asn1.result; // Should be just a simple INTEGER + break; + case "2.5.29.21": // CRLReason + this.parsedValue = asn1.result; // Should be just a simple ENUMERATED + break; + case "2.5.29.24": // InvalidityDate + this.parsedValue = asn1.result; // Should be just a simple GeneralizedTime + break; + case "2.5.29.28": // IssuingDistributionPoint + try + { + this.parsedValue = new IssuingDistributionPoint({ schema: asn1.result }); + } + catch(ex) + { + this.parsedValue = new IssuingDistributionPoint(); + this.parsedValue.parsingError = "Incorrectly formated IssuingDistributionPoint"; + } + break; + case "2.5.29.29": // CertificateIssuer + try + { + this.parsedValue = new GeneralNames({ schema: asn1.result }); // Should be just a simple + } + catch(ex) + { + this.parsedValue = new GeneralNames(); + this.parsedValue.parsingError = "Incorrectly formated GeneralNames"; + } + break; + case "2.5.29.30": // NameConstraints + try + { + this.parsedValue = new NameConstraints({ schema: asn1.result }); + } + catch(ex) + { + this.parsedValue = new NameConstraints(); + this.parsedValue.parsingError = "Incorrectly formated NameConstraints"; + } + break; + case "2.5.29.31": // CRLDistributionPoints + case "2.5.29.46": // FreshestCRL + try + { + this.parsedValue = new CRLDistributionPoints({ schema: asn1.result }); + } + catch(ex) + { + this.parsedValue = new CRLDistributionPoints(); + this.parsedValue.parsingError = "Incorrectly formated CRLDistributionPoints"; + } + break; + case "2.5.29.32": // CertificatePolicies + case "1.3.6.1.4.1.311.21.10": // szOID_APPLICATION_CERT_POLICIES - Microsoft-specific OID + try + { + this.parsedValue = new CertificatePolicies({ schema: asn1.result }); + } + catch(ex) + { + this.parsedValue = new CertificatePolicies(); + this.parsedValue.parsingError = "Incorrectly formated CertificatePolicies"; + } + break; + case "2.5.29.33": // PolicyMappings + try + { + this.parsedValue = new PolicyMappings({ schema: asn1.result }); + } + catch(ex) + { + this.parsedValue = new PolicyMappings(); + this.parsedValue.parsingError = "Incorrectly formated CertificatePolicies"; + } + break; + case "2.5.29.35": // AuthorityKeyIdentifier + try + { + this.parsedValue = new AuthorityKeyIdentifier({ schema: asn1.result }); + } + catch(ex) + { + this.parsedValue = new AuthorityKeyIdentifier(); + this.parsedValue.parsingError = "Incorrectly formated AuthorityKeyIdentifier"; + } + break; + case "2.5.29.36": // PolicyConstraints + try + { + this.parsedValue = new PolicyConstraints({ schema: asn1.result }); + } + catch(ex) + { + this.parsedValue = new PolicyConstraints(); + this.parsedValue.parsingError = "Incorrectly formated PolicyConstraints"; + } + break; + case "2.5.29.37": // ExtKeyUsage + try + { + this.parsedValue = new ExtKeyUsage({ schema: asn1.result }); + } + catch(ex) + { + this.parsedValue = new ExtKeyUsage(); + this.parsedValue.parsingError = "Incorrectly formated ExtKeyUsage"; + } + break; + case "2.5.29.54": // InhibitAnyPolicy + this.parsedValue = asn1.result; // Should be just a simple INTEGER + break; + case "1.3.6.1.5.5.7.1.1": // AuthorityInfoAccess + case "1.3.6.1.5.5.7.1.11": // SubjectInfoAccess + try + { + this.parsedValue = new InfoAccess({ schema: asn1.result }); + } + catch(ex) + { + this.parsedValue = new InfoAccess(); + this.parsedValue.parsingError = "Incorrectly formated InfoAccess"; + } + break; + case "1.3.6.1.4.1.11129.2.4.2": // SignedCertificateTimestampList + try + { + this.parsedValue = new SignedCertificateTimestampList({ schema: asn1.result }); + } + catch(ex) + { + this.parsedValue = new SignedCertificateTimestampList(); + this.parsedValue.parsingError = "Incorrectly formated SignedCertificateTimestampList"; + } + break; + case "1.3.6.1.4.1.311.20.2": // szOID_ENROLL_CERTTYPE_EXTENSION - Microsoft-specific extension + this.parsedValue = asn1.result; // Used to be simple Unicode string + break; + case "1.3.6.1.4.1.311.21.2": // szOID_CERTSRV_PREVIOUS_CERT_HASH - Microsoft-specific extension + this.parsedValue = asn1.result; // Used to be simple OctetString + break; + case "1.3.6.1.4.1.311.21.7": // szOID_CERTIFICATE_TEMPLATE - Microsoft-specific extension + try + { + this.parsedValue = new CertificateTemplate({ schema: asn1.result }); + } + catch(ex) + { + this.parsedValue = new CertificateTemplate(); + this.parsedValue.parsingError = "Incorrectly formated CertificateTemplate"; + } + break; + case "1.3.6.1.4.1.311.21.1": // szOID_CERTSRV_CA_VERSION - Microsoft-specific extension + try + { + this.parsedValue = new CAVersion({ schema: asn1.result }); + } + catch(ex) + { + this.parsedValue = new CAVersion(); + this.parsedValue.parsingError = "Incorrectly formated CAVersion"; + } + break; + case "1.3.6.1.5.5.7.1.3": // QCStatements + try + { + this.parsedValue = new QCStatements({ schema: asn1.result }); + } + catch(ex) + { + this.parsedValue = new QCStatements(); + this.parsedValue.parsingError = "Incorrectly formated QCStatements"; + } + break; + default: + } + //endregion + //endregion + } + //********************************************************************************** + /** + * Convert current object to asn1js object and set correct values + * @returns {Object} asn1js object + */ + toSchema() + { + //region Create array for output sequence + const outputArray = []; + + outputArray.push(new asn1js.ObjectIdentifier({ value: this.extnID })); + + if(this.critical !== Extension.defaultValues("critical")) + outputArray.push(new asn1js.Boolean({ value: this.critical })); + + outputArray.push(this.extnValue); + //endregion + + //region Construct and return new ASN.1 schema for this object + return (new asn1js.Sequence({ + value: outputArray + })); + //endregion + } + //********************************************************************************** + /** + * Convertion for the class to JSON object + * @returns {Object} + */ + toJSON() + { + const object = { + extnID: this.extnID, + extnValue: this.extnValue.toJSON() + }; + + if(this.critical !== Extension.defaultValues("critical")) + object.critical = this.critical; + + if("parsedValue" in this) + { + if("toJSON" in this.parsedValue) + object.parsedValue = this.parsedValue.toJSON(); + } + + return object; + } + //********************************************************************************** +} +//************************************************************************************** diff --git a/core/third-party/pkijs/Extensions.js b/core/third-party/pkijs/Extensions.js new file mode 100644 index 0000000..cc81b99 --- /dev/null +++ b/core/third-party/pkijs/Extensions.js @@ -0,0 +1,137 @@ +import * as asn1js from "./asn1.js"; +import { getParametersValue, clearProps } from "./pvutils.js"; +import Extension from "./Extension.js"; +//************************************************************************************** +/** + * Class from RFC5280 + */ +export default class Extensions +{ + //********************************************************************************** + /** + * Constructor for Extensions class + * @param {Object} [parameters={}] + * @param {Object} [parameters.schema] asn1js parsed value to initialize the class from + */ + constructor(parameters = {}) + { + //region Internal properties of the object + /** + * @type {Array.} + * @desc type + */ + this.extensions = getParametersValue(parameters, "extensions", Extensions.defaultValues("extensions")); + //endregion + + //region If input argument array contains "schema" for this object + if("schema" in parameters) + this.fromSchema(parameters.schema); + //endregion + } + //********************************************************************************** + /** + * Return default values for all class members + * @param {string} memberName String name for a class member + */ + static defaultValues(memberName) + { + switch(memberName) + { + case "extensions": + return []; + default: + throw new Error(`Invalid member name for Extensions class: ${memberName}`); + } + } + //********************************************************************************** + /** + * Return value of pre-defined ASN.1 schema for current class + * + * ASN.1 schema: + * ```asn1 + * Extensions ::= SEQUENCE SIZE (1..MAX) OF Extension + * ``` + * + * @param {Object} parameters Input parameters for the schema + * @param {boolean} optional Flag that current schema should be optional + * @returns {Object} asn1js schema object + */ + static schema(parameters = {}, optional = false) + { + /** + * @type {Object} + * @property {string} [blockName] + * @property {string} [extensions] + * @property {string} [extension] + */ + const names = getParametersValue(parameters, "names", {}); + + return (new asn1js.Sequence({ + optional, + name: (names.blockName || ""), + value: [ + new asn1js.Repeated({ + name: (names.extensions || ""), + value: Extension.schema(names.extension || {}) + }) + ] + })); + } + //********************************************************************************** + /** + * Convert parsed asn1js object into current class + * @param {!Object} schema + */ + fromSchema(schema) + { + //region Clear input data first + clearProps(schema, [ + "extensions" + ]); + //endregion + + //region Check the schema is valid + const asn1 = asn1js.compareSchema(schema, + schema, + Extensions.schema({ + names: { + extensions: "extensions" + } + }) + ); + + if(asn1.verified === false) + throw new Error("Object's schema was not verified against input data for Extensions"); + //endregion + + //region Get internal properties from parsed schema + this.extensions = Array.from(asn1.result.extensions, element => new Extension({ schema: element })); + //endregion + } + //********************************************************************************** + /** + * Convert current object to asn1js object and set correct values + * @returns {Object} asn1js object + */ + toSchema() + { + //region Construct and return new ASN.1 schema for this object + return (new asn1js.Sequence({ + value: Array.from(this.extensions, element => element.toSchema()) + })); + //endregion + } + //********************************************************************************** + /** + * Convertion for the class to JSON object + * @returns {Object} + */ + toJSON() + { + return { + extensions: Array.from(this.extensions, element => element.toJSON()) + }; + } + //********************************************************************************** +} +//************************************************************************************** diff --git a/core/third-party/pkijs/GeneralName.js b/core/third-party/pkijs/GeneralName.js new file mode 100644 index 0000000..4d682ed --- /dev/null +++ b/core/third-party/pkijs/GeneralName.js @@ -0,0 +1,644 @@ +import * as asn1js from "./asn1.js"; +import { getParametersValue, clearProps } from "./pvutils.js"; +import RelativeDistinguishedNames from "./RelativeDistinguishedNames.js"; +//************************************************************************************** +//region Additional asn1js schema elements existing inside GeneralName schema +//************************************************************************************** +/** + * Schema for "builtInStandardAttributes" of "ORAddress" + * @param {Object} parameters + * @property {Object} [names] + * @param {boolean} optional + * @returns {Sequence} + */ +function builtInStandardAttributes(parameters = {}, optional = false) +{ + //builtInStandardAttributes ::= Sequence { + // country-name CountryName OPTIONAL, + // administration-domain-name AdministrationDomainName OPTIONAL, + // network-address [0] IMPLICIT NetworkAddress OPTIONAL, + // terminal-identifier [1] IMPLICIT TerminalIdentifier OPTIONAL, + // private-domain-name [2] PrivateDomainName OPTIONAL, + // organization-name [3] IMPLICIT OrganizationName OPTIONAL, + // numeric-user-identifier [4] IMPLICIT NumericUserIdentifier OPTIONAL, + // personal-name [5] IMPLICIT PersonalName OPTIONAL, + // organizational-unit-names [6] IMPLICIT OrganizationalUnitNames OPTIONAL } + + /** + * @type {Object} + * @property {string} [country_name] + * @property {string} [administration_domain_name] + * @property {string} [network_address] + * @property {string} [terminal_identifier] + * @property {string} [private_domain_name] + * @property {string} [organization_name] + * @property {string} [numeric_user_identifier] + * @property {string} [personal_name] + * @property {string} [organizational_unit_names] + */ + const names = getParametersValue(parameters, "names", {}); + + return (new asn1js.Sequence({ + optional, + value: [ + new asn1js.Constructed({ + optional: true, + idBlock: { + tagClass: 2, // APPLICATION-SPECIFIC + tagNumber: 1 // [1] + }, + name: (names.country_name || ""), + value: [ + new asn1js.Choice({ + value: [ + new asn1js.NumericString(), + new asn1js.PrintableString() + ] + }) + ] + }), + new asn1js.Constructed({ + optional: true, + idBlock: { + tagClass: 2, // APPLICATION-SPECIFIC + tagNumber: 2 // [2] + }, + name: (names.administration_domain_name || ""), + value: [ + new asn1js.Choice({ + value: [ + new asn1js.NumericString(), + new asn1js.PrintableString() + ] + }) + ] + }), + new asn1js.Primitive({ + optional: true, + idBlock: { + tagClass: 3, // CONTEXT-SPECIFIC + tagNumber: 0 // [0] + }, + name: (names.network_address || ""), + isHexOnly: true + }), + new asn1js.Primitive({ + optional: true, + idBlock: { + tagClass: 3, // CONTEXT-SPECIFIC + tagNumber: 1 // [1] + }, + name: (names.terminal_identifier || ""), + isHexOnly: true + }), + new asn1js.Constructed({ + optional: true, + idBlock: { + tagClass: 3, // CONTEXT-SPECIFIC + tagNumber: 2 // [2] + }, + name: (names.private_domain_name || ""), + value: [ + new asn1js.Choice({ + value: [ + new asn1js.NumericString(), + new asn1js.PrintableString() + ] + }) + ] + }), + new asn1js.Primitive({ + optional: true, + idBlock: { + tagClass: 3, // CONTEXT-SPECIFIC + tagNumber: 3 // [3] + }, + name: (names.organization_name || ""), + isHexOnly: true + }), + new asn1js.Primitive({ + optional: true, + name: (names.numeric_user_identifier || ""), + idBlock: { + tagClass: 3, // CONTEXT-SPECIFIC + tagNumber: 4 // [4] + }, + isHexOnly: true + }), + new asn1js.Constructed({ + optional: true, + name: (names.personal_name || ""), + idBlock: { + tagClass: 3, // CONTEXT-SPECIFIC + tagNumber: 5 // [5] + }, + value: [ + new asn1js.Primitive({ + idBlock: { + tagClass: 3, // CONTEXT-SPECIFIC + tagNumber: 0 // [0] + }, + isHexOnly: true + }), + new asn1js.Primitive({ + optional: true, + idBlock: { + tagClass: 3, // CONTEXT-SPECIFIC + tagNumber: 1 // [1] + }, + isHexOnly: true + }), + new asn1js.Primitive({ + optional: true, + idBlock: { + tagClass: 3, // CONTEXT-SPECIFIC + tagNumber: 2 // [2] + }, + isHexOnly: true + }), + new asn1js.Primitive({ + optional: true, + idBlock: { + tagClass: 3, // CONTEXT-SPECIFIC + tagNumber: 3 // [3] + }, + isHexOnly: true + }) + ] + }), + new asn1js.Constructed({ + optional: true, + name: (names.organizational_unit_names || ""), + idBlock: { + tagClass: 3, // CONTEXT-SPECIFIC + tagNumber: 6 // [6] + }, + value: [ + new asn1js.Repeated({ + value: new asn1js.PrintableString() + }) + ] + }) + ] + })); +} +//************************************************************************************** +/** + * Schema for "builtInDomainDefinedAttributes" of "ORAddress" + * @param {boolean} optional + * @returns {Sequence} + */ +function builtInDomainDefinedAttributes(optional = false) +{ + return (new asn1js.Sequence({ + optional, + value: [ + new asn1js.PrintableString(), + new asn1js.PrintableString() + ] + })); +} +//************************************************************************************** +/** + * Schema for "builtInDomainDefinedAttributes" of "ORAddress" + * @param {boolean} optional + * @returns {Set} + */ +function extensionAttributes(optional = false) +{ + return (new asn1js.Set({ + optional, + value: [ + new asn1js.Primitive({ + optional: true, + idBlock: { + tagClass: 3, // CONTEXT-SPECIFIC + tagNumber: 0 // [0] + }, + isHexOnly: true + }), + new asn1js.Constructed({ + optional: true, + idBlock: { + tagClass: 3, // CONTEXT-SPECIFIC + tagNumber: 1 // [1] + }, + value: [new asn1js.Any()] + }) + ] + })); +} +//************************************************************************************** +//endregion +//************************************************************************************** +/** + * Class from RFC5280 + */ +export default class GeneralName +{ + //********************************************************************************** + /** + * Constructor for GeneralName class + * @param {Object} [parameters={}] + * @param {Object} [parameters.schema] asn1js parsed value to initialize the class from + * @property {number} [type] value type - from a tagged value (0 for "otherName", 1 for "rfc822Name" etc.) + * @property {Object} [value] asn1js object having GeneralName value (type depends on "type" value) + */ + constructor(parameters = {}) + { + //region Internal properties of the object + /** + * @type {number} + * @desc value type - from a tagged value (0 for "otherName", 1 for "rfc822Name" etc.) + */ + this.type = getParametersValue(parameters, "type", GeneralName.defaultValues("type")); + /** + * @type {Object} + * @desc asn1js object having GeneralName value (type depends on "type" value) + */ + this.value = getParametersValue(parameters, "value", GeneralName.defaultValues("value")); + //endregion + + //region If input argument array contains "schema" for this object + if("schema" in parameters) + this.fromSchema(parameters.schema); + //endregion + } + //********************************************************************************** + /** + * Return default values for all class members + * @param {string} memberName String name for a class member + */ + static defaultValues(memberName) + { + switch(memberName) + { + case "type": + return 9; + case "value": + return {}; + default: + throw new Error(`Invalid member name for GeneralName class: ${memberName}`); + } + } + //********************************************************************************** + /** + * Compare values with default values for all class members + * @param {string} memberName String name for a class member + * @param {*} memberValue Value to compare with default value + */ + static compareWithDefault(memberName, memberValue) + { + switch(memberName) + { + case "type": + return (memberValue === GeneralName.defaultValues(memberName)); + case "value": + return (Object.keys(memberValue).length === 0); + default: + throw new Error(`Invalid member name for GeneralName class: ${memberName}`); + } + } + //********************************************************************************** + /** + * Return value of pre-defined ASN.1 schema for current class + * + * ASN.1 schema: + * ```asn1 + * GeneralName ::= Choice { + * otherName [0] OtherName, + * rfc822Name [1] IA5String, + * dNSName [2] IA5String, + * x400Address [3] ORAddress, + * directoryName [4] value, + * ediPartyName [5] EDIPartyName, + * uniformResourceIdentifier [6] IA5String, + * iPAddress [7] OCTET STRING, + * registeredID [8] OBJECT IDENTIFIER } + * ``` + * + * @param {Object} parameters Input parameters for the schema + * @returns {Object} asn1js schema object + */ + static schema(parameters = {}) + { + /** + * @type {Object} + * @property {string} [blockName] + * @property {Object} [directoryName] + * @property {Object} [builtInStandardAttributes] + */ + const names = getParametersValue(parameters, "names", {}); + + return (new asn1js.Choice({ + value: [ + new asn1js.Constructed({ + idBlock: { + tagClass: 3, // CONTEXT-SPECIFIC + tagNumber: 0 // [0] + }, + name: (names.blockName || ""), + value: [ + new asn1js.ObjectIdentifier(), + new asn1js.Constructed({ + idBlock: { + tagClass: 3, // CONTEXT-SPECIFIC + tagNumber: 0 // [0] + }, + value: [new asn1js.Any()] + }) + ] + }), + new asn1js.Primitive({ + name: (names.blockName || ""), + idBlock: { + tagClass: 3, // CONTEXT-SPECIFIC + tagNumber: 1 // [1] + } + }), + new asn1js.Primitive({ + name: (names.blockName || ""), + idBlock: { + tagClass: 3, // CONTEXT-SPECIFIC + tagNumber: 2 // [2] + } + }), + new asn1js.Constructed({ + idBlock: { + tagClass: 3, // CONTEXT-SPECIFIC + tagNumber: 3 // [3] + }, + name: (names.blockName || ""), + value: [ + builtInStandardAttributes((names.builtInStandardAttributes || {}), false), + builtInDomainDefinedAttributes(true), + extensionAttributes(true) + ] + }), + new asn1js.Constructed({ + idBlock: { + tagClass: 3, // CONTEXT-SPECIFIC + tagNumber: 4 // [4] + }, + name: (names.blockName || ""), + value: [RelativeDistinguishedNames.schema(names.directoryName || {})] + }), + new asn1js.Constructed({ + idBlock: { + tagClass: 3, // CONTEXT-SPECIFIC + tagNumber: 5 // [5] + }, + name: (names.blockName || ""), + value: [ + new asn1js.Constructed({ + optional: true, + idBlock: { + tagClass: 3, // CONTEXT-SPECIFIC + tagNumber: 0 // [0] + }, + value: [ + new asn1js.Choice({ + value: [ + new asn1js.TeletexString(), + new asn1js.PrintableString(), + new asn1js.UniversalString(), + new asn1js.Utf8String(), + new asn1js.BmpString() + ] + }) + ] + }), + new asn1js.Constructed({ + idBlock: { + tagClass: 3, // CONTEXT-SPECIFIC + tagNumber: 1 // [1] + }, + value: [ + new asn1js.Choice({ + value: [ + new asn1js.TeletexString(), + new asn1js.PrintableString(), + new asn1js.UniversalString(), + new asn1js.Utf8String(), + new asn1js.BmpString() + ] + }) + ] + }) + ] + }), + new asn1js.Primitive({ + name: (names.blockName || ""), + idBlock: { + tagClass: 3, // CONTEXT-SPECIFIC + tagNumber: 6 // [6] + } + }), + new asn1js.Primitive({ + name: (names.blockName || ""), + idBlock: { + tagClass: 3, // CONTEXT-SPECIFIC + tagNumber: 7 // [7] + } + }), + new asn1js.Primitive({ + name: (names.blockName || ""), + idBlock: { + tagClass: 3, // CONTEXT-SPECIFIC + tagNumber: 8 // [8] + } + }) + ] + })); + } + //********************************************************************************** + /** + * Convert parsed asn1js object into current class + * @param {!Object} schema + */ + fromSchema(schema) + { + //region Clear input data first + clearProps(schema, [ + "blockName", + "otherName", + "rfc822Name", + "dNSName", + "x400Address", + "directoryName", + "ediPartyName", + "uniformResourceIdentifier", + "iPAddress", + "registeredID" + ]); + //endregion + + //region Check the schema is valid + const asn1 = asn1js.compareSchema(schema, + schema, + GeneralName.schema({ + names: { + blockName: "blockName", + otherName: "otherName", + rfc822Name: "rfc822Name", + dNSName: "dNSName", + x400Address: "x400Address", + directoryName: { + names: { + blockName: "directoryName" + } + }, + ediPartyName: "ediPartyName", + uniformResourceIdentifier: "uniformResourceIdentifier", + iPAddress: "iPAddress", + registeredID: "registeredID" + } + }) + ); + + if(asn1.verified === false) + throw new Error("Object's schema was not verified against input data for GeneralName"); + //endregion + + //region Get internal properties from parsed schema + this.type = asn1.result.blockName.idBlock.tagNumber; + + switch(this.type) + { + case 0: // otherName + this.value = asn1.result.blockName; + break; + case 1: // rfc822Name + dNSName + uniformResourceIdentifier + case 2: + case 6: + { + const value = asn1.result.blockName; + + value.idBlock.tagClass = 1; // UNIVERSAL + value.idBlock.tagNumber = 22; // IA5STRING + + const valueBER = value.toBER(false); + + this.value = asn1js.fromBER(valueBER).result.valueBlock.value; + } + break; + case 3: // x400Address + this.value = asn1.result.blockName; + break; + case 4: // directoryName + this.value = new RelativeDistinguishedNames({ schema: asn1.result.directoryName }); + break; + case 5: // ediPartyName + this.value = asn1.result.ediPartyName; + break; + case 7: // iPAddress + this.value = new asn1js.OctetString({ valueHex: asn1.result.blockName.valueBlock.valueHex }); + break; + case 8: // registeredID + { + const value = asn1.result.blockName; + + value.idBlock.tagClass = 1; // UNIVERSAL + value.idBlock.tagNumber = 6; // ObjectIdentifier + + const valueBER = value.toBER(false); + + this.value = asn1js.fromBER(valueBER).result.valueBlock.toString(); // Getting a string representation of the ObjectIdentifier + } + break; + default: + } + //endregion + } + //********************************************************************************** + /** + * Convert current object to asn1js object and set correct values + * @returns {Object} asn1js object + */ + toSchema() + { + //region Construct and return new ASN.1 schema for this object + switch(this.type) + { + case 0: + case 3: + case 5: + return new asn1js.Constructed({ + idBlock: { + tagClass: 3, // CONTEXT-SPECIFIC + tagNumber: this.type + }, + value: [ + this.value + ] + }); + case 1: + case 2: + case 6: + { + const value = new asn1js.IA5String({ value: this.value }); + + value.idBlock.tagClass = 3; + value.idBlock.tagNumber = this.type; + + return value; + } + case 4: + return new asn1js.Constructed({ + idBlock: { + tagClass: 3, // CONTEXT-SPECIFIC + tagNumber: 4 + }, + value: [this.value.toSchema()] + }); + case 7: + { + const value = this.value; + + value.idBlock.tagClass = 3; + value.idBlock.tagNumber = this.type; + + return value; + } + case 8: + { + const value = new asn1js.ObjectIdentifier({ value: this.value }); + + value.idBlock.tagClass = 3; + value.idBlock.tagNumber = this.type; + + return value; + } + default: + return GeneralName.schema(); + } + //endregion + } + //********************************************************************************** + /** + * Convertion for the class to JSON object + * @returns {Object} + */ + toJSON() + { + const _object = { + type: this.type, + value: "" + }; + + if((typeof this.value) === "string") + _object.value = this.value; + else + { + try + { + _object.value = this.value.toJSON(); + } + catch(ex){} + } + + return _object; + } + //********************************************************************************** +} +//************************************************************************************** diff --git a/core/third-party/pkijs/GeneralNames.js b/core/third-party/pkijs/GeneralNames.js new file mode 100644 index 0000000..b4b47a0 --- /dev/null +++ b/core/third-party/pkijs/GeneralNames.js @@ -0,0 +1,138 @@ +import * as asn1js from "./asn1.js"; +import { getParametersValue, clearProps } from "./pvutils.js"; +import GeneralName from "./GeneralName.js"; +//************************************************************************************** +/** + * Class from RFC5280 + */ +export default class GeneralNames +{ + //********************************************************************************** + /** + * Constructor for GeneralNames class + * @param {Object} [parameters={}] + * @param {Object} [parameters.schema] asn1js parsed value to initialize the class from + */ + constructor(parameters = {}) + { + //region Internal properties of the object + /** + * @type {Array.} + * @desc Array of "general names" + */ + this.names = getParametersValue(parameters, "names", GeneralNames.defaultValues("names")); + //endregion + + //region If input argument array contains "schema" for this object + if("schema" in parameters) + this.fromSchema(parameters.schema); + //endregion + } + //********************************************************************************** + /** + * Return default values for all class members + * @param {string} memberName String name for a class member + */ + static defaultValues(memberName) + { + switch(memberName) + { + case "names": + return []; + default: + throw new Error(`Invalid member name for GeneralNames class: ${memberName}`); + } + } + //********************************************************************************** + /** + * Return value of pre-defined ASN.1 schema for current class + * + * ASN.1 schema: + * ```asn1 + * GeneralNames ::= SEQUENCE SIZE (1..MAX) OF GeneralName + * ``` + * + * @param {Object} parameters Input parameters for the schema + * @param {boolean} [optional=false] Flag would be element optional or not + * @returns {Object} asn1js schema object + */ + static schema(parameters = {}, optional = false) + { + /** + * @type {Object} + * @property {string} utcTimeName Name for "utcTimeName" choice + * @property {string} generalTimeName Name for "generalTimeName" choice + */ + const names = getParametersValue(parameters, "names", {}); + + return (new asn1js.Sequence({ + optional, + name: (names.blockName || ""), + value: [ + new asn1js.Repeated({ + name: (names.generalNames || ""), + value: GeneralName.schema() + }) + ] + })); + } + //********************************************************************************** + /** + * Convert parsed asn1js object into current class + * @param {!Object} schema + */ + fromSchema(schema) + { + //region Clear input data first + clearProps(schema, [ + "names", + "generalNames" + ]); + //endregion + + //region Check the schema is valid + const asn1 = asn1js.compareSchema(schema, + schema, + GeneralNames.schema({ + names: { + blockName: "names", + generalNames: "generalNames" + } + }) + ); + + if(asn1.verified === false) + throw new Error("Object's schema was not verified against input data for GeneralNames"); + //endregion + + //region Get internal properties from parsed schema + this.names = Array.from(asn1.result.generalNames, element => new GeneralName({ schema: element })); + //endregion + } + //********************************************************************************** + /** + * Convert current object to asn1js object and set correct values + * @returns {Object} asn1js object + */ + toSchema() + { + //region Construct and return new ASN.1 schema for this object + return (new asn1js.Sequence({ + value: Array.from(this.names, element => element.toSchema()) + })); + //endregion + } + //********************************************************************************** + /** + * Convertion for the class to JSON object + * @returns {Object} + */ + toJSON() + { + return { + names: Array.from(this.names, element => element.toJSON()) + }; + } + //********************************************************************************** +} +//************************************************************************************** diff --git a/core/third-party/pkijs/GeneralSubtree.js b/core/third-party/pkijs/GeneralSubtree.js new file mode 100644 index 0000000..aa8a8d8 --- /dev/null +++ b/core/third-party/pkijs/GeneralSubtree.js @@ -0,0 +1,257 @@ +import * as asn1js from "./asn1.js"; +import { getParametersValue, clearProps } from "./pvutils.js"; +import GeneralName from "./GeneralName.js"; +//************************************************************************************** +/** + * Class from RFC5280 + */ +export default class GeneralSubtree +{ + //********************************************************************************** + /** + * Constructor for GeneralSubtree class + * @param {Object} [parameters={}] + * @param {Object} [parameters.schema] asn1js parsed value to initialize the class from + */ + constructor(parameters = {}) + { + //region Internal properties of the object + /** + * @type {GeneralName} + * @desc base + */ + this.base = getParametersValue(parameters, "base", GeneralSubtree.defaultValues("base")); + + /** + * @type {number|Integer} + * @desc base + */ + this.minimum = getParametersValue(parameters, "minimum", GeneralSubtree.defaultValues("minimum")); + + if("maximum" in parameters) + /** + * @type {number|Integer} + * @desc minimum + */ + this.maximum = getParametersValue(parameters, "maximum", GeneralSubtree.defaultValues("maximum")); + //endregion + + //region If input argument array contains "schema" for this object + if("schema" in parameters) + this.fromSchema(parameters.schema); + //endregion + } + //********************************************************************************** + /** + * Return default values for all class members + * @param {string} memberName String name for a class member + */ + static defaultValues(memberName) + { + switch(memberName) + { + case "base": + return new GeneralName(); + case "minimum": + return 0; + case "maximum": + return 0; + default: + throw new Error(`Invalid member name for GeneralSubtree class: ${memberName}`); + } + } + //********************************************************************************** + /** + * Return value of pre-defined ASN.1 schema for current class + * + * ASN.1 schema: + * ```asn1 + * GeneralSubtree ::= SEQUENCE { + * base GeneralName, + * minimum [0] BaseDistance DEFAULT 0, + * maximum [1] BaseDistance OPTIONAL } + * + * BaseDistance ::= INTEGER (0..MAX) + * ``` + * + * @param {Object} parameters Input parameters for the schema + * @returns {Object} asn1js schema object + */ + static schema(parameters = {}) + { + /** + * @type {Object} + * @property {string} [blockName] + * @property {string} [base] + * @property {string} [minimum] + * @property {string} [maximum] + */ + const names = getParametersValue(parameters, "names", {}); + + return (new asn1js.Sequence({ + name: (names.blockName || ""), + value: [ + GeneralName.schema(names.base || {}), + new asn1js.Constructed({ + optional: true, + idBlock: { + tagClass: 3, // CONTEXT-SPECIFIC + tagNumber: 0 // [0] + }, + value: [new asn1js.Integer({ name: (names.minimum || "") })] + }), + new asn1js.Constructed({ + optional: true, + idBlock: { + tagClass: 3, // CONTEXT-SPECIFIC + tagNumber: 1 // [1] + }, + value: [new asn1js.Integer({ name: (names.maximum || "") })] + }) + ] + })); + } + //********************************************************************************** + /** + * Convert parsed asn1js object into current class + * @param {!Object} schema + */ + fromSchema(schema) + { + //region Clear input data first + clearProps(schema, [ + "base", + "minimum", + "maximum" + ]); + //endregion + + //region Check the schema is valid + const asn1 = asn1js.compareSchema(schema, + schema, + GeneralSubtree.schema({ + names: { + base: { + names: { + blockName: "base" + } + }, + minimum: "minimum", + maximum: "maximum" + } + }) + ); + + if(asn1.verified === false) + throw new Error("Object's schema was not verified against input data for GeneralSubtree"); + //endregion + + //region Get internal properties from parsed schema + this.base = new GeneralName({ schema: asn1.result.base }); + + if("minimum" in asn1.result) + { + if(asn1.result.minimum.valueBlock.isHexOnly) + this.minimum = asn1.result.minimum; + else + this.minimum = asn1.result.minimum.valueBlock.valueDec; + } + + if("maximum" in asn1.result) + { + if(asn1.result.maximum.valueBlock.isHexOnly) + this.maximum = asn1.result.maximum; + else + this.maximum = asn1.result.maximum.valueBlock.valueDec; + } + //endregion + } + //********************************************************************************** + /** + * Convert current object to asn1js object and set correct values + * @returns {Object} asn1js object + */ + toSchema() + { + //region Create array for output sequence + const outputArray = []; + + outputArray.push(this.base.toSchema()); + + if(this.minimum !== 0) + { + let valueMinimum = 0; + + if(this.minimum instanceof asn1js.Integer) + valueMinimum = this.minimum; + else + valueMinimum = new asn1js.Integer({ value: this.minimum }); + + outputArray.push(new asn1js.Constructed({ + optional: true, + idBlock: { + tagClass: 3, // CONTEXT-SPECIFIC + tagNumber: 0 // [0] + }, + value: [valueMinimum] + })); + } + + if("maximum" in this) + { + let valueMaximum = 0; + + if(this.maximum instanceof asn1js.Integer) + valueMaximum = this.maximum; + else + valueMaximum = new asn1js.Integer({ value: this.maximum }); + + outputArray.push(new asn1js.Constructed({ + optional: true, + idBlock: { + tagClass: 3, // CONTEXT-SPECIFIC + tagNumber: 1 // [1] + }, + value: [valueMaximum] + })); + } + //endregion + + //region Construct and return new ASN.1 schema for this object + return (new asn1js.Sequence({ + value: outputArray + })); + //endregion + } + //********************************************************************************** + /** + * Convertion for the class to JSON object + * @returns {Object} + */ + toJSON() + { + const object = { + base: this.base.toJSON() + }; + + if(this.minimum !== 0) + { + if((typeof this.minimum) === "number") + object.minimum = this.minimum; + else + object.minimum = this.minimum.toJSON(); + } + + if("maximum" in this) + { + if((typeof this.maximum) === "number") + object.maximum = this.maximum; + else + object.maximum = this.maximum.toJSON(); + } + + return object; + } + //********************************************************************************** +} +//************************************************************************************** diff --git a/core/third-party/pkijs/InfoAccess.js b/core/third-party/pkijs/InfoAccess.js new file mode 100644 index 0000000..78d04d8 --- /dev/null +++ b/core/third-party/pkijs/InfoAccess.js @@ -0,0 +1,135 @@ +import * as asn1js from "./asn1.js"; +import { getParametersValue, clearProps } from "./pvutils.js"; +import AccessDescription from "./AccessDescription.js"; +//************************************************************************************** +/** + * Class from RFC5280 + */ +export default class InfoAccess +{ + //********************************************************************************** + /** + * Constructor for InfoAccess class + * @param {Object} [parameters={}] + * @param {Object} [parameters.schema] asn1js parsed value to initialize the class from + */ + constructor(parameters = {}) + { + //region Internal properties of the object + /** + * @type {Array.} + * @desc accessDescriptions + */ + this.accessDescriptions = getParametersValue(parameters, "accessDescriptions", InfoAccess.defaultValues("accessDescriptions")); + //endregion + + //region If input argument array contains "schema" for this object + if("schema" in parameters) + this.fromSchema(parameters.schema); + //endregion + } + //********************************************************************************** + /** + * Return default values for all class members + * @param {string} memberName String name for a class member + */ + static defaultValues(memberName) + { + switch(memberName) + { + case "accessDescriptions": + return []; + default: + throw new Error(`Invalid member name for InfoAccess class: ${memberName}`); + } + } + //********************************************************************************** + /** + * Return value of pre-defined ASN.1 schema for current class + * + * ASN.1 schema: + * ```asn1 + * AuthorityInfoAccessSyntax ::= + * SEQUENCE SIZE (1..MAX) OF AccessDescription + * ``` + * + * @param {Object} parameters Input parameters for the schema + * @returns {Object} asn1js schema object + */ + static schema(parameters = {}) + { + /** + * @type {Object} + * @property {string} [blockName] + * @property {string} [accessDescriptions] + */ + const names = getParametersValue(parameters, "names", {}); + + return (new asn1js.Sequence({ + name: (names.blockName || ""), + value: [ + new asn1js.Repeated({ + name: (names.accessDescriptions || ""), + value: AccessDescription.schema() + }) + ] + })); + } + //********************************************************************************** + /** + * Convert parsed asn1js object into current class + * @param {!Object} schema + */ + fromSchema(schema) + { + //region Clear input data first + clearProps(schema, [ + "accessDescriptions" + ]); + //endregion + + //region Check the schema is valid + const asn1 = asn1js.compareSchema(schema, + schema, + InfoAccess.schema({ + names: { + accessDescriptions: "accessDescriptions" + } + }) + ); + + if(asn1.verified === false) + throw new Error("Object's schema was not verified against input data for InfoAccess"); + //endregion + + //region Get internal properties from parsed schema + this.accessDescriptions = Array.from(asn1.result.accessDescriptions, element => new AccessDescription({ schema: element })); + //endregion + } + //********************************************************************************** + /** + * Convert current object to asn1js object and set correct values + * @returns {Object} asn1js object + */ + toSchema() + { + //region Construct and return new ASN.1 schema for this object + return (new asn1js.Sequence({ + value: Array.from(this.accessDescriptions, element => element.toSchema()) + })); + //endregion + } + //********************************************************************************** + /** + * Convertion for the class to JSON object + * @returns {Object} + */ + toJSON() + { + return { + accessDescriptions: Array.from(this.accessDescriptions, element => element.toJSON()) + }; + } + //********************************************************************************** +} +//************************************************************************************** diff --git a/core/third-party/pkijs/IssuerAndSerialNumber.js b/core/third-party/pkijs/IssuerAndSerialNumber.js new file mode 100644 index 0000000..60729ca --- /dev/null +++ b/core/third-party/pkijs/IssuerAndSerialNumber.js @@ -0,0 +1,155 @@ +import * as asn1js from "./asn1.js"; +import { getParametersValue, clearProps } from "./pvutils.js"; +import RelativeDistinguishedNames from "./RelativeDistinguishedNames.js"; +//************************************************************************************** +/** + * Class from RFC5652 + */ +export default class IssuerAndSerialNumber +{ + //********************************************************************************** + /** + * Constructor for IssuerAndSerialNumber class + * @param {Object} [parameters={}] + * @param {Object} [parameters.schema] asn1js parsed value to initialize the class from + */ + constructor(parameters = {}) + { + //region Internal properties of the object + /** + * @type {RelativeDistinguishedNames} + * @desc issuer + */ + this.issuer = getParametersValue(parameters, "issuer", IssuerAndSerialNumber.defaultValues("issuer")); + /** + * @type {Integer} + * @desc serialNumber + */ + this.serialNumber = getParametersValue(parameters, "serialNumber", IssuerAndSerialNumber.defaultValues("serialNumber")); + //endregion + + //region If input argument array contains "schema" for this object + if("schema" in parameters) + this.fromSchema(parameters.schema); + //endregion + } + //********************************************************************************** + /** + * Return default values for all class members + * @param {string} memberName String name for a class member + */ + static defaultValues(memberName) + { + switch(memberName) + { + case "issuer": + return new RelativeDistinguishedNames(); + case "serialNumber": + return new asn1js.Integer(); + default: + throw new Error(`Invalid member name for IssuerAndSerialNumber class: ${memberName}`); + } + } + //********************************************************************************** + /** + * Return value of pre-defined ASN.1 schema for current class + * + * ASN.1 schema: + * ```asn1 + * IssuerAndSerialNumber ::= SEQUENCE { + * issuer Name, + * serialNumber CertificateSerialNumber } + * + * CertificateSerialNumber ::= INTEGER + * ``` + * + * @param {Object} parameters Input parameters for the schema + * @returns {Object} asn1js schema object + */ + static schema(parameters = {}) + { + /** + * @type {Object} + * @property {string} [blockName] + * @property {string} [issuer] + * @property {string} [serialNumber] + */ + const names = getParametersValue(parameters, "names", {}); + + return (new asn1js.Sequence({ + name: (names.blockName || ""), + value: [ + RelativeDistinguishedNames.schema(names.issuer || {}), + new asn1js.Integer({ name: (names.serialNumber || "") }) + ] + })); + } + //********************************************************************************** + /** + * Convert parsed asn1js object into current class + * @param {!Object} schema + */ + fromSchema(schema) + { + //region Clear input data first + clearProps(schema, [ + "issuer", + "serialNumber" + ]); + //endregion + + //region Check the schema is valid + const asn1 = asn1js.compareSchema(schema, + schema, + IssuerAndSerialNumber.schema({ + names: { + issuer: { + names: { + blockName: "issuer" + } + }, + serialNumber: "serialNumber" + } + }) + ); + + if(asn1.verified === false) + throw new Error("Object's schema was not verified against input data for IssuerAndSerialNumber"); + //endregion + + //region Get internal properties from parsed schema + this.issuer = new RelativeDistinguishedNames({ schema: asn1.result.issuer }); + this.serialNumber = asn1.result.serialNumber; + //endregion + } + //********************************************************************************** + /** + * Convert current object to asn1js object and set correct values + * @returns {Object} asn1js object + */ + toSchema() + { + //region Construct and return new ASN.1 schema for this object + return (new asn1js.Sequence({ + value: [ + this.issuer.toSchema(), + this.serialNumber + ] + })); + //endregion + } + //********************************************************************************** + /** + * Convertion for the class to JSON object + * @returns {Object} + */ + toJSON() + { + return { + issuer: this.issuer.toJSON(), + serialNumber: this.serialNumber.toJSON() + }; + } + //********************************************************************************** +} +//************************************************************************************** diff --git a/core/third-party/pkijs/IssuingDistributionPoint.js b/core/third-party/pkijs/IssuingDistributionPoint.js new file mode 100644 index 0000000..50edd65 --- /dev/null +++ b/core/third-party/pkijs/IssuingDistributionPoint.js @@ -0,0 +1,449 @@ +import * as asn1js from "./asn1.js"; +import { getParametersValue, clearProps } from "./pvutils.js"; +import GeneralName from "./GeneralName.js"; +import RelativeDistinguishedNames from "./RelativeDistinguishedNames.js"; +//************************************************************************************** +/** + * Class from RFC5280 + */ +export default class IssuingDistributionPoint +{ + //********************************************************************************** + /** + * Constructor for IssuingDistributionPoint class + * @param {Object} [parameters={}] + * @param {Object} [parameters.schema] asn1js parsed value to initialize the class from + */ + constructor(parameters = {}) + { + //region Internal properties of the object + if("distributionPoint" in parameters) + /** + * @type {Array.|RelativeDistinguishedNames} + * @desc distributionPoint + */ + this.distributionPoint = getParametersValue(parameters, "distributionPoint", IssuingDistributionPoint.defaultValues("distributionPoint")); + + /** + * @type {boolean} + * @desc onlyContainsUserCerts + */ + this.onlyContainsUserCerts = getParametersValue(parameters, "onlyContainsUserCerts", IssuingDistributionPoint.defaultValues("onlyContainsUserCerts")); + + /** + * @type {boolean} + * @desc onlyContainsCACerts + */ + this.onlyContainsCACerts = getParametersValue(parameters, "onlyContainsCACerts", IssuingDistributionPoint.defaultValues("onlyContainsCACerts")); + + if("onlySomeReasons" in parameters) + /** + * @type {number} + * @desc onlySomeReasons + */ + this.onlySomeReasons = getParametersValue(parameters, "onlySomeReasons", IssuingDistributionPoint.defaultValues("onlySomeReasons")); + + /** + * @type {boolean} + * @desc indirectCRL + */ + this.indirectCRL = getParametersValue(parameters, "indirectCRL", IssuingDistributionPoint.defaultValues("indirectCRL")); + + /** + * @type {boolean} + * @desc onlyContainsAttributeCerts + */ + this.onlyContainsAttributeCerts = getParametersValue(parameters, "onlyContainsAttributeCerts", IssuingDistributionPoint.defaultValues("onlyContainsAttributeCerts")); + //endregion + + //region If input argument array contains "schema" for this object + if("schema" in parameters) + this.fromSchema(parameters.schema); + //endregion + } + //********************************************************************************** + /** + * Return default values for all class members + * @param {string} memberName String name for a class member + */ + static defaultValues(memberName) + { + switch(memberName) + { + case "distributionPoint": + return []; + case "onlyContainsUserCerts": + return false; + case "onlyContainsCACerts": + return false; + case "onlySomeReasons": + return 0; + case "indirectCRL": + return false; + case "onlyContainsAttributeCerts": + return false; + default: + throw new Error(`Invalid member name for IssuingDistributionPoint class: ${memberName}`); + } + } + //********************************************************************************** + /** + * Return value of pre-defined ASN.1 schema for current class + * + * ASN.1 schema: + * ```asn1 + * IssuingDistributionPoint ::= SEQUENCE { + * distributionPoint [0] DistributionPointName OPTIONAL, + * onlyContainsUserCerts [1] BOOLEAN DEFAULT FALSE, + * onlyContainsCACerts [2] BOOLEAN DEFAULT FALSE, + * onlySomeReasons [3] ReasonFlags OPTIONAL, + * indirectCRL [4] BOOLEAN DEFAULT FALSE, + * onlyContainsAttributeCerts [5] BOOLEAN DEFAULT FALSE } + * + * ReasonFlags ::= BIT STRING { + * unused (0), + * keyCompromise (1), + * cACompromise (2), + * affiliationChanged (3), + * superseded (4), + * cessationOfOperation (5), + * certificateHold (6), + * privilegeWithdrawn (7), + * aACompromise (8) } + * ``` + * + * @param {Object} parameters Input parameters for the schema + * @returns {Object} asn1js schema object + */ + static schema(parameters = {}) + { + /** + * @type {Object} + * @property {string} [blockName] + * @property {string} [distributionPoint] + * @property {string} [distributionPointNames] + * @property {string} [onlyContainsUserCerts] + * @property {string} [onlyContainsCACerts] + * @property {string} [onlySomeReasons] + * @property {string} [indirectCRL] + * @property {string} [onlyContainsAttributeCerts] + */ + const names = getParametersValue(parameters, "names", {}); + + return (new asn1js.Sequence({ + name: (names.blockName || ""), + value: [ + new asn1js.Constructed({ + optional: true, + idBlock: { + tagClass: 3, // CONTEXT-SPECIFIC + tagNumber: 0 // [0] + }, + value: [ + new asn1js.Choice({ + value: [ + new asn1js.Constructed({ + name: (names.distributionPoint || ""), + idBlock: { + tagClass: 3, // CONTEXT-SPECIFIC + tagNumber: 0 // [0] + }, + value: [ + new asn1js.Repeated({ + name: (names.distributionPointNames || ""), + value: GeneralName.schema() + }) + ] + }), + new asn1js.Constructed({ + name: (names.distributionPoint || ""), + idBlock: { + tagClass: 3, // CONTEXT-SPECIFIC + tagNumber: 1 // [1] + }, + value: RelativeDistinguishedNames.schema().valueBlock.value + }) + ] + }) + ] + }), + new asn1js.Primitive({ + name: (names.onlyContainsUserCerts || ""), + optional: true, + idBlock: { + tagClass: 3, // CONTEXT-SPECIFIC + tagNumber: 1 // [1] + } + }), // IMPLICIT boolean value + new asn1js.Primitive({ + name: (names.onlyContainsCACerts || ""), + optional: true, + idBlock: { + tagClass: 3, // CONTEXT-SPECIFIC + tagNumber: 2 // [2] + } + }), // IMPLICIT boolean value + new asn1js.Primitive({ + name: (names.onlySomeReasons || ""), + optional: true, + idBlock: { + tagClass: 3, // CONTEXT-SPECIFIC + tagNumber: 3 // [3] + } + }), // IMPLICIT bitstring value + new asn1js.Primitive({ + name: (names.indirectCRL || ""), + optional: true, + idBlock: { + tagClass: 3, // CONTEXT-SPECIFIC + tagNumber: 4 // [4] + } + }), // IMPLICIT boolean value + new asn1js.Primitive({ + name: (names.onlyContainsAttributeCerts || ""), + optional: true, + idBlock: { + tagClass: 3, // CONTEXT-SPECIFIC + tagNumber: 5 // [5] + } + }) // IMPLICIT boolean value + ] + })); + } + //********************************************************************************** + /** + * Convert parsed asn1js object into current class + * @param {!Object} schema + */ + fromSchema(schema) + { + //region Clear input data first + clearProps(schema, [ + "distributionPoint", + "distributionPointNames", + "onlyContainsUserCerts", + "onlyContainsCACerts", + "onlySomeReasons", + "indirectCRL", + "onlyContainsAttributeCerts" + ]); + //endregion + + //region Check the schema is valid + const asn1 = asn1js.compareSchema(schema, + schema, + IssuingDistributionPoint.schema({ + names: { + distributionPoint: "distributionPoint", + distributionPointNames: "distributionPointNames", + onlyContainsUserCerts: "onlyContainsUserCerts", + onlyContainsCACerts: "onlyContainsCACerts", + onlySomeReasons: "onlySomeReasons", + indirectCRL: "indirectCRL", + onlyContainsAttributeCerts: "onlyContainsAttributeCerts" + } + }) + ); + + if(asn1.verified === false) + throw new Error("Object's schema was not verified against input data for IssuingDistributionPoint"); + //endregion + + //region Get internal properties from parsed schema + if("distributionPoint" in asn1.result) + { + switch(true) + { + case (asn1.result.distributionPoint.idBlock.tagNumber === 0): // GENERAL_NAMES variant + this.distributionPoint = Array.from(asn1.result.distributionPointNames, element => new GeneralName({ schema: element })); + break; + case (asn1.result.distributionPoint.idBlock.tagNumber === 1): // RDN variant + { + this.distributionPoint = new RelativeDistinguishedNames({ + schema: new asn1js.Sequence({ + value: asn1.result.distributionPoint.valueBlock.value + }) + }); + } + break; + default: + throw new Error("Unknown tagNumber for distributionPoint: {$asn1.result.distributionPoint.idBlock.tagNumber}"); + } + } + + if("onlyContainsUserCerts" in asn1.result) + { + const view = new Uint8Array(asn1.result.onlyContainsUserCerts.valueBlock.valueHex); + this.onlyContainsUserCerts = (view[0] !== 0x00); + } + + if("onlyContainsCACerts" in asn1.result) + { + const view = new Uint8Array(asn1.result.onlyContainsCACerts.valueBlock.valueHex); + this.onlyContainsCACerts = (view[0] !== 0x00); + } + + if("onlySomeReasons" in asn1.result) + { + const view = new Uint8Array(asn1.result.onlySomeReasons.valueBlock.valueHex); + this.onlySomeReasons = view[0]; + } + + if("indirectCRL" in asn1.result) + { + const view = new Uint8Array(asn1.result.indirectCRL.valueBlock.valueHex); + this.indirectCRL = (view[0] !== 0x00); + } + + if("onlyContainsAttributeCerts" in asn1.result) + { + const view = new Uint8Array(asn1.result.onlyContainsAttributeCerts.valueBlock.valueHex); + this.onlyContainsAttributeCerts = (view[0] !== 0x00); + } + //endregion + } + //********************************************************************************** + /** + * Convert current object to asn1js object and set correct values + * @returns {Object} asn1js object + */ + toSchema() + { + //region Create array for output sequence + const outputArray = []; + + if("distributionPoint" in this) + { + let value; + + if(this.distributionPoint instanceof Array) + { + value = new asn1js.Constructed({ + idBlock: { + tagClass: 3, // CONTEXT-SPECIFIC + tagNumber: 0 // [0] + }, + value: Array.from(this.distributionPoint, element => element.toSchema()) + }); + } + else + { + value = this.distributionPoint.toSchema(); + + value.idBlock.tagClass = 3; // CONTEXT - SPECIFIC + value.idBlock.tagNumber = 1; // [1] + } + + outputArray.push(new asn1js.Constructed({ + idBlock: { + tagClass: 3, // CONTEXT-SPECIFIC + tagNumber: 0 // [0] + }, + value: [value] + })); + } + + if(this.onlyContainsUserCerts !== IssuingDistributionPoint.defaultValues("onlyContainsUserCerts")) + { + outputArray.push(new asn1js.Primitive({ + idBlock: { + tagClass: 3, // CONTEXT-SPECIFIC + tagNumber: 1 // [1] + }, + valueHex: (new Uint8Array([0xFF])).buffer + })); + } + + if(this.onlyContainsCACerts !== IssuingDistributionPoint.defaultValues("onlyContainsCACerts")) + { + outputArray.push(new asn1js.Primitive({ + idBlock: { + tagClass: 3, // CONTEXT-SPECIFIC + tagNumber: 2 // [2] + }, + valueHex: (new Uint8Array([0xFF])).buffer + })); + } + + if("onlySomeReasons" in this) + { + const buffer = new ArrayBuffer(1); + const view = new Uint8Array(buffer); + + view[0] = this.onlySomeReasons; + + outputArray.push(new asn1js.Primitive({ + idBlock: { + tagClass: 3, // CONTEXT-SPECIFIC + tagNumber: 3 // [3] + }, + valueHex: buffer + })); + } + + if(this.indirectCRL !== IssuingDistributionPoint.defaultValues("indirectCRL")) + { + outputArray.push(new asn1js.Primitive({ + idBlock: { + tagClass: 3, // CONTEXT-SPECIFIC + tagNumber: 4 // [4] + }, + valueHex: (new Uint8Array([0xFF])).buffer + })); + } + + if(this.onlyContainsAttributeCerts !== IssuingDistributionPoint.defaultValues("onlyContainsAttributeCerts")) + { + outputArray.push(new asn1js.Primitive({ + idBlock: { + tagClass: 3, // CONTEXT-SPECIFIC + tagNumber: 5 // [5] + }, + valueHex: (new Uint8Array([0xFF])).buffer + })); + } + //endregion + + //region Construct and return new ASN.1 schema for this object + return (new asn1js.Sequence({ + value: outputArray + })); + //endregion + } + //********************************************************************************** + /** + * Convertion for the class to JSON object + * @returns {Object} + */ + toJSON() + { + const object = {}; + + if("distributionPoint" in this) + { + if(this.distributionPoint instanceof Array) + object.distributionPoint = Array.from(this.distributionPoint, element => element.toJSON()); + else + object.distributionPoint = this.distributionPoint.toJSON(); + } + + if(this.onlyContainsUserCerts !== IssuingDistributionPoint.defaultValues("onlyContainsUserCerts")) + object.onlyContainsUserCerts = this.onlyContainsUserCerts; + + if(this.onlyContainsCACerts !== IssuingDistributionPoint.defaultValues("onlyContainsCACerts")) + object.onlyContainsCACerts = this.onlyContainsCACerts; + + if("onlySomeReasons" in this) + object.onlySomeReasons = this.onlySomeReasons; + + if(this.indirectCRL !== IssuingDistributionPoint.defaultValues("indirectCRL")) + object.indirectCRL = this.indirectCRL; + + if(this.onlyContainsAttributeCerts !== IssuingDistributionPoint.defaultValues("onlyContainsAttributeCerts")) + object.onlyContainsAttributeCerts = this.onlyContainsAttributeCerts; + + return object; + } + //********************************************************************************** +} +//************************************************************************************** diff --git a/core/third-party/pkijs/KEKIdentifier.js b/core/third-party/pkijs/KEKIdentifier.js new file mode 100644 index 0000000..c6f54f2 --- /dev/null +++ b/core/third-party/pkijs/KEKIdentifier.js @@ -0,0 +1,220 @@ +import * as asn1js from "./asn1.js"; +import { getParametersValue, clearProps } from "./pvutils.js"; +import OtherKeyAttribute from "./OtherKeyAttribute.js"; +//************************************************************************************** +/** + * Class from RFC5652 + */ +export default class KEKIdentifier +{ + //********************************************************************************** + /** + * Constructor for KEKIdentifier class + * @param {Object} [parameters={}] + * @param {Object} [parameters.schema] asn1js parsed value to initialize the class from + */ + constructor(parameters = {}) + { + //region Internal properties of the object + /** + * @type {OctetString} + * @desc keyIdentifier + */ + this.keyIdentifier = getParametersValue(parameters, "keyIdentifier", KEKIdentifier.defaultValues("keyIdentifier")); + + if("date" in parameters) + /** + * @type {GeneralizedTime} + * @desc date + */ + this.date = getParametersValue(parameters, "date", KEKIdentifier.defaultValues("date")); + if("other" in parameters) + /** + * @type {OtherKeyAttribute} + * @desc other + */ + this.other = getParametersValue(parameters, "other", KEKIdentifier.defaultValues("other")); + //endregion + + //region If input argument array contains "schema" for this object + if("schema" in parameters) + this.fromSchema(parameters.schema); + //endregion + } + //********************************************************************************** + /** + * Return default values for all class members + * @param {string} memberName String name for a class member + */ + static defaultValues(memberName) + { + switch(memberName) + { + case "keyIdentifier": + return new asn1js.OctetString(); + case "date": + return new asn1js.GeneralizedTime(); + case "other": + return new OtherKeyAttribute(); + default: + throw new Error(`Invalid member name for KEKIdentifier class: ${memberName}`); + } + } + //********************************************************************************** + /** + * Compare values with default values for all class members + * @param {string} memberName String name for a class member + * @param {*} memberValue Value to compare with default value + */ + static compareWithDefault(memberName, memberValue) + { + switch(memberName) + { + case "keyIdentifier": + return (memberValue.isEqual(KEKIdentifier.defaultValues("keyIdentifier"))); + case "date": + // noinspection OverlyComplexBooleanExpressionJS + return ((memberValue.year === 0) && + (memberValue.month === 0) && + (memberValue.day === 0) && + (memberValue.hour === 0) && + (memberValue.minute === 0) && + (memberValue.second === 0) && + (memberValue.millisecond === 0)); + case "other": + return ((memberValue.compareWithDefault("keyAttrId", memberValue.keyAttrId)) && + (("keyAttr" in memberValue) === false)); + default: + throw new Error(`Invalid member name for KEKIdentifier class: ${memberName}`); + } + } + //********************************************************************************** + /** + * Return value of pre-defined ASN.1 schema for current class + * + * ASN.1 schema: + * ```asn1 + * KEKIdentifier ::= SEQUENCE { + * keyIdentifier OCTET STRING, + * date GeneralizedTime OPTIONAL, + * other OtherKeyAttribute OPTIONAL } + * ``` + * + * @param {Object} parameters Input parameters for the schema + * @returns {Object} asn1js schema object + */ + static schema(parameters = {}) + { + /** + * @type {Object} + * @property {string} [blockName] + * @property {string} [keyIdentifier] + * @property {string} [date] + * @property {string} [other] + */ + const names = getParametersValue(parameters, "names", {}); + + return (new asn1js.Sequence({ + name: (names.blockName || ""), + value: [ + new asn1js.OctetString({ name: (names.keyIdentifier || "") }), + new asn1js.GeneralizedTime({ + optional: true, + name: (names.date || "") + }), + OtherKeyAttribute.schema(names.other || {}) + ] + })); + } + //********************************************************************************** + /** + * Convert parsed asn1js object into current class + * @param {!Object} schema + */ + fromSchema(schema) + { + //region Clear input data first + clearProps(schema, [ + "keyIdentifier", + "date", + "other" + ]); + //endregion + + //region Check the schema is valid + const asn1 = asn1js.compareSchema(schema, + schema, + KEKIdentifier.schema({ + names: { + keyIdentifier: "keyIdentifier", + date: "date", + other: { + names: { + blockName: "other" + } + } + } + }) + ); + + if(asn1.verified === false) + throw new Error("Object's schema was not verified against input data for KEKIdentifier"); + //endregion + + //region Get internal properties from parsed schema + this.keyIdentifier = asn1.result.keyIdentifier; + + if("date" in asn1.result) + this.date = asn1.result.date; + + if("other" in asn1.result) + this.other = new OtherKeyAttribute({ schema: asn1.result.other }); + //endregion + } + //********************************************************************************** + /** + * Convert current object to asn1js object and set correct values + * @returns {Object} asn1js object + */ + toSchema() + { + //region Create array for output sequence + const outputArray = []; + + outputArray.push(this.keyIdentifier); + + if("date" in this) + outputArray.push(this.date); + + if("other" in this) + outputArray.push(this.other.toSchema()); + //endregion + + //region Construct and return new ASN.1 schema for this object + return (new asn1js.Sequence({ + value: outputArray + })); + //endregion + } + //********************************************************************************** + /** + * Convertion for the class to JSON object + * @returns {Object} + */ + toJSON() + { + const _object = { + keyIdentifier: this.keyIdentifier.toJSON() + }; + + if("date" in this) + _object.date = this.date; + + if("other" in this) + _object.other = this.other.toJSON(); + + return _object; + } + //********************************************************************************** +} +//************************************************************************************** diff --git a/core/third-party/pkijs/KEKRecipientInfo.js b/core/third-party/pkijs/KEKRecipientInfo.js new file mode 100644 index 0000000..8f6656d --- /dev/null +++ b/core/third-party/pkijs/KEKRecipientInfo.js @@ -0,0 +1,221 @@ +import * as asn1js from "./asn1.js"; +import { getParametersValue, clearProps } from "./pvutils.js"; +import KEKIdentifier from "./KEKIdentifier.js"; +import AlgorithmIdentifier from "./AlgorithmIdentifier.js"; +//************************************************************************************** +/** + * Class from RFC5652 + */ +export default class KEKRecipientInfo +{ + //********************************************************************************** + /** + * Constructor for KEKRecipientInfo class + * @param {Object} [parameters={}] + * @param {Object} [parameters.schema] asn1js parsed value to initialize the class from + */ + constructor(parameters = {}) + { + //region Internal properties of the object + /** + * @type {number} + * @desc version + */ + this.version = getParametersValue(parameters, "version", KEKRecipientInfo.defaultValues("version")); + /** + * @type {KEKIdentifier} + * @desc kekid + */ + this.kekid = getParametersValue(parameters, "kekid", KEKRecipientInfo.defaultValues("kekid")); + /** + * @type {AlgorithmIdentifier} + * @desc keyEncryptionAlgorithm + */ + this.keyEncryptionAlgorithm = getParametersValue(parameters, "keyEncryptionAlgorithm", KEKRecipientInfo.defaultValues("keyEncryptionAlgorithm")); + /** + * @type {OctetString} + * @desc encryptedKey + */ + this.encryptedKey = getParametersValue(parameters, "encryptedKey", KEKRecipientInfo.defaultValues("encryptedKey")); + /** + * @type {ArrayBuffer} + * @desc preDefinedKEK KEK using to encrypt CEK + */ + this.preDefinedKEK = getParametersValue(parameters, "preDefinedKEK", KEKRecipientInfo.defaultValues("preDefinedKEK")); + //endregion + + //region If input argument array contains "schema" for this object + if("schema" in parameters) + this.fromSchema(parameters.schema); + //endregion + } + //********************************************************************************** + /** + * Return default values for all class members + * @param {string} memberName String name for a class member + */ + static defaultValues(memberName) + { + switch(memberName) + { + case "version": + return 0; + case "kekid": + return new KEKIdentifier(); + case "keyEncryptionAlgorithm": + return new AlgorithmIdentifier(); + case "encryptedKey": + return new asn1js.OctetString(); + case "preDefinedKEK": + return new ArrayBuffer(0); + default: + throw new Error(`Invalid member name for KEKRecipientInfo class: ${memberName}`); + } + } + //********************************************************************************** + /** + * Compare values with default values for all class members + * @param {string} memberName String name for a class member + * @param {*} memberValue Value to compare with default value + */ + static compareWithDefault(memberName, memberValue) + { + switch(memberName) + { + case "KEKRecipientInfo": + return (memberValue === KEKRecipientInfo.defaultValues("version")); + case "kekid": + return ((memberValue.compareWithDefault("keyIdentifier", memberValue.keyIdentifier)) && + (("date" in memberValue) === false) && + (("other" in memberValue) === false)); + case "keyEncryptionAlgorithm": + return ((memberValue.algorithmId === "") && (("algorithmParams" in memberValue) === false)); + case "encryptedKey": + return (memberValue.isEqual(KEKRecipientInfo.defaultValues("encryptedKey"))); + case "preDefinedKEK": + return (memberValue.byteLength === 0); + default: + throw new Error(`Invalid member name for KEKRecipientInfo class: ${memberName}`); + } + } + //********************************************************************************** + /** + * Return value of pre-defined ASN.1 schema for current class + * + * ASN.1 schema: + * ```asn1 + * KEKRecipientInfo ::= SEQUENCE { + * version CMSVersion, -- always set to 4 + * kekid KEKIdentifier, + * keyEncryptionAlgorithm KeyEncryptionAlgorithmIdentifier, + * encryptedKey EncryptedKey } + * ``` + * + * @param {Object} parameters Input parameters for the schema + * @returns {Object} asn1js schema object + */ + static schema(parameters = {}) + { + /** + * @type {Object} + * @property {string} [blockName] + * @property {string} [version] + * @property {string} [kekid] + * @property {string} [keyEncryptionAlgorithm] + * @property {string} [encryptedKey] + */ + const names = getParametersValue(parameters, "names", {}); + + return (new asn1js.Sequence({ + name: (names.blockName || ""), + value: [ + new asn1js.Integer({ name: (names.version || "") }), + KEKIdentifier.schema(names.kekid || {}), + AlgorithmIdentifier.schema(names.keyEncryptionAlgorithm || {}), + new asn1js.OctetString({ name: (names.encryptedKey || "") }) + ] + })); + } + //********************************************************************************** + /** + * Convert parsed asn1js object into current class + * @param {!Object} schema + */ + fromSchema(schema) + { + //region Clear input data first + clearProps(schema, [ + "version", + "kekid", + "keyEncryptionAlgorithm", + "encryptedKey" + ]); + //endregion + + //region Check the schema is valid + const asn1 = asn1js.compareSchema(schema, + schema, + KEKRecipientInfo.schema({ + names: { + version: "version", + kekid: { + names: { + blockName: "kekid" + } + }, + keyEncryptionAlgorithm: { + names: { + blockName: "keyEncryptionAlgorithm" + } + }, + encryptedKey: "encryptedKey" + } + }) + ); + + if(asn1.verified === false) + throw new Error("Object's schema was not verified against input data for KEKRecipientInfo"); + //endregion + + //region Get internal properties from parsed schema + this.version = asn1.result.version.valueBlock.valueDec; + this.kekid = new KEKIdentifier({ schema: asn1.result.kekid }); + this.keyEncryptionAlgorithm = new AlgorithmIdentifier({ schema: asn1.result.keyEncryptionAlgorithm }); + this.encryptedKey = asn1.result.encryptedKey; + //endregion + } + //********************************************************************************** + /** + * Convert current object to asn1js object and set correct values + * @returns {Object} asn1js object + */ + toSchema() + { + //region Construct and return new ASN.1 schema for this object + return (new asn1js.Sequence({ + value: [ + new asn1js.Integer({ value: this.version }), + this.kekid.toSchema(), + this.keyEncryptionAlgorithm.toSchema(), + this.encryptedKey + ] + })); + //endregion + } + //********************************************************************************** + /** + * Convertion for the class to JSON object + * @returns {Object} + */ + toJSON() + { + return { + version: this.version, + kekid: this.kekid.toJSON(), + keyEncryptionAlgorithm: this.keyEncryptionAlgorithm.toJSON(), + encryptedKey: this.encryptedKey.toJSON() + }; + } + //********************************************************************************** +} +//************************************************************************************** diff --git a/core/third-party/pkijs/KeyAgreeRecipientIdentifier.js b/core/third-party/pkijs/KeyAgreeRecipientIdentifier.js new file mode 100644 index 0000000..d5fd1eb --- /dev/null +++ b/core/third-party/pkijs/KeyAgreeRecipientIdentifier.js @@ -0,0 +1,206 @@ +import * as asn1js from "./asn1.js"; +import { getParametersValue, clearProps } from "./pvutils.js"; +import IssuerAndSerialNumber from "./IssuerAndSerialNumber.js"; +import RecipientKeyIdentifier from "./RecipientKeyIdentifier.js"; +//************************************************************************************** +/** + * Class from RFC5652 + */ +export default class KeyAgreeRecipientIdentifier +{ + //********************************************************************************** + /** + * Constructor for KeyAgreeRecipientIdentifier class + * @param {Object} [parameters={}] + * @param {Object} [parameters.schema] asn1js parsed value to initialize the class from + */ + constructor(parameters = {}) + { + //region Internal properties of the object + /** + * @type {number} + * @desc variant + */ + this.variant = getParametersValue(parameters, "variant", KeyAgreeRecipientIdentifier.defaultValues("variant")); + /** + * @type {*} + * @desc values + */ + this.value = getParametersValue(parameters, "value", KeyAgreeRecipientIdentifier.defaultValues("value")); + //endregion + + //region If input argument array contains "schema" for this object + if("schema" in parameters) + this.fromSchema(parameters.schema); + //endregion + } + //********************************************************************************** + /** + * Return default values for all class members + * @param {string} memberName String name for a class member + */ + static defaultValues(memberName) + { + switch(memberName) + { + case "variant": + return (-1); + case "value": + return {}; + default: + throw new Error(`Invalid member name for KeyAgreeRecipientIdentifier class: ${memberName}`); + } + } + //********************************************************************************** + /** + * Compare values with default values for all class members + * @param {string} memberName String name for a class member + * @param {*} memberValue Value to compare with default value + */ + static compareWithDefault(memberName, memberValue) + { + switch(memberName) + { + case "variant": + return (memberValue === (-1)); + case "value": + return (Object.keys(memberValue).length === 0); + default: + throw new Error(`Invalid member name for KeyAgreeRecipientIdentifier class: ${memberName}`); + } + } + //********************************************************************************** + /** + * Return value of pre-defined ASN.1 schema for current class + * + * ASN.1 schema: + * ```asn1 + * KeyAgreeRecipientIdentifier ::= CHOICE { + * issuerAndSerialNumber IssuerAndSerialNumber, + * rKeyId [0] IMPLICIT RecipientKeyIdentifier } + * ``` + * + * @param {Object} parameters Input parameters for the schema + * @returns {Object} asn1js schema object + */ + static schema(parameters = {}) + { + /** + * @type {Object} + * @property {string} [blockName] + * @property {string} [issuerAndSerialNumber] + * @property {string} [rKeyId] + */ + const names = getParametersValue(parameters, "names", {}); + + return (new asn1js.Choice({ + value: [ + IssuerAndSerialNumber.schema(names.issuerAndSerialNumber || { + names: { + blockName: (names.blockName || "") + } + }), + new asn1js.Constructed({ + name: (names.blockName || ""), + idBlock: { + tagClass: 3, // CONTEXT-SPECIFIC + tagNumber: 0 // [0] + }, + value: RecipientKeyIdentifier.schema(names.rKeyId || { + names: { + blockName: (names.blockName || "") + } + }).valueBlock.value + }) + ] + })); + } + //********************************************************************************** + /** + * Convert parsed asn1js object into current class + * @param {!Object} schema + */ + fromSchema(schema) + { + //region Clear input data first + clearProps(schema, [ + "blockName" + ]); + //endregion + + //region Check the schema is valid + const asn1 = asn1js.compareSchema(schema, + schema, + KeyAgreeRecipientIdentifier.schema({ + names: { + blockName: "blockName" + } + }) + ); + + if(asn1.verified === false) + throw new Error("Object's schema was not verified against input data for KeyAgreeRecipientIdentifier"); + //endregion + + //region Get internal properties from parsed schema + if(asn1.result.blockName.idBlock.tagClass === 1) + { + this.variant = 1; + this.value = new IssuerAndSerialNumber({ schema: asn1.result.blockName }); + } + else + { + this.variant = 2; + + this.value = new RecipientKeyIdentifier({ + schema: new asn1js.Sequence({ + value: asn1.result.blockName.valueBlock.value + }) + }); + } + //endregion + } + //********************************************************************************** + /** + * Convert current object to asn1js object and set correct values + * @returns {Object} asn1js object + */ + toSchema() + { + //region Construct and return new ASN.1 schema for this object + switch(this.variant) + { + case 1: + return this.value.toSchema(); + case 2: + return new asn1js.Constructed({ + idBlock: { + tagClass: 3, // CONTEXT-SPECIFIC + tagNumber: 0 // [0] + }, + value: this.value.toSchema().valueBlock.value + }); + default: + return new asn1js.Any(); + } + //endregion + } + //********************************************************************************** + /** + * Convertion for the class to JSON object + * @returns {Object} + */ + toJSON() + { + const _object = { + variant: this.variant + }; + + if((this.variant === 1) || (this.variant === 2)) + _object.value = this.value.toJSON(); + + return _object; + } + //********************************************************************************** +} +//************************************************************************************** diff --git a/core/third-party/pkijs/KeyAgreeRecipientInfo.js b/core/third-party/pkijs/KeyAgreeRecipientInfo.js new file mode 100644 index 0000000..4fe4585 --- /dev/null +++ b/core/third-party/pkijs/KeyAgreeRecipientInfo.js @@ -0,0 +1,290 @@ +import * as asn1js from "./asn1.js"; +import { getParametersValue, clearProps } from "./pvutils.js"; +import OriginatorIdentifierOrKey from "./OriginatorIdentifierOrKey.js"; +import AlgorithmIdentifier from "./AlgorithmIdentifier.js"; +import RecipientEncryptedKeys from "./RecipientEncryptedKeys.js"; +import Certificate from "./Certificate.js"; +//************************************************************************************** +/** + * Class from RFC5652 + */ +export default class KeyAgreeRecipientInfo +{ + //********************************************************************************** + /** + * Constructor for KeyAgreeRecipientInfo class + * @param {Object} [parameters={}] + * @param {Object} [parameters.schema] asn1js parsed value to initialize the class from + */ + constructor(parameters = {}) + { + //region Internal properties of the object + /** + * @type {number} + * @desc version + */ + this.version = getParametersValue(parameters, "version", KeyAgreeRecipientInfo.defaultValues("version")); + /** + * @type {OriginatorIdentifierOrKey} + * @desc originator + */ + this.originator = getParametersValue(parameters, "originator", KeyAgreeRecipientInfo.defaultValues("originator")); + + if("ukm" in parameters) + /** + * @type {OctetString} + * @desc ukm + */ + this.ukm = getParametersValue(parameters, "ukm", KeyAgreeRecipientInfo.defaultValues("ukm")); + + /** + * @type {AlgorithmIdentifier} + * @desc keyEncryptionAlgorithm + */ + this.keyEncryptionAlgorithm = getParametersValue(parameters, "keyEncryptionAlgorithm", KeyAgreeRecipientInfo.defaultValues("keyEncryptionAlgorithm")); + /** + * @type {RecipientEncryptedKeys} + * @desc recipientEncryptedKeys + */ + this.recipientEncryptedKeys = getParametersValue(parameters, "recipientEncryptedKeys", KeyAgreeRecipientInfo.defaultValues("recipientEncryptedKeys")); + /** + * @type {Certificate} + * @desc recipientCertificate For some reasons we need to store recipient's certificate here + */ + this.recipientCertificate = getParametersValue(parameters, "recipientCertificate", KeyAgreeRecipientInfo.defaultValues("recipientCertificate")); + //endregion + + //region If input argument array contains "schema" for this object + if("schema" in parameters) + this.fromSchema(parameters.schema); + //endregion + } + //********************************************************************************** + /** + * Return default values for all class members + * @param {string} memberName String name for a class member + */ + static defaultValues(memberName) + { + switch(memberName) + { + case "version": + return 0; + case "originator": + return new OriginatorIdentifierOrKey(); + case "ukm": + return new asn1js.OctetString(); + case "keyEncryptionAlgorithm": + return new AlgorithmIdentifier(); + case "recipientEncryptedKeys": + return new RecipientEncryptedKeys(); + case "recipientCertificate": + return new Certificate(); + default: + throw new Error(`Invalid member name for KeyAgreeRecipientInfo class: ${memberName}`); + } + } + //********************************************************************************** + /** + * Compare values with default values for all class members + * @param {string} memberName String name for a class member + * @param {*} memberValue Value to compare with default value + */ + static compareWithDefault(memberName, memberValue) + { + switch(memberName) + { + case "version": + return (memberValue === 0); + case "originator": + return ((memberValue.variant === (-1)) && (("value" in memberValue) === false)); + case "ukm": + return (memberValue.isEqual(KeyAgreeRecipientInfo.defaultValues("ukm"))); + case "keyEncryptionAlgorithm": + return ((memberValue.algorithmId === "") && (("algorithmParams" in memberValue) === false)); + case "recipientEncryptedKeys": + return (memberValue.encryptedKeys.length === 0); + case "recipientCertificate": + return false; // For now leave it as is + default: + throw new Error(`Invalid member name for KeyAgreeRecipientInfo class: ${memberName}`); + } + } + //********************************************************************************** + /** + * Return value of pre-defined ASN.1 schema for current class + * + * ASN.1 schema: + * ```asn1 + * KeyAgreeRecipientInfo ::= SEQUENCE { + * version CMSVersion, -- always set to 3 + * originator [0] EXPLICIT OriginatorIdentifierOrKey, + * ukm [1] EXPLICIT UserKeyingMaterial OPTIONAL, + * keyEncryptionAlgorithm KeyEncryptionAlgorithmIdentifier, + * recipientEncryptedKeys RecipientEncryptedKeys } + * ``` + * + * @param {Object} parameters Input parameters for the schema + * @returns {Object} asn1js schema object + */ + static schema(parameters = {}) + { + /** + * @type {Object} + * @property {string} [blockName] + * @property {string} [version] + * @property {string} [originator] + * @property {string} [ukm] + * @property {string} [keyEncryptionAlgorithm] + * @property {string} [recipientEncryptedKeys] + */ + const names = getParametersValue(parameters, "names", {}); + + return (new asn1js.Sequence({ + name: names.blockName || "", + value: [ + new asn1js.Integer({ name: names.version || "" }), + new asn1js.Constructed({ + idBlock: { + tagClass: 3, // CONTEXT-SPECIFIC + tagNumber: 0 // [0] + }, + value: [ + OriginatorIdentifierOrKey.schema(names.originator || {}) + ] + }), + new asn1js.Constructed({ + optional: true, + idBlock: { + tagClass: 3, // CONTEXT-SPECIFIC + tagNumber: 1 // [1] + }, + value: [new asn1js.OctetString({ name: names.ukm || "" })] + }), + AlgorithmIdentifier.schema(names.keyEncryptionAlgorithm || {}), + RecipientEncryptedKeys.schema(names.recipientEncryptedKeys || {}) + ] + })); + } + //********************************************************************************** + /** + * Convert parsed asn1js object into current class + * @param {!Object} schema + */ + fromSchema(schema) + { + //region Clear input data first + clearProps(schema, [ + "version", + "originator", + "ukm", + "keyEncryptionAlgorithm", + "recipientEncryptedKeys" + ]); + //endregion + + //region Check the schema is valid + const asn1 = asn1js.compareSchema(schema, + schema, + KeyAgreeRecipientInfo.schema({ + names: { + version: "version", + originator: { + names: { + blockName: "originator" + } + }, + ukm: "ukm", + keyEncryptionAlgorithm: { + names: { + blockName: "keyEncryptionAlgorithm" + } + }, + recipientEncryptedKeys: { + names: { + blockName: "recipientEncryptedKeys" + } + } + } + }) + ); + + if(asn1.verified === false) + throw new Error("Object's schema was not verified against input data for KeyAgreeRecipientInfo"); + //endregion + + //region Get internal properties from parsed schema + this.version = asn1.result.version.valueBlock.valueDec; + this.originator = new OriginatorIdentifierOrKey({ schema: asn1.result.originator }); + + if("ukm" in asn1.result) + this.ukm = asn1.result.ukm; + + this.keyEncryptionAlgorithm = new AlgorithmIdentifier({ schema: asn1.result.keyEncryptionAlgorithm }); + this.recipientEncryptedKeys = new RecipientEncryptedKeys({ schema: asn1.result.recipientEncryptedKeys }); + //endregion + } + //********************************************************************************** + /** + * Convert current object to asn1js object and set correct values + * @returns {Object} asn1js object + */ + toSchema() + { + //region Create array for final sequence + const outputArray = []; + + outputArray.push(new asn1js.Integer({ value: this.version })); + outputArray.push(new asn1js.Constructed({ + idBlock: { + tagClass: 3, // CONTEXT-SPECIFIC + tagNumber: 0 // [0] + }, + value: [this.originator.toSchema()] + })); + + if("ukm" in this) + { + outputArray.push(new asn1js.Constructed({ + optional: true, + idBlock: { + tagClass: 3, // CONTEXT-SPECIFIC + tagNumber: 1 // [1] + }, + value: [this.ukm] + })); + } + + outputArray.push(this.keyEncryptionAlgorithm.toSchema()); + outputArray.push(this.recipientEncryptedKeys.toSchema()); + //endregion + + //region Construct and return new ASN.1 schema for this object + return (new asn1js.Sequence({ + value: outputArray + })); + //endregion + } + //********************************************************************************** + /** + * Convertion for the class to JSON object + * @returns {Object} + */ + toJSON() + { + const _object = { + version: this.version, + originator: this.originator.toJSON() + }; + + if("ukm" in this) + _object.ukm = this.ukm.toJSON(); + + _object.keyEncryptionAlgorithm = this.keyEncryptionAlgorithm.toJSON(); + _object.recipientEncryptedKeys = this.recipientEncryptedKeys.toJSON(); + + return _object; + } + //********************************************************************************** +} +//************************************************************************************** diff --git a/core/third-party/pkijs/KeyBag.js b/core/third-party/pkijs/KeyBag.js new file mode 100644 index 0000000..e90ce52 --- /dev/null +++ b/core/third-party/pkijs/KeyBag.js @@ -0,0 +1,20 @@ +import PrivateKeyInfo from "./PrivateKeyInfo.js"; +//************************************************************************************** +/** + * Class from RFC5208 + */ +export default class KeyBag extends PrivateKeyInfo +{ + //********************************************************************************** + /** + * Constructor for Attribute class + * @param {Object} [parameters={}] + * @param {Object} [parameters.schema] asn1js parsed value to initialize the class from + */ + constructor(parameters = {}) + { + super(parameters); + } + //********************************************************************************** +} +//************************************************************************************** diff --git a/core/third-party/pkijs/KeyTransRecipientInfo.js b/core/third-party/pkijs/KeyTransRecipientInfo.js new file mode 100644 index 0000000..b579327 --- /dev/null +++ b/core/third-party/pkijs/KeyTransRecipientInfo.js @@ -0,0 +1,248 @@ +import * as asn1js from "./asn1.js"; +import { getParametersValue, clearProps } from "./pvutils.js"; +import AlgorithmIdentifier from "./AlgorithmIdentifier.js"; +import Certificate from "./Certificate.js"; +import RecipientIdentifier from "./RecipientIdentifier.js"; +import IssuerAndSerialNumber from "./IssuerAndSerialNumber.js"; +//************************************************************************************** +/** + * Class from RFC5652 + */ +export default class KeyTransRecipientInfo +{ + //********************************************************************************** + /** + * Constructor for KeyTransRecipientInfo class + * @param {Object} [parameters={}] + * @param {Object} [parameters.schema] asn1js parsed value to initialize the class from + */ + constructor(parameters = {}) + { + //region Internal properties of the object + /** + * @type {number} + * @desc version + */ + this.version = getParametersValue(parameters, "version", KeyTransRecipientInfo.defaultValues("version")); + /** + * @type {RecipientIdentifier} + * @desc rid + */ + this.rid = getParametersValue(parameters, "rid", KeyTransRecipientInfo.defaultValues("rid")); + /** + * @type {AlgorithmIdentifier} + * @desc keyEncryptionAlgorithm + */ + this.keyEncryptionAlgorithm = getParametersValue(parameters, "keyEncryptionAlgorithm", KeyTransRecipientInfo.defaultValues("keyEncryptionAlgorithm")); + /** + * @type {OctetString} + * @desc encryptedKey + */ + this.encryptedKey = getParametersValue(parameters, "encryptedKey", KeyTransRecipientInfo.defaultValues("encryptedKey")); + /** + * @type {Certificate} + * @desc recipientCertificate For some reasons we need to store recipient's certificate here + */ + this.recipientCertificate = getParametersValue(parameters, "recipientCertificate", KeyTransRecipientInfo.defaultValues("recipientCertificate")); + //endregion + + //region If input argument array contains "schema" for this object + if("schema" in parameters) + this.fromSchema(parameters.schema); + //endregion + } + //********************************************************************************** + /** + * Return default values for all class members + * @param {string} memberName String name for a class member + */ + static defaultValues(memberName) + { + switch(memberName) + { + case "version": + return (-1); + case "rid": + return {}; + case "keyEncryptionAlgorithm": + return new AlgorithmIdentifier(); + case "encryptedKey": + return new asn1js.OctetString(); + case "recipientCertificate": + return new Certificate(); + default: + throw new Error(`Invalid member name for KeyTransRecipientInfo class: ${memberName}`); + } + } + //********************************************************************************** + /** + * Compare values with default values for all class members + * @param {string} memberName String name for a class member + * @param {*} memberValue Value to compare with default value + */ + static compareWithDefault(memberName, memberValue) + { + switch(memberName) + { + case "version": + return (memberValue === KeyTransRecipientInfo.defaultValues("version")); + case "rid": + return (Object.keys(memberValue).length === 0); + case "keyEncryptionAlgorithm": + case "encryptedKey": + return memberValue.isEqual(KeyTransRecipientInfo.defaultValues(memberName)); + case "recipientCertificate": + return false; // For now we do not need to compare any values with the "recipientCertificate" + default: + throw new Error(`Invalid member name for KeyTransRecipientInfo class: ${memberName}`); + } + } + //********************************************************************************** + /** + * Return value of pre-defined ASN.1 schema for current class + * + * ASN.1 schema: + * ```asn1 + * KeyTransRecipientInfo ::= SEQUENCE { + * version CMSVersion, -- always set to 0 or 2 + * rid RecipientIdentifier, + * keyEncryptionAlgorithm KeyEncryptionAlgorithmIdentifier, + * encryptedKey EncryptedKey } + * ``` + * + * @param {Object} parameters Input parameters for the schema + * @returns {Object} asn1js schema object + */ + static schema(parameters = {}) + { + /** + * @type {Object} + * @property {string} [blockName] + * @property {string} [version] + * @property {string} [rid] + * @property {string} [keyEncryptionAlgorithm] + * @property {string} [encryptedKey] + */ + const names = getParametersValue(parameters, "names", {}); + + return (new asn1js.Sequence({ + name: (names.blockName || ""), + value: [ + new asn1js.Integer({ name: (names.version || "") }), + RecipientIdentifier.schema(names.rid || {}), + AlgorithmIdentifier.schema(names.keyEncryptionAlgorithm || {}), + new asn1js.OctetString({ name: (names.encryptedKey || "") }) + ] + })); + } + //********************************************************************************** + /** + * Convert parsed asn1js object into current class + * @param {!Object} schema + */ + fromSchema(schema) + { + //region Clear input data first + clearProps(schema, [ + "version", + "rid", + "keyEncryptionAlgorithm", + "encryptedKey" + ]); + //endregion + + //region Check the schema is valid + const asn1 = asn1js.compareSchema(schema, + schema, + KeyTransRecipientInfo.schema({ + names: { + version: "version", + rid: { + names: { + blockName: "rid" + } + }, + keyEncryptionAlgorithm: { + names: { + blockName: "keyEncryptionAlgorithm" + } + }, + encryptedKey: "encryptedKey" + } + }) + ); + + if(asn1.verified === false) + throw new Error("Object's schema was not verified against input data for KeyTransRecipientInfo"); + //endregion + + //region Get internal properties from parsed schema + this.version = asn1.result.version.valueBlock.valueDec; + + if(asn1.result.rid.idBlock.tagClass === 3) + this.rid = new asn1js.OctetString({ valueHex: asn1.result.rid.valueBlock.valueHex }); // SubjectKeyIdentifier + else + this.rid = new IssuerAndSerialNumber({ schema: asn1.result.rid }); + + this.keyEncryptionAlgorithm = new AlgorithmIdentifier({ schema: asn1.result.keyEncryptionAlgorithm }); + this.encryptedKey = asn1.result.encryptedKey; + //endregion + } + //********************************************************************************** + /** + * Convert current object to asn1js object and set correct values + * @returns {Object} asn1js object + */ + toSchema() + { + //region Create array for output sequence + const outputArray = []; + + if(this.rid instanceof IssuerAndSerialNumber) + { + this.version = 0; + + outputArray.push(new asn1js.Integer({ value: this.version })); + outputArray.push(this.rid.toSchema()); + } + else + { + this.version = 2; + + outputArray.push(new asn1js.Integer({ value: this.version })); + outputArray.push(new asn1js.Primitive({ + idBlock: { + tagClass: 3, // CONTEXT-SPECIFIC + tagNumber: 0 // [0] + }, + valueHex: this.rid.valueBlock.valueHex + })); + } + + outputArray.push(this.keyEncryptionAlgorithm.toSchema()); + outputArray.push(this.encryptedKey); + //endregion + + //region Construct and return new ASN.1 schema for this object + return (new asn1js.Sequence({ + value: outputArray + })); + //endregion + } + //********************************************************************************** + /** + * Convertion for the class to JSON object + * @returns {Object} + */ + toJSON() + { + return { + version: this.version, + rid: this.rid.toJSON(), + keyEncryptionAlgorithm: this.keyEncryptionAlgorithm.toJSON(), + encryptedKey: this.encryptedKey.toJSON() + }; + } + //********************************************************************************** +} +//************************************************************************************** diff --git a/core/third-party/pkijs/MacData.js b/core/third-party/pkijs/MacData.js new file mode 100644 index 0000000..fd6795a --- /dev/null +++ b/core/third-party/pkijs/MacData.js @@ -0,0 +1,214 @@ +import * as asn1js from "./asn1.js"; +import { getParametersValue, clearProps } from "./pvutils.js"; +import DigestInfo from "./DigestInfo.js"; +//************************************************************************************** +/** + * Class from RFC7292 + */ +export default class MacData +{ + //********************************************************************************** + /** + * Constructor for MacData class + * @param {Object} [parameters={}] + * @param {Object} [parameters.schema] asn1js parsed value to initialize the class from + */ + constructor(parameters = {}) + { + //region Internal properties of the object + /** + * @type {DigestInfo} + * @desc mac + */ + this.mac = getParametersValue(parameters, "mac", MacData.defaultValues("mac")); + /** + * @type {OctetString} + * @desc macSalt + */ + this.macSalt = getParametersValue(parameters, "macSalt", MacData.defaultValues("macSalt")); + + if("iterations" in parameters) + /** + * @type {number} + * @desc iterations + */ + this.iterations = getParametersValue(parameters, "iterations", MacData.defaultValues("iterations")); + //endregion + + //region If input argument array contains "schema" for this object + if("schema" in parameters) + this.fromSchema(parameters.schema); + //endregion + } + //********************************************************************************** + /** + * Return default values for all class members + * @param {string} memberName String name for a class member + */ + static defaultValues(memberName) + { + switch(memberName) + { + case "mac": + return new DigestInfo(); + case "macSalt": + return new asn1js.OctetString(); + case "iterations": + return 1; + default: + throw new Error(`Invalid member name for MacData class: ${memberName}`); + } + } + //********************************************************************************** + /** + * Compare values with default values for all class members + * @param {string} memberName String name for a class member + * @param {*} memberValue Value to compare with default value + */ + static compareWithDefault(memberName, memberValue) + { + switch(memberName) + { + case "mac": + return ((DigestInfo.compareWithDefault("digestAlgorithm", memberValue.digestAlgorithm)) && + (DigestInfo.compareWithDefault("digest", memberValue.digest))); + case "macSalt": + return (memberValue.isEqual(MacData.defaultValues(memberName))); + case "iterations": + return (memberValue === MacData.defaultValues(memberName)); + default: + throw new Error(`Invalid member name for MacData class: ${memberName}`); + } + } + //********************************************************************************** + /** + * Return value of pre-defined ASN.1 schema for current class + * + * ASN.1 schema: + * ```asn1 + * MacData ::= SEQUENCE { + * mac DigestInfo, + * macSalt OCTET STRING, + * iterations INTEGER DEFAULT 1 + * -- Note: The default is for historical reasons and its use is + * -- deprecated. A higher value, like 1024 is recommended. + * } + * ``` + * + * @param {Object} parameters Input parameters for the schema + * @returns {Object} asn1js schema object + */ + static schema(parameters = {}) + { + + /** + * @type {Object} + * @property {string} [blockName] + * @property {string} [optional] + * @property {string} [mac] + * @property {string} [macSalt] + * @property {string} [iterations] + */ + const names = getParametersValue(parameters, "names", {}); + + return (new asn1js.Sequence({ + name: (names.blockName || ""), + optional: (names.optional || true), + value: [ + DigestInfo.schema(names.mac || { + names: { + blockName: "mac" + } + }), + new asn1js.OctetString({ name: (names.macSalt || "macSalt") }), + new asn1js.Integer({ + optional: true, + name: (names.iterations || "iterations") + }) + ] + })); + } + //********************************************************************************** + /** + * Convert parsed asn1js object into current class + * @param {!Object} schema + */ + fromSchema(schema) + { + //region Clear input data first + clearProps(schema, [ + "mac", + "macSalt", + "iterations" + ]); + //endregion + + //region Check the schema is valid + const asn1 = asn1js.compareSchema(schema, + schema, + MacData.schema({ + names: { + mac: { + names: { + blockName: "mac" + } + }, + macSalt: "macSalt", + iterations: "iterations" + } + }) + ); + + if(asn1.verified === false) + throw new Error("Object's schema was not verified against input data for MacData"); + //endregion + + //region Get internal properties from parsed schema + this.mac = new DigestInfo({ schema: asn1.result.mac }); + this.macSalt = asn1.result.macSalt; + + if("iterations" in asn1.result) + this.iterations = asn1.result.iterations.valueBlock.valueDec; + //endregion + } + //********************************************************************************** + /** + * Convert current object to asn1js object and set correct values + * @returns {Object} asn1js object + */ + toSchema() + { + //region Construct and return new ASN.1 schema for this object + const outputArray = [ + this.mac.toSchema(), + this.macSalt + ]; + + if("iterations" in this) + outputArray.push(new asn1js.Integer({ value: this.iterations })); + + return (new asn1js.Sequence({ + value: outputArray + })); + //endregion + } + //********************************************************************************** + /** + * Convertion for the class to JSON object + * @returns {Object} + */ + toJSON() + { + const output = { + mac: this.mac.toJSON(), + macSalt: this.macSalt.toJSON() + }; + + if("iterations" in this) + output.iterations = this.iterations.toJSON(); + + return output; + } + //********************************************************************************** +} +//************************************************************************************** diff --git a/core/third-party/pkijs/MessageImprint.js b/core/third-party/pkijs/MessageImprint.js new file mode 100644 index 0000000..cae62f1 --- /dev/null +++ b/core/third-party/pkijs/MessageImprint.js @@ -0,0 +1,171 @@ +import * as asn1js from "./asn1.js"; +import { getParametersValue, clearProps } from "./pvutils.js"; +import AlgorithmIdentifier from "./AlgorithmIdentifier.js"; +//************************************************************************************** +/** + * Class from RFC3161 + */ +export default class MessageImprint +{ + //********************************************************************************** + /** + * Constructor for MessageImprint class + * @param {Object} [parameters={}] + * @param {Object} [parameters.schema] asn1js parsed value to initialize the class from + */ + constructor(parameters = {}) + { + //region Internal properties of the object + /** + * @type {AlgorithmIdentifier} + * @desc hashAlgorithm + */ + this.hashAlgorithm = getParametersValue(parameters, "hashAlgorithm", MessageImprint.defaultValues("hashAlgorithm")); + /** + * @type {OctetString} + * @desc hashedMessage + */ + this.hashedMessage = getParametersValue(parameters, "hashedMessage", MessageImprint.defaultValues("hashedMessage")); + //endregion + + //region If input argument array contains "schema" for this object + if("schema" in parameters) + this.fromSchema(parameters.schema); + //endregion + } + //********************************************************************************** + /** + * Return default values for all class members + * @param {string} memberName String name for a class member + */ + static defaultValues(memberName) + { + switch(memberName) + { + case "hashAlgorithm": + return new AlgorithmIdentifier(); + case "hashedMessage": + return new asn1js.OctetString(); + default: + throw new Error(`Invalid member name for MessageImprint class: ${memberName}`); + } + } + //********************************************************************************** + /** + * Compare values with default values for all class members + * @param {string} memberName String name for a class member + * @param {*} memberValue Value to compare with default value + */ + static compareWithDefault(memberName, memberValue) + { + switch(memberName) + { + case "hashAlgorithm": + return ((memberValue.algorithmId === "") && (("algorithmParams" in memberValue) === false)); + case "hashedMessage": + return (memberValue.isEqual(MessageImprint.defaultValues(memberName)) === 0); + default: + throw new Error(`Invalid member name for MessageImprint class: ${memberName}`); + } + } + //********************************************************************************** + /** + * Return value of pre-defined ASN.1 schema for current class + * + * ASN.1 schema: + * ```asn1 + * MessageImprint ::= SEQUENCE { + * hashAlgorithm AlgorithmIdentifier, + * hashedMessage OCTET STRING } + * ``` + * + * @param {Object} parameters Input parameters for the schema + * @returns {Object} asn1js schema object + */ + static schema(parameters = {}) + { + /** + * @type {Object} + * @property {string} [blockName] + * @property {string} [hashAlgorithm] + * @property {string} [hashedMessage] + */ + const names = getParametersValue(parameters, "names", {}); + + return (new asn1js.Sequence({ + name: (names.blockName || ""), + value: [ + AlgorithmIdentifier.schema(names.hashAlgorithm || {}), + new asn1js.OctetString({ name: (names.hashedMessage || "") }) + ] + })); + } + //********************************************************************************** + /** + * Convert parsed asn1js object into current class + * @param {!Object} schema + */ + fromSchema(schema) + { + //region Clear input data first + clearProps(schema, [ + "hashAlgorithm", + "hashedMessage" + ]); + //endregion + + //region Check the schema is valid + const asn1 = asn1js.compareSchema(schema, + schema, + MessageImprint.schema({ + names: { + hashAlgorithm: { + names: { + blockName: "hashAlgorithm" + } + }, + hashedMessage: "hashedMessage" + } + }) + ); + + if(asn1.verified === false) + throw new Error("Object's schema was not verified against input data for MessageImprint"); + //endregion + + //region Get internal properties from parsed schema + this.hashAlgorithm = new AlgorithmIdentifier({ schema: asn1.result.hashAlgorithm }); + this.hashedMessage = asn1.result.hashedMessage; + //endregion + } + //********************************************************************************** + /** + * Convert current object to asn1js object and set correct values + * @returns {Object} asn1js object + */ + toSchema() + { + //region Construct and return new ASN.1 schema for this object + return (new asn1js.Sequence({ + value: [ + this.hashAlgorithm.toSchema(), + this.hashedMessage + ] + })); + //endregion + } + //********************************************************************************** + /** + * Convertion for the class to JSON object + * @returns {Object} + */ + toJSON() + { + return { + hashAlgorithm: this.hashAlgorithm.toJSON(), + hashedMessage: this.hashedMessage.toJSON() + }; + } + //********************************************************************************** +} +//************************************************************************************** diff --git a/core/third-party/pkijs/NameConstraints.js b/core/third-party/pkijs/NameConstraints.js new file mode 100644 index 0000000..12eb43b --- /dev/null +++ b/core/third-party/pkijs/NameConstraints.js @@ -0,0 +1,207 @@ +import * as asn1js from "./asn1.js"; +import { getParametersValue, clearProps } from "./pvutils.js"; +import GeneralSubtree from "./GeneralSubtree.js"; +//************************************************************************************** +/** + * Class from RFC5280 + */ +export default class NameConstraints +{ + //********************************************************************************** + /** + * Constructor for NameConstraints class + * @param {Object} [parameters={}] + * @param {Object} [parameters.schema] asn1js parsed value to initialize the class from + */ + constructor(parameters = {}) + { + //region Internal properties of the object + if("permittedSubtrees" in parameters) + /** + * @type {Array.} + * @desc permittedSubtrees + */ + this.permittedSubtrees = getParametersValue(parameters, "permittedSubtrees", NameConstraints.defaultValues("permittedSubtrees")); + + if("excludedSubtrees" in parameters) + /** + * @type {Array.} + * @desc excludedSubtrees + */ + this.excludedSubtrees = getParametersValue(parameters, "excludedSubtrees", NameConstraints.defaultValues("excludedSubtrees")); + //endregion + + //region If input argument array contains "schema" for this object + if("schema" in parameters) + this.fromSchema(parameters.schema); + //endregion + } + //********************************************************************************** + /** + * Return default values for all class members + * @param {string} memberName String name for a class member + */ + static defaultValues(memberName) + { + switch(memberName) + { + case "permittedSubtrees": + return []; + case "excludedSubtrees": + return []; + default: + throw new Error(`Invalid member name for NameConstraints class: ${memberName}`); + } + } + //********************************************************************************** + /** + * Return value of pre-defined ASN.1 schema for current class + * + * ASN.1 schema: + * ```asn1 + * NameConstraints ::= SEQUENCE { + * permittedSubtrees [0] GeneralSubtrees OPTIONAL, + * excludedSubtrees [1] GeneralSubtrees OPTIONAL } + * ``` + * + * @param {Object} parameters Input parameters for the schema + * @returns {Object} asn1js schema object + */ + static schema(parameters = {}) + { + /** + * @type {Object} + * @property {string} [blockName] + * @property {string} [permittedSubtrees] + * @property {string} [excludedSubtrees] + */ + const names = getParametersValue(parameters, "names", {}); + + return (new asn1js.Sequence({ + name: (names.blockName || ""), + value: [ + new asn1js.Constructed({ + optional: true, + idBlock: { + tagClass: 3, // CONTEXT-SPECIFIC + tagNumber: 0 // [0] + }, + value: [ + new asn1js.Repeated({ + name: (names.permittedSubtrees || ""), + value: GeneralSubtree.schema() + }) + ] + }), + new asn1js.Constructed({ + optional: true, + idBlock: { + tagClass: 3, // CONTEXT-SPECIFIC + tagNumber: 1 // [1] + }, + value: [ + new asn1js.Repeated({ + name: (names.excludedSubtrees || ""), + value: GeneralSubtree.schema() + }) + ] + }) + ] + })); + } + //********************************************************************************** + /** + * Convert parsed asn1js object into current class + * @param {!Object} schema + */ + fromSchema(schema) + { + //region Clear input data first + clearProps(schema, [ + "permittedSubtrees", + "excludedSubtrees" + ]); + //endregion + + //region Check the schema is valid + const asn1 = asn1js.compareSchema(schema, + schema, + NameConstraints.schema({ + names: { + permittedSubtrees: "permittedSubtrees", + excludedSubtrees: "excludedSubtrees" + } + }) + ); + + if(asn1.verified === false) + throw new Error("Object's schema was not verified against input data for NameConstraints"); + //endregion + + //region Get internal properties from parsed schema + if("permittedSubtrees" in asn1.result) + this.permittedSubtrees = Array.from(asn1.result.permittedSubtrees, element => new GeneralSubtree({ schema: element })); + + if("excludedSubtrees" in asn1.result) + this.excludedSubtrees = Array.from(asn1.result.excludedSubtrees, element => new GeneralSubtree({ schema: element })); + //endregion + } + //********************************************************************************** + /** + * Convert current object to asn1js object and set correct values + * @returns {Object} asn1js object + */ + toSchema() + { + //region Create array for output sequence + const outputArray = []; + + if("permittedSubtrees" in this) + { + outputArray.push(new asn1js.Constructed({ + idBlock: { + tagClass: 3, // CONTEXT-SPECIFIC + tagNumber: 0 // [0] + }, + value: Array.from(this.permittedSubtrees, element => element.toSchema()) + })); + } + + if("excludedSubtrees" in this) + { + outputArray.push(new asn1js.Constructed({ + idBlock: { + tagClass: 3, // CONTEXT-SPECIFIC + tagNumber: 1 // [1] + }, + value: Array.from(this.excludedSubtrees, element => element.toSchema()) + })); + } + //endregion + + //region Construct and return new ASN.1 schema for this object + return (new asn1js.Sequence({ + value: outputArray + })); + //endregion + } + //********************************************************************************** + /** + * Convertion for the class to JSON object + * @returns {Object} + */ + toJSON() + { + const object = {}; + + if("permittedSubtrees" in this) + object.permittedSubtrees = Array.from(this.permittedSubtrees, element => element.toJSON()); + + if("excludedSubtrees" in this) + object.excludedSubtrees = Array.from(this.excludedSubtrees, element => element.toJSON()); + + return object; + } + //********************************************************************************** +} +//************************************************************************************** diff --git a/core/third-party/pkijs/OCSPRequest.js b/core/third-party/pkijs/OCSPRequest.js new file mode 100644 index 0000000..09d530a --- /dev/null +++ b/core/third-party/pkijs/OCSPRequest.js @@ -0,0 +1,304 @@ +import * as asn1js from "./asn1.js"; +import { getParametersValue, clearProps } from "./pvutils.js"; +import { getEngine } from "./common.js"; +import TBSRequest from "./TBSRequest.js"; +import Signature from "./Signature.js"; +import Request from "./Request.js"; +import CertID from "./CertID.js"; +//************************************************************************************** +/** + * Class from RFC6960 + */ +export default class OCSPRequest +{ + //********************************************************************************** + /** + * Constructor for OCSPRequest class + * @param {Object} [parameters={}] + * @param {Object} [parameters.schema] asn1js parsed value to initialize the class from + */ + constructor(parameters = {}) + { + //region Internal properties of the object + /** + * @type {TBSRequest} + * @desc tbsRequest + */ + this.tbsRequest = getParametersValue(parameters, "tbsRequest", OCSPRequest.defaultValues("tbsRequest")); + + if("optionalSignature" in parameters) + /** + * @type {Signature} + * @desc optionalSignature + */ + this.optionalSignature = getParametersValue(parameters, "optionalSignature", OCSPRequest.defaultValues("optionalSignature")); + //endregion + + //region If input argument array contains "schema" for this object + if("schema" in parameters) + this.fromSchema(parameters.schema); + //endregion + } + //********************************************************************************** + /** + * Return default values for all class members + * @param {string} memberName String name for a class member + */ + static defaultValues(memberName) + { + switch(memberName) + { + case "tbsRequest": + return new TBSRequest(); + case "optionalSignature": + return new Signature(); + default: + throw new Error(`Invalid member name for OCSPRequest class: ${memberName}`); + } + } + //********************************************************************************** + /** + * Compare values with default values for all class members + * @param {string} memberName String name for a class member + * @param {*} memberValue Value to compare with default value + */ + static compareWithDefault(memberName, memberValue) + { + switch(memberName) + { + case "tbsRequest": + // noinspection OverlyComplexBooleanExpressionJS + return ((TBSRequest.compareWithDefault("tbs", memberValue.tbs)) && + (TBSRequest.compareWithDefault("version", memberValue.version)) && + (TBSRequest.compareWithDefault("requestorName", memberValue.requestorName)) && + (TBSRequest.compareWithDefault("requestList", memberValue.requestList)) && + (TBSRequest.compareWithDefault("requestExtensions", memberValue.requestExtensions))); + case "optionalSignature": + return ((Signature.compareWithDefault("signatureAlgorithm", memberValue.signatureAlgorithm)) && + (Signature.compareWithDefault("signature", memberValue.signature)) && + (Signature.compareWithDefault("certs", memberValue.certs))); + default: + throw new Error(`Invalid member name for OCSPRequest class: ${memberName}`); + } + } + //********************************************************************************** + /** + * Return value of pre-defined ASN.1 schema for current class + * + * ASN.1 schema: + * ```asn1 + * OCSPRequest ::= SEQUENCE { + * tbsRequest TBSRequest, + * optionalSignature [0] EXPLICIT Signature OPTIONAL } + * ``` + * + * @param {Object} parameters Input parameters for the schema + * @returns {Object} asn1js schema object + */ + static schema(parameters = {}) + { + /** + * @type {Object} + * @property {string} [blockName] + * @property {string} [tbsRequest] + * @property {string} [optionalSignature] + */ + const names = getParametersValue(parameters, "names", {}); + + return (new asn1js.Sequence({ + name: names.blockName || "OCSPRequest", + value: [ + TBSRequest.schema(names.tbsRequest || { + names: { + blockName: "tbsRequest" + } + }), + new asn1js.Constructed({ + optional: true, + idBlock: { + tagClass: 3, // CONTEXT-SPECIFIC + tagNumber: 0 // [0] + }, + value: [ + Signature.schema(names.optionalSignature || { + names: { + blockName: "optionalSignature" + } + }) + ] + }) + ] + })); + } + //********************************************************************************** + /** + * Convert parsed asn1js object into current class + * @param {!Object} schema + */ + fromSchema(schema) + { + //region Clear input data first + clearProps(schema, [ + "tbsRequest", + "optionalSignature" + ]); + //endregion + + //region Check the schema is valid + const asn1 = asn1js.compareSchema(schema, + schema, + OCSPRequest.schema() + ); + + if(asn1.verified === false) + throw new Error("Object's schema was not verified against input data for OCSPRequest"); + //endregion + + //region Get internal properties from parsed schema + this.tbsRequest = new TBSRequest({ schema: asn1.result.tbsRequest }); + if("optionalSignature" in asn1.result) + this.optionalSignature = new Signature({ schema: asn1.result.optionalSignature }); + //endregion + } + //********************************************************************************** + /** + * Convert current object to asn1js object and set correct values + * @param {boolean} encodeFlag If param equal to false then create TBS schema via decoding stored value. In othe case create TBS schema via assembling from TBS parts. + * @returns {Object} asn1js object + */ + toSchema(encodeFlag = false) + { + //region Create array for output sequence + const outputArray = []; + + outputArray.push(this.tbsRequest.toSchema(encodeFlag)); + if("optionalSignature" in this) + outputArray.push(this.optionalSignature.toSchema()); + //endregion + + //region Construct and return new ASN.1 schema for this object + return (new asn1js.Sequence({ + value: outputArray + })); + //endregion + } + //********************************************************************************** + /** + * Convertion for the class to JSON object + * @returns {Object} + */ + toJSON() + { + const _object = { + tbsRequest: this.tbsRequest.toJSON() + }; + + if("optionalSignature" in this) + _object.optionalSignature = this.optionalSignature.toJSON(); + + return _object; + } + //********************************************************************************** + /** + * Making OCSP Request for specific certificate + * @param {Certificate} certificate Certificate making OCSP Request for + * @param {Object} parameters Additional parameters + * @returns {Promise} + */ + createForCertificate(certificate, parameters) + { + //region Initial variables + let sequence = Promise.resolve(); + + const certID = new CertID(); + //endregion + + //region Create OCSP certificate identifier for the certificate + sequence = sequence.then(() => + certID.createForCertificate(certificate, parameters) + ); + //endregion + + //region Make final request data + sequence = sequence.then(() => + { + this.tbsRequest = new TBSRequest({ + requestList: [ + new Request({ + reqCert: certID + }) + ] + }); + }, error => + Promise.reject(error) + ); + //endregion + + return sequence; + } + //********************************************************************************** + /** + * Make signature for current OCSP Request + * @param {Object} privateKey Private key for "subjectPublicKeyInfo" structure + * @param {string} [hashAlgorithm] Hashing algorithm. Default SHA-1 + * @returns {Promise} + */ + sign(privateKey, hashAlgorithm = "SHA-1") + { + //region Initial checking + //region Check private key + if(typeof privateKey === "undefined") + return Promise.reject("Need to provide a private key for signing"); + //endregion + + //region Check that "optionalSignature" exists in the current request + if(("optionalSignature" in this) === false) + return Promise.reject("Need to create \"optionalSignature\" field before signing"); + //endregion + //endregion + + //region Initial variables + let sequence = Promise.resolve(); + let parameters; + + let tbs; + + const engine = getEngine(); + //endregion + + //region Get a "default parameters" for current algorithm and set correct signature algorithm + sequence = sequence.then(() => engine.subtle.getSignatureParameters(privateKey, hashAlgorithm)); + + sequence = sequence.then(result => + { + parameters = result.parameters; + this.optionalSignature.signatureAlgorithm = result.signatureAlgorithm; + }); + //endregion + + //region Create TBS data for signing + sequence = sequence.then(() => + { + tbs = this.tbsRequest.toSchema(true).toBER(false); + }); + //endregion + + //region Signing TBS data on provided private key + sequence = sequence.then(() => engine.subtle.signWithPrivateKey(tbs, privateKey, parameters)); + + sequence = sequence.then(result => + { + this.optionalSignature.signature = new asn1js.BitString({ valueHex: result }); + }); + //endregion + + return sequence; + } + //********************************************************************************** + verify() + { + // TODO: Create the function + } + //********************************************************************************** +} +//************************************************************************************** diff --git a/core/third-party/pkijs/OCSPResponse.js b/core/third-party/pkijs/OCSPResponse.js new file mode 100644 index 0000000..e1d9df0 --- /dev/null +++ b/core/third-party/pkijs/OCSPResponse.js @@ -0,0 +1,299 @@ +import * as asn1js from "./asn1.js"; +import { getParametersValue, clearProps } from "./pvutils.js"; +import ResponseBytes from "./ResponseBytes.js"; +import BasicOCSPResponse from "./BasicOCSPResponse.js"; +//************************************************************************************** +/** + * Class from RFC6960 + */ +export default class OCSPResponse +{ + //********************************************************************************** + /** + * Constructor for OCSPResponse class + * @param {Object} [parameters={}] + * @param {Object} [parameters.schema] asn1js parsed value to initialize the class from + */ + constructor(parameters = {}) + { + //region Internal properties of the object + /** + * @type {Enumerated} + * @desc responseStatus + */ + this.responseStatus = getParametersValue(parameters, "responseStatus", OCSPResponse.defaultValues("responseStatus")); + + if("responseBytes" in parameters) + /** + * @type {ResponseBytes} + * @desc responseBytes + */ + this.responseBytes = getParametersValue(parameters, "responseBytes", OCSPResponse.defaultValues("responseBytes")); + //endregion + + //region If input argument array contains "schema" for this object + if("schema" in parameters) + this.fromSchema(parameters.schema); + //endregion + } + //********************************************************************************** + /** + * Return default values for all class members + * @param {string} memberName String name for a class member + */ + static defaultValues(memberName) + { + switch(memberName) + { + case "responseStatus": + return new asn1js.Enumerated(); + case "responseBytes": + return new ResponseBytes(); + default: + throw new Error(`Invalid member name for OCSPResponse class: ${memberName}`); + } + } + //********************************************************************************** + /** + * Compare values with default values for all class members + * @param {string} memberName String name for a class member + * @param {*} memberValue Value to compare with default value + */ + static compareWithDefault(memberName, memberValue) + { + switch(memberName) + { + case "responseStatus": + return (memberValue.isEqual(OCSPResponse.defaultValues(memberName))); + case "responseBytes": + return ((ResponseBytes.compareWithDefault("responseType", memberValue.responseType)) && + (ResponseBytes.compareWithDefault("response", memberValue.response))); + default: + throw new Error(`Invalid member name for OCSPResponse class: ${memberName}`); + } + } + //********************************************************************************** + /** + * Return value of pre-defined ASN.1 schema for current class + * + * ASN.1 schema: + * ```asn1 + * OCSPResponse ::= SEQUENCE { + * responseStatus OCSPResponseStatus, + * responseBytes [0] EXPLICIT ResponseBytes OPTIONAL } + * + * OCSPResponseStatus ::= ENUMERATED { + * successful (0), -- Response has valid confirmations + * malformedRequest (1), -- Illegal confirmation request + * internalError (2), -- Internal error in issuer + * tryLater (3), -- Try again later + * -- (4) is not used + * sigRequired (5), -- Must sign the request + * unauthorized (6) -- Request unauthorized + * } + * ``` + * + * @param {Object} parameters Input parameters for the schema + * @returns {Object} asn1js schema object + */ + static schema(parameters = {}) + { + /** + * @type {Object} + * @property {string} [blockName] + * @property {string} [responseStatus] + * @property {string} [responseBytes] + */ + const names = getParametersValue(parameters, "names", {}); + + return (new asn1js.Sequence({ + name: (names.blockName || "OCSPResponse"), + value: [ + new asn1js.Enumerated({ name: (names.responseStatus || "responseStatus") }), + new asn1js.Constructed({ + optional: true, + idBlock: { + tagClass: 3, // CONTEXT-SPECIFIC + tagNumber: 0 // [0] + }, + value: [ + ResponseBytes.schema(names.responseBytes || { + names: { + blockName: "responseBytes" + } + }) + ] + }) + ] + })); + } + //********************************************************************************** + /** + * Convert parsed asn1js object into current class + * @param {!Object} schema + */ + fromSchema(schema) + { + //region Clear input data first + clearProps(schema, [ + "responseStatus", + "responseBytes" + ]); + //endregion + + //region Check the schema is valid + const asn1 = asn1js.compareSchema(schema, + schema, + OCSPResponse.schema() + ); + + if(asn1.verified === false) + throw new Error("Object's schema was not verified against input data for OCSPResponse"); + //endregion + + //region Get internal properties from parsed schema + this.responseStatus = asn1.result.responseStatus; + if("responseBytes" in asn1.result) + this.responseBytes = new ResponseBytes({ schema: asn1.result.responseBytes }); + //endregion + } + //********************************************************************************** + /** + * Convert current object to asn1js object and set correct values + * @returns {Object} asn1js object + */ + toSchema() + { + //region Create array for output sequence + const outputArray = []; + + outputArray.push(this.responseStatus); + if("responseBytes" in this) + { + outputArray.push(new asn1js.Constructed({ + idBlock: { + tagClass: 3, // CONTEXT-SPECIFIC + tagNumber: 0 // [0] + }, + value: [this.responseBytes.toSchema()] + })); + } + //endregion + + //region Construct and return new ASN.1 schema for this object + return (new asn1js.Sequence({ + value: outputArray + })); + //endregion + } + //********************************************************************************** + /** + * Convertion for the class to JSON object + * @returns {Object} + */ + toJSON() + { + const _object = { + responseStatus: this.responseStatus.toJSON() + }; + + if("responseBytes" in this) + _object.responseBytes = this.responseBytes.toJSON(); + + return _object; + } + //********************************************************************************** + /** + * Get OCSP response status for specific certificate + * @param {Certificate} certificate + * @param {Certificate} issuerCertificate + * @returns {*} + */ + getCertificateStatus(certificate, issuerCertificate) + { + //region Initial variables + let basicResponse; + + const result = { + isForCertificate: false, + status: 2 // 0 = good, 1 = revoked, 2 = unknown + }; + //endregion + + //region Check that "ResponseBytes" contain "OCSP_BASIC_RESPONSE" + if(("responseBytes" in this) === false) + return result; + + if(this.responseBytes.responseType !== "1.3.6.1.5.5.7.48.1.1") // id-pkix-ocsp-basic + return result; + + try + { + const asn1Basic = asn1js.fromBER(this.responseBytes.response.valueBlock.valueHex); + basicResponse = new BasicOCSPResponse({ schema: asn1Basic.result }); + } + catch(ex) + { + return result; + } + //endregion + + return basicResponse.getCertificateStatus(certificate, issuerCertificate); + } + //********************************************************************************** + /** + * Make a signature for current OCSP Response + * @param {Object} privateKey Private key for "subjectPublicKeyInfo" structure + * @param {string} [hashAlgorithm] Hashing algorithm. Default SHA-1 + * @returns {Promise} + */ + sign(privateKey, hashAlgorithm) + { + //region Check that ResponseData has type BasicOCSPResponse and sign it + if(this.responseBytes.responseType === "1.3.6.1.5.5.7.48.1.1") + { + const asn1 = asn1js.fromBER(this.responseBytes.response.valueBlock.valueHex); + const basicResponse = new BasicOCSPResponse({ schema: asn1.result }); + + return basicResponse.sign(privateKey, hashAlgorithm); + } + + return Promise.reject(`Unknown ResponseBytes type: ${this.responseBytes.responseType}`); + //endregion + } + //********************************************************************************** + /** + * Verify current OCSP Response + * @param {Certificate|null} issuerCertificate In order to decrease size of resp issuer cert could be ommited. In such case you need manually provide it. + * @returns {Promise} + */ + verify(issuerCertificate = null) + { + //region Check that ResponseBytes exists in the object + if(("responseBytes" in this) === false) + return Promise.reject("Empty ResponseBytes field"); + //endregion + + //region Check that ResponceData has type BasicOCSPResponse and verify it + if(this.responseBytes.responseType === "1.3.6.1.5.5.7.48.1.1") + { + const asn1 = asn1js.fromBER(this.responseBytes.response.valueBlock.valueHex); + const basicResponse = new BasicOCSPResponse({ schema: asn1.result }); + + if(issuerCertificate !== null) + { + if(("certs" in basicResponse) === false) + basicResponse.certs = []; + + basicResponse.certs.push(issuerCertificate); + } + + return basicResponse.verify(); + } + + return Promise.reject(`Unknown ResponseBytes type: ${this.responseBytes.responseType}`); + //endregion + } + //********************************************************************************** +} +//************************************************************************************** diff --git a/core/third-party/pkijs/OriginatorIdentifierOrKey.js b/core/third-party/pkijs/OriginatorIdentifierOrKey.js new file mode 100644 index 0000000..7910f44 --- /dev/null +++ b/core/third-party/pkijs/OriginatorIdentifierOrKey.js @@ -0,0 +1,228 @@ +import * as asn1js from "./asn1.js"; +import { getParametersValue, clearProps } from "./pvutils.js"; +import IssuerAndSerialNumber from "./IssuerAndSerialNumber.js"; +import OriginatorPublicKey from "./OriginatorPublicKey.js"; +//************************************************************************************** +/** + * Class from RFC5652 + */ +export default class OriginatorIdentifierOrKey +{ + //********************************************************************************** + /** + * Constructor for OriginatorIdentifierOrKey class + * @param {Object} [parameters={}] + * @param {Object} [parameters.schema] asn1js parsed value to initialize the class from + */ + constructor(parameters = {}) + { + //region Internal properties of the object + /** + * @type {number} + * @desc variant + */ + this.variant = getParametersValue(parameters, "variant", OriginatorIdentifierOrKey.defaultValues("variant")); + + if("value" in parameters) + /** + * @type {IssuerAndSerialNumber|OctetString|OriginatorPublicKey} + * @desc value + */ + this.value = getParametersValue(parameters, "value", OriginatorIdentifierOrKey.defaultValues("value")); + //endregion + + //region If input argument array contains "schema" for this object + if("schema" in parameters) + this.fromSchema(parameters.schema); + //endregion + } + //********************************************************************************** + /** + * Return default values for all class members + * @param {string} memberName String name for a class member + */ + static defaultValues(memberName) + { + switch(memberName) + { + case "variant": + return (-1); + case "value": + return {}; + default: + throw new Error(`Invalid member name for OriginatorIdentifierOrKey class: ${memberName}`); + } + } + //********************************************************************************** + /** + * Compare values with default values for all class members + * @param {string} memberName String name for a class member + * @param {*} memberValue Value to compare with default value + */ + static compareWithDefault(memberName, memberValue) + { + switch(memberName) + { + case "variant": + return (memberValue === (-1)); + case "value": + return (Object.keys(memberValue).length === 0); + default: + throw new Error(`Invalid member name for OriginatorIdentifierOrKey class: ${memberName}`); + } + } + //********************************************************************************** + /** + * Return value of pre-defined ASN.1 schema for current class + * + * ASN.1 schema: + * ```asn1 + * OriginatorIdentifierOrKey ::= CHOICE { + * issuerAndSerialNumber IssuerAndSerialNumber, + * subjectKeyIdentifier [0] SubjectKeyIdentifier, + * originatorKey [1] OriginatorPublicKey } + * ``` + * + * @param {Object} parameters Input parameters for the schema + * @returns {Object} asn1js schema object + */ + static schema(parameters = {}) + { + /** + * @type {Object} + * @property {string} [blockName] + */ + const names = getParametersValue(parameters, "names", {}); + + return (new asn1js.Choice({ + value: [ + IssuerAndSerialNumber.schema({ + names: { + blockName: (names.blockName || "") + } + }), + new asn1js.Primitive({ + idBlock: { + tagClass: 3, // CONTEXT-SPECIFIC + tagNumber: 0 // [0] + }, + name: (names.blockName || "") + }), + new asn1js.Constructed({ + idBlock: { + tagClass: 3, // CONTEXT-SPECIFIC + tagNumber: 1 // [1] + }, + name: (names.blockName || ""), + value: OriginatorPublicKey.schema().valueBlock.value + }) + ] + })); + } + //********************************************************************************** + /** + * Convert parsed asn1js object into current class + * @param {!Object} schema + */ + fromSchema(schema) + { + //region Clear input data first + clearProps(schema, [ + "blockName" + ]); + //endregion + + //region Check the schema is valid + const asn1 = asn1js.compareSchema(schema, + schema, + OriginatorIdentifierOrKey.schema({ + names: { + blockName: "blockName" + } + }) + ); + + if(asn1.verified === false) + throw new Error("Object's schema was not verified against input data for OriginatorIdentifierOrKey"); + //endregion + + //region Get internal properties from parsed schema + if(asn1.result.blockName.idBlock.tagClass === 1) + { + this.variant = 1; + this.value = new IssuerAndSerialNumber({ schema: asn1.result.blockName }); + } + else + { + if(asn1.result.blockName.idBlock.tagNumber === 0) + { + //region Create "OCTETSTRING" from "ASN1_PRIMITIVE" + asn1.result.blockName.idBlock.tagClass = 1; // UNIVERSAL + asn1.result.blockName.idBlock.tagNumber = 4; // OCTETSTRING + //endregion + + this.variant = 2; + this.value = asn1.result.blockName; + } + else + { + this.variant = 3; + this.value = new OriginatorPublicKey({ + schema: new asn1js.Sequence({ + value: asn1.result.blockName.valueBlock.value + }) + }); + } + } + //endregion + } + //********************************************************************************** + /** + * Convert current object to asn1js object and set correct values + * @returns {Object} asn1js object + */ + toSchema() + { + //region Construct and return new ASN.1 schema for this object + switch(this.variant) + { + case 1: + return this.value.toSchema(); + case 2: + this.value.idBlock.tagClass = 3; // CONTEXT-SPECIFIC + this.value.idBlock.tagNumber = 0; // [0] + + return this.value; + case 3: + { + const _schema = this.value.toSchema(); + + _schema.idBlock.tagClass = 3; // CONTEXT-SPECIFIC + _schema.idBlock.tagNumber = 1; // [1] + + return _schema; + } + default: + return new asn1js.Any(); + } + //endregion + } + //********************************************************************************** + /** + * Convertion for the class to JSON object + * @returns {Object} + */ + toJSON() + { + const _object = { + variant: this.variant + }; + + if((this.variant === 1) || (this.variant === 2) || (this.variant === 3)) + _object.value = this.value.toJSON(); + + return _object; + } + //********************************************************************************** +} +//************************************************************************************** diff --git a/core/third-party/pkijs/OriginatorInfo.js b/core/third-party/pkijs/OriginatorInfo.js new file mode 100644 index 0000000..5f6eb4e --- /dev/null +++ b/core/third-party/pkijs/OriginatorInfo.js @@ -0,0 +1,228 @@ +import * as asn1js from "./asn1.js"; +import { getParametersValue, clearProps } from "./pvutils.js"; +import CertificateSet from "./CertificateSet.js"; +import RevocationInfoChoices from "./RevocationInfoChoices.js"; +//************************************************************************************** +/** + * Class from RFC5652 + */ +export default class OriginatorInfo +{ + //********************************************************************************** + /** + * Constructor for OriginatorInfo class + * @param {Object} [parameters={}] + * @param {Object} [parameters.schema] asn1js parsed value to initialize the class from + */ + constructor(parameters = {}) + { + //region Internal properties of the object + if("certs" in parameters) + /** + * @type {CertificateSet} + * @desc certs + */ + this.certs = getParametersValue(parameters, "certs", OriginatorInfo.defaultValues("certs")); + + if("crls" in parameters) + /** + * @type {RevocationInfoChoices} + * @desc crls + */ + this.crls = getParametersValue(parameters, "crls", OriginatorInfo.defaultValues("crls")); + //endregion + + //region If input argument array contains "schema" for this object + if("schema" in parameters) + this.fromSchema(parameters.schema); + //endregion + } + //********************************************************************************** + /** + * Return default values for all class members + * @param {string} memberName String name for a class member + */ + static defaultValues(memberName) + { + switch(memberName) + { + case "certs": + return new CertificateSet(); + case "crls": + return new RevocationInfoChoices(); + default: + throw new Error(`Invalid member name for OriginatorInfo class: ${memberName}`); + } + } + //********************************************************************************** + /** + * Compare values with default values for all class members + * @param {string} memberName String name for a class member + * @param {*} memberValue Value to compare with default value + */ + static compareWithDefault(memberName, memberValue) + { + switch(memberName) + { + case "certs": + return (memberValue.certificates.length === 0); + case "crls": + return ((memberValue.crls.length === 0) && (memberValue.otherRevocationInfos.length === 0)); + default: + throw new Error(`Invalid member name for OriginatorInfo class: ${memberName}`); + } + } + //********************************************************************************** + /** + * Return value of pre-defined ASN.1 schema for current class + * + * ASN.1 schema: + * ```asn1 + * OriginatorInfo ::= SEQUENCE { + * certs [0] IMPLICIT CertificateSet OPTIONAL, + * crls [1] IMPLICIT RevocationInfoChoices OPTIONAL } + * ``` + * + * @param {Object} parameters Input parameters for the schema + * @returns {Object} asn1js schema object + */ + static schema(parameters = {}) + { + /** + * @type {Object} + * @property {string} [blockName] + * @property {string} [certs] + * @property {string} [crls] + */ + const names = getParametersValue(parameters, "names", {}); + + return (new asn1js.Sequence({ + name: (names.blockName || ""), + value: [ + new asn1js.Constructed({ + name: (names.certs || ""), + optional: true, + idBlock: { + tagClass: 3, // CONTEXT-SPECIFIC + tagNumber: 0 // [0] + }, + value: CertificateSet.schema().valueBlock.value + }), + new asn1js.Constructed({ + name: (names.crls || ""), + optional: true, + idBlock: { + tagClass: 3, // CONTEXT-SPECIFIC + tagNumber: 1 // [1] + }, + value: RevocationInfoChoices.schema().valueBlock.value + }) + ] + })); + } + //********************************************************************************** + /** + * Convert parsed asn1js object into current class + * @param {!Object} schema + */ + fromSchema(schema) + { + //region Clear input data first + clearProps(schema, [ + "certs", + "crls" + ]); + //endregion + + //region Check the schema is valid + const asn1 = asn1js.compareSchema(schema, + schema, + OriginatorInfo.schema({ + names: { + certs: "certs", + crls: "crls" + } + }) + ); + + if(asn1.verified === false) + throw new Error("Object's schema was not verified against input data for OriginatorInfo"); + //endregion + + //region Get internal properties from parsed schema + if("certs" in asn1.result) + { + this.certs = new CertificateSet({ + schema: new asn1js.Set({ + value: asn1.result.certs.valueBlock.value + }) + }); + } + + if("crls" in asn1.result) + { + this.crls = new RevocationInfoChoices({ + schema: new asn1js.Set({ + value: asn1.result.crls.valueBlock.value + }) + }); + } + //endregion + } + //********************************************************************************** + /** + * Convert current object to asn1js object and set correct values + * @returns {Object} asn1js object + */ + toSchema() + { + const sequenceValue = []; + + if("certs" in this) + { + sequenceValue.push(new asn1js.Constructed({ + idBlock: { + tagClass: 3, // CONTEXT-SPECIFIC + tagNumber: 0 // [0] + }, + value: this.certs.toSchema().valueBlock.value + })); + } + + if("crls" in this) + { + sequenceValue.push(new asn1js.Constructed({ + idBlock: { + tagClass: 3, // CONTEXT-SPECIFIC + tagNumber: 1 // [1] + }, + value: this.crls.toSchema().valueBlock.value + })); + } + + //region Construct and return new ASN.1 schema for this object + return (new asn1js.Sequence({ + value: sequenceValue + })); + //endregion + } + //********************************************************************************** + /** + * Convertion for the class to JSON object + * @returns {Object} + */ + toJSON() + { + const object = {}; + + if("certs" in this) + object.certs = this.certs.toJSON(); + + if("crls" in this) + object.crls = this.crls.toJSON(); + + return object; + } + //********************************************************************************** +} +//************************************************************************************** diff --git a/core/third-party/pkijs/OriginatorPublicKey.js b/core/third-party/pkijs/OriginatorPublicKey.js new file mode 100644 index 0000000..3648491 --- /dev/null +++ b/core/third-party/pkijs/OriginatorPublicKey.js @@ -0,0 +1,170 @@ +import * as asn1js from "./asn1.js"; +import { getParametersValue, clearProps } from "./pvutils.js"; +import AlgorithmIdentifier from "./AlgorithmIdentifier.js"; +//************************************************************************************** +/** + * Class from RFC5652 + */ +export default class OriginatorPublicKey +{ + //********************************************************************************** + /** + * Constructor for OriginatorPublicKey class + * @param {Object} [parameters={}] + * @param {Object} [parameters.schema] asn1js parsed value to initialize the class from + */ + constructor(parameters = {}) + { + //region Internal properties of the object + /** + * @type {AlgorithmIdentifier} + * @desc algorithm + */ + this.algorithm = getParametersValue(parameters, "algorithm", OriginatorPublicKey.defaultValues("algorithm")); + /** + * @type {BitString} + * @desc publicKey + */ + this.publicKey = getParametersValue(parameters, "publicKey", OriginatorPublicKey.defaultValues("publicKey")); + //endregion + + //region If input argument array contains "schema" for this object + if("schema" in parameters) + this.fromSchema(parameters.schema); + //endregion + } + //********************************************************************************** + /** + * Return default values for all class members + * @param {string} memberName String name for a class member + */ + static defaultValues(memberName) + { + switch(memberName) + { + case "algorithm": + return new AlgorithmIdentifier(); + case "publicKey": + return new asn1js.BitString(); + default: + throw new Error(`Invalid member name for OriginatorPublicKey class: ${memberName}`); + } + } + //********************************************************************************** + /** + * Compare values with default values for all class members + * @param {string} memberName String name for a class member + * @param {*} memberValue Value to compare with default value + */ + static compareWithDefault(memberName, memberValue) + { + switch(memberName) + { + case "algorithm": + case "publicKey": + return (memberValue.isEqual(OriginatorPublicKey.defaultValues(memberName))); + default: + throw new Error(`Invalid member name for OriginatorPublicKey class: ${memberName}`); + } + } + //********************************************************************************** + /** + * Return value of pre-defined ASN.1 schema for current class + * + * ASN.1 schema: + * ```asn1 + * OriginatorPublicKey ::= SEQUENCE { + * algorithm AlgorithmIdentifier, + * publicKey BIT STRING } + * ``` + * + * @param {Object} parameters Input parameters for the schema + * @returns {Object} asn1js schema object + */ + static schema(parameters = {}) + { + /** + * @type {Object} + * @property {string} [blockName] + * @property {string} [algorithm] + * @property {string} [publicKey] + */ + const names = getParametersValue(parameters, "names", {}); + + return (new asn1js.Sequence({ + name: (names.blockName || ""), + value: [ + AlgorithmIdentifier.schema(names.algorithm || {}), + new asn1js.BitString({ name: (names.publicKey || "") }) + ] + })); + } + //********************************************************************************** + /** + * Convert parsed asn1js object into current class + * @param {!Object} schema + */ + fromSchema(schema) + { + //region Clear input data first + clearProps(schema, [ + "algorithm", + "publicKey" + ]); + //endregion + + //region Check the schema is valid + const asn1 = asn1js.compareSchema(schema, + schema, + OriginatorPublicKey.schema({ + names: { + algorithm: { + names: { + blockName: "algorithm" + } + }, + publicKey: "publicKey" + } + }) + ); + + if(asn1.verified === false) + throw new Error("Object's schema was not verified against input data for OriginatorPublicKey"); + //endregion + + //region Get internal properties from parsed schema + this.algorithm = new AlgorithmIdentifier({ schema: asn1.result.algorithm }); + this.publicKey = asn1.result.publicKey; + //endregion + } + //********************************************************************************** + /** + * Convert current object to asn1js object and set correct values + * @returns {Object} asn1js object + */ + toSchema() + { + //region Construct and return new ASN.1 schema for this object + return (new asn1js.Sequence({ + value: [ + this.algorithm.toSchema(), + this.publicKey + ] + })); + //endregion + } + //********************************************************************************** + /** + * Convertion for the class to JSON object + * @returns {Object} + */ + toJSON() + { + return { + algorithm: this.algorithm.toJSON(), + publicKey: this.publicKey.toJSON() + }; + } + //********************************************************************************** +} +//************************************************************************************** diff --git a/core/third-party/pkijs/OtherCertificateFormat.js b/core/third-party/pkijs/OtherCertificateFormat.js new file mode 100644 index 0000000..75cdca6 --- /dev/null +++ b/core/third-party/pkijs/OtherCertificateFormat.js @@ -0,0 +1,147 @@ +import * as asn1js from "./asn1.js"; +import { getParametersValue, clearProps } from "./pvutils.js"; +//************************************************************************************** +/** + * Class from RFC5652 + */ +export default class OtherCertificateFormat +{ + //********************************************************************************** + /** + * Constructor for OtherCertificateFormat class + * @param {Object} [parameters={}] + * @param {Object} [parameters.schema] asn1js parsed value to initialize the class from + */ + constructor(parameters = {}) + { + //region Internal properties of the object + /** + * @type {string} + * @desc otherCertFormat + */ + this.otherCertFormat = getParametersValue(parameters, "otherCertFormat", OtherCertificateFormat.defaultValues("otherCertFormat")); + /** + * @type {Any} + * @desc otherCert + */ + this.otherCert = getParametersValue(parameters, "otherCert", OtherCertificateFormat.defaultValues("otherCert")); + //endregion + + //region If input argument array contains "schema" for this object + if("schema" in parameters) + this.fromSchema(parameters.schema); + //endregion + } + //********************************************************************************** + /** + * Return default values for all class members + * @param {string} memberName String name for a class member + */ + static defaultValues(memberName) + { + switch(memberName) + { + case "otherCertFormat": + return ""; + case "otherCert": + return new asn1js.Any(); + default: + throw new Error(`Invalid member name for OtherCertificateFormat class: ${memberName}`); + } + } + //********************************************************************************** + /** + * Return value of pre-defined ASN.1 schema for current class + * + * ASN.1 schema: + * ```asn1 + * OtherCertificateFormat ::= SEQUENCE { + * otherCertFormat OBJECT IDENTIFIER, + * otherCert ANY DEFINED BY otherCertFormat } + * ``` + * + * @param {Object} parameters Input parameters for the schema + * @returns {Object} asn1js schema object + */ + static schema(parameters = {}) + { + /** + * @type {Object} + * @property {string} [blockName] + * @property {string} [otherCertFormat] + * @property {string} [otherCert] + */ + const names = getParametersValue(parameters, "names", {}); + + return (new asn1js.Sequence({ + name: (names.blockName || ""), + value: [ + new asn1js.ObjectIdentifier({ name: (names.otherCertFormat || "otherCertFormat") }), + new asn1js.Any({ name: (names.otherCert || "otherCert") }) + ] + })); + } + //********************************************************************************** + /** + * Convert parsed asn1js object into current class + * @param {!Object} schema + */ + fromSchema(schema) + { + //region Clear input data first + clearProps(schema, [ + "otherCertFormat", + "otherCert" + ]); + //endregion + + //region Check the schema is valid + const asn1 = asn1js.compareSchema(schema, + schema, + OtherCertificateFormat.schema() + ); + + if(asn1.verified === false) + throw new Error("Object's schema was not verified against input data for OtherCertificateFormat"); + //endregion + + //region Get internal properties from parsed schema + this.otherCertFormat = asn1.result.otherCertFormat.valueBlock.toString(); + this.otherCert = asn1.result.otherCert; + //endregion + } + //********************************************************************************** + /** + * Convert current object to asn1js object and set correct values + * @returns {Object} asn1js object + */ + toSchema() + { + //region Construct and return new ASN.1 schema for this object + return (new asn1js.Sequence({ + value: [ + new asn1js.ObjectIdentifier({ value: this.otherCertFormat }), + this.otherCert + ] + })); + //endregion + } + //********************************************************************************** + /** + * Convertion for the class to JSON object + * @returns {Object} + */ + toJSON() + { + const object = { + otherCertFormat: this.otherCertFormat + }; + + if(!(this.otherCert instanceof asn1js.Any)) + object.otherCert = this.otherCert.toJSON(); + + return object; + } + //********************************************************************************** +} +//************************************************************************************** diff --git a/core/third-party/pkijs/OtherKeyAttribute.js b/core/third-party/pkijs/OtherKeyAttribute.js new file mode 100644 index 0000000..d8004de --- /dev/null +++ b/core/third-party/pkijs/OtherKeyAttribute.js @@ -0,0 +1,185 @@ +import * as asn1js from "./asn1.js"; +import { getParametersValue, clearProps } from "./pvutils.js"; +//************************************************************************************** +/** + * Class from RFC5652 + */ +export default class OtherKeyAttribute +{ + //********************************************************************************** + /** + * Constructor for OtherKeyAttribute class + * @param {Object} [parameters={}] + * @param {Object} [parameters.schema] asn1js parsed value to initialize the class from + */ + constructor(parameters = {}) + { + //region Internal properties of the object + /** + * @type {string} + * @desc keyAttrId + */ + this.keyAttrId = getParametersValue(parameters, "keyAttrId", OtherKeyAttribute.defaultValues("keyAttrId")); + + if("keyAttr" in parameters) + /** + * @type {*} + * @desc keyAttr + */ + this.keyAttr = getParametersValue(parameters, "keyAttr", OtherKeyAttribute.defaultValues("keyAttr")); + //endregion + + //region If input argument array contains "schema" for this object + if("schema" in parameters) + this.fromSchema(parameters.schema); + //endregion + } + //********************************************************************************** + /** + * Return default values for all class members + * @param {string} memberName String name for a class member + */ + static defaultValues(memberName) + { + switch(memberName) + { + case "keyAttrId": + return ""; + case "keyAttr": + return {}; + default: + throw new Error(`Invalid member name for OtherKeyAttribute class: ${memberName}`); + } + } + //********************************************************************************** + /** + * Compare values with default values for all class members + * @param {string} memberName String name for a class member + * @param {*} memberValue Value to compare with default value + */ + static compareWithDefault(memberName, memberValue) + { + switch(memberName) + { + case "keyAttrId": + return (memberValue === ""); + case "keyAttr": + return (Object.keys(memberValue).length === 0); + default: + throw new Error(`Invalid member name for OtherKeyAttribute class: ${memberName}`); + } + } + //********************************************************************************** + /** + * Return value of pre-defined ASN.1 schema for current class + * + * ASN.1 schema: + * ```asn1 + * OtherKeyAttribute ::= SEQUENCE { + * keyAttrId OBJECT IDENTIFIER, + * keyAttr ANY DEFINED BY keyAttrId OPTIONAL } + * ``` + * + * @param {Object} parameters Input parameters for the schema + * @returns {Object} asn1js schema object + */ + static schema(parameters = {}) + { + /** + * @type {Object} + * @property {string} [blockName] + * @property {string} [optional] + * @property {string} [keyAttrId] + * @property {string} [keyAttr] + */ + const names = getParametersValue(parameters, "names", {}); + + return (new asn1js.Sequence({ + optional: (names.optional || true), + name: (names.blockName || ""), + value: [ + new asn1js.ObjectIdentifier({ name: (names.keyAttrId || "") }), + new asn1js.Any({ + optional: true, + name: (names.keyAttr || "") + }) + ] + })); + } + //********************************************************************************** + /** + * Convert parsed asn1js object into current class + * @param {!Object} schema + */ + fromSchema(schema) + { + //region Clear input data first + clearProps(schema, [ + "keyAttrId", + "keyAttr" + ]); + //endregion + + //region Check the schema is valid + const asn1 = asn1js.compareSchema(schema, + schema, + OtherKeyAttribute.schema({ + names: { + keyAttrId: "keyAttrId", + keyAttr: "keyAttr" + } + }) + ); + + if(asn1.verified === false) + throw new Error("Object's schema was not verified against input data for OtherKeyAttribute"); + //endregion + + //region Get internal properties from parsed schema + this.keyAttrId = asn1.result.keyAttrId.valueBlock.toString(); + + if("keyAttr" in asn1.result) + this.keyAttr = asn1.result.keyAttr; + //endregion + } + //********************************************************************************** + /** + * Convert current object to asn1js object and set correct values + * @returns {Object} asn1js object + */ + toSchema() + { + //region Create array for output sequence + const outputArray = []; + + outputArray.push(new asn1js.ObjectIdentifier({ value: this.keyAttrId })); + + if("keyAttr" in this) + outputArray.push(this.keyAttr); + //endregion + + //region Construct and return new ASN.1 schema for this object + return (new asn1js.Sequence({ + value: outputArray + })); + //endregion + } + //********************************************************************************** + /** + * Convertion for the class to JSON object + * @returns {Object} + */ + toJSON() + { + const _object = { + keyAttrId: this.keyAttrId + }; + + if("keyAttr" in this) + _object.keyAttr = this.keyAttr.toJSON(); + + return _object; + } + //********************************************************************************** +} +//************************************************************************************** diff --git a/core/third-party/pkijs/OtherPrimeInfo.js b/core/third-party/pkijs/OtherPrimeInfo.js new file mode 100644 index 0000000..277eb3c --- /dev/null +++ b/core/third-party/pkijs/OtherPrimeInfo.js @@ -0,0 +1,190 @@ +import * as asn1js from "./asn1.js"; +import { getParametersValue, toBase64, arrayBufferToString, stringToArrayBuffer, fromBase64, clearProps } from "./pvutils.js"; +//************************************************************************************** +/** + * Class from RFC3447 + */ +export default class OtherPrimeInfo +{ + //********************************************************************************** + /** + * Constructor for OtherPrimeInfo class + * @param {Object} [parameters={}] + * @param {Object} [parameters.schema] asn1js parsed value to initialize the class from + */ + constructor(parameters = {}) + { + //region Internal properties of the object + /** + * @type {Integer} + * @desc prime + */ + this.prime = getParametersValue(parameters, "prime", OtherPrimeInfo.defaultValues("prime")); + /** + * @type {Integer} + * @desc exponent + */ + this.exponent = getParametersValue(parameters, "exponent", OtherPrimeInfo.defaultValues("exponent")); + /** + * @type {Integer} + * @desc coefficient + */ + this.coefficient = getParametersValue(parameters, "coefficient", OtherPrimeInfo.defaultValues("coefficient")); + //endregion + + //region If input argument array contains "schema" for this object + if("schema" in parameters) + this.fromSchema(parameters.schema); + //endregion + //region If input argument array contains "json" for this object + if("json" in parameters) + this.fromJSON(parameters.json); + //endregion + } + //********************************************************************************** + /** + * Return default values for all class members + * @param {string} memberName String name for a class member + */ + static defaultValues(memberName) + { + switch(memberName) + { + case "prime": + return new asn1js.Integer(); + case "exponent": + return new asn1js.Integer(); + case "coefficient": + return new asn1js.Integer(); + default: + throw new Error(`Invalid member name for OtherPrimeInfo class: ${memberName}`); + } + } + //********************************************************************************** + /** + * Return value of pre-defined ASN.1 schema for current class + * + * ASN.1 schema: + * ```asn1 + * OtherPrimeInfo ::= Sequence { + * prime Integer, -- ri + * exponent Integer, -- di + * coefficient Integer -- ti + * } + * ``` + * + * @param {Object} parameters Input parameters for the schema + * @returns {Object} asn1js schema object + */ + static schema(parameters = {}) + { + + /** + * @type {Object} + * @property {string} prime + * @property {string} exponent + * @property {string} coefficient + */ + const names = getParametersValue(parameters, "names", {}); + + return (new asn1js.Sequence({ + name: (names.blockName || ""), + value: [ + new asn1js.Integer({ name: (names.prime || "") }), + new asn1js.Integer({ name: (names.exponent || "") }), + new asn1js.Integer({ name: (names.coefficient || "") }) + ] + })); + } + //********************************************************************************** + /** + * Convert parsed asn1js object into current class + * @param {!Object} schema + */ + fromSchema(schema) + { + //region Clear input data first + clearProps(schema, [ + "prime", + "exponent", + "coefficient" + ]); + //endregion + + //region Check the schema is valid + const asn1 = asn1js.compareSchema(schema, + schema, + OtherPrimeInfo.schema({ + names: { + prime: "prime", + exponent: "exponent", + coefficient: "coefficient" + } + }) + ); + + if(asn1.verified === false) + throw new Error("Object's schema was not verified against input data for OtherPrimeInfo"); + //endregion + + //region Get internal properties from parsed schema + this.prime = asn1.result.prime.convertFromDER(); + this.exponent = asn1.result.exponent.convertFromDER(); + this.coefficient = asn1.result.coefficient.convertFromDER(); + //endregion + } + //********************************************************************************** + /** + * Convert current object to asn1js object and set correct values + * @returns {Object} asn1js object + */ + toSchema() + { + //region Construct and return new ASN.1 schema for this object + return (new asn1js.Sequence({ + value: [ + this.prime.convertToDER(), + this.exponent.convertToDER(), + this.coefficient.convertToDER() + ] + })); + //endregion + } + //********************************************************************************** + /** + * Convertion for the class to JSON object + * @returns {Object} + */ + toJSON() + { + return { + r: toBase64(arrayBufferToString(this.prime.valueBlock.valueHex), true, true), + d: toBase64(arrayBufferToString(this.exponent.valueBlock.valueHex), true, true), + t: toBase64(arrayBufferToString(this.coefficient.valueBlock.valueHex), true, true) + }; + } + //********************************************************************************** + /** + * Convert JSON value into current object + * @param {Object} json + */ + fromJSON(json) + { + if("r" in json) + this.prime = new asn1js.Integer({ valueHex: stringToArrayBuffer(fromBase64(json.r, true)) }); + else + throw new Error("Absent mandatory parameter \"r\""); + + if("d" in json) + this.exponent = new asn1js.Integer({ valueHex: stringToArrayBuffer(fromBase64(json.d, true)) }); + else + throw new Error("Absent mandatory parameter \"d\""); + + if("t" in json) + this.coefficient = new asn1js.Integer({ valueHex: stringToArrayBuffer(fromBase64(json.t, true)) }); + else + throw new Error("Absent mandatory parameter \"t\""); + } + //********************************************************************************** +} +//************************************************************************************** diff --git a/core/third-party/pkijs/OtherRecipientInfo.js b/core/third-party/pkijs/OtherRecipientInfo.js new file mode 100644 index 0000000..216fe84 --- /dev/null +++ b/core/third-party/pkijs/OtherRecipientInfo.js @@ -0,0 +1,170 @@ +import * as asn1js from "./asn1.js"; +import { getParametersValue, clearProps } from "./pvutils.js"; +//************************************************************************************** +/** + * Class from RFC5652 + */ +export default class OtherRecipientInfo +{ + //********************************************************************************** + /** + * Constructor for OtherRecipientInfo class + * @param {Object} [parameters={}] + * @param {Object} [parameters.schema] asn1js parsed value to initialize the class from + */ + constructor(parameters = {}) + { + //region Internal properties of the object + /** + * @type {string} + * @desc oriType + */ + this.oriType = getParametersValue(parameters, "oriType", OtherRecipientInfo.defaultValues("oriType")); + /** + * @type {*} + * @desc oriValue + */ + this.oriValue = getParametersValue(parameters, "oriValue", OtherRecipientInfo.defaultValues("oriValue")); + //endregion + + //region If input argument array contains "schema" for this object + if("schema" in parameters) + this.fromSchema(parameters.schema); + //endregion + } + //********************************************************************************** + /** + * Return default values for all class members + * @param {string} memberName String name for a class member + */ + static defaultValues(memberName) + { + switch(memberName) + { + case "oriType": + return ""; + case "oriValue": + return {}; + default: + throw new Error(`Invalid member name for OtherRecipientInfo class: ${memberName}`); + } + } + //********************************************************************************** + /** + * Compare values with default values for all class members + * @param {string} memberName String name for a class member + * @param {*} memberValue Value to compare with default value + */ + static compareWithDefault(memberName, memberValue) + { + switch(memberName) + { + case "oriType": + return (memberValue === ""); + case "oriValue": + return (Object.keys(memberValue).length === 0); + default: + throw new Error(`Invalid member name for OtherRecipientInfo class: ${memberName}`); + } + } + //********************************************************************************** + /** + * Return value of pre-defined ASN.1 schema for current class + * + * ASN.1 schema: + * ```asn1 + * OtherRecipientInfo ::= SEQUENCE { + * oriType OBJECT IDENTIFIER, + * oriValue ANY DEFINED BY oriType } + * ``` + * + * @param {Object} parameters Input parameters for the schema + * @returns {Object} asn1js schema object + */ + static schema(parameters = {}) + { + /** + * @type {Object} + * @property {string} [blockName] + * @property {string} [oriType] + * @property {string} [oriValue] + */ + const names = getParametersValue(parameters, "names", {}); + + return (new asn1js.Sequence({ + name: (names.blockName || ""), + value: [ + new asn1js.ObjectIdentifier({ name: (names.oriType || "") }), + new asn1js.Any({ name: (names.oriValue || "") }) + ] + })); + } + //********************************************************************************** + /** + * Convert parsed asn1js object into current class + * @param {!Object} schema + */ + fromSchema(schema) + { + //region Clear input data first + clearProps(schema, [ + "oriType", + "oriValue" + ]); + //endregion + + //region Check the schema is valid + const asn1 = asn1js.compareSchema(schema, + schema, + OtherRecipientInfo.schema({ + names: { + oriType: "oriType", + oriValue: "oriValue" + } + }) + ); + + if(asn1.verified === false) + throw new Error("Object's schema was not verified against input data for OtherRecipientInfo"); + //endregion + + //region Get internal properties from parsed schema + this.oriType = asn1.result.oriType.valueBlock.toString(); + this.oriValue = asn1.result.oriValue; + //endregion + } + //********************************************************************************** + /** + * Convert current object to asn1js object and set correct values + * @returns {Object} asn1js object + */ + toSchema() + { + //region Construct and return new ASN.1 schema for this object + return (new asn1js.Sequence({ + value: [ + new asn1js.ObjectIdentifier({ value: this.oriType }), + this.oriValue + ] + })); + //endregion + } + //********************************************************************************** + /** + * Convertion for the class to JSON object + * @returns {Object} + */ + toJSON() + { + const _object = { + oriType: this.oriType + }; + + if(OtherRecipientInfo.compareWithDefault("oriValue", this.oriValue) === false) + _object.oriValue = this.oriValue.toJSON(); + + return _object; + } + //********************************************************************************** +} +//************************************************************************************** diff --git a/core/third-party/pkijs/OtherRevocationInfoFormat.js b/core/third-party/pkijs/OtherRevocationInfoFormat.js new file mode 100644 index 0000000..e28e528 --- /dev/null +++ b/core/third-party/pkijs/OtherRevocationInfoFormat.js @@ -0,0 +1,147 @@ +import * as asn1js from "./asn1.js"; +import { getParametersValue, clearProps } from "./pvutils.js"; +//************************************************************************************** +/** + * Class from RFC5652 + */ +export default class OtherRevocationInfoFormat +{ + //********************************************************************************** + /** + * Constructor for OtherRevocationInfoFormat class + * @param {Object} [parameters={}] + * @param {Object} [parameters.schema] asn1js parsed value to initialize the class from + */ + constructor(parameters = {}) + { + //region Internal properties of the object + /** + * @type {string} + * @desc otherRevInfoFormat + */ + this.otherRevInfoFormat = getParametersValue(parameters, "otherRevInfoFormat", OtherRevocationInfoFormat.defaultValues("otherRevInfoFormat")); + /** + * @type {Any} + * @desc otherRevInfo + */ + this.otherRevInfo = getParametersValue(parameters, "otherRevInfo", OtherRevocationInfoFormat.defaultValues("otherRevInfo")); + //endregion + + //region If input argument array contains "schema" for this object + if("schema" in parameters) + this.fromSchema(parameters.schema); + //endregion + } + //********************************************************************************** + /** + * Return default values for all class members + * @param {string} memberName String name for a class member + */ + static defaultValues(memberName) + { + switch(memberName) + { + case "otherRevInfoFormat": + return ""; + case "otherRevInfo": + return new asn1js.Any(); + default: + throw new Error(`Invalid member name for OtherRevocationInfoFormat class: ${memberName}`); + } + } + //********************************************************************************** + /** + * Return value of pre-defined ASN.1 schema for current class + * + * ASN.1 schema: + * ```asn1 + * OtherCertificateFormat ::= SEQUENCE { + * otherRevInfoFormat OBJECT IDENTIFIER, + * otherRevInfo ANY DEFINED BY otherCertFormat } + * ``` + * + * @param {Object} parameters Input parameters for the schema + * @returns {Object} asn1js schema object + */ + static schema(parameters = {}) + { + /** + * @type {Object} + * @property {string} [blockName] + * @property {string} [otherRevInfoFormat] + * @property {string} [otherRevInfo] + */ + const names = getParametersValue(parameters, "names", {}); + + return (new asn1js.Sequence({ + name: (names.blockName || ""), + value: [ + new asn1js.ObjectIdentifier({ name: (names.otherRevInfoFormat || "otherRevInfoFormat") }), + new asn1js.Any({ name: (names.otherRevInfo || "otherRevInfo") }) + ] + })); + } + //********************************************************************************** + /** + * Convert parsed asn1js object into current class + * @param {!Object} schema + */ + fromSchema(schema) + { + //region Clear input data first + clearProps(schema, [ + "otherRevInfoFormat", + "otherRevInfo" + ]); + //endregion + + //region Check the schema is valid + const asn1 = asn1js.compareSchema(schema, + schema, + OtherRevocationInfoFormat.schema() + ); + + if(asn1.verified === false) + throw new Error("Object's schema was not verified against input data for OtherRevocationInfoFormat"); + //endregion + + //region Get internal properties from parsed schema + this.otherRevInfoFormat = asn1.result.otherRevInfoFormat.valueBlock.toString(); + this.otherRevInfo = asn1.result.otherRevInfo; + //endregion + } + //********************************************************************************** + /** + * Convert current object to asn1js object and set correct values + * @returns {Object} asn1js object + */ + toSchema() + { + //region Construct and return new ASN.1 schema for this object + return (new asn1js.Sequence({ + value: [ + new asn1js.ObjectIdentifier({ value: this.otherRevInfoFormat }), + this.otherRevInfo + ] + })); + //endregion + } + //********************************************************************************** + /** + * Convertion for the class to JSON object + * @returns {Object} + */ + toJSON() + { + const object = { + otherRevInfoFormat: this.otherRevInfoFormat + }; + + if(!(this.otherRevInfo instanceof asn1js.Any)) + object.otherRevInfo = this.otherRevInfo.toJSON(); + + return object; + } + //********************************************************************************** +} +//************************************************************************************** diff --git a/core/third-party/pkijs/PBES2Params.js b/core/third-party/pkijs/PBES2Params.js new file mode 100644 index 0000000..0f7e4a1 --- /dev/null +++ b/core/third-party/pkijs/PBES2Params.js @@ -0,0 +1,157 @@ +import * as asn1js from "./asn1.js"; +import { getParametersValue, clearProps } from "./pvutils.js"; +import AlgorithmIdentifier from "./AlgorithmIdentifier.js"; +//************************************************************************************** +/** + * Class from RFC2898 + */ +export default class PBES2Params +{ + //********************************************************************************** + /** + * Constructor for PBES2Params class + * @param {Object} [parameters={}] + * @param {Object} [parameters.schema] asn1js parsed value to initialize the class from + */ + constructor(parameters = {}) + { + //region Internal properties of the object + /** + * @type {AlgorithmIdentifier} + * @desc keyDerivationFunc + */ + this.keyDerivationFunc = getParametersValue(parameters, "keyDerivationFunc", PBES2Params.defaultValues("keyDerivationFunc")); + /** + * @type {AlgorithmIdentifier} + * @desc encryptionScheme + */ + this.encryptionScheme = getParametersValue(parameters, "encryptionScheme", PBES2Params.defaultValues("encryptionScheme")); + //endregion + + //region If input argument array contains "schema" for this object + if("schema" in parameters) + this.fromSchema(parameters.schema); + //endregion + } + //********************************************************************************** + /** + * Return default values for all class members + * @param {string} memberName String name for a class member + */ + static defaultValues(memberName) + { + switch(memberName) + { + case "keyDerivationFunc": + return new AlgorithmIdentifier(); + case "encryptionScheme": + return new AlgorithmIdentifier(); + default: + throw new Error(`Invalid member name for PBES2Params class: ${memberName}`); + } + } + //********************************************************************************** + /** + * Return value of pre-defined ASN.1 schema for current class + * + * ASN.1 schema: + * ```asn1 + * PBES2-params ::= SEQUENCE { + * keyDerivationFunc AlgorithmIdentifier {{PBES2-KDFs}}, + * encryptionScheme AlgorithmIdentifier {{PBES2-Encs}} } + * ``` + * + * @param {Object} parameters Input parameters for the schema + * @returns {Object} asn1js schema object + */ + static schema(parameters = {}) + { + /** + * @type {Object} + * @property {string} [blockName] + * @property {string} [keyDerivationFunc] + * @property {string} [encryptionScheme] + */ + const names = getParametersValue(parameters, "names", {}); + + return (new asn1js.Sequence({ + name: (names.blockName || ""), + value: [ + AlgorithmIdentifier.schema(names.keyDerivationFunc || {}), + AlgorithmIdentifier.schema(names.encryptionScheme || {}) + ] + })); + } + //********************************************************************************** + /** + * Convert parsed asn1js object into current class + * @param {!Object} schema + */ + fromSchema(schema) + { + //region Clear input data first + clearProps(schema, [ + "keyDerivationFunc", + "encryptionScheme" + ]); + //endregion + + //region Check the schema is valid + const asn1 = asn1js.compareSchema(schema, + schema, + PBES2Params.schema({ + names: { + keyDerivationFunc: { + names: { + blockName: "keyDerivationFunc" + } + }, + encryptionScheme: { + names: { + blockName: "encryptionScheme" + } + } + } + }) + ); + + if(asn1.verified === false) + throw new Error("Object's schema was not verified against input data for PBES2Params"); + //endregion + + //region Get internal properties from parsed schema + this.keyDerivationFunc = new AlgorithmIdentifier({ schema: asn1.result.keyDerivationFunc }); + this.encryptionScheme = new AlgorithmIdentifier({ schema: asn1.result.encryptionScheme }); + //endregion + } + //********************************************************************************** + /** + * Convert current object to asn1js object and set correct values + * @returns {Object} asn1js object + */ + toSchema() + { + //region Construct and return new ASN.1 schema for this object + return (new asn1js.Sequence({ + value: [ + this.keyDerivationFunc.toSchema(), + this.encryptionScheme.toSchema() + ] + })); + //endregion + } + //********************************************************************************** + /** + * Convertion for the class to JSON object + * @returns {Object} + */ + toJSON() + { + return { + keyDerivationFunc: this.keyDerivationFunc.toJSON(), + encryptionScheme: this.encryptionScheme.toJSON() + }; + } + //********************************************************************************** +} +//************************************************************************************** diff --git a/core/third-party/pkijs/PBKDF2Params.js b/core/third-party/pkijs/PBKDF2Params.js new file mode 100644 index 0000000..a83daaa --- /dev/null +++ b/core/third-party/pkijs/PBKDF2Params.js @@ -0,0 +1,242 @@ +import * as asn1js from "./asn1.js"; +import { getParametersValue, clearProps } from "./pvutils.js"; +import AlgorithmIdentifier from "./AlgorithmIdentifier.js"; +//************************************************************************************** +/** + * Class from RFC2898 + */ +export default class PBKDF2Params +{ + //********************************************************************************** + /** + * Constructor for PBKDF2Params class + * @param {Object} [parameters={}] + * @param {Object} [parameters.schema] asn1js parsed value to initialize the class from + */ + constructor(parameters = {}) + { + //region Internal properties of the object + /** + * @type {Object} + * @desc salt + */ + this.salt = getParametersValue(parameters, "salt", PBKDF2Params.defaultValues("salt")); + /** + * @type {number} + * @desc iterationCount + */ + this.iterationCount = getParametersValue(parameters, "iterationCount", PBKDF2Params.defaultValues("iterationCount")); + + if("keyLength" in parameters) + /** + * @type {number} + * @desc keyLength + */ + this.keyLength = getParametersValue(parameters, "keyLength", PBKDF2Params.defaultValues("keyLength")); + + if("prf" in parameters) + /** + * @type {AlgorithmIdentifier} + * @desc prf + */ + this.prf = getParametersValue(parameters, "prf", PBKDF2Params.defaultValues("prf")); + //endregion + + //region If input argument array contains "schema" for this object + if("schema" in parameters) + this.fromSchema(parameters.schema); + //endregion + } + //********************************************************************************** + /** + * Return default values for all class members + * @param {string} memberName String name for a class member + */ + static defaultValues(memberName) + { + switch(memberName) + { + case "salt": + return {}; + case "iterationCount": + return (-1); + case "keyLength": + return 0; + case "prf": + return new AlgorithmIdentifier({ + algorithmId: "1.3.14.3.2.26", // SHA-1 + algorithmParams: new asn1js.Null() + }); + default: + throw new Error(`Invalid member name for PBKDF2Params class: ${memberName}`); + } + } + //********************************************************************************** + /** + * Return value of pre-defined ASN.1 schema for current class + * + * ASN.1 schema: + * ```asn1 + * PBKDF2-params ::= SEQUENCE { + * salt CHOICE { + * specified OCTET STRING, + * otherSource AlgorithmIdentifier }, + * iterationCount INTEGER (1..MAX), + * keyLength INTEGER (1..MAX) OPTIONAL, + * prf AlgorithmIdentifier + * DEFAULT { algorithm hMAC-SHA1, parameters NULL } } + * ``` + * + * @param {Object} parameters Input parameters for the schema + * @returns {Object} asn1js schema object + */ + static schema(parameters = {}) + { + /** + * @type {Object} + * @property {string} [blockName] + * @property {string} [saltPrimitive] + * @property {string} [saltConstructed] + * @property {string} [iterationCount] + * @property {string} [keyLength] + * @property {string} [prf] + */ + const names = getParametersValue(parameters, "names", {}); + + return (new asn1js.Sequence({ + name: (names.blockName || ""), + value: [ + new asn1js.Choice({ + value: [ + new asn1js.OctetString({ name: (names.saltPrimitive || "") }), + AlgorithmIdentifier.schema(names.saltConstructed || {}) + ] + }), + new asn1js.Integer({ name: (names.iterationCount || "") }), + new asn1js.Integer({ + name: (names.keyLength || ""), + optional: true + }), + AlgorithmIdentifier.schema(names.prf || { + names: { + optional: true + } + }) + ] + })); + } + //********************************************************************************** + /** + * Convert parsed asn1js object into current class + * @param {!Object} schema + */ + fromSchema(schema) + { + //region Clear input data first + clearProps(schema, [ + "salt", + "iterationCount", + "keyLength", + "prf" + ]); + //endregion + + //region Check the schema is valid + const asn1 = asn1js.compareSchema(schema, + schema, + PBKDF2Params.schema({ + names: { + saltPrimitive: "salt", + saltConstructed: { + names: { + blockName: "salt" + } + }, + iterationCount: "iterationCount", + keyLength: "keyLength", + prf: { + names: { + blockName: "prf", + optional: true + } + } + } + }) + ); + + if(asn1.verified === false) + throw new Error("Object's schema was not verified against input data for PBKDF2Params"); + //endregion + + //region Get internal properties from parsed schema + this.salt = asn1.result.salt; + this.iterationCount = asn1.result.iterationCount.valueBlock.valueDec; + + if("keyLength" in asn1.result) + this.keyLength = asn1.result.keyLength.valueBlock.valueDec; + + if("prf" in asn1.result) + this.prf = new AlgorithmIdentifier({ schema: asn1.result.prf }); + //endregion + } + //********************************************************************************** + /** + * Convert current object to asn1js object and set correct values + * @returns {Object} asn1js object + */ + toSchema() + { + //region Create array for output sequence + const outputArray = []; + + outputArray.push(this.salt); + outputArray.push(new asn1js.Integer({ value: this.iterationCount })); + + if("keyLength" in this) + { + if(PBKDF2Params.defaultValues("keyLength") !== this.keyLength) + outputArray.push(new asn1js.Integer({ value: this.keyLength })); + } + + if("prf" in this) + { + if(PBKDF2Params.defaultValues("prf").isEqual(this.prf) === false) + outputArray.push(this.prf.toSchema()); + } + //endregion + + //region Construct and return new ASN.1 schema for this object + return (new asn1js.Sequence({ + value: outputArray + })); + //endregion + } + //********************************************************************************** + /** + * Convertion for the class to JSON object + * @returns {Object} + */ + toJSON() + { + const _object = { + salt: this.salt.toJSON(), + iterationCount: this.iterationCount + }; + + if("keyLength" in this) + { + if(PBKDF2Params.defaultValues("keyLength") !== this.keyLength) + _object.keyLength = this.keyLength; + } + + if("prf" in this) + { + if(PBKDF2Params.defaultValues("prf").isEqual(this.prf) === false) + _object.prf = this.prf.toJSON(); + } + + return _object; + } + //********************************************************************************** +} +//************************************************************************************** diff --git a/core/third-party/pkijs/PFX.js b/core/third-party/pkijs/PFX.js new file mode 100644 index 0000000..526aee1 --- /dev/null +++ b/core/third-party/pkijs/PFX.js @@ -0,0 +1,650 @@ +import * as asn1js from "./asn1.js"; +import { getParametersValue, utilConcatBuf, clearProps } from "./pvutils.js"; +import { getCrypto, getEngine, getRandomValues, getOIDByAlgorithm, getAlgorithmByOID } from "./common.js"; +import ContentInfo from "./ContentInfo.js"; +import MacData from "./MacData.js"; +import DigestInfo from "./DigestInfo.js"; +import AlgorithmIdentifier from "./AlgorithmIdentifier.js"; +import SignedData from "./SignedData.js"; +import EncapsulatedContentInfo from "./EncapsulatedContentInfo.js"; +import Attribute from "./Attribute.js"; +import SignerInfo from "./SignerInfo.js"; +import IssuerAndSerialNumber from "./IssuerAndSerialNumber.js"; +import SignedAndUnsignedAttributes from "./SignedAndUnsignedAttributes.js"; +import AuthenticatedSafe from "./AuthenticatedSafe.js"; +//************************************************************************************** +/** + * Class from RFC7292 + */ +export default class PFX +{ + //********************************************************************************** + /** + * Constructor for PFX class + * @param {Object} [parameters={}] + * @param {Object} [parameters.schema] asn1js parsed value to initialize the class from + */ + constructor(parameters = {}) + { + //region Internal properties of the object + /** + * @type {number} + * @desc version + */ + this.version = getParametersValue(parameters, "version", PFX.defaultValues("version")); + /** + * @type {ContentInfo} + * @desc authSafe + */ + this.authSafe = getParametersValue(parameters, "authSafe", PFX.defaultValues("authSafe")); + + if("macData" in parameters) + /** + * @type {MacData} + * @desc macData + */ + this.macData = getParametersValue(parameters, "macData", PFX.defaultValues("macData")); + + if("parsedValue" in parameters) + /** + * @type {*} + * @desc parsedValue + */ + this.parsedValue = getParametersValue(parameters, "parsedValue", PFX.defaultValues("parsedValue")); + //endregion + + //region If input argument array contains "schema" for this object + if("schema" in parameters) + this.fromSchema(parameters.schema); + //endregion + } + //********************************************************************************** + /** + * Return default values for all class members + * @param {string} memberName String name for a class member + */ + static defaultValues(memberName) + { + switch(memberName) + { + case "version": + return 3; + case "authSafe": + return (new ContentInfo()); + case "macData": + return (new MacData()); + case "parsedValue": + return {}; + default: + throw new Error(`Invalid member name for PFX class: ${memberName}`); + } + } + //********************************************************************************** + /** + * Compare values with default values for all class members + * @param {string} memberName String name for a class member + * @param {*} memberValue Value to compare with default value + */ + static compareWithDefault(memberName, memberValue) + { + switch(memberName) + { + case "version": + return (memberValue === PFX.defaultValues(memberName)); + case "authSafe": + return ((ContentInfo.compareWithDefault("contentType", memberValue.contentType)) && + (ContentInfo.compareWithDefault("content", memberValue.content))); + case "macData": + return ((MacData.compareWithDefault("mac", memberValue.mac)) && + (MacData.compareWithDefault("macSalt", memberValue.macSalt)) && + (MacData.compareWithDefault("iterations", memberValue.iterations))); + case "parsedValue": + return ((memberValue instanceof Object) && (Object.keys(memberValue).length === 0)); + default: + throw new Error(`Invalid member name for PFX class: ${memberName}`); + } + } + //********************************************************************************** + /** + * Return value of pre-defined ASN.1 schema for current class + * + * ASN.1 schema: + * ```asn1 + * PFX ::= SEQUENCE { + * version INTEGER {v3(3)}(v3,...), + * authSafe ContentInfo, + * macData MacData OPTIONAL + * } + * ``` + * + * @param {Object} parameters Input parameters for the schema + * @returns {Object} asn1js schema object + */ + static schema(parameters = {}) + { + /** + * @type {Object} + * @property {string} [blockName] + * @property {string} [version] + * @property {string} [authSafe] + * @property {string} [macData] + */ + const names = getParametersValue(parameters, "names", {}); + + return (new asn1js.Sequence({ + name: (names.blockName || ""), + value: [ + new asn1js.Integer({ name: (names.version || "version") }), + ContentInfo.schema(names.authSafe || { + names: { + blockName: "authSafe" + } + }), + MacData.schema(names.macData || { + names: { + blockName: "macData", + optional: true + } + }) + ] + })); + } + //********************************************************************************** + /** + * Convert parsed asn1js object into current class + * @param {!Object} schema + */ + fromSchema(schema) + { + //region Clear input data first + clearProps(schema, [ + "version", + "authSafe", + "macData" + ]); + //endregion + + //region Check the schema is valid + const asn1 = asn1js.compareSchema(schema, + schema, + PFX.schema({ + names: { + version: "version", + authSafe: { + names: { + blockName: "authSafe" + } + }, + macData: { + names: { + blockName: "macData" + } + } + } + }) + ); + + if(asn1.verified === false) + throw new Error("Object's schema was not verified against input data for PFX"); + //endregion + + //region Get internal properties from parsed schema + this.version = asn1.result.version.valueBlock.valueDec; + this.authSafe = new ContentInfo({ schema: asn1.result.authSafe }); + + if("macData" in asn1.result) + this.macData = new MacData({ schema: asn1.result.macData }); + //endregion + } + //********************************************************************************** + /** + * Convert current object to asn1js object and set correct values + * @returns {Object} asn1js object + */ + toSchema() + { + //region Construct and return new ASN.1 schema for this object + const outputArray = [ + new asn1js.Integer({ value: this.version }), + this.authSafe.toSchema() + ]; + + if("macData" in this) + outputArray.push(this.macData.toSchema()); + + return (new asn1js.Sequence({ + value: outputArray + })); + //endregion + } + //********************************************************************************** + /** + * Convertion for the class to JSON object + * @returns {Object} + */ + toJSON() + { + const output = { + version: this.version, + authSafe: this.authSafe.toJSON() + }; + + if("macData" in this) + output.macData = this.macData.toJSON(); + + return output; + } + //********************************************************************************** + /** + * Making ContentInfo from "parsedValue" object + * @param {Object} parameters Parameters, specific to each "integrity mode" + */ + makeInternalValues(parameters = {}) + { + //region Check mandatory parameter + if((parameters instanceof Object) === false) + return Promise.reject("The \"parameters\" must has \"Object\" type"); + + if(("parsedValue" in this) === false) + return Promise.reject("Please call \"parseValues\" function first in order to make \"parsedValue\" data"); + + if(("integrityMode" in this.parsedValue) === false) + return Promise.reject("Absent mandatory parameter \"integrityMode\" inside \"parsedValue\""); + //endregion + + //region Initial variables + let sequence = Promise.resolve(); + //endregion + + //region Get a "crypto" extension + const crypto = getCrypto(); + if(typeof crypto === "undefined") + return Promise.reject("Unable to create WebCrypto object"); + //endregion + + //region Makes values for each particular integrity mode + //region Check that we do have neccessary fields in "parsedValue" object + if(("authenticatedSafe" in this.parsedValue) === false) + return Promise.reject("Absent mandatory parameter \"authenticatedSafe\" in \"parsedValue\""); + //endregion + + switch(this.parsedValue.integrityMode) + { + //region HMAC-based integrity + case 0: + { + //region Check additional mandatory parameters + if(("iterations" in parameters) === false) + return Promise.reject("Absent mandatory parameter \"iterations\""); + + if(("pbkdf2HashAlgorithm" in parameters) === false) + return Promise.reject("Absent mandatory parameter \"pbkdf2HashAlgorithm\""); + + if(("hmacHashAlgorithm" in parameters) === false) + return Promise.reject("Absent mandatory parameter \"hmacHashAlgorithm\""); + + if(("password" in parameters) === false) + return Promise.reject("Absent mandatory parameter \"password\""); + //endregion + + //region Initial variables + const saltBuffer = new ArrayBuffer(64); + const saltView = new Uint8Array(saltBuffer); + + getRandomValues(saltView); + + const data = this.parsedValue.authenticatedSafe.toSchema().toBER(false); + + this.authSafe = new ContentInfo({ + contentType: "1.2.840.113549.1.7.1", + content: new asn1js.OctetString({ valueHex: data }) + }); + //endregion + + //region Call current crypto engine for making HMAC-based data stamp + const engine = getEngine(); + + if(("stampDataWithPassword" in engine.subtle) === false) + return Promise.reject(`No support for "stampDataWithPassword" in current engine "${engine.name}"`); + + sequence = sequence.then(() => + engine.subtle.stampDataWithPassword({ + password: parameters.password, + hashAlgorithm: parameters.hmacHashAlgorithm, + salt: saltBuffer, + iterationCount: parameters.iterations, + contentToStamp: data + }) + ); + //endregion + + //region Make "MacData" values + sequence = sequence.then( + result => + { + this.macData = new MacData({ + mac: new DigestInfo({ + digestAlgorithm: new AlgorithmIdentifier({ + algorithmId: getOIDByAlgorithm({ name: parameters.hmacHashAlgorithm }) + }), + digest: new asn1js.OctetString({ valueHex: result }) + }), + macSalt: new asn1js.OctetString({ valueHex: saltBuffer }), + iterations: parameters.iterations + }); + }, + error => Promise.reject(error) + ); + //endregion + //endregion + } + break; + //endregion + //region publicKey-based integrity + case 1: + { + //region Check additional mandatory parameters + if(("signingCertificate" in parameters) === false) + return Promise.reject("Absent mandatory parameter \"signingCertificate\""); + + if(("privateKey" in parameters) === false) + return Promise.reject("Absent mandatory parameter \"privateKey\""); + + if(("hashAlgorithm" in parameters) === false) + return Promise.reject("Absent mandatory parameter \"hashAlgorithm\""); + //endregion + + //region Making data to be signed + // NOTE: all internal data for "authenticatedSafe" must be already prepared. + // Thus user must call "makeValues" for all internal "SafeContent" value with appropriate parameters. + // Or user can choose to use values from initial parsing of existing PKCS#12 data. + + const toBeSigned = this.parsedValue.authenticatedSafe.toSchema().toBER(false); + //endregion + + //region Initial variables + const cmsSigned = new SignedData({ + version: 1, + encapContentInfo: new EncapsulatedContentInfo({ + eContentType: "1.2.840.113549.1.7.1", // "data" content type + eContent: new asn1js.OctetString({ valueHex: toBeSigned }) + }), + certificates: [parameters.signingCertificate] + }); + //endregion + + //region Making additional attributes for CMS Signed Data + //region Create a message digest + sequence = sequence.then( + () => crypto.digest({ name: parameters.hashAlgorithm }, new Uint8Array(toBeSigned)) + ); + //endregion + + //region Combine all signed extensions + sequence = sequence.then( + result => + { + //region Initial variables + const signedAttr = []; + //endregion + + //region contentType + signedAttr.push(new Attribute({ + type: "1.2.840.113549.1.9.3", + values: [ + new asn1js.ObjectIdentifier({ value: "1.2.840.113549.1.7.1" }) + ] + })); + //endregion + //region signingTime + signedAttr.push(new Attribute({ + type: "1.2.840.113549.1.9.5", + values: [ + new asn1js.UTCTime({ valueDate: new Date() }) + ] + })); + //endregion + //region messageDigest + signedAttr.push(new Attribute({ + type: "1.2.840.113549.1.9.4", + values: [ + new asn1js.OctetString({ valueHex: result }) + ] + })); + //endregion + + //region Making final value for "SignerInfo" type + cmsSigned.signerInfos.push(new SignerInfo({ + version: 1, + sid: new IssuerAndSerialNumber({ + issuer: parameters.signingCertificate.issuer, + serialNumber: parameters.signingCertificate.serialNumber + }), + signedAttrs: new SignedAndUnsignedAttributes({ + type: 0, + attributes: signedAttr + }) + })); + //endregion + }, + error => Promise.reject(`Error during making digest for message: ${error}`) + ); + //endregion + //endregion + + //region Signing CMS Signed Data + sequence = sequence.then( + () => cmsSigned.sign(parameters.privateKey, 0, parameters.hashAlgorithm) + ); + //endregion + + //region Making final CMS_CONTENT_INFO type + sequence = sequence.then( + () => + { + this.authSafe = new ContentInfo({ + contentType: "1.2.840.113549.1.7.2", + content: cmsSigned.toSchema(true) + }); + }, + error => Promise.reject(`Error during making signature: ${error}`) + ); + //endregion + } + break; + //endregion + //region default + default: + return Promise.reject(`Parameter "integrityMode" has unknown value: ${parameters.integrityMode}`); + //endregion + } + //endregion + + return sequence; + } + //********************************************************************************** + parseInternalValues(parameters) + { + //region Check input data from "parameters" + if((parameters instanceof Object) === false) + return Promise.reject("The \"parameters\" must has \"Object\" type"); + + if(("checkIntegrity" in parameters) === false) + parameters.checkIntegrity = true; + //endregion + + //region Initial variables + let sequence = Promise.resolve(); + //endregion + + //region Get a "crypto" extension + const crypto = getCrypto(); + if(typeof crypto === "undefined") + return Promise.reject("Unable to create WebCrypto object"); + //endregion + + //region Create value for "this.parsedValue.authenticatedSafe" and check integrity + this.parsedValue = {}; + + switch(this.authSafe.contentType) + { + //region data + case "1.2.840.113549.1.7.1": + { + //region Check additional mandatory parameters + if(("password" in parameters) === false) + return Promise.reject("Absent mandatory parameter \"password\""); + //endregion + + //region Integrity based on HMAC + this.parsedValue.integrityMode = 0; + //endregion + + //region Check that we do have OCTETSTRING as "content" + if((this.authSafe.content instanceof asn1js.OctetString) === false) + return Promise.reject("Wrong type of \"this.authSafe.content\""); + //endregion + + //region Check we have "constructive encoding" for AuthSafe content + let authSafeContent = new ArrayBuffer(0); + + if(this.authSafe.content.valueBlock.isConstructed) + { + for(const contentValue of this.authSafe.content.valueBlock.value) + authSafeContent = utilConcatBuf(authSafeContent, contentValue.valueBlock.valueHex); + } + else + authSafeContent = this.authSafe.content.valueBlock.valueHex; + //endregion + + //region Parse internal ASN.1 data + const asn1 = asn1js.fromBER(authSafeContent); + if(asn1.offset === (-1)) + return Promise.reject("Error during parsing of ASN.1 data inside \"this.authSafe.content\""); + //endregion + + //region Set "authenticatedSafe" value + this.parsedValue.authenticatedSafe = new AuthenticatedSafe({ schema: asn1.result }); + //endregion + + //region Check integrity + if(parameters.checkIntegrity) + { + //region Check that "MacData" exists + if(("macData" in this) === false) + return Promise.reject("Absent \"macData\" value, can not check PKCS#12 data integrity"); + //endregion + + //region Initial variables + const hashAlgorithm = getAlgorithmByOID(this.macData.mac.digestAlgorithm.algorithmId); + if(("name" in hashAlgorithm) === false) + return Promise.reject(`Unsupported digest algorithm: ${this.macData.mac.digestAlgorithm.algorithmId}`); + //endregion + + //region Call current crypto engine for verifying HMAC-based data stamp + const engine = getEngine(); + + sequence = sequence.then(() => + engine.subtle.verifyDataStampedWithPassword({ + password: parameters.password, + hashAlgorithm: hashAlgorithm.name, + salt: this.macData.macSalt.valueBlock.valueHex, + iterationCount: this.macData.iterations, + contentToVerify: authSafeContent, + signatureToVerify: this.macData.mac.digest.valueBlock.valueHex + }) + ); + //endregion + + //region Verify HMAC signature + sequence = sequence.then( + result => + { + if(result === false) + return Promise.reject("Integrity for the PKCS#12 data is broken!"); + + return Promise.resolve(); + }, + error => Promise.reject(error) + ); + //endregion + } + //endregion + } + break; + //endregion + //region signedData + case "1.2.840.113549.1.7.2": + { + //region Integrity based on signature using public key + this.parsedValue.integrityMode = 1; + //endregion + + //region Parse CMS Signed Data + const cmsSigned = new SignedData({ schema: this.authSafe.content }); + //endregion + + //region Check that we do have OCTETSTRING as "content" + if(("eContent" in cmsSigned.encapContentInfo) === false) + return Promise.reject("Absent of attached data in \"cmsSigned.encapContentInfo\""); + + if((cmsSigned.encapContentInfo.eContent instanceof asn1js.OctetString) === false) + return Promise.reject("Wrong type of \"cmsSigned.encapContentInfo.eContent\""); + //endregion + + //region Create correct data block for verification + let data = new ArrayBuffer(0); + + if(cmsSigned.encapContentInfo.eContent.idBlock.isConstructed === false) + data = cmsSigned.encapContentInfo.eContent.valueBlock.valueHex; + else + { + for(let i = 0; i < cmsSigned.encapContentInfo.eContent.valueBlock.value.length; i++) + data = utilConcatBuf(data, cmsSigned.encapContentInfo.eContent.valueBlock.value[i].valueBlock.valueHex); + } + //endregion + + //region Parse internal ASN.1 data + const asn1 = asn1js.fromBER(data); + if(asn1.offset === (-1)) + return Promise.reject("Error during parsing of ASN.1 data inside \"this.authSafe.content\""); + //endregion + + //region Set "authenticatedSafe" value + this.parsedValue.authenticatedSafe = new AuthenticatedSafe({ schema: asn1.result }); + //endregion + + //region Check integrity + sequence = sequence.then( + () => cmsSigned.verify({ signer: 0, checkChain: false }) + ).then( + result => + { + if(result === false) + return Promise.reject("Integrity for the PKCS#12 data is broken!"); + + return Promise.resolve(); + }, + error => Promise.reject(`Error during integrity verification: ${error}`) + ); + //endregion + } + break; + //endregion + //region default + default: + return Promise.reject(`Incorrect value for "this.authSafe.contentType": ${this.authSafe.contentType}`); + //endregion + } + //endregion + + //region Return result of the function + return sequence.then( + () => this, + error => Promise.reject(`Error during parsing: ${error}`) + ); + //endregion + } + //********************************************************************************** +} +//************************************************************************************** diff --git a/core/third-party/pkijs/PKCS8ShroudedKeyBag.js b/core/third-party/pkijs/PKCS8ShroudedKeyBag.js new file mode 100644 index 0000000..1c786f0 --- /dev/null +++ b/core/third-party/pkijs/PKCS8ShroudedKeyBag.js @@ -0,0 +1,285 @@ +import * as asn1js from "./asn1.js"; +import { getParametersValue, clearProps } from "./pvutils.js"; +import AlgorithmIdentifier from "./AlgorithmIdentifier.js"; +import EncryptedData from "./EncryptedData.js"; +import EncryptedContentInfo from "./EncryptedContentInfo.js"; +import PrivateKeyInfo from "./PrivateKeyInfo.js"; +//************************************************************************************** +/** + * Class from RFC7292 + */ +export default class PKCS8ShroudedKeyBag +{ + //********************************************************************************** + /** + * Constructor for PKCS8ShroudedKeyBag class + * @param {Object} [parameters={}] + * @param {Object} [parameters.schema] asn1js parsed value to initialize the class from + */ + constructor(parameters = {}) + { + //region Internal properties of the object + /** + * @type {AlgorithmIdentifier} + * @desc encryptionAlgorithm + */ + this.encryptionAlgorithm = getParametersValue(parameters, "encryptionAlgorithm", PKCS8ShroudedKeyBag.defaultValues("encryptionAlgorithm")); + /** + * @type {OctetString} + * @desc encryptedData + */ + this.encryptedData = getParametersValue(parameters, "encryptedData", PKCS8ShroudedKeyBag.defaultValues("encryptedData")); + + if("parsedValue" in parameters) + /** + * @type {*} + * @desc parsedValue + */ + this.parsedValue = getParametersValue(parameters, "parsedValue", PKCS8ShroudedKeyBag.defaultValues("parsedValue")); + //endregion + + //region If input argument array contains "schema" for this object + if("schema" in parameters) + this.fromSchema(parameters.schema); + //endregion + } + //********************************************************************************** + /** + * Return default values for all class members + * @param {string} memberName String name for a class member + */ + static defaultValues(memberName) + { + switch(memberName) + { + case "encryptionAlgorithm": + return (new AlgorithmIdentifier()); + case "encryptedData": + return (new asn1js.OctetString()); + case "parsedValue": + return {}; + default: + throw new Error(`Invalid member name for PKCS8ShroudedKeyBag class: ${memberName}`); + } + } + //********************************************************************************** + /** + * Compare values with default values for all class members + * @param {string} memberName String name for a class member + * @param {*} memberValue Value to compare with default value + */ + static compareWithDefault(memberName, memberValue) + { + switch(memberName) + { + case "encryptionAlgorithm": + return ((AlgorithmIdentifier.compareWithDefault("algorithmId", memberValue.algorithmId)) && + (("algorithmParams" in memberValue) === false)); + case "encryptedData": + return (memberValue.isEqual(PKCS8ShroudedKeyBag.defaultValues(memberName))); + case "parsedValue": + return ((memberValue instanceof Object) && (Object.keys(memberValue).length === 0)); + default: + throw new Error(`Invalid member name for PKCS8ShroudedKeyBag class: ${memberName}`); + } + } + //********************************************************************************** + /** + * Return value of pre-defined ASN.1 schema for current class + * + * ASN.1 schema: + * ```asn1 + * PKCS8ShroudedKeyBag ::= EncryptedPrivateKeyInfo + * + * EncryptedPrivateKeyInfo ::= SEQUENCE { + * encryptionAlgorithm AlgorithmIdentifier {{KeyEncryptionAlgorithms}}, + * encryptedData EncryptedData + * } + * + * EncryptedData ::= OCTET STRING + * ``` + * + * @param {Object} parameters Input parameters for the schema + * @returns {Object} asn1js schema object + */ + static schema(parameters = {}) + { + /** + * @type {Object} + * @property {string} [blockName] + * @property {string} [encryptionAlgorithm] + * @property {string} [encryptedData] + */ + const names = getParametersValue(parameters, "names", {}); + + return (new asn1js.Sequence({ + name: (names.blockName || ""), + value: [ + AlgorithmIdentifier.schema(names.encryptionAlgorithm || { + names: { + blockName: "encryptionAlgorithm" + } + }), + new asn1js.Choice({ + value: [ + new asn1js.OctetString({ name: (names.encryptedData || "encryptedData") }), + new asn1js.OctetString({ + idBlock: { + isConstructed: true + }, + name: (names.encryptedData || "encryptedData") + }) + ] + }) + ] + })); + } + //********************************************************************************** + /** + * Convert parsed asn1js object into current class + * @param {!Object} schema + */ + fromSchema(schema) + { + //region Clear input data first + clearProps(schema, [ + "encryptionAlgorithm", + "encryptedData" + ]); + //endregion + + //region Check the schema is valid + const asn1 = asn1js.compareSchema(schema, + schema, + PKCS8ShroudedKeyBag.schema({ + names: { + encryptionAlgorithm: { + names: { + blockName: "encryptionAlgorithm" + } + }, + encryptedData: "encryptedData" + } + }) + ); + + if(asn1.verified === false) + throw new Error("Object's schema was not verified against input data for PKCS8ShroudedKeyBag"); + //endregion + + //region Get internal properties from parsed schema + this.encryptionAlgorithm = new AlgorithmIdentifier({ schema: asn1.result.encryptionAlgorithm }); + this.encryptedData = asn1.result.encryptedData; + //endregion + } + //********************************************************************************** + /** + * Convert current object to asn1js object and set correct values + * @returns {Object} asn1js object + */ + toSchema() + { + //region Construct and return new ASN.1 schema for this object + return (new asn1js.Sequence({ + value: [ + this.encryptionAlgorithm.toSchema(), + this.encryptedData + ] + })); + //endregion + } + //********************************************************************************** + /** + * Convertion for the class to JSON object + * @returns {Object} + */ + toJSON() + { + return { + encryptionAlgorithm: this.encryptionAlgorithm.toJSON(), + encryptedData: this.encryptedData.toJSON() + }; + } + //********************************************************************************** + parseInternalValues(parameters) + { + //region Initial variables + let sequence = Promise.resolve(); + + const cmsEncrypted = new EncryptedData({ + encryptedContentInfo: new EncryptedContentInfo({ + contentEncryptionAlgorithm: this.encryptionAlgorithm, + encryptedContent: this.encryptedData + }) + }); + //endregion + + //region Decrypt internal data + sequence = sequence.then( + () => cmsEncrypted.decrypt(parameters), + error => Promise.reject(error) + ); + //endregion + + //region Initialize "parsedValue" with decrypted PKCS#8 private key + sequence = sequence.then( + /** + * @param {ArrayBuffer} result + */ + result => + { + const asn1 = asn1js.fromBER(result); + if(asn1.offset === (-1)) + return Promise.reject("Error during parsing ASN.1 data"); + + this.parsedValue = new PrivateKeyInfo({ schema: asn1.result }); + + return Promise.resolve(); + }, + error => Promise.reject(error) + ); + //endregion + + return sequence; + } + //********************************************************************************** + makeInternalValues(parameters) + { + //region Check that we do have "parsedValue" + if(("parsedValue" in this) === false) + return Promise.reject("Please initialize \"parsedValue\" first"); + //endregion + + //region Initial variables + let sequence = Promise.resolve(); + + const cmsEncrypted = new EncryptedData(); + //endregion + + //region Encrypt internal data + sequence = sequence.then( + () => + { + parameters.contentToEncrypt = this.parsedValue.toSchema().toBER(false); + + return cmsEncrypted.encrypt(parameters); + }, + error => Promise.reject(error) + ); + //endregion + + //region Initialize internal values + sequence = sequence.then( + () => + { + this.encryptionAlgorithm = cmsEncrypted.encryptedContentInfo.contentEncryptionAlgorithm; + this.encryptedData = cmsEncrypted.encryptedContentInfo.encryptedContent; + } + ); + //endregion + + return sequence; + } + //********************************************************************************** +} +//************************************************************************************** diff --git a/core/third-party/pkijs/PKIStatusInfo.js b/core/third-party/pkijs/PKIStatusInfo.js new file mode 100644 index 0000000..b535d06 --- /dev/null +++ b/core/third-party/pkijs/PKIStatusInfo.js @@ -0,0 +1,227 @@ +import * as asn1js from "./asn1.js"; +import { getParametersValue, clearProps } from "./pvutils.js"; +//************************************************************************************** +/** + * Class from RFC3161 + */ +export default class PKIStatusInfo +{ + //********************************************************************************** + /** + * Constructor for PKIStatusInfo class + * @param {Object} [parameters={}] + * @param {Object} [parameters.schema] asn1js parsed value to initialize the class from + */ + constructor(parameters = {}) + { + //region Internal properties of the object + /** + * @type {number} + * @desc status + */ + this.status = getParametersValue(parameters, "status", PKIStatusInfo.defaultValues("status")); + + if("statusStrings" in parameters) + /** + * @type {Array.} + * @desc statusStrings + */ + this.statusStrings = getParametersValue(parameters, "statusStrings", PKIStatusInfo.defaultValues("statusStrings")); + + if("failInfo" in parameters) + /** + * @type {BitString} + * @desc failInfo + */ + this.failInfo = getParametersValue(parameters, "failInfo", PKIStatusInfo.defaultValues("failInfo")); + //endregion + + //region If input argument array contains "schema" for this object + if("schema" in parameters) + this.fromSchema(parameters.schema); + //endregion + } + //********************************************************************************** + /** + * Return default values for all class members + * @param {string} memberName String name for a class member + */ + static defaultValues(memberName) + { + switch(memberName) + { + case "status": + return 2; + case "statusStrings": + return []; + case "failInfo": + return new asn1js.BitString(); + default: + throw new Error(`Invalid member name for PKIStatusInfo class: ${memberName}`); + } + } + //********************************************************************************** + /** + * Compare values with default values for all class members + * @param {string} memberName String name for a class member + * @param {*} memberValue Value to compare with default value + */ + static compareWithDefault(memberName, memberValue) + { + switch(memberName) + { + case "status": + return (memberValue === PKIStatusInfo.defaultValues(memberName)); + case "statusStrings": + return (memberValue.length === 0); + case "failInfo": + return (memberValue.isEqual(PKIStatusInfo.defaultValues(memberName))); + default: + throw new Error(`Invalid member name for PKIStatusInfo class: ${memberName}`); + } + } + //********************************************************************************** + /** + * Return value of pre-defined ASN.1 schema for current class + * + * ASN.1 schema: + * ```asn1 + * PKIStatusInfo ::= SEQUENCE { + * status PKIStatus, + * statusString PKIFreeText OPTIONAL, + * failInfo PKIFailureInfo OPTIONAL } + * ``` + * + * @param {Object} parameters Input parameters for the schema + * @returns {Object} asn1js schema object + */ + static schema(parameters = {}) + { + /** + * @type {Object} + * @property {string} [blockName] + * @property {string} [status] + * @property {string} [statusStrings] + * @property {string} [failInfo] + */ + const names = getParametersValue(parameters, "names", {}); + + return (new asn1js.Sequence({ + name: (names.blockName || ""), + value: [ + new asn1js.Integer({ name: (names.status || "") }), + new asn1js.Sequence({ + optional: true, + value: [ + new asn1js.Repeated({ + name: (names.statusStrings || ""), + value: new asn1js.Utf8String() + }) + ] + }), + new asn1js.BitString({ + name: (names.failInfo || ""), + optional: true + }) + ] + })); + } + //********************************************************************************** + /** + * Convert parsed asn1js object into current class + * @param {!Object} schema + */ + fromSchema(schema) + { + //region Clear input data first + clearProps(schema, [ + "status", + "statusStrings", + "failInfo" + ]); + //endregion + + //region Check the schema is valid + const asn1 = asn1js.compareSchema(schema, + schema, + PKIStatusInfo.schema({ + names: { + status: "status", + statusStrings: "statusStrings", + failInfo: "failInfo" + } + }) + ); + + if(asn1.verified === false) + throw new Error("Object's schema was not verified against input data for PKIStatusInfo"); + //endregion + + //region Get internal properties from parsed schema + const _status = asn1.result.status; + + if((_status.valueBlock.isHexOnly === true) || + (_status.valueBlock.valueDec < 0) || + (_status.valueBlock.valueDec > 5)) + throw new Error("PKIStatusInfo \"status\" has invalid value"); + + this.status = _status.valueBlock.valueDec; + + if("statusStrings" in asn1.result) + this.statusStrings = asn1.result.statusStrings; + if("failInfo" in asn1.result) + this.failInfo = asn1.result.failInfo; + //endregion + } + //********************************************************************************** + /** + * Convert current object to asn1js object and set correct values + * @returns {Object} asn1js object + */ + toSchema() + { + //region Create array of output sequence + const outputArray = []; + + outputArray.push(new asn1js.Integer({ value: this.status })); + + if("statusStrings" in this) + { + outputArray.push(new asn1js.Sequence({ + optional: true, + value: this.statusStrings + })); + } + + if("failInfo" in this) + outputArray.push(this.failInfo); + //endregion + + //region Construct and return new ASN.1 schema for this object + return (new asn1js.Sequence({ + value: outputArray + })); + //endregion + } + //********************************************************************************** + /** + * Convertion for the class to JSON object + * @returns {Object} + */ + toJSON() + { + const _object = { + status: this.status + }; + + if("statusStrings" in this) + _object.statusStrings = Array.from(this.statusStrings, element => element.toJSON()); + + if("failInfo" in this) + _object.failInfo = this.failInfo.toJSON(); + + return _object; + } + //********************************************************************************** +} +//************************************************************************************** diff --git a/core/third-party/pkijs/PasswordRecipientinfo.js b/core/third-party/pkijs/PasswordRecipientinfo.js new file mode 100644 index 0000000..b6670eb --- /dev/null +++ b/core/third-party/pkijs/PasswordRecipientinfo.js @@ -0,0 +1,247 @@ +import * as asn1js from "./asn1.js"; +import { getParametersValue, clearProps } from "./pvutils.js"; +import AlgorithmIdentifier from "./AlgorithmIdentifier.js"; +//************************************************************************************** +/** + * Class from RFC5652 + */ +export default class PasswordRecipientinfo +{ + //********************************************************************************** + /** + * Constructor for PasswordRecipientinfo class + * @param {Object} [parameters={}] + * @param {Object} [parameters.schema] asn1js parsed value to initialize the class from + */ + constructor(parameters = {}) + { + //region Internal properties of the object + /** + * @type {number} + * @desc version + */ + this.version = getParametersValue(parameters, "version", PasswordRecipientinfo.defaultValues("version")); + + if("keyDerivationAlgorithm" in parameters) + /** + * @type {AlgorithmIdentifier} + * @desc keyDerivationAlgorithm + */ + this.keyDerivationAlgorithm = getParametersValue(parameters, "keyDerivationAlgorithm", PasswordRecipientinfo.defaultValues("keyDerivationAlgorithm")); + + /** + * @type {AlgorithmIdentifier} + * @desc keyEncryptionAlgorithm + */ + this.keyEncryptionAlgorithm = getParametersValue(parameters, "keyEncryptionAlgorithm", PasswordRecipientinfo.defaultValues("keyEncryptionAlgorithm")); + /** + * @type {OctetString} + * @desc encryptedKey + */ + this.encryptedKey = getParametersValue(parameters, "encryptedKey", PasswordRecipientinfo.defaultValues("encryptedKey")); + /** + * @type {ArrayBuffer} + * @desc password Password to derive key from + */ + this.password = getParametersValue(parameters, "password", PasswordRecipientinfo.defaultValues("password")); + //endregion + + //region If input argument array contains "schema" for this object + if("schema" in parameters) + this.fromSchema(parameters.schema); + //endregion + } + //********************************************************************************** + /** + * Return default values for all class members + * @param {string} memberName String name for a class member + */ + static defaultValues(memberName) + { + switch(memberName) + { + case "version": + return (-1); + case "keyDerivationAlgorithm": + return new AlgorithmIdentifier(); + case "keyEncryptionAlgorithm": + return new AlgorithmIdentifier(); + case "encryptedKey": + return new asn1js.OctetString(); + case "password": + return new ArrayBuffer(0); + default: + throw new Error(`Invalid member name for PasswordRecipientinfo class: ${memberName}`); + } + } + //********************************************************************************** + /** + * Compare values with default values for all class members + * @param {string} memberName String name for a class member + * @param {*} memberValue Value to compare with default value + */ + static compareWithDefault(memberName, memberValue) + { + switch(memberName) + { + case "version": + return (memberValue === (-1)); + case "keyDerivationAlgorithm": + case "keyEncryptionAlgorithm": + return ((memberValue.algorithmId === "") && (("algorithmParams" in memberValue) === false)); + case "encryptedKey": + return (memberValue.isEqual(PasswordRecipientinfo.defaultValues("encryptedKey"))); + case "password": + return (memberValue.byteLength === 0); + default: + throw new Error(`Invalid member name for PasswordRecipientinfo class: ${memberName}`); + } + } + //********************************************************************************** + /** + * Return value of pre-defined ASN.1 schema for current class + * + * ASN.1 schema: + * ```asn1 + * PasswordRecipientInfo ::= SEQUENCE { + * version CMSVersion, -- Always set to 0 + * keyDerivationAlgorithm [0] KeyDerivationAlgorithmIdentifier OPTIONAL, + * keyEncryptionAlgorithm KeyEncryptionAlgorithmIdentifier, + * encryptedKey EncryptedKey } + * ``` + * + * @param {Object} parameters Input parameters for the schema + * @returns {Object} asn1js schema object + */ + static schema(parameters = {}) + { + /** + * @type {Object} + * @property {string} [blockName] + * @property {string} [keyDerivationAlgorithm] + * @property {string} [keyEncryptionAlgorithm] + * @property {string} [encryptedKey] + */ + const names = getParametersValue(parameters, "names", {}); + + return (new asn1js.Sequence({ + name: (names.blockName || ""), + value: [ + new asn1js.Integer({ name: (names.version || "") }), + new asn1js.Constructed({ + name: (names.keyDerivationAlgorithm || ""), + optional: true, + idBlock: { + tagClass: 3, // CONTEXT-SPECIFIC + tagNumber: 0 // [0] + }, + value: AlgorithmIdentifier.schema().valueBlock.value + }), + AlgorithmIdentifier.schema(names.keyEncryptionAlgorithm || {}), + new asn1js.OctetString({ name: (names.encryptedKey || "") }) + ] + })); + } + //********************************************************************************** + /** + * Convert parsed asn1js object into current class + * @param {!Object} schema + */ + fromSchema(schema) + { + //region Clear input data first + clearProps(schema, [ + "version", + "keyDerivationAlgorithm", + "keyEncryptionAlgorithm", + "encryptedKey" + ]); + //endregion + + //region Check the schema is valid + const asn1 = asn1js.compareSchema(schema, + schema, + PasswordRecipientinfo.schema({ + names: { + version: "version", + keyDerivationAlgorithm: "keyDerivationAlgorithm", + keyEncryptionAlgorithm: { + names: { + blockName: "keyEncryptionAlgorithm" + } + }, + encryptedKey: "encryptedKey" + } + }) + ); + + if(asn1.verified === false) + throw new Error("Object's schema was not verified against input data for PasswordRecipientinfo"); + //endregion + + //region Get internal properties from parsed schema + this.version = asn1.result.version.valueBlock.valueDec; + + if("keyDerivationAlgorithm" in asn1.result) + { + this.keyDerivationAlgorithm = new AlgorithmIdentifier({ + schema: new asn1js.Sequence({ + value: asn1.result.keyDerivationAlgorithm.valueBlock.value + }) + }); + } + + this.keyEncryptionAlgorithm = new AlgorithmIdentifier({ schema: asn1.result.keyEncryptionAlgorithm }); + this.encryptedKey = asn1.result.encryptedKey; + //endregion + } + //********************************************************************************** + /** + * Convert current object to asn1js object and set correct values + * @returns {Object} asn1js object + */ + toSchema() + { + //region Create output array for sequence + const outputArray = []; + + outputArray.push(new asn1js.Integer({ value: this.version })); + + if("keyDerivationAlgorithm" in this) + { + outputArray.push(new asn1js.Constructed({ + idBlock: { + tagClass: 3, // CONTEXT-SPECIFIC + tagNumber: 0 // [0] + }, + value: this.keyDerivationAlgorithm.toSchema().valueBlock.value + })); + } + + outputArray.push(this.keyEncryptionAlgorithm.toSchema()); + outputArray.push(this.encryptedKey); + //endregion + + //region Construct and return new ASN.1 schema for this object + return (new asn1js.Sequence({ + value: outputArray + })); + //endregion + } + //********************************************************************************** + /** + * Convertion for the class to JSON object + * @returns {Object} + */ + toJSON() + { + return { + version: this.version, + keyDerivationAlgorithm: this.keyDerivationAlgorithm.toJSON(), + keyEncryptionAlgorithm: this.keyEncryptionAlgorithm.toJSON(), + encryptedKey: this.encryptedKey.toJSON() + }; + } + //********************************************************************************** +} +//************************************************************************************** diff --git a/core/third-party/pkijs/PolicyConstraints.js b/core/third-party/pkijs/PolicyConstraints.js new file mode 100644 index 0000000..b200c0a --- /dev/null +++ b/core/third-party/pkijs/PolicyConstraints.js @@ -0,0 +1,216 @@ +import * as asn1js from "./asn1.js"; +import { getParametersValue, clearProps } from "./pvutils.js"; +//************************************************************************************** +/** + * Class from RFC5280 + */ +export default class PolicyConstraints +{ + //********************************************************************************** + /** + * Constructor for PolicyConstraints class + * @param {Object} [parameters={}] + * @param {Object} [parameters.schema] asn1js parsed value to initialize the class from + */ + constructor(parameters = {}) + { + //region Internal properties of the object + if("requireExplicitPolicy" in parameters) + /** + * @type {number} + * @desc requireExplicitPolicy + */ + this.requireExplicitPolicy = getParametersValue(parameters, "requireExplicitPolicy", PolicyConstraints.defaultValues("requireExplicitPolicy")); + + if("inhibitPolicyMapping" in parameters) + /** + * @type {number} + * @desc Value of the TIME class + */ + this.inhibitPolicyMapping = getParametersValue(parameters, "inhibitPolicyMapping", PolicyConstraints.defaultValues("inhibitPolicyMapping")); + //endregion + + //region If input argument array contains "schema" for this object + if("schema" in parameters) + this.fromSchema(parameters.schema); + //endregion + } + //********************************************************************************** + /** + * Return default values for all class members + * @param {string} memberName String name for a class member + */ + static defaultValues(memberName) + { + switch(memberName) + { + case "requireExplicitPolicy": + return 0; + case "inhibitPolicyMapping": + return 0; + default: + throw new Error(`Invalid member name for PolicyConstraints class: ${memberName}`); + } + } + //********************************************************************************** + /** + * Return value of pre-defined ASN.1 schema for current class + * + * ASN.1 schema: + * ```asn1 + * PolicyConstraints ::= SEQUENCE { + * requireExplicitPolicy [0] SkipCerts OPTIONAL, + * inhibitPolicyMapping [1] SkipCerts OPTIONAL } + * + * SkipCerts ::= INTEGER (0..MAX) + * ``` + * + * @param {Object} parameters Input parameters for the schema + * @returns {Object} asn1js schema object + */ + static schema(parameters = {}) + { + /** + * @type {Object} + * @property {string} [blockName] + * @property {string} [requireExplicitPolicy] + * @property {string} [inhibitPolicyMapping] + */ + const names = getParametersValue(parameters, "names", {}); + + return (new asn1js.Sequence({ + name: (names.blockName || ""), + value: [ + new asn1js.Primitive({ + name: (names.requireExplicitPolicy || ""), + optional: true, + idBlock: { + tagClass: 3, // CONTEXT-SPECIFIC + tagNumber: 0 // [0] + } + }), // IMPLICIT integer value + new asn1js.Primitive({ + name: (names.inhibitPolicyMapping || ""), + optional: true, + idBlock: { + tagClass: 3, // CONTEXT-SPECIFIC + tagNumber: 1 // [1] + } + }) // IMPLICIT integer value + ] + })); + } + //********************************************************************************** + /** + * Convert parsed asn1js object into current class + * @param {!Object} schema + */ + fromSchema(schema) + { + //region Clear input data first + clearProps(schema, [ + "requireExplicitPolicy", + "inhibitPolicyMapping" + ]); + //endregion + + //region Check the schema is valid + const asn1 = asn1js.compareSchema(schema, + schema, + PolicyConstraints.schema({ + names: { + requireExplicitPolicy: "requireExplicitPolicy", + inhibitPolicyMapping: "inhibitPolicyMapping" + } + }) + ); + + if(asn1.verified === false) + throw new Error("Object's schema was not verified against input data for PolicyConstraints"); + //endregion + + //region Get internal properties from parsed schema + if("requireExplicitPolicy" in asn1.result) + { + const field1 = asn1.result.requireExplicitPolicy; + + field1.idBlock.tagClass = 1; // UNIVERSAL + field1.idBlock.tagNumber = 2; // INTEGER + + const ber1 = field1.toBER(false); + const int1 = asn1js.fromBER(ber1); + + this.requireExplicitPolicy = int1.result.valueBlock.valueDec; + } + + if("inhibitPolicyMapping" in asn1.result) + { + const field2 = asn1.result.inhibitPolicyMapping; + + field2.idBlock.tagClass = 1; // UNIVERSAL + field2.idBlock.tagNumber = 2; // INTEGER + + const ber2 = field2.toBER(false); + const int2 = asn1js.fromBER(ber2); + + this.inhibitPolicyMapping = int2.result.valueBlock.valueDec; + } + //endregion + } + //********************************************************************************** + /** + * Convert current object to asn1js object and set correct values + * @returns {Object} asn1js object + */ + toSchema() + { + //region Create correct values for output sequence + const outputArray = []; + + if("requireExplicitPolicy" in this) + { + const int1 = new asn1js.Integer({ value: this.requireExplicitPolicy }); + + int1.idBlock.tagClass = 3; // CONTEXT-SPECIFIC + int1.idBlock.tagNumber = 0; // [0] + + outputArray.push(int1); + } + + if("inhibitPolicyMapping" in this) + { + const int2 = new asn1js.Integer({ value: this.inhibitPolicyMapping }); + + int2.idBlock.tagClass = 3; // CONTEXT-SPECIFIC + int2.idBlock.tagNumber = 1; // [1] + + outputArray.push(int2); + } + //endregion + + //region Construct and return new ASN.1 schema for this object + return (new asn1js.Sequence({ + value: outputArray + })); + //endregion + } + //********************************************************************************** + /** + * Convertion for the class to JSON object + * @returns {Object} + */ + toJSON() + { + const object = {}; + + if("requireExplicitPolicy" in this) + object.requireExplicitPolicy = this.requireExplicitPolicy; + + if("inhibitPolicyMapping" in this) + object.inhibitPolicyMapping = this.inhibitPolicyMapping; + + return object; + } + //********************************************************************************** +} +//************************************************************************************** diff --git a/core/third-party/pkijs/PolicyInformation.js b/core/third-party/pkijs/PolicyInformation.js new file mode 100644 index 0000000..aa6ea23 --- /dev/null +++ b/core/third-party/pkijs/PolicyInformation.js @@ -0,0 +1,178 @@ +import * as asn1js from "./asn1.js"; +import { getParametersValue, clearProps } from "./pvutils.js"; +import PolicyQualifierInfo from "./PolicyQualifierInfo.js"; +//************************************************************************************** +/** + * Class from RFC5280 + */ +export default class PolicyInformation +{ + //********************************************************************************** + /** + * Constructor for PolicyInformation class + * @param {Object} [parameters={}] + * @param {Object} [parameters.schema] asn1js parsed value to initialize the class from + */ + constructor(parameters = {}) + { + //region Internal properties of the object + /** + * @type {string} + * @desc policyIdentifier + */ + this.policyIdentifier = getParametersValue(parameters, "policyIdentifier", PolicyInformation.defaultValues("policyIdentifier")); + + if("policyQualifiers" in parameters) + /** + * @type {Array.} + * @desc Value of the TIME class + */ + this.policyQualifiers = getParametersValue(parameters, "policyQualifiers", PolicyInformation.defaultValues("policyQualifiers")); + //endregion + + //region If input argument array contains "schema" for this object + if("schema" in parameters) + this.fromSchema(parameters.schema); + //endregion + } + //********************************************************************************** + /** + * Return default values for all class members + * @param {string} memberName String name for a class member + */ + static defaultValues(memberName) + { + switch(memberName) + { + case "policyIdentifier": + return ""; + case "policyQualifiers": + return []; + default: + throw new Error(`Invalid member name for PolicyInformation class: ${memberName}`); + } + } + //********************************************************************************** + /** + * Return value of pre-defined ASN.1 schema for current class + * + * ASN.1 schema: + * ```asn1 + * PolicyInformation ::= SEQUENCE { + * policyIdentifier CertPolicyId, + * policyQualifiers SEQUENCE SIZE (1..MAX) OF + * PolicyQualifierInfo OPTIONAL } + * + * CertPolicyId ::= OBJECT IDENTIFIER + * ``` + * + * @param {Object} parameters Input parameters for the schema + * @returns {Object} asn1js schema object + */ + static schema(parameters = {}) + { + /** + * @type {Object} + * @property {string} [blockName] + * @property {string} [policyIdentifier] + * @property {string} [policyQualifiers] + */ + const names = getParametersValue(parameters, "names", {}); + + return (new asn1js.Sequence({ + name: (names.blockName || ""), + value: [ + new asn1js.ObjectIdentifier({ name: (names.policyIdentifier || "") }), + new asn1js.Sequence({ + optional: true, + value: [ + new asn1js.Repeated({ + name: (names.policyQualifiers || ""), + value: PolicyQualifierInfo.schema() + }) + ] + }) + ] + })); + } + //********************************************************************************** + /** + * Convert parsed asn1js object into current class + * @param {!Object} schema + */ + fromSchema(schema) + { + //region Clear input data first + clearProps(schema, [ + "policyIdentifier", + "policyQualifiers" + ]); + //endregion + + //region Check the schema is valid + const asn1 = asn1js.compareSchema(schema, + schema, + PolicyInformation.schema({ + names: { + policyIdentifier: "policyIdentifier", + policyQualifiers: "policyQualifiers" + } + }) + ); + + if(asn1.verified === false) + throw new Error("Object's schema was not verified against input data for PolicyInformation"); + //endregion + + //region Get internal properties from parsed schema + this.policyIdentifier = asn1.result.policyIdentifier.valueBlock.toString(); + + if("policyQualifiers" in asn1.result) + this.policyQualifiers = Array.from(asn1.result.policyQualifiers, element => new PolicyQualifierInfo({ schema: element })); + //endregion + } + //********************************************************************************** + /** + * Convert current object to asn1js object and set correct values + * @returns {Object} asn1js object + */ + toSchema() + { + //region Create array for output sequence + const outputArray = []; + + outputArray.push(new asn1js.ObjectIdentifier({ value: this.policyIdentifier })); + + if("policyQualifiers" in this) + { + outputArray.push(new asn1js.Sequence({ + value: Array.from(this.policyQualifiers, element => element.toSchema()) + })); + } + //endregion + + //region Construct and return new ASN.1 schema for this object + return (new asn1js.Sequence({ + value: outputArray + })); + //endregion + } + //********************************************************************************** + /** + * Convertion for the class to JSON object + * @returns {Object} + */ + toJSON() + { + const object = { + policyIdentifier: this.policyIdentifier + }; + + if("policyQualifiers" in this) + object.policyQualifiers = Array.from(this.policyQualifiers, element => element.toJSON()); + + return object; + } + //********************************************************************************** +} +//************************************************************************************** diff --git a/core/third-party/pkijs/PolicyMapping.js b/core/third-party/pkijs/PolicyMapping.js new file mode 100644 index 0000000..2cf8fd5 --- /dev/null +++ b/core/third-party/pkijs/PolicyMapping.js @@ -0,0 +1,148 @@ +import * as asn1js from "./asn1.js"; +import { getParametersValue, clearProps } from "./pvutils.js"; +//************************************************************************************** +/** + * Class from RFC5280 + */ +export default class PolicyMapping +{ + //********************************************************************************** + /** + * Constructor for PolicyMapping class + * @param {Object} [parameters={}] + * @param {Object} [parameters.schema] asn1js parsed value to initialize the class from + */ + constructor(parameters = {}) + { + //region Internal properties of the object + /** + * @type {string} + * @desc issuerDomainPolicy + */ + this.issuerDomainPolicy = getParametersValue(parameters, "issuerDomainPolicy", PolicyMapping.defaultValues("issuerDomainPolicy")); + /** + * @type {string} + * @desc subjectDomainPolicy + */ + this.subjectDomainPolicy = getParametersValue(parameters, "subjectDomainPolicy", PolicyMapping.defaultValues("subjectDomainPolicy")); + //endregion + + //region If input argument array contains "schema" for this object + if("schema" in parameters) + this.fromSchema(parameters.schema); + //endregion + } + //********************************************************************************** + /** + * Return default values for all class members + * @param {string} memberName String name for a class member + */ + static defaultValues(memberName) + { + switch(memberName) + { + case "issuerDomainPolicy": + return ""; + case "subjectDomainPolicy": + return ""; + default: + throw new Error(`Invalid member name for PolicyMapping class: ${memberName}`); + } + } + //********************************************************************************** + /** + * Return value of pre-defined ASN.1 schema for current class + * + * ASN.1 schema: + * ```asn1 + * PolicyMapping ::= SEQUENCE { + * issuerDomainPolicy CertPolicyId, + * subjectDomainPolicy CertPolicyId } + * ``` + * + * @param {Object} parameters Input parameters for the schema + * @returns {Object} asn1js schema object + */ + static schema(parameters = {}) + { + /** + * @type {Object} + * @property {string} [blockName] + * @property {string} [issuerDomainPolicy] + * @property {string} [subjectDomainPolicy] + */ + const names = getParametersValue(parameters, "names", {}); + + return (new asn1js.Sequence({ + name: (names.blockName || ""), + value: [ + new asn1js.ObjectIdentifier({ name: (names.issuerDomainPolicy || "") }), + new asn1js.ObjectIdentifier({ name: (names.subjectDomainPolicy || "") }) + ] + })); + } + //********************************************************************************** + /** + * Convert parsed asn1js object into current class + * @param {!Object} schema + */ + fromSchema(schema) + { + //region Clear input data first + clearProps(schema, [ + "issuerDomainPolicy", + "subjectDomainPolicy" + ]); + //endregion + + //region Check the schema is valid + const asn1 = asn1js.compareSchema(schema, + schema, + PolicyMapping.schema({ + names: { + issuerDomainPolicy: "issuerDomainPolicy", + subjectDomainPolicy: "subjectDomainPolicy" + } + }) + ); + + if(asn1.verified === false) + throw new Error("Object's schema was not verified against input data for PolicyMapping"); + //endregion + + //region Get internal properties from parsed schema + this.issuerDomainPolicy = asn1.result.issuerDomainPolicy.valueBlock.toString(); + this.subjectDomainPolicy = asn1.result.subjectDomainPolicy.valueBlock.toString(); + //endregion + } + //********************************************************************************** + /** + * Convert current object to asn1js object and set correct values + * @returns {Object} asn1js object + */ + toSchema() + { + //region Construct and return new ASN.1 schema for this object + return (new asn1js.Sequence({ + value: [ + new asn1js.ObjectIdentifier({ value: this.issuerDomainPolicy }), + new asn1js.ObjectIdentifier({ value: this.subjectDomainPolicy }) + ] + })); + //endregion + } + //********************************************************************************** + /** + * Convertion for the class to JSON object + * @returns {Object} + */ + toJSON() + { + return { + issuerDomainPolicy: this.issuerDomainPolicy, + subjectDomainPolicy: this.subjectDomainPolicy + }; + } + //********************************************************************************** +} +//************************************************************************************** diff --git a/core/third-party/pkijs/PolicyMappings.js b/core/third-party/pkijs/PolicyMappings.js new file mode 100644 index 0000000..21f8611 --- /dev/null +++ b/core/third-party/pkijs/PolicyMappings.js @@ -0,0 +1,135 @@ +import * as asn1js from "./asn1.js"; +import { getParametersValue, clearProps } from "./pvutils.js"; +import PolicyMapping from "./PolicyMapping.js"; +//************************************************************************************** +/** + * Class from RFC5280 + */ +export default class PolicyMappings +{ + //********************************************************************************** + /** + * Constructor for PolicyMappings class + * @param {Object} [parameters={}] + * @param {Object} [parameters.schema] asn1js parsed value to initialize the class from + */ + constructor(parameters = {}) + { + //region Internal properties of the object + /** + * @type {Array.} + * @desc mappings + */ + this.mappings = getParametersValue(parameters, "mappings", PolicyMappings.defaultValues("mappings")); + //endregion + + //region If input argument array contains "schema" for this object + if("schema" in parameters) + this.fromSchema(parameters.schema); + //endregion + } + //********************************************************************************** + /** + * Return default values for all class members + * @param {string} memberName String name for a class member + */ + static defaultValues(memberName) + { + switch(memberName) + { + case "mappings": + return []; + default: + throw new Error(`Invalid member name for PolicyMappings class: ${memberName}`); + } + } + //********************************************************************************** + /** + * Return value of pre-defined ASN.1 schema for current class + * + * ASN.1 schema: + * ```asn1 + * PolicyMappings ::= SEQUENCE SIZE (1..MAX) OF PolicyMapping + * ``` + * + * @param {Object} parameters Input parameters for the schema + * @returns {Object} asn1js schema object + */ + static schema(parameters = {}) + { + /** + * @type {Object} + * @property {string} [blockName] + * @property {string} [utcTimeName] Name for "utcTimeName" choice + * @property {string} [generalTimeName] Name for "generalTimeName" choice + */ + const names = getParametersValue(parameters, "names", {}); + + return (new asn1js.Sequence({ + name: (names.blockName || ""), + value: [ + new asn1js.Repeated({ + name: (names.mappings || ""), + value: PolicyMapping.schema() + }) + ] + })); + } + //********************************************************************************** + /** + * Convert parsed asn1js object into current class + * @param {!Object} schema + */ + fromSchema(schema) + { + //region Clear input data first + clearProps(schema, [ + "mappings" + ]); + //endregion + + //region Check the schema is valid + const asn1 = asn1js.compareSchema(schema, + schema, + PolicyMappings.schema({ + names: { + mappings: "mappings" + } + }) + ); + + if(asn1.verified === false) + throw new Error("Object's schema was not verified against input data for PolicyMappings"); + //endregion + + //region Get internal properties from parsed schema + this.mappings = Array.from(asn1.result.mappings, element => new PolicyMapping({ schema: element })); + //endregion + } + //********************************************************************************** + /** + * Convert current object to asn1js object and set correct values + * @returns {Object} asn1js object + */ + toSchema() + { + //region Construct and return new ASN.1 schema for this object + return (new asn1js.Sequence({ + value: Array.from(this.mappings, element => element.toSchema()) + })); + //endregion + } + //********************************************************************************** + /** + * Convertion for the class to JSON object + * @returns {Object} + */ + toJSON() + { + return { + mappings: Array.from(this.mappings, element => element.toJSON()) + }; + } + //********************************************************************************** +} +//************************************************************************************** diff --git a/core/third-party/pkijs/PolicyQualifierInfo.js b/core/third-party/pkijs/PolicyQualifierInfo.js new file mode 100644 index 0000000..8a31ea0 --- /dev/null +++ b/core/third-party/pkijs/PolicyQualifierInfo.js @@ -0,0 +1,154 @@ +import * as asn1js from "./asn1.js"; +import { getParametersValue, clearProps } from "./pvutils.js"; +//************************************************************************************** +/** + * Class from RFC5280 + */ +export default class PolicyQualifierInfo +{ + //********************************************************************************** + /** + * Constructor for PolicyQualifierInfo class + * @param {Object} [parameters={}] + * @param {Object} [parameters.schema] asn1js parsed value to initialize the class from + */ + constructor(parameters = {}) + { + //region Internal properties of the object + /** + * @type {string} + * @desc policyQualifierId + */ + this.policyQualifierId = getParametersValue(parameters, "policyQualifierId", PolicyQualifierInfo.defaultValues("policyQualifierId")); + /** + * @type {Object} + * @desc qualifier + */ + this.qualifier = getParametersValue(parameters, "qualifier", PolicyQualifierInfo.defaultValues("qualifier")); + //endregion + + //region If input argument array contains "schema" for this object + if("schema" in parameters) + this.fromSchema(parameters.schema); + //endregion + } + //********************************************************************************** + /** + * Return default values for all class members + * @param {string} memberName String name for a class member + */ + static defaultValues(memberName) + { + switch(memberName) + { + case "policyQualifierId": + return ""; + case "qualifier": + return new asn1js.Any(); + default: + throw new Error(`Invalid member name for PolicyQualifierInfo class: ${memberName}`); + } + } + //********************************************************************************** + /** + * Return value of pre-defined ASN.1 schema for current class + * + * ASN.1 schema: + * ```asn1 + * PolicyQualifierInfo ::= SEQUENCE { + * policyQualifierId PolicyQualifierId, + * qualifier ANY DEFINED BY policyQualifierId } + * + * id-qt OBJECT IDENTIFIER ::= { id-pkix 2 } + * id-qt-cps OBJECT IDENTIFIER ::= { id-qt 1 } + * id-qt-unotice OBJECT IDENTIFIER ::= { id-qt 2 } + * + * PolicyQualifierId ::= OBJECT IDENTIFIER ( id-qt-cps | id-qt-unotice ) + * ``` + * + * @param {Object} parameters Input parameters for the schema + * @returns {Object} asn1js schema object + */ + static schema(parameters = {}) + { + /** + * @type {Object} + * @property {string} [blockName] + * @property {string} [policyQualifierId] + * @property {string} [qualifier] + */ + const names = getParametersValue(parameters, "names", {}); + + return (new asn1js.Sequence({ + name: (names.blockName || ""), + value: [ + new asn1js.ObjectIdentifier({ name: (names.policyQualifierId || "") }), + new asn1js.Any({ name: (names.qualifier || "") }) + ] + })); + } + //********************************************************************************** + /** + * Convert parsed asn1js object into current class + * @param {!Object} schema + */ + fromSchema(schema) + { + //region Clear input data first + clearProps(schema, [ + "policyQualifierId", + "qualifier" + ]); + //endregion + + //region Check the schema is valid + const asn1 = asn1js.compareSchema(schema, + schema, + PolicyQualifierInfo.schema({ + names: { + policyQualifierId: "policyQualifierId", + qualifier: "qualifier" + } + }) + ); + + if(asn1.verified === false) + throw new Error("Object's schema was not verified against input data for PolicyQualifierInfo"); + //endregion + + //region Get internal properties from parsed schema + this.policyQualifierId = asn1.result.policyQualifierId.valueBlock.toString(); + this.qualifier = asn1.result.qualifier; + //endregion + } + //********************************************************************************** + /** + * Convert current object to asn1js object and set correct values + * @returns {Object} asn1js object + */ + toSchema() + { + //region Construct and return new ASN.1 schema for this object + return (new asn1js.Sequence({ + value: [ + new asn1js.ObjectIdentifier({ value: this.policyQualifierId }), + this.qualifier + ] + })); + //endregion + } + //********************************************************************************** + /** + * Convertion for the class to JSON object + * @returns {Object} + */ + toJSON() + { + return { + policyQualifierId: this.policyQualifierId, + qualifier: this.qualifier.toJSON() + }; + } + //********************************************************************************** +} +//************************************************************************************** diff --git a/core/third-party/pkijs/PrivateKeyInfo.js b/core/third-party/pkijs/PrivateKeyInfo.js new file mode 100644 index 0000000..54a1378 --- /dev/null +++ b/core/third-party/pkijs/PrivateKeyInfo.js @@ -0,0 +1,329 @@ +import * as asn1js from "./asn1.js"; +import { getParametersValue, clearProps } from "./pvutils.js"; +import AlgorithmIdentifier from "./AlgorithmIdentifier.js"; +import Attribute from "./Attribute.js"; +import ECPrivateKey from "./ECPrivateKey.js"; +import RSAPrivateKey from "./RSAPrivateKey.js"; +//************************************************************************************** +/** + * Class from RFC5208 + */ +export default class PrivateKeyInfo +{ + //********************************************************************************** + /** + * Constructor for PrivateKeyInfo class + * @param {Object} [parameters={}] + * @param {Object} [parameters.schema] asn1js parsed value to initialize the class from + */ + constructor(parameters = {}) + { + //region Internal properties of the object + /** + * @type {number} + * @desc version + */ + this.version = getParametersValue(parameters, "version", PrivateKeyInfo.defaultValues("version")); + /** + * @type {AlgorithmIdentifier} + * @desc privateKeyAlgorithm + */ + this.privateKeyAlgorithm = getParametersValue(parameters, "privateKeyAlgorithm", PrivateKeyInfo.defaultValues("privateKeyAlgorithm")); + /** + * @type {OctetString} + * @desc privateKey + */ + this.privateKey = getParametersValue(parameters, "privateKey", PrivateKeyInfo.defaultValues("privateKey")); + + if("attributes" in parameters) + /** + * @type {Array.} + * @desc attributes + */ + this.attributes = getParametersValue(parameters, "attributes", PrivateKeyInfo.defaultValues("attributes")); + + if("parsedKey" in parameters) + /** + * @type {ECPrivateKey|RSAPrivateKey} + * @desc Parsed public key value + */ + this.parsedKey = getParametersValue(parameters, "parsedKey", PrivateKeyInfo.defaultValues("parsedKey")); + //endregion + + //region If input argument array contains "schema" for this object + if("schema" in parameters) + this.fromSchema(parameters.schema); + //endregion + //region If input argument array contains "json" for this object + if("json" in parameters) + this.fromJSON(parameters.json); + //endregion + } + //********************************************************************************** + /** + * Return default values for all class members + * @param {string} memberName String name for a class member + */ + static defaultValues(memberName) + { + switch(memberName) + { + case "version": + return 0; + case "privateKeyAlgorithm": + return new AlgorithmIdentifier(); + case "privateKey": + return new asn1js.OctetString(); + case "attributes": + return []; + case "parsedKey": + return {}; + default: + throw new Error(`Invalid member name for PrivateKeyInfo class: ${memberName}`); + } + } + //********************************************************************************** + /** + * Return value of pre-defined ASN.1 schema for current class + * + * ASN.1 schema: + * ```asn1 + * PrivateKeyInfo ::= SEQUENCE { + * version Version, + * privateKeyAlgorithm AlgorithmIdentifier {{PrivateKeyAlgorithms}}, + * privateKey PrivateKey, + * attributes [0] Attributes OPTIONAL } + * + * Version ::= INTEGER {v1(0)} (v1,...) + * + * PrivateKey ::= OCTET STRING + * + * Attributes ::= SET OF Attribute + * ``` + * + * @param {Object} parameters Input parameters for the schema + * @returns {Object} asn1js schema object + */ + static schema(parameters = {}) + { + /** + * @type {Object} + * @property {string} [blockName] + * @property {string} [version] + * @property {string} [privateKeyAlgorithm] + * @property {string} [privateKey] + * @property {string} [attributes] + */ + const names = getParametersValue(parameters, "names", {}); + + return (new asn1js.Sequence({ + name: (names.blockName || ""), + value: [ + new asn1js.Integer({ name: (names.version || "") }), + AlgorithmIdentifier.schema(names.privateKeyAlgorithm || {}), + new asn1js.OctetString({ name: (names.privateKey || "") }), + new asn1js.Constructed({ + optional: true, + idBlock: { + tagClass: 3, // CONTEXT-SPECIFIC + tagNumber: 0 // [0] + }, + value: [ + new asn1js.Repeated({ + name: (names.attributes || ""), + value: Attribute.schema() + }) + ] + }) + ] + })); + } + //********************************************************************************** + /** + * Convert parsed asn1js object into current class + * @param {!Object} schema + */ + fromSchema(schema) + { + //region Clear input data first + clearProps(schema, [ + "version", + "privateKeyAlgorithm", + "privateKey", + "attributes" + ]); + //endregion + + //region Check the schema is valid + const asn1 = asn1js.compareSchema(schema, + schema, + PrivateKeyInfo.schema({ + names: { + version: "version", + privateKeyAlgorithm: { + names: { + blockName: "privateKeyAlgorithm" + } + }, + privateKey: "privateKey", + attributes: "attributes" + } + }) + ); + + if(asn1.verified === false) + throw new Error("Object's schema was not verified against input data for PrivateKeyInfo"); + //endregion + + //region Get internal properties from parsed schema + this.version = asn1.result.version.valueBlock.valueDec; + this.privateKeyAlgorithm = new AlgorithmIdentifier({ schema: asn1.result.privateKeyAlgorithm }); + this.privateKey = asn1.result.privateKey; + + if("attributes" in asn1.result) + this.attributes = Array.from(asn1.result.attributes, element => new Attribute({ schema: element })); + + switch(this.privateKeyAlgorithm.algorithmId) + { + case "1.2.840.113549.1.1.1": // RSA + { + const privateKeyASN1 = asn1js.fromBER(this.privateKey.valueBlock.valueHex); + if(privateKeyASN1.offset !== (-1)) + this.parsedKey = new RSAPrivateKey({ schema: privateKeyASN1.result }); + } + break; + case "1.2.840.10045.2.1": // ECDSA + if("algorithmParams" in this.privateKeyAlgorithm) + { + if(this.privateKeyAlgorithm.algorithmParams instanceof asn1js.ObjectIdentifier) + { + const privateKeyASN1 = asn1js.fromBER(this.privateKey.valueBlock.valueHex); + if(privateKeyASN1.offset !== (-1)) + { + this.parsedKey = new ECPrivateKey({ + namedCurve: this.privateKeyAlgorithm.algorithmParams.valueBlock.toString(), + schema: privateKeyASN1.result + }); + } + } + } + break; + default: + } + //endregion + } + //********************************************************************************** + /** + * Convert current object to asn1js object and set correct values + * @returns {Object} asn1js object + */ + toSchema() + { + //region Create array for output sequence + const outputArray = [ + new asn1js.Integer({ value: this.version }), + this.privateKeyAlgorithm.toSchema(), + this.privateKey + ]; + + if("attributes" in this) + { + outputArray.push(new asn1js.Constructed({ + optional: true, + idBlock: { + tagClass: 3, // CONTEXT-SPECIFIC + tagNumber: 0 // [0] + }, + value: Array.from(this.attributes, element => element.toSchema()) + })); + } + //endregion + + //region Construct and return new ASN.1 schema for this object + return (new asn1js.Sequence({ + value: outputArray + })); + //endregion + } + //********************************************************************************** + /** + * Convertion for the class to JSON object + * @returns {Object} + */ + toJSON() + { + //region Return common value in case we do not have enough info fo making JWK + if(("parsedKey" in this) === false) + { + const object = { + version: this.version, + privateKeyAlgorithm: this.privateKeyAlgorithm.toJSON(), + privateKey: this.privateKey.toJSON() + }; + + if("attributes" in this) + object.attributes = Array.from(this.attributes, element => element.toJSON()); + + return object; + } + //endregion + + //region Making JWK + const jwk = {}; + + switch(this.privateKeyAlgorithm.algorithmId) + { + case "1.2.840.10045.2.1": // ECDSA + jwk.kty = "EC"; + break; + case "1.2.840.113549.1.1.1": // RSA + jwk.kty = "RSA"; + break; + default: + } + + const publicKeyJWK = this.parsedKey.toJSON(); + + for(const key of Object.keys(publicKeyJWK)) + jwk[key] = publicKeyJWK[key]; + + return jwk; + //endregion + } + //********************************************************************************** + /** + * Convert JSON value into current object + * @param {Object} json + */ + fromJSON(json) + { + if("kty" in json) + { + switch(json.kty.toUpperCase()) + { + case "EC": + this.parsedKey = new ECPrivateKey({ json }); + + this.privateKeyAlgorithm = new AlgorithmIdentifier({ + algorithmId: "1.2.840.10045.2.1", + algorithmParams: new asn1js.ObjectIdentifier({ value: this.parsedKey.namedCurve }) + }); + break; + case "RSA": + this.parsedKey = new RSAPrivateKey({ json }); + + this.privateKeyAlgorithm = new AlgorithmIdentifier({ + algorithmId: "1.2.840.113549.1.1.1", + algorithmParams: new asn1js.Null() + }); + break; + default: + throw new Error(`Invalid value for "kty" parameter: ${json.kty}`); + } + + this.privateKey = new asn1js.OctetString({ valueHex: this.parsedKey.toSchema().toBER(false) }); + } + } + //********************************************************************************** +} +//************************************************************************************** diff --git a/core/third-party/pkijs/PrivateKeyUsagePeriod.js b/core/third-party/pkijs/PrivateKeyUsagePeriod.js new file mode 100644 index 0000000..a173bbe --- /dev/null +++ b/core/third-party/pkijs/PrivateKeyUsagePeriod.js @@ -0,0 +1,207 @@ +import * as asn1js from "./asn1.js"; +import { getParametersValue, clearProps } from "./pvutils.js"; +//************************************************************************************** +/** + * Class from RFC5280 + */ +export default class PrivateKeyUsagePeriod +{ + //********************************************************************************** + /** + * Constructor for PrivateKeyUsagePeriod class + * @param {Object} [parameters={}] + * @param {Object} [parameters.schema] asn1js parsed value to initialize the class from + */ + constructor(parameters = {}) + { + //region Internal properties of the object + if("notBefore" in parameters) + /** + * @type {Date} + * @desc notBefore + */ + this.notBefore = getParametersValue(parameters, "notBefore", PrivateKeyUsagePeriod.defaultValues("notBefore")); + + if("notAfter" in parameters) + /** + * @type {Date} + * @desc notAfter + */ + this.notAfter = getParametersValue(parameters, "notAfter", PrivateKeyUsagePeriod.defaultValues("notAfter")); + //endregion + + //region If input argument array contains "schema" for this object + if("schema" in parameters) + this.fromSchema(parameters.schema); + //endregion + } + //********************************************************************************** + /** + * Return default values for all class members + * @param {string} memberName String name for a class member + */ + static defaultValues(memberName) + { + switch(memberName) + { + case "notBefore": + return new Date(); + case "notAfter": + return new Date(); + default: + throw new Error(`Invalid member name for PrivateKeyUsagePeriod class: ${memberName}`); + } + } + //********************************************************************************** + /** + * Return value of pre-defined ASN.1 schema for current class + * + * ASN.1 schema: + * ```asn1 + * PrivateKeyUsagePeriod OID ::= 2.5.29.16 + * + * PrivateKeyUsagePeriod ::= SEQUENCE { + * notBefore [0] GeneralizedTime OPTIONAL, + * notAfter [1] GeneralizedTime OPTIONAL } + * -- either notBefore or notAfter MUST be present + * ``` + * + * @param {Object} parameters Input parameters for the schema + * @returns {Object} asn1js schema object + */ + static schema(parameters = {}) + { + /** + * @type {Object} + * @property {string} [blockName] + * @property {string} [notBefore] + * @property {string} [notAfter] + */ + const names = getParametersValue(parameters, "names", {}); + + return (new asn1js.Sequence({ + name: (names.blockName || ""), + value: [ + new asn1js.Primitive({ + name: (names.notBefore || ""), + optional: true, + idBlock: { + tagClass: 3, // CONTEXT-SPECIFIC + tagNumber: 0 // [0] + } + }), + new asn1js.Primitive({ + name: (names.notAfter || ""), + optional: true, + idBlock: { + tagClass: 3, // CONTEXT-SPECIFIC + tagNumber: 1 // [1] + } + }) + ] + })); + } + //********************************************************************************** + /** + * Convert parsed asn1js object into current class + * @param {!Object} schema + */ + fromSchema(schema) + { + //region Clear input data first + clearProps(schema, [ + "notBefore", + "notAfter" + ]); + //endregion + + //region Check the schema is valid + const asn1 = asn1js.compareSchema(schema, + schema, + PrivateKeyUsagePeriod.schema({ + names: { + notBefore: "notBefore", + notAfter: "notAfter" + } + }) + ); + + if(asn1.verified === false) + throw new Error("Object's schema was not verified against input data for PrivateKeyUsagePeriod"); + //endregion + + //region Get internal properties from parsed schema + if("notBefore" in asn1.result) + { + const localNotBefore = new asn1js.GeneralizedTime(); + localNotBefore.fromBuffer(asn1.result.notBefore.valueBlock.valueHex); + this.notBefore = localNotBefore.toDate(); + } + + if("notAfter" in asn1.result) + { + const localNotAfter = new asn1js.GeneralizedTime({ valueHex: asn1.result.notAfter.valueBlock.valueHex }); + localNotAfter.fromBuffer(asn1.result.notAfter.valueBlock.valueHex); + this.notAfter = localNotAfter.toDate(); + } + //endregion + } + //********************************************************************************** + /** + * Convert current object to asn1js object and set correct values + * @returns {Object} asn1js object + */ + toSchema() + { + //region Create array for output sequence + const outputArray = []; + + if("notBefore" in this) + { + outputArray.push(new asn1js.Primitive({ + idBlock: { + tagClass: 3, // CONTEXT-SPECIFIC + tagNumber: 0 // [0] + }, + valueHex: (new asn1js.GeneralizedTime({ valueDate: this.notBefore })).valueBlock.valueHex + })); + } + + if("notAfter" in this) + { + outputArray.push(new asn1js.Primitive({ + idBlock: { + tagClass: 3, // CONTEXT-SPECIFIC + tagNumber: 1 // [1] + }, + valueHex: (new asn1js.GeneralizedTime({ valueDate: this.notAfter })).valueBlock.valueHex + })); + } + //endregion + + //region Construct and return new ASN.1 schema for this object + return (new asn1js.Sequence({ + value: outputArray + })); + //endregion + } + //********************************************************************************** + /** + * Convertion for the class to JSON object + * @returns {Object} + */ + toJSON() + { + const object = {}; + + if("notBefore" in this) + object.notBefore = this.notBefore; + + if("notAfter" in this) + object.notAfter = this.notAfter; + + return object; + } + //********************************************************************************** +} +//************************************************************************************** diff --git a/core/third-party/pkijs/PublicKeyInfo.js b/core/third-party/pkijs/PublicKeyInfo.js new file mode 100644 index 0000000..665d5ec --- /dev/null +++ b/core/third-party/pkijs/PublicKeyInfo.js @@ -0,0 +1,311 @@ +import * as asn1js from "./asn1.js"; +import { getParametersValue, clearProps } from "./pvutils.js"; +import { getCrypto } from "./common.js"; +import AlgorithmIdentifier from "./AlgorithmIdentifier.js"; +import ECPublicKey from "./ECPublicKey.js"; +import RSAPublicKey from "./RSAPublicKey.js"; +//************************************************************************************** +/** + * Class from RFC5280 + */ +export default class PublicKeyInfo +{ + //********************************************************************************** + /** + * Constructor for PublicKeyInfo class + * @param {Object} [parameters={}] + * @param {Object} [parameters.schema] asn1js parsed value to initialize the class from + */ + constructor(parameters = {}) + { + //region Internal properties of the object + /** + * @type {AlgorithmIdentifier} + * @desc Algorithm identifier + */ + this.algorithm = getParametersValue(parameters, "algorithm", PublicKeyInfo.defaultValues("algorithm")); + /** + * @type {BitString} + * @desc Subject public key value + */ + this.subjectPublicKey = getParametersValue(parameters, "subjectPublicKey", PublicKeyInfo.defaultValues("subjectPublicKey")); + + if("parsedKey" in parameters) + /** + * @type {ECPublicKey|RSAPublicKey} + * @desc Parsed public key value + */ + this.parsedKey = getParametersValue(parameters, "parsedKey", PublicKeyInfo.defaultValues("parsedKey")); + //endregion + + //region If input argument array contains "schema" for this object + if("schema" in parameters) + this.fromSchema(parameters.schema); + //endregion + //region If input argument array contains "json" for this object + if("json" in parameters) + this.fromJSON(parameters.json); + //endregion + } + //********************************************************************************** + /** + * Return default values for all class members + * @param {string} memberName String name for a class member + */ + static defaultValues(memberName) + { + switch(memberName) + { + case "algorithm": + return new AlgorithmIdentifier(); + case "subjectPublicKey": + return new asn1js.BitString(); + default: + throw new Error(`Invalid member name for PublicKeyInfo class: ${memberName}`); + } + } + //********************************************************************************** + /** + * Return value of pre-defined ASN.1 schema for current class + * + * ASN.1 schema: + * ```asn1 + * SubjectPublicKeyInfo ::= Sequence { + * algorithm AlgorithmIdentifier, + * subjectPublicKey BIT STRING } + * ``` + * + * @param {Object} parameters Input parameters for the schema + * @returns {Object} asn1js schema object + */ + static schema(parameters = {}) + { + /** + * @type {Object} + * @property {string} [blockName] + * @property {string} [algorithm] + * @property {string} [subjectPublicKey] + */ + const names = getParametersValue(parameters, "names", {}); + + return (new asn1js.Sequence({ + name: (names.blockName || ""), + value: [ + AlgorithmIdentifier.schema(names.algorithm || {}), + new asn1js.BitString({ name: (names.subjectPublicKey || "") }) + ] + })); + } + //********************************************************************************** + /** + * Convert parsed asn1js object into current class + * @param {!Object} schema + */ + fromSchema(schema) + { + //region Clear input data first + clearProps(schema, [ + "algorithm", + "subjectPublicKey" + ]); + //endregion + + //region Check the schema is valid + const asn1 = asn1js.compareSchema(schema, + schema, + PublicKeyInfo.schema({ + names: { + algorithm: { + names: { + blockName: "algorithm" + } + }, + subjectPublicKey: "subjectPublicKey" + } + }) + ); + + if(asn1.verified === false) + throw new Error("Object's schema was not verified against input data for PublicKeyInfo"); + //endregion + + //region Get internal properties from parsed schema + this.algorithm = new AlgorithmIdentifier({ schema: asn1.result.algorithm }); + this.subjectPublicKey = asn1.result.subjectPublicKey; + + switch(this.algorithm.algorithmId) + { + case "1.2.840.10045.2.1": // ECDSA + if("algorithmParams" in this.algorithm) + { + if(this.algorithm.algorithmParams.constructor.blockName() === asn1js.ObjectIdentifier.blockName()) + { + try + { + this.parsedKey = new ECPublicKey({ + namedCurve: this.algorithm.algorithmParams.valueBlock.toString(), + schema: this.subjectPublicKey.valueBlock.valueHex + }); + } + catch(ex){} // Could be a problems during recognision of internal public key data here. Let's ignore them. + } + } + break; + case "1.2.840.113549.1.1.1": // RSA + { + const publicKeyASN1 = asn1js.fromBER(this.subjectPublicKey.valueBlock.valueHex); + if(publicKeyASN1.offset !== (-1)) + { + try + { + this.parsedKey = new RSAPublicKey({ schema: publicKeyASN1.result }); + } + catch(ex){} // Could be a problems during recognision of internal public key data here. Let's ignore them. + } + } + break; + default: + } + //endregion + } + //********************************************************************************** + /** + * Convert current object to asn1js object and set correct values + * @returns {Object} asn1js object + */ + toSchema() + { + //region Construct and return new ASN.1 schema for this object + return (new asn1js.Sequence({ + value: [ + this.algorithm.toSchema(), + this.subjectPublicKey + ] + })); + //endregion + } + //********************************************************************************** + /** + * Convertion for the class to JSON object + * @returns {Object} + */ + toJSON() + { + //region Return common value in case we do not have enough info fo making JWK + if(("parsedKey" in this) === false) + { + return { + algorithm: this.algorithm.toJSON(), + subjectPublicKey: this.subjectPublicKey.toJSON() + }; + } + //endregion + + //region Making JWK + const jwk = {}; + + switch(this.algorithm.algorithmId) + { + case "1.2.840.10045.2.1": // ECDSA + jwk.kty = "EC"; + break; + case "1.2.840.113549.1.1.1": // RSA + jwk.kty = "RSA"; + break; + default: + } + + const publicKeyJWK = this.parsedKey.toJSON(); + + for(const key of Object.keys(publicKeyJWK)) + jwk[key] = publicKeyJWK[key]; + + return jwk; + //endregion + } + //********************************************************************************** + /** + * Convert JSON value into current object + * @param {Object} json + */ + fromJSON(json) + { + if("kty" in json) + { + switch(json.kty.toUpperCase()) + { + case "EC": + this.parsedKey = new ECPublicKey({ json }); + + this.algorithm = new AlgorithmIdentifier({ + algorithmId: "1.2.840.10045.2.1", + algorithmParams: new asn1js.ObjectIdentifier({ value: this.parsedKey.namedCurve }) + }); + break; + case "RSA": + this.parsedKey = new RSAPublicKey({ json }); + + this.algorithm = new AlgorithmIdentifier({ + algorithmId: "1.2.840.113549.1.1.1", + algorithmParams: new asn1js.Null() + }); + break; + default: + throw new Error(`Invalid value for "kty" parameter: ${json.kty}`); + } + + this.subjectPublicKey = new asn1js.BitString({ valueHex: this.parsedKey.toSchema().toBER(false) }); + } + } + //********************************************************************************** + importKey(publicKey) + { + //region Initial variables + let sequence = Promise.resolve(); + const _this = this; + //endregion + + //region Initial check + if(typeof publicKey === "undefined") + return Promise.reject("Need to provide publicKey input parameter"); + //endregion + + //region Get a "crypto" extension + const crypto = getCrypto(); + if(typeof crypto === "undefined") + return Promise.reject("Unable to create WebCrypto object"); + //endregion + + //region Export public key + sequence = sequence.then(() => + crypto.exportKey("spki", publicKey)); + //endregion + + //region Initialize internal variables by parsing exported value + sequence = sequence.then( + /** + * @param {ArrayBuffer} exportedKey + */ + exportedKey => + { + const asn1 = asn1js.fromBER(exportedKey); + try + { + _this.fromSchema(asn1.result); + } + catch(exception) + { + return Promise.reject("Error during initializing object from schema"); + } + + return undefined; + }, + error => Promise.reject(`Error during exporting public key: ${error}`) + ); + //endregion + + return sequence; + } + //********************************************************************************** +} +//************************************************************************************** diff --git a/core/third-party/pkijs/QCStatements.js b/core/third-party/pkijs/QCStatements.js new file mode 100644 index 0000000..99ecc31 --- /dev/null +++ b/core/third-party/pkijs/QCStatements.js @@ -0,0 +1,327 @@ +import * as asn1js from "./asn1.js"; +import { getParametersValue, clearProps } from "./pvutils.js"; +//************************************************************************************** +/** + * Class from RFC3739 + */ +export class QCStatement +{ + //********************************************************************************** + /** + * Constructor for QCStatement class + * @param {Object} [parameters={}] + * @param {Object} [parameters.schema] asn1js parsed value to initialize the class from + */ + constructor(parameters = {}) + { + //region Internal properties of the object + /** + * @type {string} + */ + this.id = getParametersValue(parameters, "id", QCStatement.defaultValues("id")); + + if("type" in parameters) + { + /** + * @type {*} Any data described by "id" + */ + this.type = getParametersValue(parameters, "type", QCStatement.defaultValues("type")); + } + //endregion + + //region If input argument array contains "schema" for this object + if("schema" in parameters) + this.fromSchema(parameters.schema); + //endregion + } + //********************************************************************************** + /** + * Return default values for all class members + * @param {string} memberName String name for a class member + */ + static defaultValues(memberName) + { + switch(memberName) + { + case "id": + return ""; + case "type": + return new asn1js.Null(); + default: + throw new Error(`Invalid member name for QCStatement class: ${memberName}`); + } + } + //********************************************************************************** + /** + * Compare values with default values for all class members + * @param {string} memberName String name for a class member + * @param {*} memberValue Value to compare with default value + */ + static compareWithDefault(memberName, memberValue) + { + switch(memberName) + { + case "id": + return (memberValue === ""); + case "type": + return (memberValue instanceof asn1js.Null); + default: + throw new Error(`Invalid member name for QCStatement class: ${memberName}`); + } + } + //********************************************************************************** + /** + * Return value of pre-defined ASN.1 schema for current class + * + * ASN.1 schema: + * ```asn1 + * QCStatement ::= SEQUENCE { + * statementId QC-STATEMENT.&id({SupportedStatements}), + * statementInfo QC-STATEMENT.&Type({SupportedStatements}{@statementId}) OPTIONAL + * } + * ``` + * + * @param {Object} parameters Input parameters for the schema + * @returns {Object} asn1js schema object + */ + static schema(parameters = {}) + { + /** + * @type {Object} + * @property {string} [blockName] + * @property {string} [id] + * @property {string} [type] + */ + const names = getParametersValue(parameters, "names", {}); + + return (new asn1js.Sequence({ + name: (names.blockName || ""), + value: [ + new asn1js.ObjectIdentifier({ name: (names.id || "") }), + new asn1js.Any({ + name: (names.type || ""), + optional: true + }) + ] + })); + } + //********************************************************************************** + /** + * Convert parsed asn1js object into current class + * @param {!Object} schema + */ + fromSchema(schema) + { + //region Clear input data first + clearProps(schema, [ + "id", + "type" + ]); + //endregion + + //region Check the schema is valid + const asn1 = asn1js.compareSchema(schema, + schema, + QCStatement.schema({ + names: { + id: "id", + type: "type" + } + }) + ); + + if(asn1.verified === false) + throw new Error("Object's schema was not verified against input data for QCStatement"); + //endregion + + //region Get internal properties from parsed schema + this.id = asn1.result.id.valueBlock.toString(); + + if("type" in asn1.result) + this.type = asn1.result.type; + //endregion + } + //********************************************************************************** + /** + * Convert current object to asn1js object and set correct values + * @returns {Object} asn1js object + */ + toSchema() + { + const value = [ + new asn1js.ObjectIdentifier({ value: this.id }) + ]; + + if("type" in this) + value.push(this.type); + + //region Construct and return new ASN.1 schema for this object + return (new asn1js.Sequence({ + value + })); + //endregion + } + //********************************************************************************** + /** + * Convertion for the class to JSON object + * @returns {Object} + */ + toJSON() + { + const object = { + id: this.id + }; + + if("type" in this) + object.type = this.type.toJSON(); + + return object; + } + //********************************************************************************** +} +//************************************************************************************** +/** + * Class from RFC3739 + */ +export default class QCStatements +{ + //********************************************************************************** + /** + * Constructor for QCStatements class + * @param {Object} [parameters={}] + * @param {Object} [parameters.schema] asn1js parsed value to initialize the class from + */ + constructor(parameters = {}) + { + //region Internal properties of the object + /** + * @type {Array} + */ + this.values = getParametersValue(parameters, "values", QCStatements.defaultValues("values")); + //endregion + + //region If input argument array contains "schema" for this object + if("schema" in parameters) + this.fromSchema(parameters.schema); + //endregion + } + //********************************************************************************** + /** + * Return default values for all class members + * @param {string} memberName String name for a class member + */ + static defaultValues(memberName) + { + switch(memberName) + { + case "values": + return []; + default: + throw new Error(`Invalid member name for QCStatements class: ${memberName}`); + } + } + //********************************************************************************** + /** + * Compare values with default values for all class members + * @param {string} memberName String name for a class member + * @param {*} memberValue Value to compare with default value + */ + static compareWithDefault(memberName, memberValue) + { + switch(memberName) + { + case "values": + return (memberValue.length === 0); + default: + throw new Error(`Invalid member name for QCStatements class: ${memberName}`); + } + } + //********************************************************************************** + /** + * Return value of pre-defined ASN.1 schema for current class + * + * ASN.1 schema: + * ```asn1 + * QCStatements ::= SEQUENCE OF QCStatement + * ``` + * + * @param {Object} parameters Input parameters for the schema + * @returns {Object} asn1js schema object + */ + static schema(parameters = {}) + { + /** + * @type {Object} + * @property {string} [blockName] + * @property {string} [values] + */ + const names = getParametersValue(parameters, "names", {}); + + return (new asn1js.Sequence({ + name: (names.blockName || ""), + value: [ + new asn1js.Repeated({ + name: (names.values || ""), + value: QCStatement.schema(names.value || {}) + }), + ] + })); + } + //********************************************************************************** + /** + * Convert parsed asn1js object into current class + * @param {!Object} schema + */ + fromSchema(schema) + { + //region Clear input data first + clearProps(schema, [ + "values" + ]); + //endregion + + //region Check the schema is valid + const asn1 = asn1js.compareSchema(schema, + schema, + QCStatements.schema({ + names: { + values: "values" + } + }) + ); + + if(asn1.verified === false) + throw new Error("Object's schema was not verified against input data for QCStatements"); + //endregion + + //region Get internal properties from parsed schema + this.values = Array.from(asn1.result.values, element => new QCStatement({ schema: element })); + //endregion + } + //********************************************************************************** + /** + * Convert current object to asn1js object and set correct values + * @returns {Object} asn1js object + */ + toSchema() + { + //region Construct and return new ASN.1 schema for this object + return (new asn1js.Sequence({ + value: Array.from(this.values, element => element.toSchema()) + })); + //endregion + } + //********************************************************************************** + /** + * Convertion for the class to JSON object + * @returns {Object} + */ + toJSON() + { + return { + extensions: Array.from(this.values, element => element.toJSON()) + }; + } + //********************************************************************************** +} +//************************************************************************************** diff --git a/core/third-party/pkijs/README.MD b/core/third-party/pkijs/README.MD new file mode 100644 index 0000000..00b0910 --- /dev/null +++ b/core/third-party/pkijs/README.MD @@ -0,0 +1,130 @@ +## DESCRIPTION OF THE PROJECT + +PKIjs designed to be a helper for everyone making any PKI-related applications. +Currently PKI defined by a set of documents, and usually these documents have form in RFC (Requst For Comments) managed by IETF. +PKIjs respects this situation and provide to user a flexible environment based on existing set of RFCs, related to PKI. + +| RFC number | RFC name | +|----------------|----------------| +|RFC5280|Internet X.509 Public Key Infrastructure Certificate and Certificate Revocation List (CRL) Profile| +|RFC3161|Internet X.509 Public Key Infrastructure Time-Stamp Protocol (TSP)| +|RFC5652|Cryptographic Message Syntax (CMS)| +|RFC3447|Public-Key Cryptography Standards (PKCS) #1: RSA Cryptography Specifications Version 2.1| +|RFC5753|Use of Elliptic Curve Cryptography (ECC) Algorithms in Cryptographic Message Syntax (CMS)| +|RFC2898|PKCS #5: Password-Based Cryptography Specification| +|RFC6960|X.509 Internet Public Key Infrastructure Online Certificate Status Protocol - OCSP| +|RFC2986|PKCS #10: Certification Request Syntax Specification Version 1.7| +|RFC7292|PKCS #12: Personal Information Exchange Syntax v1.1| +|RFC6318|Suite B in Secure/Multipurpose Internet Mail Extensions (S/MIME)| +|RFC5915|Elliptic Curve Private Key Structure| +|RFC5480|Elliptic Curve Cryptography Subject Public Key Information| +|RFC5208|Public-Key Cryptography Standards (PKCS) #8: Private-Key Information Syntax Specification Version 1.2| +|RFC4055|Additional Algorithms and Identifiers for RSA Cryptography for use in the Internet X.509 Public Key Infrastructure Certificate and Certificate Revocation List (CRL) Profile| + +PKI.js made of many specialized classes, each of them is responsible for handling one structure from specific RFC. For example, in order to handle X.509 certificate, described in RFC5280, PKI.js has class "Certificate". Each class inside PKI.js is inside separate file. +Name of each class equals to name from RFC document. Here is a table with PKI.js class names and related RFCs: + +| Class Name | RFC number | +|----------------|----------------| +|AccessDescription|RFC5280| +|Accuracy|RFC3161| +|AlgorithmIdentifier|RFC5280| +|AltName|RFC5280| +|Attribute|RFC2986| +|AttributeTypeAndValue|RFC5280| +|AuthenticatedSafe|RFC7292| +|AuthorityKeyIdentifier|RFC5280| +|BasicConstraints|RFC5280| +|BasicOCSPResponse|RFC6960| +|CRLBag|RFC7292| +|CRLDistributionPoints|RFC5280| +|CertBag|RFC7292| +|CertID|RFC6960| +|Certificate|RFC5280| +|CertificatePolicies|RFC5280| +|CertificateRevocationList|RFC5280| +|CertificateSet|RFC5652| +|CertificationRequest|RFC2986| +|ContentInfo|RFC5652| +|DigestInfo|RFC3447| +|DistributionPoint|RFC5280| +|ECCCMSSharedInfo|RFC6318| +|ECPrivateKey|RFC5915| +|ECPublicKey|RFC5480| +|EncapsulatedContentInfo|RFC5652| +|EncryptedContentInfo|RFC5652| +|EncryptedData|RFC5652| +|EnvelopedData|RFC5652| +|ExtKeyUsage|RFC5280| +|Extension|RFC5280| +|Extensions|RFC5280| +|GeneralName|RFC5280| +|GeneralNames|RFC5280| +|GeneralSubtree|RFC5280| +|InfoAccess|RFC5280| +|IssuerAndSerialNumber|RFC5652| +|IssuingDistributionPoint|RFC5280| +|KEKIdentifier|RFC5652| +|KEKRecipientInfo|RFC5652| +|KeyAgreeRecipientIdentifier|RFC5652| +|KeyAgreeRecipientInfo|RFC5652| +|KeyBag|RFC5208| +|KeyTransRecipientInfo|RFC5652| +|MacData|RFC7292| +|MessageImprint|RFC3161| +|NameConstraints|RFC5280| +|OCSPRequest|RFC6960| +|OCSPResponse|RFC6960| +|OriginatorIdentifierOrKey|RFC5652| +|OriginatorInfo|RFC5652| +|OriginatorPublicKey|RFC5652| +|OtherCertificateFormat|RFC5652| +|OtherKeyAttribute|RFC5652| +|OtherPrimeInfo|RFC3447| +|OtherRecipientInfo|RFC5652| +|OtherRevocationInfoFormat|RFC5652| +|PBES2Params|RFC2898| +|PBKDF2Params|RFC2898| +|PFX|RFC7292| +|PKCS8ShroudedKeyBag|RFC7292| +|PKIStatusInfo|RFC3161| +|PasswordRecipientinfo|RFC5652| +|PolicyConstraints|RFC5280| +|PolicyInformation|RFC5280| +|PolicyMapping|RFC5280| +|PolicyMappings|RFC5280| +|PolicyQualifierInfo|RFC5280| +|PrivateKeyInfo|RFC5208| +|PrivateKeyUsagePeriod|RFC5280| +|PublicKeyInfo|RFC5280| +|RSAESOAEPParams|RFC3447| +|RSAPrivateKey|RFC3447| +|RSAPublicKey|RFC3447| +|RSASSAPSSParams|RFC4055| +|RecipientEncryptedKey|RFC5652| +|RecipientEncryptedKeys|RFC5652| +|RecipientIdentifier|RFC5652| +|RecipientInfo|RFC5652| +|RecipientKeyIdentifier|RFC5652| +|RelativeDistinguishedNames|RFC5280| +|Request|RFC6960| +|ResponseBytes|RFC6960| +|ResponseData|RFC6960| +|RevocationInfoChoices|RFC5652| +|RevokedCertificate|RFC5280| +|SafeBag|RFC7292| +|SafeContents|RFC7292| +|SecretBag|RFC7292| +|Signature|RFC6960| +|SignedAndUnsignedAttributes|RFC5652| +|SignedData|RFC5652| +|SignerInfo|RFC5652| +|SingleResponse|RFC6960| +|SubjectDirectoryAttributes|RFC5280| +|TBSRequest|RFC6960| +|TSTInfo|RFC3161| +|Time|RFC5280 +|TimeStampReq|RFC3161| +|TimeStampResp|RFC3161| + +PKI.js library could be extended very easily to handle additional types from any RFC. If you have a special need for any RFC's new types please create issue on GitHub. diff --git a/core/third-party/pkijs/RSAESOAEPParams.js b/core/third-party/pkijs/RSAESOAEPParams.js new file mode 100644 index 0000000..cd75ad1 --- /dev/null +++ b/core/third-party/pkijs/RSAESOAEPParams.js @@ -0,0 +1,255 @@ +import * as asn1js from "./asn1.js"; +import { getParametersValue, clearProps } from "./pvutils.js"; +import AlgorithmIdentifier from "./AlgorithmIdentifier.js"; +//************************************************************************************** +/** + * Class from RFC3447 + */ +export default class RSAESOAEPParams +{ + //********************************************************************************** + /** + * Constructor for RSAESOAEPParams class + * @param {Object} [parameters={}] + * @param {Object} [parameters.schema] asn1js parsed value to initialize the class from + */ + constructor(parameters = {}) + { + //region Internal properties of the object + /** + * @type {AlgorithmIdentifier} + * @desc hashAlgorithm + */ + this.hashAlgorithm = getParametersValue(parameters, "hashAlgorithm", RSAESOAEPParams.defaultValues("hashAlgorithm")); + /** + * @type {AlgorithmIdentifier} + * @desc maskGenAlgorithm + */ + this.maskGenAlgorithm = getParametersValue(parameters, "maskGenAlgorithm", RSAESOAEPParams.defaultValues("maskGenAlgorithm")); + /** + * @type {AlgorithmIdentifier} + * @desc pSourceAlgorithm + */ + this.pSourceAlgorithm = getParametersValue(parameters, "pSourceAlgorithm", RSAESOAEPParams.defaultValues("pSourceAlgorithm")); + //endregion + + //region If input argument array contains "schema" for this object + if("schema" in parameters) + this.fromSchema(parameters.schema); + //endregion + } + //********************************************************************************** + /** + * Return default values for all class members + * @param {string} memberName String name for a class member + */ + static defaultValues(memberName) + { + switch(memberName) + { + case "hashAlgorithm": + return new AlgorithmIdentifier({ + algorithmId: "1.3.14.3.2.26", // SHA-1 + algorithmParams: new asn1js.Null() + }); + case "maskGenAlgorithm": + return new AlgorithmIdentifier({ + algorithmId: "1.2.840.113549.1.1.8", // MGF1 + algorithmParams: (new AlgorithmIdentifier({ + algorithmId: "1.3.14.3.2.26", // SHA-1 + algorithmParams: new asn1js.Null() + })).toSchema() + }); + case "pSourceAlgorithm": + return new AlgorithmIdentifier({ + algorithmId: "1.2.840.113549.1.1.9", // id-pSpecified + algorithmParams: new asn1js.OctetString({ valueHex: (new Uint8Array([0xda, 0x39, 0xa3, 0xee, 0x5e, 0x6b, 0x4b, 0x0d, 0x32, 0x55, 0xbf, 0xef, 0x95, 0x60, 0x18, 0x90, 0xaf, 0xd8, 0x07, 0x09])).buffer }) // SHA-1 hash of empty string + }); + default: + throw new Error(`Invalid member name for RSAESOAEPParams class: ${memberName}`); + } + } + //********************************************************************************** + /** + * Return value of pre-defined ASN.1 schema for current class + * + * ASN.1 schema: + * ```asn1 + * RSAES-OAEP-params ::= SEQUENCE { + * hashAlgorithm [0] HashAlgorithm DEFAULT sha1, + * maskGenAlgorithm [1] MaskGenAlgorithm DEFAULT mgf1SHA1, + * pSourceAlgorithm [2] PSourceAlgorithm DEFAULT pSpecifiedEmpty + * } + * ``` + * + * @param {Object} parameters Input parameters for the schema + * @returns {Object} asn1js schema object + */ + static schema(parameters = {}) + { + /** + * @type {Object} + * @property {string} [blockName] + * @property {string} [hashAlgorithm] + * @property {string} [maskGenAlgorithm] + * @property {string} [pSourceAlgorithm] + */ + const names = getParametersValue(parameters, "names", {}); + + return (new asn1js.Sequence({ + name: (names.blockName || ""), + value: [ + new asn1js.Constructed({ + idBlock: { + tagClass: 3, // CONTEXT-SPECIFIC + tagNumber: 0 // [0] + }, + optional: true, + value: [AlgorithmIdentifier.schema(names.hashAlgorithm || {})] + }), + new asn1js.Constructed({ + idBlock: { + tagClass: 3, // CONTEXT-SPECIFIC + tagNumber: 1 // [1] + }, + optional: true, + value: [AlgorithmIdentifier.schema(names.maskGenAlgorithm || {})] + }), + new asn1js.Constructed({ + idBlock: { + tagClass: 3, // CONTEXT-SPECIFIC + tagNumber: 2 // [2] + }, + optional: true, + value: [AlgorithmIdentifier.schema(names.pSourceAlgorithm || {})] + }) + ] + })); + } + //********************************************************************************** + /** + * Convert parsed asn1js object into current class + * @param {!Object} schema + */ + fromSchema(schema) + { + //region Clear input data first + clearProps(schema, [ + "hashAlgorithm", + "maskGenAlgorithm", + "pSourceAlgorithm" + ]); + //endregion + + //region Check the schema is valid + const asn1 = asn1js.compareSchema(schema, + schema, + RSAESOAEPParams.schema({ + names: { + hashAlgorithm: { + names: { + blockName: "hashAlgorithm" + } + }, + maskGenAlgorithm: { + names: { + blockName: "maskGenAlgorithm" + } + }, + pSourceAlgorithm: { + names: { + blockName: "pSourceAlgorithm" + } + } + } + }) + ); + + if(asn1.verified === false) + throw new Error("Object's schema was not verified against input data for RSAESOAEPParams"); + //endregion + + //region Get internal properties from parsed schema + if("hashAlgorithm" in asn1.result) + this.hashAlgorithm = new AlgorithmIdentifier({ schema: asn1.result.hashAlgorithm }); + + if("maskGenAlgorithm" in asn1.result) + this.maskGenAlgorithm = new AlgorithmIdentifier({ schema: asn1.result.maskGenAlgorithm }); + + if("pSourceAlgorithm" in asn1.result) + this.pSourceAlgorithm = new AlgorithmIdentifier({ schema: asn1.result.pSourceAlgorithm }); + //endregion + } + //********************************************************************************** + /** + * Convert current object to asn1js object and set correct values + * @returns {Object} asn1js object + */ + toSchema() + { + //region Create array for output sequence + const outputArray = []; + + if(!this.hashAlgorithm.isEqual(RSAESOAEPParams.defaultValues("hashAlgorithm"))) + { + outputArray.push(new asn1js.Constructed({ + idBlock: { + tagClass: 3, // CONTEXT-SPECIFIC + tagNumber: 0 // [0] + }, + value: [this.hashAlgorithm.toSchema()] + })); + } + + if(!this.maskGenAlgorithm.isEqual(RSAESOAEPParams.defaultValues("maskGenAlgorithm"))) + { + outputArray.push(new asn1js.Constructed({ + idBlock: { + tagClass: 3, // CONTEXT-SPECIFIC + tagNumber: 1 // [1] + }, + value: [this.maskGenAlgorithm.toSchema()] + })); + } + + if(!this.pSourceAlgorithm.isEqual(RSAESOAEPParams.defaultValues("pSourceAlgorithm"))) + { + outputArray.push(new asn1js.Constructed({ + idBlock: { + tagClass: 3, // CONTEXT-SPECIFIC + tagNumber: 2 // [2] + }, + value: [this.pSourceAlgorithm.toSchema()] + })); + } + //endregion + + //region Construct and return new ASN.1 schema for this object + return (new asn1js.Sequence({ + value: outputArray + })); + //endregion + } + //********************************************************************************** + /** + * Convertion for the class to JSON object + * @returns {Object} + */ + toJSON() + { + const object = {}; + + if(!this.hashAlgorithm.isEqual(RSAESOAEPParams.defaultValues("hashAlgorithm"))) + object.hashAlgorithm = this.hashAlgorithm.toJSON(); + + if(!this.maskGenAlgorithm.isEqual(RSAESOAEPParams.defaultValues("maskGenAlgorithm"))) + object.maskGenAlgorithm = this.maskGenAlgorithm.toJSON(); + + if(!this.pSourceAlgorithm.isEqual(RSAESOAEPParams.defaultValues("pSourceAlgorithm"))) + object.pSourceAlgorithm = this.pSourceAlgorithm.toJSON(); + + return object; + } + //********************************************************************************** +} +//************************************************************************************** diff --git a/core/third-party/pkijs/RSAPrivateKey.js b/core/third-party/pkijs/RSAPrivateKey.js new file mode 100644 index 0000000..0ba723d --- /dev/null +++ b/core/third-party/pkijs/RSAPrivateKey.js @@ -0,0 +1,356 @@ +import * as asn1js from "./asn1.js"; +import { getParametersValue, toBase64, arrayBufferToString, stringToArrayBuffer, fromBase64, clearProps } from "./pvutils.js"; +import OtherPrimeInfo from "./OtherPrimeInfo.js"; +//************************************************************************************** +/** + * Class from RFC3447 + */ +export default class RSAPrivateKey +{ + //********************************************************************************** + /** + * Constructor for RSAPrivateKey class + * @param {Object} [parameters={}] + * @param {Object} [parameters.schema] asn1js parsed value to initialize the class from + */ + constructor(parameters = {}) + { + //region Internal properties of the object + /** + * @type {number} + * @desc version + */ + this.version = getParametersValue(parameters, "version", RSAPrivateKey.defaultValues("version")); + /** + * @type {Integer} + * @desc modulus + */ + this.modulus = getParametersValue(parameters, "modulus", RSAPrivateKey.defaultValues("modulus")); + /** + * @type {Integer} + * @desc publicExponent + */ + this.publicExponent = getParametersValue(parameters, "publicExponent", RSAPrivateKey.defaultValues("publicExponent")); + /** + * @type {Integer} + * @desc privateExponent + */ + this.privateExponent = getParametersValue(parameters, "privateExponent", RSAPrivateKey.defaultValues("privateExponent")); + /** + * @type {Integer} + * @desc prime1 + */ + this.prime1 = getParametersValue(parameters, "prime1", RSAPrivateKey.defaultValues("prime1")); + /** + * @type {Integer} + * @desc prime2 + */ + this.prime2 = getParametersValue(parameters, "prime2", RSAPrivateKey.defaultValues("prime2")); + /** + * @type {Integer} + * @desc exponent1 + */ + this.exponent1 = getParametersValue(parameters, "exponent1", RSAPrivateKey.defaultValues("exponent1")); + /** + * @type {Integer} + * @desc exponent2 + */ + this.exponent2 = getParametersValue(parameters, "exponent2", RSAPrivateKey.defaultValues("exponent2")); + /** + * @type {Integer} + * @desc coefficient + */ + this.coefficient = getParametersValue(parameters, "coefficient", RSAPrivateKey.defaultValues("coefficient")); + + if("otherPrimeInfos" in parameters) + /** + * @type {Array.} + * @desc otherPrimeInfos + */ + this.otherPrimeInfos = getParametersValue(parameters, "otherPrimeInfos", RSAPrivateKey.defaultValues("otherPrimeInfos")); + //endregion + + //region If input argument array contains "schema" for this object + if("schema" in parameters) + this.fromSchema(parameters.schema); + //endregion + //region If input argument array contains "json" for this object + if("json" in parameters) + this.fromJSON(parameters.json); + //endregion + } + //********************************************************************************** + /** + * Return default values for all class members + * @param {string} memberName String name for a class member + */ + static defaultValues(memberName) + { + switch(memberName) + { + case "version": + return 0; + case "modulus": + return new asn1js.Integer(); + case "publicExponent": + return new asn1js.Integer(); + case "privateExponent": + return new asn1js.Integer(); + case "prime1": + return new asn1js.Integer(); + case "prime2": + return new asn1js.Integer(); + case "exponent1": + return new asn1js.Integer(); + case "exponent2": + return new asn1js.Integer(); + case "coefficient": + return new asn1js.Integer(); + case "otherPrimeInfos": + return []; + default: + throw new Error(`Invalid member name for RSAPrivateKey class: ${memberName}`); + } + } + //********************************************************************************** + /** + * Return value of pre-defined ASN.1 schema for current class + * + * ASN.1 schema: + * ```asn1 + * RSAPrivateKey ::= Sequence { + * version Version, + * modulus Integer, -- n + * publicExponent Integer, -- e + * privateExponent Integer, -- d + * prime1 Integer, -- p + * prime2 Integer, -- q + * exponent1 Integer, -- d mod (p-1) + * exponent2 Integer, -- d mod (q-1) + * coefficient Integer, -- (inverse of q) mod p + * otherPrimeInfos OtherPrimeInfos OPTIONAL + * } + * + * OtherPrimeInfos ::= Sequence SIZE(1..MAX) OF OtherPrimeInfo + * ``` + * + * @param {Object} parameters Input parameters for the schema + * @returns {Object} asn1js schema object + */ + static schema(parameters = {}) + { + /** + * @type {Object} + * @property {string} [blockName] + * @property {string} [version] + * @property {string} [modulus] + * @property {string} [publicExponent] + * @property {string} [privateExponent] + * @property {string} [prime1] + * @property {string} [prime2] + * @property {string} [exponent1] + * @property {string} [exponent2] + * @property {string} [coefficient] + * @property {string} [otherPrimeInfosName] + * @property {Object} [otherPrimeInfo] + */ + const names = getParametersValue(parameters, "names", {}); + + return (new asn1js.Sequence({ + name: (names.blockName || ""), + value: [ + new asn1js.Integer({ name: (names.version || "") }), + new asn1js.Integer({ name: (names.modulus || "") }), + new asn1js.Integer({ name: (names.publicExponent || "") }), + new asn1js.Integer({ name: (names.privateExponent || "") }), + new asn1js.Integer({ name: (names.prime1 || "") }), + new asn1js.Integer({ name: (names.prime2 || "") }), + new asn1js.Integer({ name: (names.exponent1 || "") }), + new asn1js.Integer({ name: (names.exponent2 || "") }), + new asn1js.Integer({ name: (names.coefficient || "") }), + new asn1js.Sequence({ + optional: true, + value: [ + new asn1js.Repeated({ + name: (names.otherPrimeInfosName || ""), + value: OtherPrimeInfo.schema(names.otherPrimeInfo || {}) + }) + ] + }) + ] + })); + } + //********************************************************************************** + /** + * Convert parsed asn1js object into current class + * @param {!Object} schema + */ + fromSchema(schema) + { + //region Clear input data first + clearProps(schema, [ + "version", + "modulus", + "publicExponent", + "privateExponent", + "prime1", + "prime2", + "exponent1", + "exponent2", + "coefficient", + "otherPrimeInfos" + ]); + //endregion + + //region Check the schema is valid + const asn1 = asn1js.compareSchema(schema, + schema, + RSAPrivateKey.schema({ + names: { + version: "version", + modulus: "modulus", + publicExponent: "publicExponent", + privateExponent: "privateExponent", + prime1: "prime1", + prime2: "prime2", + exponent1: "exponent1", + exponent2: "exponent2", + coefficient: "coefficient", + otherPrimeInfo: { + names: { + blockName: "otherPrimeInfos" + } + } + } + }) + ); + + if(asn1.verified === false) + throw new Error("Object's schema was not verified against input data for RSAPrivateKey"); + //endregion + + //region Get internal properties from parsed schema + this.version = asn1.result.version.valueBlock.valueDec; + this.modulus = asn1.result.modulus.convertFromDER(256); + this.publicExponent = asn1.result.publicExponent; + this.privateExponent = asn1.result.privateExponent.convertFromDER(256); + this.prime1 = asn1.result.prime1.convertFromDER(128); + this.prime2 = asn1.result.prime2.convertFromDER(128); + this.exponent1 = asn1.result.exponent1.convertFromDER(128); + this.exponent2 = asn1.result.exponent2.convertFromDER(128); + this.coefficient = asn1.result.coefficient.convertFromDER(128); + + if("otherPrimeInfos" in asn1.result) + this.otherPrimeInfos = Array.from(asn1.result.otherPrimeInfos, element => new OtherPrimeInfo({ schema: element })); + //endregion + } + //********************************************************************************** + /** + * Convert current object to asn1js object and set correct values + * @returns {Object} asn1js object + */ + toSchema() + { + //region Create array for output sequence + const outputArray = []; + + outputArray.push(new asn1js.Integer({ value: this.version })); + outputArray.push(this.modulus.convertToDER()); + outputArray.push(this.publicExponent); + outputArray.push(this.privateExponent.convertToDER()); + outputArray.push(this.prime1.convertToDER()); + outputArray.push(this.prime2.convertToDER()); + outputArray.push(this.exponent1.convertToDER()); + outputArray.push(this.exponent2.convertToDER()); + outputArray.push(this.coefficient.convertToDER()); + + if("otherPrimeInfos" in this) + { + outputArray.push(new asn1js.Sequence({ + value: Array.from(this.otherPrimeInfos, element => element.toSchema()) + })); + } + //endregion + + //region Construct and return new ASN.1 schema for this object + return (new asn1js.Sequence({ + value: outputArray + })); + //endregion + } + //********************************************************************************** + /** + * Convertion for the class to JSON object + * @returns {Object} + */ + toJSON() + { + const jwk = { + n: toBase64(arrayBufferToString(this.modulus.valueBlock.valueHex), true, true, true), + e: toBase64(arrayBufferToString(this.publicExponent.valueBlock.valueHex), true, true, true), + d: toBase64(arrayBufferToString(this.privateExponent.valueBlock.valueHex), true, true, true), + p: toBase64(arrayBufferToString(this.prime1.valueBlock.valueHex), true, true, true), + q: toBase64(arrayBufferToString(this.prime2.valueBlock.valueHex), true, true, true), + dp: toBase64(arrayBufferToString(this.exponent1.valueBlock.valueHex), true, true, true), + dq: toBase64(arrayBufferToString(this.exponent2.valueBlock.valueHex), true, true, true), + qi: toBase64(arrayBufferToString(this.coefficient.valueBlock.valueHex), true, true, true) + }; + + if("otherPrimeInfos" in this) + jwk.oth = Array.from(this.otherPrimeInfos, element => element.toJSON()); + + return jwk; + } + //********************************************************************************** + /** + * Convert JSON value into current object + * @param {Object} json + */ + fromJSON(json) + { + if("n" in json) + this.modulus = new asn1js.Integer({ valueHex: stringToArrayBuffer(fromBase64(json.n, true, true)) }); + else + throw new Error("Absent mandatory parameter \"n\""); + + if("e" in json) + this.publicExponent = new asn1js.Integer({ valueHex: stringToArrayBuffer(fromBase64(json.e, true, true)) }); + else + throw new Error("Absent mandatory parameter \"e\""); + + if("d" in json) + this.privateExponent = new asn1js.Integer({ valueHex: stringToArrayBuffer(fromBase64(json.d, true, true)) }); + else + throw new Error("Absent mandatory parameter \"d\""); + + if("p" in json) + this.prime1 = new asn1js.Integer({ valueHex: stringToArrayBuffer(fromBase64(json.p, true, true)) }); + else + throw new Error("Absent mandatory parameter \"p\""); + + if("q" in json) + this.prime2 = new asn1js.Integer({ valueHex: stringToArrayBuffer(fromBase64(json.q, true, true)) }); + else + throw new Error("Absent mandatory parameter \"q\""); + + if("dp" in json) + this.exponent1 = new asn1js.Integer({ valueHex: stringToArrayBuffer(fromBase64(json.dp, true, true)) }); + else + throw new Error("Absent mandatory parameter \"dp\""); + + if("dq" in json) + this.exponent2 = new asn1js.Integer({ valueHex: stringToArrayBuffer(fromBase64(json.dq, true, true)) }); + else + throw new Error("Absent mandatory parameter \"dq\""); + + if("qi" in json) + this.coefficient = new asn1js.Integer({ valueHex: stringToArrayBuffer(fromBase64(json.qi, true, true)) }); + else + throw new Error("Absent mandatory parameter \"qi\""); + + if("oth" in json) + this.otherPrimeInfos = Array.from(json.oth, element => new OtherPrimeInfo({ json: element })); + } + //********************************************************************************** +} +//************************************************************************************** diff --git a/core/third-party/pkijs/RSAPublicKey.js b/core/third-party/pkijs/RSAPublicKey.js new file mode 100644 index 0000000..473627d --- /dev/null +++ b/core/third-party/pkijs/RSAPublicKey.js @@ -0,0 +1,174 @@ +import * as asn1js from "./asn1.js"; +import { getParametersValue, toBase64, arrayBufferToString, stringToArrayBuffer, fromBase64, nearestPowerOf2, clearProps } from "./pvutils.js"; +//************************************************************************************** +/** + * Class from RFC3447 + */ +export default class RSAPublicKey +{ + //********************************************************************************** + /** + * Constructor for RSAPublicKey class + * @param {Object} [parameters={}] + * @param {Object} [parameters.schema] asn1js parsed value to initialize the class from + * @property {Integer} [modulus] + * @property {Integer} [publicExponent] + */ + constructor(parameters = {}) + { + //region Internal properties of the object + /** + * @type {Integer} + * @desc Modulus part of RSA public key + */ + this.modulus = getParametersValue(parameters, "modulus", RSAPublicKey.defaultValues("modulus")); + /** + * @type {Integer} + * @desc Public exponent of RSA public key + */ + this.publicExponent = getParametersValue(parameters, "publicExponent", RSAPublicKey.defaultValues("publicExponent")); + //endregion + + //region If input argument array contains "schema" for this object + if("schema" in parameters) + this.fromSchema(parameters.schema); + //endregion + //region If input argument array contains "json" for this object + if("json" in parameters) + this.fromJSON(parameters.json); + //endregion + } + //********************************************************************************** + /** + * Return default values for all class members + * @param {string} memberName String name for a class member + */ + static defaultValues(memberName) + { + switch(memberName) + { + case "modulus": + return new asn1js.Integer(); + case "publicExponent": + return new asn1js.Integer(); + default: + throw new Error(`Invalid member name for RSAPublicKey class: ${memberName}`); + } + } + //********************************************************************************** + /** + * Return value of pre-defined ASN.1 schema for current class + * + * ASN.1 schema: + * ```asn1 + * RSAPublicKey ::= Sequence { + * modulus Integer, -- n + * publicExponent Integer -- e + * } + * ``` + * + * @param {Object} parameters Input parameters for the schema + * @returns {Object} asn1js schema object + */ + static schema(parameters = {}) + { + /** + * @type {Object} + * @property {string} utcTimeName Name for "utcTimeName" choice + * @property {string} generalTimeName Name for "generalTimeName" choice + */ + const names = getParametersValue(parameters, "names", {}); + + return (new asn1js.Sequence({ + name: (names.blockName || ""), + value: [ + new asn1js.Integer({ name: (names.modulus || "") }), + new asn1js.Integer({ name: (names.publicExponent || "") }) + ] + })); + } + //********************************************************************************** + /** + * Convert parsed asn1js object into current class + * @param {!Object} schema + */ + fromSchema(schema) + { + //region Clear input data first + clearProps(schema, [ + "modulus", + "publicExponent" + ]); + //endregion + + //region Check the schema is valid + const asn1 = asn1js.compareSchema(schema, + schema, + RSAPublicKey.schema({ + names: { + modulus: "modulus", + publicExponent: "publicExponent" + } + }) + ); + + if(asn1.verified === false) + throw new Error("Object's schema was not verified against input data for RSAPublicKey"); + //endregion + + //region Get internal properties from parsed schema + this.modulus = asn1.result.modulus.convertFromDER(256); + this.publicExponent = asn1.result.publicExponent; + //endregion + } + //********************************************************************************** + /** + * Convert current object to asn1js object and set correct values + * @returns {Object} asn1js object + */ + toSchema() + { + //region Construct and return new ASN.1 schema for this object + return (new asn1js.Sequence({ + value: [ + this.modulus.convertToDER(), + this.publicExponent + ] + })); + //endregion + } + //********************************************************************************** + /** + * Convertion for the class to JSON object + * @returns {Object} + */ + toJSON() + { + return { + n: toBase64(arrayBufferToString(this.modulus.valueBlock.valueHex), true, true, true), + e: toBase64(arrayBufferToString(this.publicExponent.valueBlock.valueHex), true, true, true) + }; + } + //********************************************************************************** + /** + * Convert JSON value into current object + * @param {Object} json + */ + fromJSON(json) + { + if("n" in json) + { + const array = stringToArrayBuffer(fromBase64(json.n, true)); + this.modulus = new asn1js.Integer({ valueHex: array.slice(0, Math.pow(2, nearestPowerOf2(array.byteLength))) }); + } + else + throw new Error("Absent mandatory parameter \"n\""); + + if("e" in json) + this.publicExponent = new asn1js.Integer({ valueHex: stringToArrayBuffer(fromBase64(json.e, true)).slice(0, 3) }); + else + throw new Error("Absent mandatory parameter \"e\""); + } + //********************************************************************************** +} +//************************************************************************************** diff --git a/core/third-party/pkijs/RSASSAPSSParams.js b/core/third-party/pkijs/RSASSAPSSParams.js new file mode 100644 index 0000000..cf6a6f6 --- /dev/null +++ b/core/third-party/pkijs/RSASSAPSSParams.js @@ -0,0 +1,283 @@ +import * as asn1js from "./asn1.js"; +import { getParametersValue, clearProps } from "./pvutils.js"; +import AlgorithmIdentifier from "./AlgorithmIdentifier.js"; +//************************************************************************************** +/** + * Class from RFC4055 + */ +export default class RSASSAPSSParams +{ + //********************************************************************************** + /** + * Constructor for RSASSAPSSParams class + * @param {Object} [parameters={}] + * @param {Object} [parameters.schema] asn1js parsed value to initialize the class from + */ + constructor(parameters = {}) + { + //region Internal properties of the object + /** + * @type {AlgorithmIdentifier} + * @desc Algorithms of hashing (DEFAULT sha1) + */ + this.hashAlgorithm = getParametersValue(parameters, "hashAlgorithm", RSASSAPSSParams.defaultValues("hashAlgorithm")); + /** + * @type {AlgorithmIdentifier} + * @desc Algorithm of "mask generaion function (MGF)" (DEFAULT mgf1SHA1) + */ + this.maskGenAlgorithm = getParametersValue(parameters, "maskGenAlgorithm", RSASSAPSSParams.defaultValues("maskGenAlgorithm")); + /** + * @type {number} + * @desc Salt length (DEFAULT 20) + */ + this.saltLength = getParametersValue(parameters, "saltLength", RSASSAPSSParams.defaultValues("saltLength")); + /** + * @type {number} + * @desc (DEFAULT 1) + */ + this.trailerField = getParametersValue(parameters, "trailerField", RSASSAPSSParams.defaultValues("trailerField")); + //endregion + + //region If input argument array contains "schema" for this object + if("schema" in parameters) + this.fromSchema(parameters.schema); + //endregion + } + //********************************************************************************** + /** + * Return default values for all class members + * @param {string} memberName String name for a class member + */ + static defaultValues(memberName) + { + switch(memberName) + { + case "hashAlgorithm": + return new AlgorithmIdentifier({ + algorithmId: "1.3.14.3.2.26", // SHA-1 + algorithmParams: new asn1js.Null() + }); + case "maskGenAlgorithm": + return new AlgorithmIdentifier({ + algorithmId: "1.2.840.113549.1.1.8", // MGF1 + algorithmParams: (new AlgorithmIdentifier({ + algorithmId: "1.3.14.3.2.26", // SHA-1 + algorithmParams: new asn1js.Null() + })).toSchema() + }); + case "saltLength": + return 20; + case "trailerField": + return 1; + default: + throw new Error(`Invalid member name for RSASSAPSSParams class: ${memberName}`); + } + } + //********************************************************************************** + /** + * Return value of pre-defined ASN.1 schema for current class + * + * ASN.1 schema: + * ```asn1 + * RSASSA-PSS-params ::= Sequence { + * hashAlgorithm [0] HashAlgorithm DEFAULT sha1Identifier, + * maskGenAlgorithm [1] MaskGenAlgorithm DEFAULT mgf1SHA1Identifier, + * saltLength [2] Integer DEFAULT 20, + * trailerField [3] Integer DEFAULT 1 } + * ``` + * + * @param {Object} parameters Input parameters for the schema + * @returns {Object} asn1js schema object + */ + static schema(parameters = {}) + { + /** + * @type {Object} + * @property {string} [blockName] + * @property {string} [hashAlgorithm] + * @property {string} [maskGenAlgorithm] + * @property {string} [saltLength] + * @property {string} [trailerField] + */ + const names = getParametersValue(parameters, "names", {}); + + return (new asn1js.Sequence({ + name: (names.blockName || ""), + value: [ + new asn1js.Constructed({ + idBlock: { + tagClass: 3, // CONTEXT-SPECIFIC + tagNumber: 0 // [0] + }, + optional: true, + value: [AlgorithmIdentifier.schema(names.hashAlgorithm || {})] + }), + new asn1js.Constructed({ + idBlock: { + tagClass: 3, // CONTEXT-SPECIFIC + tagNumber: 1 // [1] + }, + optional: true, + value: [AlgorithmIdentifier.schema(names.maskGenAlgorithm || {})] + }), + new asn1js.Constructed({ + idBlock: { + tagClass: 3, // CONTEXT-SPECIFIC + tagNumber: 2 // [2] + }, + optional: true, + value: [new asn1js.Integer({ name: (names.saltLength || "") })] + }), + new asn1js.Constructed({ + idBlock: { + tagClass: 3, // CONTEXT-SPECIFIC + tagNumber: 3 // [3] + }, + optional: true, + value: [new asn1js.Integer({ name: (names.trailerField || "") })] + }) + ] + })); + } + //********************************************************************************** + /** + * Convert parsed asn1js object into current class + * @param {!Object} schema + */ + fromSchema(schema) + { + //region Clear input data first + clearProps(schema, [ + "hashAlgorithm", + "maskGenAlgorithm", + "saltLength", + "trailerField" + ]); + //endregion + + //region Check the schema is valid + const asn1 = asn1js.compareSchema(schema, + schema, + RSASSAPSSParams.schema({ + names: { + hashAlgorithm: { + names: { + blockName: "hashAlgorithm" + } + }, + maskGenAlgorithm: { + names: { + blockName: "maskGenAlgorithm" + } + }, + saltLength: "saltLength", + trailerField: "trailerField" + } + }) + ); + + if(asn1.verified === false) + throw new Error("Object's schema was not verified against input data for RSASSAPSSParams"); + //endregion + + //region Get internal properties from parsed schema + if("hashAlgorithm" in asn1.result) + this.hashAlgorithm = new AlgorithmIdentifier({ schema: asn1.result.hashAlgorithm }); + + if("maskGenAlgorithm" in asn1.result) + this.maskGenAlgorithm = new AlgorithmIdentifier({ schema: asn1.result.maskGenAlgorithm }); + + if("saltLength" in asn1.result) + this.saltLength = asn1.result.saltLength.valueBlock.valueDec; + + if("trailerField" in asn1.result) + this.trailerField = asn1.result.trailerField.valueBlock.valueDec; + //endregion + } + //********************************************************************************** + /** + * Convert current object to asn1js object and set correct values + * @returns {Object} asn1js object + */ + toSchema() + { + //region Create array for output sequence + const outputArray = []; + + if(!this.hashAlgorithm.isEqual(RSASSAPSSParams.defaultValues("hashAlgorithm"))) + { + outputArray.push(new asn1js.Constructed({ + idBlock: { + tagClass: 3, // CONTEXT-SPECIFIC + tagNumber: 0 // [0] + }, + value: [this.hashAlgorithm.toSchema()] + })); + } + + if(!this.maskGenAlgorithm.isEqual(RSASSAPSSParams.defaultValues("maskGenAlgorithm"))) + { + outputArray.push(new asn1js.Constructed({ + idBlock: { + tagClass: 3, // CONTEXT-SPECIFIC + tagNumber: 1 // [1] + }, + value: [this.maskGenAlgorithm.toSchema()] + })); + } + + if(this.saltLength !== RSASSAPSSParams.defaultValues("saltLength")) + { + outputArray.push(new asn1js.Constructed({ + idBlock: { + tagClass: 3, // CONTEXT-SPECIFIC + tagNumber: 2 // [2] + }, + value: [new asn1js.Integer({ value: this.saltLength })] + })); + } + + if(this.trailerField !== RSASSAPSSParams.defaultValues("trailerField")) + { + outputArray.push(new asn1js.Constructed({ + idBlock: { + tagClass: 3, // CONTEXT-SPECIFIC + tagNumber: 3 // [3] + }, + value: [new asn1js.Integer({ value: this.trailerField })] + })); + } + //endregion + + //region Construct and return new ASN.1 schema for this object + return (new asn1js.Sequence({ + value: outputArray + })); + //endregion + } + //********************************************************************************** + /** + * Convertion for the class to JSON object + * @returns {Object} + */ + toJSON() + { + const object = {}; + + if(!this.hashAlgorithm.isEqual(RSASSAPSSParams.defaultValues("hashAlgorithm"))) + object.hashAlgorithm = this.hashAlgorithm.toJSON(); + + if(!this.maskGenAlgorithm.isEqual(RSASSAPSSParams.defaultValues("maskGenAlgorithm"))) + object.maskGenAlgorithm = this.maskGenAlgorithm.toJSON(); + + if(this.saltLength !== RSASSAPSSParams.defaultValues("saltLength")) + object.saltLength = this.saltLength; + + if(this.trailerField !== RSASSAPSSParams.defaultValues("trailerField")) + object.trailerField = this.trailerField; + + return object; + } + //********************************************************************************** +} +//************************************************************************************** diff --git a/core/third-party/pkijs/RecipientEncryptedKey.js b/core/third-party/pkijs/RecipientEncryptedKey.js new file mode 100644 index 0000000..a2fdbc7 --- /dev/null +++ b/core/third-party/pkijs/RecipientEncryptedKey.js @@ -0,0 +1,173 @@ +import * as asn1js from "./asn1.js"; +import { getParametersValue, clearProps } from "./pvutils.js"; +import KeyAgreeRecipientIdentifier from "./KeyAgreeRecipientIdentifier.js"; +//************************************************************************************** +/** + * Class from RFC5652 + */ +export default class RecipientEncryptedKey +{ + //********************************************************************************** + /** + * Constructor for RecipientEncryptedKey class + * @param {Object} [parameters={}] + * @param {Object} [parameters.schema] asn1js parsed value to initialize the class from + */ + constructor(parameters = {}) + { + //region Internal properties of the object + /** + * @type {KeyAgreeRecipientIdentifier} + * @desc rid + */ + this.rid = getParametersValue(parameters, "rid", RecipientEncryptedKey.defaultValues("rid")); + /** + * @type {OctetString} + * @desc encryptedKey + */ + this.encryptedKey = getParametersValue(parameters, "encryptedKey", RecipientEncryptedKey.defaultValues("encryptedKey")); + //endregion + + //region If input argument array contains "schema" for this object + if("schema" in parameters) + this.fromSchema(parameters.schema); + //endregion + } + //********************************************************************************** + /** + * Return default values for all class members + * @param {string} memberName String name for a class member + */ + static defaultValues(memberName) + { + switch(memberName) + { + case "rid": + return new KeyAgreeRecipientIdentifier(); + case "encryptedKey": + return new asn1js.OctetString(); + default: + throw new Error(`Invalid member name for RecipientEncryptedKey class: ${memberName}`); + } + } + //********************************************************************************** + /** + * Compare values with default values for all class members + * @param {string} memberName String name for a class member + * @param {*} memberValue Value to compare with default value + */ + static compareWithDefault(memberName, memberValue) + { + switch(memberName) + { + case "rid": + return ((memberValue.variant === (-1)) && (("value" in memberValue) === false)); + case "encryptedKey": + return (memberValue.isEqual(RecipientEncryptedKey.defaultValues("encryptedKey"))); + default: + throw new Error(`Invalid member name for RecipientEncryptedKey class: ${memberName}`); + } + } + //********************************************************************************** + /** + * Return value of pre-defined ASN.1 schema for current class + * + * ASN.1 schema: + * ```asn1 + * RecipientEncryptedKey ::= SEQUENCE { + * rid KeyAgreeRecipientIdentifier, + * encryptedKey EncryptedKey } + * + * EncryptedKey ::= OCTET STRING + * ``` + * + * @param {Object} parameters Input parameters for the schema + * @returns {Object} asn1js schema object + */ + static schema(parameters = {}) + { + /** + * @type {Object} + * @property {string} [blockName] + * @property {string} [rid] + * @property {string} [encryptedKey] + */ + const names = getParametersValue(parameters, "names", {}); + + return (new asn1js.Sequence({ + name: (names.blockName || ""), + value: [ + KeyAgreeRecipientIdentifier.schema(names.rid || {}), + new asn1js.OctetString({ name: (names.encryptedKey || "") }) + ] + })); + } + //********************************************************************************** + /** + * Convert parsed asn1js object into current class + * @param {!Object} schema + */ + fromSchema(schema) + { + //region Clear input data first + clearProps(schema, [ + "rid", + "encryptedKey" + ]); + //endregion + + //region Check the schema is valid + const asn1 = asn1js.compareSchema(schema, + schema, + RecipientEncryptedKey.schema({ + names: { + rid: { + names: { + blockName: "rid" + } + }, + encryptedKey: "encryptedKey" + } + }) + ); + + if(asn1.verified === false) + throw new Error("Object's schema was not verified against input data for RecipientEncryptedKey"); + //endregion + + //region Get internal properties from parsed schema + this.rid = new KeyAgreeRecipientIdentifier({ schema: asn1.result.rid }); + this.encryptedKey = asn1.result.encryptedKey; + //endregion + } + //********************************************************************************** + /** + * Convert current object to asn1js object and set correct values + * @returns {Object} asn1js object + */ + toSchema() + { + //region Construct and return new ASN.1 schema for this object + return (new asn1js.Sequence({ + value: [ + this.rid.toSchema(), + this.encryptedKey + ] + })); + //endregion + } + //********************************************************************************** + /** + * Convertion for the class to JSON object + * @returns {Object} + */ + toJSON() + { + return { + rid: this.rid.toJSON(), + encryptedKey: this.encryptedKey.toJSON() + }; + } + //********************************************************************************** +} +//************************************************************************************** diff --git a/core/third-party/pkijs/RecipientEncryptedKeys.js b/core/third-party/pkijs/RecipientEncryptedKeys.js new file mode 100644 index 0000000..41fe681 --- /dev/null +++ b/core/third-party/pkijs/RecipientEncryptedKeys.js @@ -0,0 +1,150 @@ +import * as asn1js from "./asn1.js"; +import { getParametersValue, clearProps } from "./pvutils.js"; +import RecipientEncryptedKey from "./RecipientEncryptedKey.js"; +//************************************************************************************** +/** + * Class from RFC5652 + */ +export default class RecipientEncryptedKeys +{ + //********************************************************************************** + /** + * Constructor for RecipientEncryptedKeys class + * @param {Object} [parameters={}] + * @param {Object} [parameters.schema] asn1js parsed value to initialize the class from + */ + constructor(parameters = {}) + { + //region Internal properties of the object + /** + * @type {Array.} + * @desc encryptedKeys + */ + this.encryptedKeys = getParametersValue(parameters, "encryptedKeys", RecipientEncryptedKeys.defaultValues("encryptedKeys")); + //endregion + + //region If input argument array contains "schema" for this object + if("schema" in parameters) + this.fromSchema(parameters.schema); + //endregion + } + //********************************************************************************** + /** + * Return default values for all class members + * @param {string} memberName String name for a class member + */ + static defaultValues(memberName) + { + switch(memberName) + { + case "encryptedKeys": + return []; + default: + throw new Error(`Invalid member name for RecipientEncryptedKeys class: ${memberName}`); + } + } + //********************************************************************************** + /** + * Compare values with default values for all class members + * @param {string} memberName String name for a class member + * @param {*} memberValue Value to compare with default value + */ + static compareWithDefault(memberName, memberValue) + { + switch(memberName) + { + case "encryptedKeys": + return (memberValue.length === 0); + default: + throw new Error(`Invalid member name for RecipientEncryptedKeys class: ${memberName}`); + } + } + //********************************************************************************** + /** + * Return value of pre-defined ASN.1 schema for current class + * + * ASN.1 schema: + * ```asn1 + * RecipientEncryptedKeys ::= SEQUENCE OF RecipientEncryptedKey + * ``` + * + * @param {Object} parameters Input parameters for the schema + * @returns {Object} asn1js schema object + */ + static schema(parameters = {}) + { + /** + * @type {Object} + * @property {string} [blockName] + * @property {string} [RecipientEncryptedKeys] + */ + const names = getParametersValue(parameters, "names", {}); + + return (new asn1js.Sequence({ + name: (names.blockName || ""), + value: [ + new asn1js.Repeated({ + name: (names.RecipientEncryptedKeys || ""), + value: RecipientEncryptedKey.schema() + }) + ] + })); + } + //********************************************************************************** + /** + * Convert parsed asn1js object into current class + * @param {!Object} schema + */ + fromSchema(schema) + { + //region Clear input data first + clearProps(schema, [ + "RecipientEncryptedKeys" + ]); + //endregion + + //region Check the schema is valid + const asn1 = asn1js.compareSchema(schema, + schema, + RecipientEncryptedKeys.schema({ + names: { + RecipientEncryptedKeys: "RecipientEncryptedKeys" + } + }) + ); + + if(asn1.verified === false) + throw new Error("Object's schema was not verified against input data for RecipientEncryptedKeys"); + //endregion + + //region Get internal properties from parsed schema + this.encryptedKeys = Array.from(asn1.result.RecipientEncryptedKeys, element => new RecipientEncryptedKey({ schema: element })); + //endregion + } + //********************************************************************************** + /** + * Convert current object to asn1js object and set correct values + * @returns {Object} asn1js object + */ + toSchema() + { + //region Construct and return new ASN.1 schema for this object + return (new asn1js.Sequence({ + value: Array.from(this.encryptedKeys, element => element.toSchema()) + })); + //endregion + } + //********************************************************************************** + /** + * Convertion for the class to JSON object + * @returns {Object} + */ + toJSON() + { + return { + encryptedKeys: Array.from(this.encryptedKeys, element => element.toJSON()) + }; + } + //********************************************************************************** +} +//************************************************************************************** diff --git a/core/third-party/pkijs/RecipientIdentifier.js b/core/third-party/pkijs/RecipientIdentifier.js new file mode 100644 index 0000000..17a82b8 --- /dev/null +++ b/core/third-party/pkijs/RecipientIdentifier.js @@ -0,0 +1,197 @@ +import * as asn1js from "./asn1.js"; +import { getParametersValue, clearProps } from "./pvutils.js"; +import IssuerAndSerialNumber from "./IssuerAndSerialNumber.js"; +//************************************************************************************** +/** + * Class from RFC5652 + */ +export default class RecipientIdentifier +{ + //********************************************************************************** + /** + * Constructor for RecipientIdentifier class + * @param {Object} [parameters={}] + * @param {Object} [parameters.schema] asn1js parsed value to initialize the class from + */ + constructor(parameters = {}) + { + //region Internal properties of the object + /** + * @type {number} + * @desc variant + */ + this.variant = getParametersValue(parameters, "variant", RecipientIdentifier.defaultValues("variant")); + + if("value" in parameters) + /** + * @type {*} + * @desc value + */ + this.value = getParametersValue(parameters, "value", RecipientIdentifier.defaultValues("value")); + //endregion + + //region If input argument array contains "schema" for this object + if("schema" in parameters) + this.fromSchema(parameters.schema); + //endregion + } + //********************************************************************************** + /** + * Return default values for all class members + * @param {string} memberName String name for a class member + */ + static defaultValues(memberName) + { + switch(memberName) + { + case "variant": + return (-1); + case "value": + return {}; + default: + throw new Error(`Invalid member name for RecipientIdentifier class: ${memberName}`); + } + } + //********************************************************************************** + /** + * Compare values with default values for all class members + * @param {string} memberName String name for a class member + * @param {*} memberValue Value to compare with default value + */ + static compareWithDefault(memberName, memberValue) + { + switch(memberName) + { + case "variant": + return (memberValue === (-1)); + case "values": + return (Object.keys(memberValue).length === 0); + default: + throw new Error(`Invalid member name for RecipientIdentifier class: ${memberName}`); + } + } + //********************************************************************************** + /** + * Return value of pre-defined ASN.1 schema for current class + * + * ASN.1 schema: + * ```asn1 + * RecipientIdentifier ::= CHOICE { + * issuerAndSerialNumber IssuerAndSerialNumber, + * subjectKeyIdentifier [0] SubjectKeyIdentifier } + * + * SubjectKeyIdentifier ::= OCTET STRING + * ``` + * + * @param {Object} parameters Input parameters for the schema + * @returns {Object} asn1js schema object + */ + static schema(parameters = {}) + { + /** + * @type {Object} + * @property {string} [blockName] + */ + const names = getParametersValue(parameters, "names", {}); + + return (new asn1js.Choice({ + value: [ + IssuerAndSerialNumber.schema({ + names: { + blockName: (names.blockName || "") + } + }), + new asn1js.Primitive({ + name: (names.blockName || ""), + idBlock: { + tagClass: 3, // CONTEXT-SPECIFIC + tagNumber: 0 // [0] + } + }) + ] + })); + } + //********************************************************************************** + /** + * Convert parsed asn1js object into current class + * @param {!Object} schema + */ + fromSchema(schema) + { + //region Clear input data first + clearProps(schema, [ + "blockName" + ]); + //endregion + + //region Check the schema is valid + const asn1 = asn1js.compareSchema(schema, + schema, + RecipientIdentifier.schema({ + names: { + blockName: "blockName" + } + }) + ); + + if(asn1.verified === false) + throw new Error("Object's schema was not verified against input data for RecipientIdentifier"); + //endregion + + //region Get internal properties from parsed schema + if(asn1.result.blockName.idBlock.tagClass === 1) + { + this.variant = 1; + this.value = new IssuerAndSerialNumber({ schema: asn1.result.blockName }); + } + else + { + this.variant = 2; + this.value = new asn1js.OctetString({ valueHex: asn1.result.blockName.valueBlock.valueHex }) ; + } + //endregion + } + //********************************************************************************** + /** + * Convert current object to asn1js object and set correct values + * @returns {Object} asn1js object + */ + toSchema() + { + //region Construct and return new ASN.1 schema for this object + switch(this.variant) + { + case 1: + return this.value.toSchema(); + case 2: + return new asn1js.Primitive({ + idBlock: { + tagClass: 3, // CONTEXT-SPECIFIC + tagNumber: 0 // [0] + }, + valueHex: this.value.valueBlock.valueHex + }); + default: + return new asn1js.Any(); + } + //endregion + } + //********************************************************************************** + /** + * Convertion for the class to JSON object + * @returns {Object} + */ + toJSON() + { + const _object = { + variant: this.variant + }; + + if((this.variant === 1) || (this.variant === 2)) + _object.value = this.value.toJSON(); + + return _object; + } + //********************************************************************************** +} +//************************************************************************************** diff --git a/core/third-party/pkijs/RecipientInfo.js b/core/third-party/pkijs/RecipientInfo.js new file mode 100644 index 0000000..9cc4b73 --- /dev/null +++ b/core/third-party/pkijs/RecipientInfo.js @@ -0,0 +1,258 @@ +import * as asn1js from "./asn1.js"; +import { getParametersValue, clearProps } from "./pvutils.js"; +import KeyTransRecipientInfo from "./KeyTransRecipientInfo.js"; +import KeyAgreeRecipientInfo from "./KeyAgreeRecipientInfo.js"; +import KEKRecipientInfo from "./KEKRecipientInfo.js"; +import PasswordRecipientinfo from "./PasswordRecipientinfo.js"; +import OtherRecipientInfo from "./OtherRecipientInfo.js"; +//************************************************************************************** +/** + * Class from RFC5652 + */ +export default class RecipientInfo +{ + //********************************************************************************** + /** + * Constructor for RecipientInfo class + * @param {Object} [parameters={}] + * @param {Object} [parameters.schema] asn1js parsed value to initialize the class from + */ + constructor(parameters = {}) + { + //region Internal properties of the object + /** + * @type {string} + * @desc variant + */ + this.variant = getParametersValue(parameters, "variant", RecipientInfo.defaultValues("variant")); + + if("value" in parameters) + /** + * @type {*} + * @desc value + */ + this.value = getParametersValue(parameters, "value", RecipientInfo.defaultValues("value")); + //endregion + + //region If input argument array contains "schema" for this object + if("schema" in parameters) + this.fromSchema(parameters.schema); + //endregion + } + //********************************************************************************** + /** + * Return default values for all class members + * @param {string} memberName String name for a class member + */ + static defaultValues(memberName) + { + switch(memberName) + { + case "variant": + return (-1); + case "value": + return {}; + default: + throw new Error(`Invalid member name for RecipientInfo class: ${memberName}`); + } + } + //********************************************************************************** + /** + * Compare values with default values for all class members + * @param {string} memberName String name for a class member + * @param {*} memberValue Value to compare with default value + */ + static compareWithDefault(memberName, memberValue) + { + switch(memberName) + { + case "variant": + return (memberValue === RecipientInfo.defaultValues(memberName)); + case "value": + return (Object.keys(memberValue).length === 0); + default: + throw new Error(`Invalid member name for RecipientInfo class: ${memberName}`); + } + } + //********************************************************************************** + /** + * Return value of pre-defined ASN.1 schema for current class + * + * ASN.1 schema: + * ```asn1 + * RecipientInfo ::= CHOICE { + * ktri KeyTransRecipientInfo, + * kari [1] KeyAgreeRecipientInfo, + * kekri [2] KEKRecipientInfo, + * pwri [3] PasswordRecipientinfo, + * ori [4] OtherRecipientInfo } + * ``` + * + * @param {Object} parameters Input parameters for the schema + * @returns {Object} asn1js schema object + */ + static schema(parameters = {}) + { + /** + * @type {Object} + * @property {string} [blockName] + * @property {string} [type] + * @property {string} [setName] + * @property {string} [values] + */ + const names = getParametersValue(parameters, "names", {}); + + return (new asn1js.Choice({ + value: [ + KeyTransRecipientInfo.schema({ + names: { + blockName: (names.blockName || "") + } + }), + new asn1js.Constructed({ + name: (names.blockName || ""), + idBlock: { + tagClass: 3, // CONTEXT-SPECIFIC + tagNumber: 1 // [1] + }, + value: KeyAgreeRecipientInfo.schema().valueBlock.value + }), + new asn1js.Constructed({ + name: (names.blockName || ""), + idBlock: { + tagClass: 3, // CONTEXT-SPECIFIC + tagNumber: 2 // [2] + }, + value: KEKRecipientInfo.schema().valueBlock.value + }), + new asn1js.Constructed({ + name: (names.blockName || ""), + idBlock: { + tagClass: 3, // CONTEXT-SPECIFIC + tagNumber: 3 // [3] + }, + value: PasswordRecipientinfo.schema().valueBlock.value + }), + new asn1js.Constructed({ + name: (names.blockName || ""), + idBlock: { + tagClass: 3, // CONTEXT-SPECIFIC + tagNumber: 4 // [4] + }, + value: OtherRecipientInfo.schema().valueBlock.value + }) + ] + })); + } + //********************************************************************************** + /** + * Convert parsed asn1js object into current class + * @param {!Object} schema + */ + fromSchema(schema) + { + //region Clear input data first + clearProps(schema, [ + "blockName" + ]); + //endregion + + //region Check the schema is valid + const asn1 = asn1js.compareSchema(schema, + schema, + RecipientInfo.schema({ + names: { + blockName: "blockName" + } + }) + ); + + if(asn1.verified === false) + throw new Error("Object's schema was not verified against input data for RecipientInfo"); + //endregion + + //region Get internal properties from parsed schema + if(asn1.result.blockName.idBlock.tagClass === 1) + { + this.variant = 1; + this.value = new KeyTransRecipientInfo({ schema: asn1.result.blockName }); + } + else + { + //region Create "SEQUENCE" from "ASN1_CONSTRUCTED" + const blockSequence = new asn1js.Sequence({ + value: asn1.result.blockName.valueBlock.value + }); + //endregion + + switch(asn1.result.blockName.idBlock.tagNumber) + { + case 1: + this.variant = 2; + this.value = new KeyAgreeRecipientInfo({ schema: blockSequence }); + break; + case 2: + this.variant = 3; + this.value = new KEKRecipientInfo({ schema: blockSequence }); + break; + case 3: + this.variant = 4; + this.value = new PasswordRecipientinfo({ schema: blockSequence }); + break; + case 4: + this.variant = 5; + this.value = new OtherRecipientInfo({ schema: blockSequence }); + break; + default: + throw new Error("Incorrect structure of RecipientInfo block"); + } + } + //endregion + } + //********************************************************************************** + /** + * Convert current object to asn1js object and set correct values + * @returns {Object} asn1js object + */ + toSchema() + { + //region Construct and return new ASN.1 schema for this object + const _schema = this.value.toSchema(); + + switch(this.variant) + { + case 1: + return _schema; + case 2: + case 3: + case 4: + //region Create "ASN1_CONSTRUCTED" from "SEQUENCE" + _schema.idBlock.tagClass = 3; // CONTEXT-SPECIFIC + _schema.idBlock.tagNumber = (this.variant - 1); + //endregion + + return _schema; + default: + return new asn1js.Any(); + } + //endregion + } + //********************************************************************************** + /** + * Convertion for the class to JSON object + * @returns {Object} + */ + toJSON() + { + const _object = { + variant: this.variant + }; + + if((this.variant >= 1) && (this.variant <= 4)) + _object.value = this.value.toJSON(); + + return _object; + } + //********************************************************************************** +} +//************************************************************************************** diff --git a/core/third-party/pkijs/RecipientKeyIdentifier.js b/core/third-party/pkijs/RecipientKeyIdentifier.js new file mode 100644 index 0000000..edb88e2 --- /dev/null +++ b/core/third-party/pkijs/RecipientKeyIdentifier.js @@ -0,0 +1,220 @@ +import * as asn1js from "./asn1.js"; +import { getParametersValue, clearProps } from "./pvutils.js"; +import OtherKeyAttribute from "./OtherKeyAttribute.js"; +//************************************************************************************** +/** + * Class from RFC5652 + */ +export default class RecipientKeyIdentifier +{ + //********************************************************************************** + /** + * Constructor for RecipientKeyIdentifier class + * @param {Object} [parameters={}] + * @param {Object} [parameters.schema] asn1js parsed value to initialize the class from + */ + constructor(parameters = {}) + { + //region Internal properties of the object + /** + * @type {OctetString} + * @desc subjectKeyIdentifier + */ + this.subjectKeyIdentifier = getParametersValue(parameters, "subjectKeyIdentifier", RecipientKeyIdentifier.defaultValues("subjectKeyIdentifier")); + + if("date" in parameters) + /** + * @type {GeneralizedTime} + * @desc date + */ + this.date = getParametersValue(parameters, "date", RecipientKeyIdentifier.defaultValues("date")); + + if("other" in parameters) + /** + * @type {OtherKeyAttribute} + * @desc other + */ + this.other = getParametersValue(parameters, "other", RecipientKeyIdentifier.defaultValues("other")); + //endregion + + //region If input argument array contains "schema" for this object + if("schema" in parameters) + this.fromSchema(parameters.schema); + //endregion + } + //********************************************************************************** + /** + * Return default values for all class members + * @param {string} memberName String name for a class member + */ + static defaultValues(memberName) + { + switch(memberName) + { + case "subjectKeyIdentifier": + return new asn1js.OctetString(); + case "date": + return new asn1js.GeneralizedTime(); + case "other": + return new OtherKeyAttribute(); + default: + throw new Error(`Invalid member name for RecipientKeyIdentifier class: ${memberName}`); + } + } + //********************************************************************************** + /** + * Compare values with default values for all class members + * @param {string} memberName String name for a class member + * @param {*} memberValue Value to compare with default value + */ + static compareWithDefault(memberName, memberValue) + { + switch(memberName) + { + case "subjectKeyIdentifier": + return (memberValue.isEqual(RecipientKeyIdentifier.defaultValues("subjectKeyIdentifier"))); + case "date": + // noinspection OverlyComplexBooleanExpressionJS + return ((memberValue.year === 0) && + (memberValue.month === 0) && + (memberValue.day === 0) && + (memberValue.hour === 0) && + (memberValue.minute === 0) && + (memberValue.second === 0) && + (memberValue.millisecond === 0)); + case "other": + return ((memberValue.keyAttrId === "") && (("keyAttr" in memberValue) === false)); + default: + throw new Error(`Invalid member name for RecipientKeyIdentifier class: ${memberName}`); + } + } + //********************************************************************************** + /** + * Return value of pre-defined ASN.1 schema for current class + * + * ASN.1 schema: + * ```asn1 + * RecipientKeyIdentifier ::= SEQUENCE { + * subjectKeyIdentifier SubjectKeyIdentifier, + * date GeneralizedTime OPTIONAL, + * other OtherKeyAttribute OPTIONAL } + * ``` + * + * @param {Object} parameters Input parameters for the schema + * @returns {Object} asn1js schema object + */ + static schema(parameters = {}) + { + /** + * @type {Object} + * @property {string} [blockName] + * @property {string} [type] + * @property {string} [setName] + * @property {string} [values] + */ + const names = getParametersValue(parameters, "names", {}); + + return (new asn1js.Sequence({ + name: (names.blockName || ""), + value: [ + new asn1js.OctetString({ name: (names.subjectKeyIdentifier || "") }), + new asn1js.GeneralizedTime({ + optional: true, + name: (names.date || "") + }), + OtherKeyAttribute.schema(names.other || {}) + ] + })); + } + //********************************************************************************** + /** + * Convert parsed asn1js object into current class + * @param {!Object} schema + */ + fromSchema(schema) + { + //region Clear input data first + clearProps(schema, [ + "subjectKeyIdentifier", + "date", + "other" + ]); + //endregion + + //region Check the schema is valid + const asn1 = asn1js.compareSchema(schema, + schema, + RecipientKeyIdentifier.schema({ + names: { + subjectKeyIdentifier: "subjectKeyIdentifier", + date: "date", + other: { + names: { + blockName: "other" + } + } + } + }) + ); + + if(asn1.verified === false) + throw new Error("Object's schema was not verified against input data for RecipientKeyIdentifier"); + //endregion + + //region Get internal properties from parsed schema + this.subjectKeyIdentifier = asn1.result.subjectKeyIdentifier; + + if("date" in asn1.result) + this.date = asn1.result.date; + + if("other" in asn1.result) + this.other = new OtherKeyAttribute({ schema: asn1.result.other }); + //endregion + } + //********************************************************************************** + /** + * Convert current object to asn1js object and set correct values + * @returns {Object} asn1js object + */ + toSchema() + { + //region Create array for output sequence + const outputArray = []; + + outputArray.push(this.subjectKeyIdentifier); + + if("date" in this) + outputArray.push(this.date); + + if("other" in this) + outputArray.push(this.other.toSchema()); + //endregion + + //region Construct and return new ASN.1 schema for this object + return (new asn1js.Sequence({ + value: outputArray + })); + //endregion + } + //********************************************************************************** + /** + * Convertion for the class to JSON object + * @returns {Object} + */ + toJSON() + { + const _object = { + subjectKeyIdentifier: this.subjectKeyIdentifier.toJSON() + }; + + if("date" in this) + _object.date = this.date; + + if("other" in this) + _object.other = this.other.toJSON(); + + return _object; + } + //********************************************************************************** +} +//************************************************************************************** diff --git a/core/third-party/pkijs/RelativeDistinguishedNames.js b/core/third-party/pkijs/RelativeDistinguishedNames.js new file mode 100644 index 0000000..86b1b61 --- /dev/null +++ b/core/third-party/pkijs/RelativeDistinguishedNames.js @@ -0,0 +1,217 @@ +import * as asn1js from "./asn1.js"; +import { getParametersValue, isEqualBuffer, clearProps } from "./pvutils.js"; +import AttributeTypeAndValue from "./AttributeTypeAndValue.js"; +//************************************************************************************** +/** + * Class from RFC5280 + */ +export default class RelativeDistinguishedNames +{ + //********************************************************************************** + /** + * Constructor for RelativeDistinguishedNames class + * @param {Object} [parameters={}] + * @param {Object} [parameters.schema] asn1js parsed value to initialize the class from + * @property {Array.} [typesAndValues] Array of "type and value" objects + * @property {ArrayBuffer} [valueBeforeDecode] Value of the RDN before decoding from schema + */ + constructor(parameters = {}) + { + //region Internal properties of the object + /** + * @type {Array.} + * @desc Array of "type and value" objects + */ + this.typesAndValues = getParametersValue(parameters, "typesAndValues", RelativeDistinguishedNames.defaultValues("typesAndValues")); + /** + * @type {ArrayBuffer} + * @desc Value of the RDN before decoding from schema + */ + this.valueBeforeDecode = getParametersValue(parameters, "valueBeforeDecode", RelativeDistinguishedNames.defaultValues("valueBeforeDecode")); + //endregion + + //region If input argument array contains "schema" for this object + if("schema" in parameters) + this.fromSchema(parameters.schema); + //endregion + } + //********************************************************************************** + /** + * Return default values for all class members + * @param {string} memberName String name for a class member + */ + static defaultValues(memberName) + { + switch(memberName) + { + case "typesAndValues": + return []; + case "valueBeforeDecode": + return new ArrayBuffer(0); + default: + throw new Error(`Invalid member name for RelativeDistinguishedNames class: ${memberName}`); + } + } + //********************************************************************************** + /** + * Compare values with default values for all class members + * @param {string} memberName String name for a class member + * @param {*} memberValue Value to compare with default value + */ + static compareWithDefault(memberName, memberValue) + { + switch(memberName) + { + case "typesAndValues": + return (memberValue.length === 0); + case "valueBeforeDecode": + return (memberValue.byteLength === 0); + default: + throw new Error(`Invalid member name for RelativeDistinguishedNames class: ${memberName}`); + } + } + //********************************************************************************** + /** + * Return value of pre-defined ASN.1 schema for current class + * + * ASN.1 schema: + * ```asn1 + * RDNSequence ::= Sequence OF RelativeDistinguishedName + * + * RelativeDistinguishedName ::= + * SET SIZE (1..MAX) OF AttributeTypeAndValue + * ``` + * + * @param {Object} parameters Input parameters for the schema + * @returns {Object} asn1js schema object + */ + static schema(parameters = {}) + { + /** + * @type {Object} + * @property {string} [blockName] Name for entire block + * @property {string} [repeatedSequence] Name for "repeatedSequence" block + * @property {string} [repeatedSet] Name for "repeatedSet" block + * @property {string} [typeAndValue] Name for "typeAndValue" block + */ + const names = getParametersValue(parameters, "names", {}); + + return (new asn1js.Sequence({ + name: (names.blockName || ""), + value: [ + new asn1js.Repeated({ + name: (names.repeatedSequence || ""), + value: new asn1js.Set({ + value: [ + new asn1js.Repeated({ + name: (names.repeatedSet || ""), + value: AttributeTypeAndValue.schema(names.typeAndValue || {}) + }) + ] + }) + }) + ] + })); + } + //********************************************************************************** + /** + * Convert parsed asn1js object into current class + * @param {!Object} schema + */ + fromSchema(schema) + { + //region Clear input data first + clearProps(schema, [ + "RDN", + "typesAndValues" + ]); + //endregion + + //region Check the schema is valid + const asn1 = asn1js.compareSchema(schema, + schema, + RelativeDistinguishedNames.schema({ + names: { + blockName: "RDN", + repeatedSet: "typesAndValues" + } + }) + ); + + if(asn1.verified === false) + throw new Error("Object's schema was not verified against input data for RelativeDistinguishedNames"); + //endregion + + //region Get internal properties from parsed schema + if("typesAndValues" in asn1.result) // Could be a case when there is no "types and values" + this.typesAndValues = Array.from(asn1.result.typesAndValues, element => new AttributeTypeAndValue({ schema: element })); + + // noinspection JSUnresolvedVariable + this.valueBeforeDecode = asn1.result.RDN.valueBeforeDecode; + //endregion + } + //********************************************************************************** + /** + * Convert current object to asn1js object and set correct values + * @returns {Object} asn1js object + */ + toSchema() + { + //region Decode stored TBS value + if(this.valueBeforeDecode.byteLength === 0) // No stored encoded array, create "from scratch" + { + return (new asn1js.Sequence({ + value: [new asn1js.Set({ + value: Array.from(this.typesAndValues, element => element.toSchema()) + })] + })); + } + + const asn1 = asn1js.fromBER(this.valueBeforeDecode); + //endregion + + //region Construct and return new ASN.1 schema for this object + return asn1.result; + //endregion + } + //********************************************************************************** + /** + * Convertion for the class to JSON object + * @returns {Object} + */ + toJSON() + { + return { + typesAndValues: Array.from(this.typesAndValues, element => element.toJSON()) + }; + } + //********************************************************************************** + /** + * Compare two RDN values, or RDN with ArrayBuffer value + * @param {(RelativeDistinguishedNames|ArrayBuffer)} compareTo The value compare to current + * @returns {boolean} + */ + isEqual(compareTo) + { + if(compareTo instanceof RelativeDistinguishedNames) + { + if(this.typesAndValues.length !== compareTo.typesAndValues.length) + return false; + + for(const [index, typeAndValue] of this.typesAndValues.entries()) + { + if(typeAndValue.isEqual(compareTo.typesAndValues[index]) === false) + return false; + } + + return true; + } + + if(compareTo instanceof ArrayBuffer) + return isEqualBuffer(this.valueBeforeDecode, compareTo); + + return false; + } + //********************************************************************************** +} +//************************************************************************************** diff --git a/core/third-party/pkijs/Request.js b/core/third-party/pkijs/Request.js new file mode 100644 index 0000000..de7636b --- /dev/null +++ b/core/third-party/pkijs/Request.js @@ -0,0 +1,215 @@ +import * as asn1js from "./asn1.js"; +import { getParametersValue, clearProps } from "./pvutils.js"; +import CertID from "./CertID.js"; +import Extension from "./Extension.js"; +//************************************************************************************** +/** + * Class from RFC6960 + */ +export default class Request +{ + //********************************************************************************** + /** + * Constructor for Request class + * @param {Object} [parameters={}] + * @param {Object} [parameters.schema] asn1js parsed value to initialize the class from + */ + constructor(parameters = {}) + { + //region Internal properties of the object + /** + * @type {CertID} + * @desc reqCert + */ + this.reqCert = getParametersValue(parameters, "reqCert", Request.defaultValues("reqCert")); + + if("singleRequestExtensions" in parameters) + /** + * @type {Array.} + * @desc singleRequestExtensions + */ + this.singleRequestExtensions = getParametersValue(parameters, "singleRequestExtensions", Request.defaultValues("singleRequestExtensions")); + //endregion + + //region If input argument array contains "schema" for this object + if("schema" in parameters) + this.fromSchema(parameters.schema); + //endregion + } + //********************************************************************************** + /** + * Return default values for all class members + * @param {string} memberName String name for a class member + */ + static defaultValues(memberName) + { + switch(memberName) + { + case "reqCert": + return new CertID(); + case "singleRequestExtensions": + return []; + default: + throw new Error(`Invalid member name for Request class: ${memberName}`); + } + } + //********************************************************************************** + /** + * Compare values with default values for all class members + * @param {string} memberName String name for a class member + * @param {*} memberValue Value to compare with default value + */ + static compareWithDefault(memberName, memberValue) + { + switch(memberName) + { + case "reqCert": + return (memberValue.isEqual(Request.defaultValues(memberName))); + case "singleRequestExtensions": + return (memberValue.length === 0); + default: + throw new Error(`Invalid member name for Request class: ${memberName}`); + } + } + //********************************************************************************** + /** + * Return value of pre-defined ASN.1 schema for current class + * + * ASN.1 schema: + * ```asn1 + * Request ::= SEQUENCE { + * reqCert CertID, + * singleRequestExtensions [0] EXPLICIT Extensions OPTIONAL } + * ``` + * + * @param {Object} parameters Input parameters for the schema + * @returns {Object} asn1js schema object + */ + static schema(parameters = {}) + { + /** + * @type {Object} + * @property {string} [blockName] + * @property {string} [reqCert] + * @property {string} [extensions] + * @property {string} [singleRequestExtensions] + */ + const names = getParametersValue(parameters, "names", {}); + + return (new asn1js.Sequence({ + name: (names.blockName || ""), + value: [ + CertID.schema(names.reqCert || {}), + new asn1js.Constructed({ + optional: true, + idBlock: { + tagClass: 3, // CONTEXT-SPECIFIC + tagNumber: 0 // [0] + }, + value: [Extension.schema(names.extensions || { + names: { + blockName: (names.singleRequestExtensions || "") + } + })] + }) + ] + })); + } + //********************************************************************************** + /** + * Convert parsed asn1js object into current class + * @param {!Object} schema + */ + fromSchema(schema) + { + //region Clear input data first + clearProps(schema, [ + "reqCert", + "singleRequestExtensions" + ]); + //endregion + + //region Check the schema is valid + const asn1 = asn1js.compareSchema(schema, + schema, + Request.schema({ + names: { + reqCert: { + names: { + blockName: "reqCert" + } + }, + singleRequestExtensions: { + names: { + blockName: "singleRequestExtensions" + } + } + } + }) + ); + + if(asn1.verified === false) + throw new Error("Object's schema was not verified against input data for Request"); + //endregion + + //region Get internal properties from parsed schema + this.reqCert = new CertID({ schema: asn1.result.reqCert }); + + if("singleRequestExtensions" in asn1.result) + this.singleRequestExtensions = Array.from(asn1.result.singleRequestExtensions.valueBlock.value, element => new Extension({ schema: element })); + //endregion + } + //********************************************************************************** + /** + * Convert current object to asn1js object and set correct values + * @returns {Object} asn1js object + */ + toSchema() + { + //region Create array for output sequence + const outputArray = []; + + outputArray.push(this.reqCert.toSchema()); + + if("singleRequestExtensions" in this) + { + outputArray.push(new asn1js.Constructed({ + optional: true, + idBlock: { + tagClass: 3, // CONTEXT-SPECIFIC + tagNumber: 0 // [0] + }, + value: [ + new asn1js.Sequence({ + value: Array.from(this.singleRequestExtensions, element => element.toSchema()) + }) + ] + })); + } + //endregion + + //region Construct and return new ASN.1 schema for this object + return (new asn1js.Sequence({ + value: outputArray + })); + //endregion + } + //********************************************************************************** + /** + * Convertion for the class to JSON object + * @returns {Object} + */ + toJSON() + { + const _object = { + reqCert: this.reqCert.toJSON() + }; + + if("singleRequestExtensions" in this) + _object.singleRequestExtensions = Array.from(this.singleRequestExtensions, element => element.toJSON()); + + return _object; + } + //********************************************************************************** +} +//************************************************************************************** diff --git a/core/third-party/pkijs/ResponseBytes.js b/core/third-party/pkijs/ResponseBytes.js new file mode 100644 index 0000000..cfdb754 --- /dev/null +++ b/core/third-party/pkijs/ResponseBytes.js @@ -0,0 +1,166 @@ +import * as asn1js from "./asn1.js"; +import { getParametersValue, clearProps } from "./pvutils.js"; +//************************************************************************************** +/** + * Class from RFC6960 + */ +export default class ResponseBytes +{ + //********************************************************************************** + /** + * Constructor for ResponseBytes class + * @param {Object} [parameters={}] + * @param {Object} [parameters.schema] asn1js parsed value to initialize the class from + */ + constructor(parameters = {}) + { + //region Internal properties of the object + /** + * @type {string} + * @desc responseType + */ + this.responseType = getParametersValue(parameters, "responseType", ResponseBytes.defaultValues("responseType")); + /** + * @type {OctetString} + * @desc response + */ + this.response = getParametersValue(parameters, "response", ResponseBytes.defaultValues("response")); + //endregion + + //region If input argument array contains "schema" for this object + if("schema" in parameters) + this.fromSchema(parameters.schema); + //endregion + } + //********************************************************************************** + /** + * Return default values for all class members + * @param {string} memberName String name for a class member + */ + static defaultValues(memberName) + { + switch(memberName) + { + case "responseType": + return ""; + case "response": + return new asn1js.OctetString(); + default: + throw new Error(`Invalid member name for ResponseBytes class: ${memberName}`); + } + } + //********************************************************************************** + /** + * Compare values with default values for all class members + * @param {string} memberName String name for a class member + * @param {*} memberValue Value to compare with default value + */ + static compareWithDefault(memberName, memberValue) + { + switch(memberName) + { + case "responseType": + return (memberValue === ""); + case "response": + return (memberValue.isEqual(ResponseBytes.defaultValues(memberName))); + default: + throw new Error(`Invalid member name for ResponseBytes class: ${memberName}`); + } + } + //********************************************************************************** + /** + * Return value of pre-defined ASN.1 schema for current class + * + * ASN.1 schema: + * ```asn1 + * ResponseBytes ::= SEQUENCE { + * responseType OBJECT IDENTIFIER, + * response OCTET STRING } + * ``` + * + * @param {Object} parameters Input parameters for the schema + * @returns {Object} asn1js schema object + */ + static schema(parameters = {}) + { + /** + * @type {Object} + * @property {string} [blockName] + * @property {string} [responseType] + * @property {string} [response] + */ + const names = getParametersValue(parameters, "names", {}); + + return (new asn1js.Sequence({ + name: (names.blockName || ""), + value: [ + new asn1js.ObjectIdentifier({ name: (names.responseType || "") }), + new asn1js.OctetString({ name: (names.response || "") }) + ] + })); + } + //********************************************************************************** + /** + * Convert parsed asn1js object into current class + * @param {!Object} schema + */ + fromSchema(schema) + { + //region Clear input data first + clearProps(schema, [ + "responseType", + "response" + ]); + //endregion + + //region Check the schema is valid + const asn1 = asn1js.compareSchema(schema, + schema, + ResponseBytes.schema({ + names: { + responseType: "responseType", + response: "response" + } + }) + ); + + if(asn1.verified === false) + throw new Error("Object's schema was not verified against input data for ResponseBytes"); + //endregion + + //region Get internal properties from parsed schema + this.responseType = asn1.result.responseType.valueBlock.toString(); + this.response = asn1.result.response; + //endregion + } + //********************************************************************************** + /** + * Convert current object to asn1js object and set correct values + * @returns {Object} asn1js object + */ + toSchema() + { + //region Construct and return new ASN.1 schema for this object + return (new asn1js.Sequence({ + value: [ + new asn1js.ObjectIdentifier({ value: this.responseType }), + this.response + ] + })); + //endregion + } + //********************************************************************************** + /** + * Convertion for the class to JSON object + * @returns {Object} + */ + toJSON() + { + return { + responseType: this.responseType, + response: this.response.toJSON() + }; + } + //********************************************************************************** +} +//************************************************************************************** diff --git a/core/third-party/pkijs/ResponseData.js b/core/third-party/pkijs/ResponseData.js new file mode 100644 index 0000000..c4c79ae --- /dev/null +++ b/core/third-party/pkijs/ResponseData.js @@ -0,0 +1,350 @@ +import * as asn1js from "./asn1.js"; +import { getParametersValue, clearProps } from "./pvutils.js"; +import RelativeDistinguishedNames from "./RelativeDistinguishedNames.js"; +import SingleResponse from "./SingleResponse.js"; +import Extension from "./Extension.js"; +import Extensions from "./Extensions.js"; +//************************************************************************************** +/** + * Class from RFC6960 + */ +export default class ResponseData +{ + //********************************************************************************** + /** + * Constructor for ResponseData class + * @param {Object} [parameters={}] + * @param {Object} [parameters.schema] asn1js parsed value to initialize the class from + */ + constructor(parameters = {}) + { + //region Internal properties of the object + /** + * @type {ArrayBuffer} + * @desc tbs + */ + this.tbs = getParametersValue(parameters, "tbs", ResponseData.defaultValues("tbs")); + /** + * @type {Object} + * @desc responderID + */ + this.responderID = getParametersValue(parameters, "responderID", ResponseData.defaultValues("responderID")); + /** + * @type {Date} + * @desc producedAt + */ + this.producedAt = getParametersValue(parameters, "producedAt", ResponseData.defaultValues("producedAt")); + /** + * @type {Array.} + * @desc responses + */ + this.responses = getParametersValue(parameters, "responses", ResponseData.defaultValues("responses")); + + if("responseExtensions" in parameters) + /** + * @type {Array.} + * @desc responseExtensions + */ + this.responseExtensions = getParametersValue(parameters, "responseExtensions", ResponseData.defaultValues("responseExtensions")); + //endregion + + //region If input argument array contains "schema" for this object + if("schema" in parameters) + this.fromSchema(parameters.schema); + //endregion + } + //********************************************************************************** + /** + * Return default values for all class members + * @param {string} memberName String name for a class member + */ + static defaultValues(memberName) + { + switch(memberName) + { + case "tbs": + return new ArrayBuffer(0); + case "responderID": + return {}; + case "producedAt": + return new Date(0, 0, 0); + case "responses": + case "responseExtensions": + return []; + default: + throw new Error(`Invalid member name for ResponseData class: ${memberName}`); + } + } + //********************************************************************************** + /** + * Compare values with default values for all class members + * @param {string} memberName String name for a class member + * @param {*} memberValue Value to compare with default value + */ + static compareWithDefault(memberName, memberValue) + { + switch(memberName) + { + case "tbs": + return (memberValue.byteLength === 0); + case "responderID": + return (Object.keys(memberValue).length === 0); + case "producedAt": + return (memberValue === ResponseData.defaultValues(memberName)); + case "responses": + case "responseExtensions": + return (memberValue.length === 0); + default: + throw new Error(`Invalid member name for ResponseData class: ${memberName}`); + } + } + //********************************************************************************** + /** + * Return value of pre-defined ASN.1 schema for current class + * + * ASN.1 schema: + * ```asn1 + * ResponseData ::= SEQUENCE { + * version [0] EXPLICIT Version DEFAULT v1, + * responderID ResponderID, + * producedAt GeneralizedTime, + * responses SEQUENCE OF SingleResponse, + * responseExtensions [1] EXPLICIT Extensions OPTIONAL } + * ``` + * + * @param {Object} parameters Input parameters for the schema + * @returns {Object} asn1js schema object + */ + static schema(parameters = {}) + { + /** + * @type {Object} + * @property {string} [blockName] + * @property {string} [version] + * @property {string} [ResponseDataByName] + * @property {string} [ResponseDataByKey] + * @property {string} [producedAt] + * @property {string} [response] + * @property {string} [extensions] + */ + const names = getParametersValue(parameters, "names", {}); + + return (new asn1js.Sequence({ + name: (names.blockName || "ResponseData"), + value: [ + new asn1js.Constructed({ + optional: true, + idBlock: { + tagClass: 3, // CONTEXT-SPECIFIC + tagNumber: 0 // [0] + }, + value: [new asn1js.Integer({ name: (names.version || "ResponseData.version") })] + }), + new asn1js.Choice({ + value: [ + new asn1js.Constructed({ + name: (names.responderID || "ResponseData.responderID"), + idBlock: { + tagClass: 3, // CONTEXT-SPECIFIC + tagNumber: 1 // [1] + }, + value: [RelativeDistinguishedNames.schema(names.ResponseDataByName || { + names: { + blockName: "ResponseData.byName" + } + })] + }), + new asn1js.Constructed({ + name: (names.responderID || "ResponseData.responderID"), + idBlock: { + tagClass: 3, // CONTEXT-SPECIFIC + tagNumber: 2 // [2] + }, + value: [new asn1js.OctetString({ name: (names.ResponseDataByKey || "ResponseData.byKey") })] + }) + ] + }), + new asn1js.GeneralizedTime({ name: (names.producedAt || "ResponseData.producedAt") }), + new asn1js.Sequence({ + value: [ + new asn1js.Repeated({ + name: "ResponseData.responses", + value: SingleResponse.schema(names.response || {}) + }) + ] + }), + new asn1js.Constructed({ + optional: true, + idBlock: { + tagClass: 3, // CONTEXT-SPECIFIC + tagNumber: 1 // [1] + }, + value: [Extensions.schema(names.extensions || { + names: { + blockName: "ResponseData.responseExtensions" + } + })] + }) // EXPLICIT SEQUENCE value + ] + })); + } + //********************************************************************************** + /** + * Convert parsed asn1js object into current class + * @param {!Object} schema + */ + fromSchema(schema) + { + //region Clear input data first + clearProps(schema, [ + "ResponseData", + "ResponseData.version", + "ResponseData.responderID", + "ResponseData.producedAt", + "ResponseData.responses", + "ResponseData.responseExtensions" + ]); + //endregion + + //region Check the schema is valid + const asn1 = asn1js.compareSchema(schema, + schema, + ResponseData.schema() + ); + + if(asn1.verified === false) + throw new Error("Object's schema was not verified against input data for ResponseData"); + //endregion + + //region Get internal properties from parsed schema + this.tbs = asn1.result.ResponseData.valueBeforeDecode; + + if("ResponseData.version" in asn1.result) + this.version = asn1.result["ResponseData.version"].valueBlock.valueDec; + + if(asn1.result["ResponseData.responderID"].idBlock.tagNumber === 1) + this.responderID = new RelativeDistinguishedNames({ schema: asn1.result["ResponseData.responderID"].valueBlock.value[0] }); + else + this.responderID = asn1.result["ResponseData.responderID"].valueBlock.value[0]; // OCTETSTRING + + this.producedAt = asn1.result["ResponseData.producedAt"].toDate(); + this.responses = Array.from(asn1.result["ResponseData.responses"], element => new SingleResponse({ schema: element })); + + if("ResponseData.responseExtensions" in asn1.result) + this.responseExtensions = Array.from(asn1.result["ResponseData.responseExtensions"].valueBlock.value, element => new Extension({ schema: element })); + //endregion + } + //********************************************************************************** + /** + * Convert current object to asn1js object and set correct values + * @param {boolean} encodeFlag If param equal to false then create TBS schema via decoding stored value. In othe case create TBS schema via assembling from TBS parts. + * @returns {Object} asn1js object + */ + toSchema(encodeFlag = false) + { + //region Decode stored TBS value + let tbsSchema; + + if(encodeFlag === false) + { + if(this.tbs.length === 0) // No stored certificate TBS part + return ResponseData.schema(); + + tbsSchema = asn1js.fromBER(this.tbs).result; + } + //endregion + //region Create TBS schema via assembling from TBS parts + else + { + const outputArray = []; + + if("version" in this) + { + outputArray.push(new asn1js.Constructed({ + idBlock: { + tagClass: 3, // CONTEXT-SPECIFIC + tagNumber: 0 // [0] + }, + value: [new asn1js.Integer({ value: this.version })] + })); + } + + if(this.responderID instanceof RelativeDistinguishedNames) + { + outputArray.push(new asn1js.Constructed({ + idBlock: { + tagClass: 3, // CONTEXT-SPECIFIC + tagNumber: 1 // [1] + }, + value: [this.responderID.toSchema()] + })); + } + else + { + outputArray.push(new asn1js.Constructed({ + idBlock: { + tagClass: 3, // CONTEXT-SPECIFIC + tagNumber: 2 // [2] + }, + value: [this.responderID] + })); + } + + outputArray.push(new asn1js.GeneralizedTime({ valueDate: this.producedAt })); + + outputArray.push(new asn1js.Sequence({ + value: Array.from(this.responses, element => element.toSchema()) + })); + + if("responseExtensions" in this) + { + outputArray.push(new asn1js.Constructed({ + idBlock: { + tagClass: 3, // CONTEXT-SPECIFIC + tagNumber: 1 // [1] + }, + value: [new asn1js.Sequence({ + value: Array.from(this.responseExtensions, element => element.toSchema()) + })] + })); + } + + tbsSchema = new asn1js.Sequence({ + value: outputArray + }); + } + //endregion + + //region Construct and return new ASN.1 schema for this object + return tbsSchema; + //endregion + } + //********************************************************************************** + /** + * Convertion for the class to JSON object + * @returns {Object} + */ + toJSON() + { + const _object = {}; + + if("version" in this) + _object.version = this.version; + + if("responderID" in this) + _object.responderID = this.responderID; + + if("producedAt" in this) + _object.producedAt = this.producedAt; + + if("responses" in this) + _object.responses = Array.from(this.responses, element => element.toJSON()); + + if("responseExtensions" in this) + _object.responseExtensions = Array.from(this.responseExtensions, element => element.toJSON()); + + return _object; + } + //********************************************************************************** +} +//************************************************************************************** diff --git a/core/third-party/pkijs/RevocationInfoChoices.js b/core/third-party/pkijs/RevocationInfoChoices.js new file mode 100644 index 0000000..ad55c5d --- /dev/null +++ b/core/third-party/pkijs/RevocationInfoChoices.js @@ -0,0 +1,184 @@ +import * as asn1js from "./asn1.js"; +import { getParametersValue, clearProps } from "./pvutils.js"; +import CertificateRevocationList from "./CertificateRevocationList.js"; +import OtherRevocationInfoFormat from "./OtherRevocationInfoFormat.js"; +//************************************************************************************** +/** + * Class from RFC5652 + */ +export default class RevocationInfoChoices +{ + //********************************************************************************** + /** + * Constructor for RevocationInfoChoices class + * @param {Object} [parameters={}] + * @param {Object} [parameters.schema] asn1js parsed value to initialize the class from + */ + constructor(parameters = {}) + { + //region Internal properties of the object + /** + * @type {Array.} + * @desc crls + */ + this.crls = getParametersValue(parameters, "crls", RevocationInfoChoices.defaultValues("crls")); + /** + * @type {Array.} + * @desc otherRevocationInfos + */ + this.otherRevocationInfos = getParametersValue(parameters, "otherRevocationInfos", RevocationInfoChoices.defaultValues("otherRevocationInfos")); + //endregion + + //region If input argument array contains "schema" for this object + if("schema" in parameters) + this.fromSchema(parameters.schema); + //endregion + } + //********************************************************************************** + /** + * Return default values for all class members + * @param {string} memberName String name for a class member + */ + static defaultValues(memberName) + { + switch(memberName) + { + case "crls": + return []; + case "otherRevocationInfos": + return []; + default: + throw new Error(`Invalid member name for RevocationInfoChoices class: ${memberName}`); + } + } + //********************************************************************************** + /** + * Return value of pre-defined ASN.1 schema for current class + * + * ASN.1 schema: + * ```asn1 + * RevocationInfoChoices ::= SET OF RevocationInfoChoice + * + * RevocationInfoChoice ::= CHOICE { + * crl CertificateList, + * other [1] IMPLICIT OtherRevocationInfoFormat } + * ``` + * + * @param {Object} parameters Input parameters for the schema + * @returns {Object} asn1js schema object + */ + static schema(parameters = {}) + { + /** + * @type {Object} + * @property {string} [blockName] + * @property {string} [crls] + */ + const names = getParametersValue(parameters, "names", {}); + + return (new asn1js.Set({ + name: (names.blockName || ""), + value: [ + new asn1js.Repeated({ + name: (names.crls || ""), + value: new asn1js.Choice({ + value: [ + CertificateRevocationList.schema(), + new asn1js.Constructed({ + idBlock: { + tagClass: 3, // CONTEXT-SPECIFIC + tagNumber: 1 // [1] + }, + value: [ + new asn1js.ObjectIdentifier(), + new asn1js.Any() + ] + }) + ] + }) + }) + ] + })); + } + //********************************************************************************** + /** + * Convert parsed asn1js object into current class + * @param {!Object} schema + */ + fromSchema(schema) + { + //region Clear input data first + clearProps(schema, [ + "crls" + ]); + //endregion + + //region Check the schema is valid + const asn1 = asn1js.compareSchema(schema, + schema, + RevocationInfoChoices.schema({ + names: { + crls: "crls" + } + }) + ); + + if(asn1.verified === false) + throw new Error("Object's schema was not verified against input data for RevocationInfoChoices"); + //endregion + + //region Get internal properties from parsed schema + for(const element of asn1.result.crls) + { + if(element.idBlock.tagClass === 1) + this.crls.push(new CertificateRevocationList({ schema: element })); + else + this.otherRevocationInfos.push(new OtherRevocationInfoFormat({ schema: element })); + } + + //endregion + } + //********************************************************************************** + /** + * Convert current object to asn1js object and set correct values + * @returns {Object} asn1js object + */ + toSchema() + { + //region Create array for output set + const outputArray = []; + + outputArray.push(...Array.from(this.crls, element => element.toSchema())); + + outputArray.push(...Array.from(this.otherRevocationInfos, element => + { + const schema = element.toSchema(); + + schema.idBlock.tagClass = 3; + schema.idBlock.tagNumber = 1; + + return schema; + })); + //endregion + + //region Construct and return new ASN.1 schema for this object + return (new asn1js.Set({ + value: outputArray + })); + //endregion + } + //********************************************************************************** + /** + * Convertion for the class to JSON object + * @returns {Object} + */ + toJSON() + { + return { + crls: Array.from(this.crls, element => element.toJSON()), + otherRevocationInfos: Array.from(this.otherRevocationInfos, element => element.toJSON()) + }; + } + //********************************************************************************** +} +//************************************************************************************** diff --git a/core/third-party/pkijs/RevokedCertificate.js b/core/third-party/pkijs/RevokedCertificate.js new file mode 100644 index 0000000..80d6a9f --- /dev/null +++ b/core/third-party/pkijs/RevokedCertificate.js @@ -0,0 +1,184 @@ +import * as asn1js from "./asn1.js"; +import { getParametersValue, clearProps } from "./pvutils.js"; +import Time from "./Time.js"; +import Extensions from "./Extensions.js"; +//************************************************************************************** +/** + * Class from RFC5280 + */ +export default class RevokedCertificate +{ + //********************************************************************************** + /** + * Constructor for RevokedCertificate class + * @param {Object} [parameters={}] + * @param {Object} [parameters.schema] asn1js parsed value to initialize the class from + */ + constructor(parameters = {}) + { + //region Internal properties of the object + /** + * @type {Integer} + * @desc userCertificate + */ + this.userCertificate = getParametersValue(parameters, "userCertificate", RevokedCertificate.defaultValues("userCertificate")); + /** + * @type {Time} + * @desc revocationDate + */ + this.revocationDate = getParametersValue(parameters, "revocationDate", RevokedCertificate.defaultValues("revocationDate")); + + if("crlEntryExtensions" in parameters) + /** + * @type {Extensions} + * @desc crlEntryExtensions + */ + this.crlEntryExtensions = getParametersValue(parameters, "crlEntryExtensions", RevokedCertificate.defaultValues("crlEntryExtensions")); + //endregion + + //region If input argument array contains "schema" for this object + if("schema" in parameters) + this.fromSchema(parameters.schema); + //endregion + } + //********************************************************************************** + /** + * Return default values for all class members + * @param {string} memberName String name for a class member + */ + static defaultValues(memberName) + { + switch(memberName) + { + case "userCertificate": + return new asn1js.Integer(); + case "revocationDate": + return new Time(); + case "crlEntryExtensions": + return new Extensions(); + default: + throw new Error(`Invalid member name for RevokedCertificate class: ${memberName}`); + } + } + //********************************************************************************** + /** + * Return value of pre-defined ASN.1 schema for current class + * + * ASN.1 schema: + * ```asn1 + * revokedCertificates SEQUENCE OF SEQUENCE { + * userCertificate CertificateSerialNumber, + * revocationDate Time, + * crlEntryExtensions Extensions OPTIONAL + * -- if present, version MUST be v2 + * } OPTIONAL, + * ``` + * + * @param {Object} parameters Input parameters for the schema + * @returns {Object} asn1js schema object + */ + static schema(parameters = {}) + { + /** + * @type {Object} + * @property {string} [blockName] + * @property {string} [userCertificate] + * @property {string} [revocationDate] + * @property {string} [crlEntryExtensions] + */ + const names = getParametersValue(parameters, "names", {}); + + return new asn1js.Sequence({ + name: (names.blockName || ""), + value: [ + new asn1js.Integer({ name: (names.userCertificate || "userCertificate") }), + Time.schema({ + names: { + utcTimeName: (names.revocationDate || "revocationDate"), + generalTimeName: (names.revocationDate || "revocationDate") + } + }), + Extensions.schema({ + names: { + blockName: (names.crlEntryExtensions || "crlEntryExtensions") + } + }, true) + ] + }); + } + //********************************************************************************** + /** + * Convert parsed asn1js object into current class + * @param {!Object} schema + */ + fromSchema(schema) + { + //region Clear input data first + clearProps(schema, [ + "userCertificate", + "revocationDate", + "crlEntryExtensions" + ]); + //endregion + + //region Check the schema is valid + const asn1 = asn1js.compareSchema(schema, + schema, + RevokedCertificate.schema() + ); + + if(asn1.verified === false) + throw new Error("Object's schema was not verified against input data for RevokedCertificate"); + //endregion + + //region Get internal properties from parsed schema + this.userCertificate = asn1.result.userCertificate; + this.revocationDate = new Time({ schema: asn1.result.revocationDate }); + + if("crlEntryExtensions" in asn1.result) + this.crlEntryExtensions = new Extensions({ schema: asn1.result.crlEntryExtensions }); + //endregion + } + //********************************************************************************** + /** + * Convert current object to asn1js object and set correct values + * @returns {Object} asn1js object + */ + toSchema() + { + //region Create array for output sequence + const outputArray = [ + this.userCertificate, + this.revocationDate.toSchema() + ]; + + if("crlEntryExtensions" in this) + outputArray.push(this.crlEntryExtensions.toSchema()); + //endregion + + //region Construct and return new ASN.1 schema for this object + return (new asn1js.Sequence({ + value: outputArray + })); + //endregion + } + //********************************************************************************** + /** + * Convertion for the class to JSON object + * @returns {Object} + */ + toJSON() + { + const object = { + userCertificate: this.userCertificate.toJSON(), + revocationDate: this.revocationDate.toJSON + }; + + if("crlEntryExtensions" in this) + object.crlEntryExtensions = this.crlEntryExtensions.toJSON(); + + return object; + } + //********************************************************************************** +} +//************************************************************************************** diff --git a/core/third-party/pkijs/SafeBag.js b/core/third-party/pkijs/SafeBag.js new file mode 100644 index 0000000..f2d39d1 --- /dev/null +++ b/core/third-party/pkijs/SafeBag.js @@ -0,0 +1,250 @@ +import * as asn1js from "./asn1.js"; +import { getParametersValue, clearProps } from "./pvutils.js"; +import Attribute from "./Attribute.js"; +import PrivateKeyInfo from "./PrivateKeyInfo.js"; +import PKCS8ShroudedKeyBag from "./PKCS8ShroudedKeyBag.js"; +import CertBag from "./CertBag.js"; +import CRLBag from "./CRLBag.js"; +import SecretBag from "./SecretBag.js"; +import SafeContents from "./SafeContents.js"; +//************************************************************************************** +/** + * Class from RFC7292 + */ +export default class SafeBag +{ + //********************************************************************************** + /** + * Constructor for SafeBag class + * @param {Object} [parameters={}] + * @param {Object} [parameters.schema] asn1js parsed value to initialize the class from + */ + constructor(parameters = {}) + { + //region Internal properties of the object + /** + * @type {string} + * @desc bagId + */ + this.bagId = getParametersValue(parameters, "bagId", SafeBag.defaultValues("bagId")); + /** + * @type {*} + * @desc bagValue + */ + this.bagValue = getParametersValue(parameters, "bagValue", SafeBag.defaultValues("bagValue")); + + if("bagAttributes" in parameters) + /** + * @type {Array.} + * @desc bagAttributes + */ + this.bagAttributes = getParametersValue(parameters, "bagAttributes", SafeBag.defaultValues("bagAttributes")); + //endregion + + //region If input argument array contains "schema" for this object + if("schema" in parameters) + this.fromSchema(parameters.schema); + //endregion + } + //********************************************************************************** + /** + * Return default values for all class members + * @param {string} memberName String name for a class member + */ + static defaultValues(memberName) + { + switch(memberName) + { + case "bagId": + return ""; + case "bagValue": + return (new asn1js.Any()); + case "bagAttributes": + return []; + default: + throw new Error(`Invalid member name for SafeBag class: ${memberName}`); + } + } + //********************************************************************************** + /** + * Compare values with default values for all class members + * @param {string} memberName String name for a class member + * @param {*} memberValue Value to compare with default value + */ + static compareWithDefault(memberName, memberValue) + { + switch(memberName) + { + case "bagId": + return (memberValue === ""); + case "bagValue": + return (memberValue instanceof asn1js.Any); + case "bagAttributes": + return (memberValue.length === 0); + default: + throw new Error(`Invalid member name for SafeBag class: ${memberName}`); + } + } + //********************************************************************************** + /** + * Return value of pre-defined ASN.1 schema for current class + * + * ASN.1 schema: + * ```asn1 + * SafeBag ::= SEQUENCE { + * bagId BAG-TYPE.&id ({PKCS12BagSet}), + * bagValue [0] EXPLICIT BAG-TYPE.&Type({PKCS12BagSet}{@bagId}), + * bagAttributes SET OF PKCS12Attribute OPTIONAL + * } + * ``` + * + * @param {Object} parameters Input parameters for the schema + * @returns {Object} asn1js schema object + */ + static schema(parameters = {}) + { + /** + * @type {Object} + * @property {string} [blockName] + * @property {string} [bagId] + * @property {string} [bagValue] + * @property {string} [bagAttributes] + */ + const names = getParametersValue(parameters, "names", {}); + + return (new asn1js.Sequence({ + name: (names.blockName || ""), + value: [ + new asn1js.ObjectIdentifier({ name: (names.bagId || "bagId") }), + new asn1js.Constructed({ + idBlock: { + tagClass: 3, // CONTEXT-SPECIFIC + tagNumber: 0 // [0] + }, + value: [new asn1js.Any({ name: (names.bagValue || "bagValue") })] // EXPLICIT ANY value + }), + new asn1js.Set({ + optional: true, + value: [ + new asn1js.Repeated({ + name: (names.bagAttributes || "bagAttributes"), + value: Attribute.schema() + }) + ] + }) + ] + })); + } + //********************************************************************************** + /** + * Convert parsed asn1js object into current class + * @param {!Object} schema + */ + fromSchema(schema) + { + //region Clear input data first + clearProps(schema, [ + "bagId", + "bagValue", + "bagAttributes" + ]); + //endregion + + //region Check the schema is valid + const asn1 = asn1js.compareSchema(schema, + schema, + SafeBag.schema({ + names: { + bagId: "bagId", + bagValue: "bagValue", + bagAttributes: "bagAttributes" + } + }) + ); + + if(asn1.verified === false) + throw new Error("Object's schema was not verified against input data for SafeBag"); + //endregion + + //region Get internal properties from parsed schema + this.bagId = asn1.result.bagId.valueBlock.toString(); + + switch(this.bagId) + { + case "1.2.840.113549.1.12.10.1.1": // keyBag + this.bagValue = new PrivateKeyInfo({ schema: asn1.result.bagValue }); + break; + case "1.2.840.113549.1.12.10.1.2": // pkcs8ShroudedKeyBag + this.bagValue = new PKCS8ShroudedKeyBag({ schema: asn1.result.bagValue }); + break; + case "1.2.840.113549.1.12.10.1.3": // certBag + this.bagValue = new CertBag({ schema: asn1.result.bagValue }); + break; + case "1.2.840.113549.1.12.10.1.4": // crlBag + this.bagValue = new CRLBag({ schema: asn1.result.bagValue }); + break; + case "1.2.840.113549.1.12.10.1.5": // secretBag + this.bagValue = new SecretBag({ schema: asn1.result.bagValue }); + break; + case "1.2.840.113549.1.12.10.1.6": // safeContentsBag + this.bagValue = new SafeContents({ schema: asn1.result.bagValue }); + break; + default: + throw new Error(`Invalid "bagId" for SafeBag: ${this.bagId}`); + } + + if("bagAttributes" in asn1.result) + this.bagAttributes = Array.from(asn1.result.bagAttributes, element => new Attribute({ schema: element })); + //endregion + } + //********************************************************************************** + /** + * Convert current object to asn1js object and set correct values + * @returns {Object} asn1js object + */ + toSchema() + { + //region Construct and return new ASN.1 schema for this object + const outputArray = [ + new asn1js.ObjectIdentifier({ value: this.bagId }), + new asn1js.Constructed({ + idBlock: { + tagClass: 3, // CONTEXT-SPECIFIC + tagNumber: 0 // [0] + }, + value: [this.bagValue.toSchema()] + }) + ]; + + if("bagAttributes" in this) + { + outputArray.push(new asn1js.Set({ + value: Array.from(this.bagAttributes, element => element.toSchema()) + })); + } + + return (new asn1js.Sequence({ + value: outputArray + })); + //endregion + } + //********************************************************************************** + /** + * Convertion for the class to JSON object + * @returns {Object} + */ + toJSON() + { + const output = { + bagId: this.bagId, + bagValue: this.bagValue.toJSON() + }; + + if("bagAttributes" in this) + output.bagAttributes = Array.from(this.bagAttributes, element => element.toJSON()); + + return output; + } + //********************************************************************************** +} +//************************************************************************************** diff --git a/core/third-party/pkijs/SafeContents.js b/core/third-party/pkijs/SafeContents.js new file mode 100644 index 0000000..e585f76 --- /dev/null +++ b/core/third-party/pkijs/SafeContents.js @@ -0,0 +1,150 @@ +import * as asn1js from "./asn1.js"; +import { getParametersValue, clearProps } from "./pvutils.js"; +import SafeBag from "./SafeBag.js"; +//************************************************************************************** +/** + * Class from RFC7292 + */ +export default class SafeContents +{ + //********************************************************************************** + /** + * Constructor for SafeContents class + * @param {Object} [parameters={}] + * @param {Object} [parameters.schema] asn1js parsed value to initialize the class from + */ + constructor(parameters = {}) + { + //region Internal properties of the object + /** + * @type {Array.} + * @desc safeBags + */ + this.safeBags = getParametersValue(parameters, "safeBags", SafeContents.defaultValues("safeBags")); + //endregion + + //region If input argument array contains "schema" for this object + if("schema" in parameters) + this.fromSchema(parameters.schema); + //endregion + } + //********************************************************************************** + /** + * Return default values for all class members + * @param {string} memberName String name for a class member + */ + static defaultValues(memberName) + { + switch(memberName) + { + case "safeBags": + return []; + default: + throw new Error(`Invalid member name for SafeContents class: ${memberName}`); + } + } + //********************************************************************************** + /** + * Compare values with default values for all class members + * @param {string} memberName String name for a class member + * @param {*} memberValue Value to compare with default value + */ + static compareWithDefault(memberName, memberValue) + { + switch(memberName) + { + case "safeBags": + return (memberValue.length === 0); + default: + throw new Error(`Invalid member name for SafeContents class: ${memberName}`); + } + } + //********************************************************************************** + /** + * Return value of pre-defined ASN.1 schema for current class + * + * ASN.1 schema: + * ```asn1 + * SafeContents ::= SEQUENCE OF SafeBag + * ``` + * + * @param {Object} parameters Input parameters for the schema + * @returns {Object} asn1js schema object + */ + static schema(parameters = {}) + { + /** + * @type {Object} + * @property {string} [blockName] + * @property {string} [safeBags] + */ + const names = getParametersValue(parameters, "names", {}); + + return (new asn1js.Sequence({ + name: (names.blockName || ""), + value: [ + new asn1js.Repeated({ + name: (names.safeBags || ""), + value: SafeBag.schema() + }) + ] + })); + } + //********************************************************************************** + /** + * Convert parsed asn1js object into current class + * @param {!Object} schema + */ + fromSchema(schema) + { + //region Clear input data first + clearProps(schema, [ + "safeBags" + ]); + //endregion + + //region Check the schema is valid + const asn1 = asn1js.compareSchema(schema, + schema, + SafeContents.schema({ + names: { + safeBags: "safeBags" + } + }) + ); + + if(asn1.verified === false) + throw new Error("Object's schema was not verified against input data for SafeContents"); + //endregion + + //region Get internal properties from parsed schema + this.safeBags = Array.from(asn1.result.safeBags, element => new SafeBag({ schema: element })); + //endregion + } + //********************************************************************************** + /** + * Convert current object to asn1js object and set correct values + * @returns {Object} asn1js object + */ + toSchema() + { + //region Construct and return new ASN.1 schema for this object + return (new asn1js.Sequence({ + value: Array.from(this.safeBags, element => element.toSchema()) + })); + //endregion + } + //********************************************************************************** + /** + * Convertion for the class to JSON object + * @returns {Object} + */ + toJSON() + { + return { + safeBags: Array.from(this.safeBags, element => element.toJSON()) + }; + } + //********************************************************************************** +} +//************************************************************************************** diff --git a/core/third-party/pkijs/SecretBag.js b/core/third-party/pkijs/SecretBag.js new file mode 100644 index 0000000..d132755 --- /dev/null +++ b/core/third-party/pkijs/SecretBag.js @@ -0,0 +1,179 @@ +import * as asn1js from "./asn1.js"; +import { getParametersValue, clearProps } from "./pvutils.js"; +//************************************************************************************** +/** + * Class from RFC7292 + */ +export default class SecretBag +{ + //********************************************************************************** + /** + * Constructor for SecretBag class + * @param {Object} [parameters={}] + * @param {Object} [parameters.schema] asn1js parsed value to initialize the class from + */ + constructor(parameters = {}) + { + //region Internal properties of the object + /** + * @type {string} + * @desc secretTypeId + */ + this.secretTypeId = getParametersValue(parameters, "secretTypeId", SecretBag.defaultValues("secretTypeId")); + /** + * @type {*} + * @desc secretValue + */ + this.secretValue = getParametersValue(parameters, "secretValue", SecretBag.defaultValues("secretValue")); + //endregion + + //region If input argument array contains "schema" for this object + if("schema" in parameters) + this.fromSchema(parameters.schema); + //endregion + } + //********************************************************************************** + /** + * Return default values for all class members + * @param {string} memberName String name for a class member + */ + static defaultValues(memberName) + { + switch(memberName) + { + case "secretTypeId": + return ""; + case "secretValue": + return (new asn1js.Any()); + default: + throw new Error(`Invalid member name for SecretBag class: ${memberName}`); + } + } + //********************************************************************************** + /** + * Compare values with default values for all class members + * @param {string} memberName String name for a class member + * @param {*} memberValue Value to compare with default value + */ + static compareWithDefault(memberName, memberValue) + { + switch(memberName) + { + case "secretTypeId": + return (memberValue === ""); + case "secretValue": + return (memberValue instanceof asn1js.Any); + default: + throw new Error(`Invalid member name for SecretBag class: ${memberName}`); + } + } + //********************************************************************************** + /** + * Return value of pre-defined ASN.1 schema for current class + * + * ASN.1 schema: + * ```asn1 + * SecretBag ::= SEQUENCE { + * secretTypeId BAG-TYPE.&id ({SecretTypes}), + * secretValue [0] EXPLICIT BAG-TYPE.&Type ({SecretTypes}{@secretTypeId}) + * } + * ``` + * + * @param {Object} parameters Input parameters for the schema + * @returns {Object} asn1js schema object + */ + static schema(parameters = {}) + { + /** + * @type {Object} + * @property {string} [blockName] + * @property {string} [id] + * @property {string} [value] + */ + const names = getParametersValue(parameters, "names", {}); + + return (new asn1js.Sequence({ + name: (names.blockName || ""), + value: [ + new asn1js.ObjectIdentifier({ name: (names.id || "id") }), + new asn1js.Constructed({ + idBlock: { + tagClass: 3, // CONTEXT-SPECIFIC + tagNumber: 0 // [0] + }, + value: [new asn1js.Any({ name: (names.value || "value") })] // EXPLICIT ANY value + }) + ] + })); + } + //********************************************************************************** + /** + * Convert parsed asn1js object into current class + * @param {!Object} schema + */ + fromSchema(schema) + { + //region Clear input data first + clearProps(schema, [ + "secretTypeId", + "secretValue" + ]); + //endregion + + //region Check the schema is valid + const asn1 = asn1js.compareSchema(schema, + schema, + SecretBag.schema({ + names: { + id: "secretTypeId", + value: "secretValue" + } + }) + ); + + if(asn1.verified === false) + throw new Error("Object's schema was not verified against input data for SecretBag"); + //endregion + + //region Get internal properties from parsed schema + this.secretTypeId = asn1.result.secretTypeId.valueBlock.toString(); + this.secretValue = asn1.result.secretValue; + //endregion + } + //********************************************************************************** + /** + * Convert current object to asn1js object and set correct values + * @returns {Object} asn1js object + */ + toSchema() + { + //region Construct and return new ASN.1 schema for this object + return (new asn1js.Sequence({ + value: [ + new asn1js.ObjectIdentifier({ value: this.secretTypeId }), + new asn1js.Constructed({ + idBlock: { + tagClass: 3, // CONTEXT-SPECIFIC + tagNumber: 0 // [0] + }, + value: [this.secretValue.toSchema()] + }) + ] + })); + //endregion + } + //********************************************************************************** + /** + * Convertion for the class to JSON object + * @returns {Object} + */ + toJSON() + { + return { + secretTypeId: this.secretTypeId, + secretValue: this.secretValue.toJSON() + }; + } + //********************************************************************************** +} +//************************************************************************************** diff --git a/core/third-party/pkijs/Signature.js b/core/third-party/pkijs/Signature.js new file mode 100644 index 0000000..49e0dea --- /dev/null +++ b/core/third-party/pkijs/Signature.js @@ -0,0 +1,230 @@ +import * as asn1js from "./asn1.js"; +import { getParametersValue, clearProps } from "./pvutils.js"; +import AlgorithmIdentifier from "./AlgorithmIdentifier.js"; +import Certificate from "./Certificate.js"; +//************************************************************************************** +/** + * Class from RFC6960 + */ +export default class Signature +{ + //********************************************************************************** + /** + * Constructor for Signature class + * @param {Object} [parameters={}] + * @param {Object} [parameters.schema] asn1js parsed value to initialize the class from + */ + constructor(parameters = {}) + { + //region Internal properties of the object + /** + * @type {AlgorithmIdentifier} + * @desc signatureAlgorithm + */ + this.signatureAlgorithm = getParametersValue(parameters, "signatureAlgorithm", Signature.defaultValues("signatureAlgorithm")); + /** + * @type {BitString} + * @desc signature + */ + this.signature = getParametersValue(parameters, "signature", Signature.defaultValues("signature")); + + if("certs" in parameters) + /** + * @type {Array.} + * @desc certs + */ + this.certs = getParametersValue(parameters, "certs", Signature.defaultValues("certs")); + //endregion + + //region If input argument array contains "schema" for this object + if("schema" in parameters) + this.fromSchema(parameters.schema); + //endregion + } + //********************************************************************************** + /** + * Return default values for all class members + * @param {string} memberName String name for a class member + */ + static defaultValues(memberName) + { + switch(memberName) + { + case "signatureAlgorithm": + return new AlgorithmIdentifier(); + case "signature": + return new asn1js.BitString(); + case "certs": + return []; + default: + throw new Error(`Invalid member name for Signature class: ${memberName}`); + } + } + //********************************************************************************** + /** + * Compare values with default values for all class members + * @param {string} memberName String name for a class member + * @param {*} memberValue Value to compare with default value + */ + static compareWithDefault(memberName, memberValue) + { + switch(memberName) + { + case "signatureAlgorithm": + return ((memberValue.algorithmId === "") && (("algorithmParams" in memberValue) === false)); + case "signature": + return (memberValue.isEqual(Signature.defaultValues(memberName))); + case "certs": + return (memberValue.length === 0); + default: + throw new Error(`Invalid member name for Signature class: ${memberName}`); + } + } + //********************************************************************************** + /** + * Return value of pre-defined ASN.1 schema for current class + * + * ASN.1 schema: + * ```asn1 + * Signature ::= SEQUENCE { + * signatureAlgorithm AlgorithmIdentifier, + * signature BIT STRING, + * certs [0] EXPLICIT SEQUENCE OF Certificate OPTIONAL } + * ``` + * + * @param {Object} parameters Input parameters for the schema + * @returns {Object} asn1js schema object + */ + static schema(parameters = {}) + { + /** + * @type {Object} + * @property {string} [blockName] + * @property {string} [signatureAlgorithm] + * @property {string} [signature] + * @property {string} [certs] + */ + const names = getParametersValue(parameters, "names", {}); + + return (new asn1js.Sequence({ + name: (names.blockName || ""), + value: [ + AlgorithmIdentifier.schema(names.signatureAlgorithm || {}), + new asn1js.BitString({ name: (names.signature || "") }), + new asn1js.Constructed({ + optional: true, + idBlock: { + tagClass: 3, // CONTEXT-SPECIFIC + tagNumber: 0 // [0] + }, + value: [ + new asn1js.Sequence({ + value: [new asn1js.Repeated({ + name: (names.certs || ""), + value: Certificate.schema(names.certs || {}) + })] + }) + ] + }) + ] + })); + } + //********************************************************************************** + /** + * Convert parsed asn1js object into current class + * @param {!Object} schema + */ + fromSchema(schema) + { + //region Clear input data first + clearProps(schema, [ + "signatureAlgorithm", + "signature", + "certs" + ]); + //endregion + + //region Check the schema is valid + const asn1 = asn1js.compareSchema(schema, + schema, + Signature.schema({ + names: { + signatureAlgorithm: { + names: { + blockName: "signatureAlgorithm" + } + }, + signature: "signature", + certs: "certs" + } + }) + ); + + if(asn1.verified === false) + throw new Error("Object's schema was not verified against input data for Signature"); + //endregion + + //region Get internal properties from parsed schema + this.signatureAlgorithm = new AlgorithmIdentifier({ schema: asn1.result.signatureAlgorithm }); + this.signature = asn1.result.signature; + + if("certs" in asn1.result) + this.certs = Array.from(asn1.result.certs, element => new Certificate({ schema: element })); + //endregion + } + //********************************************************************************** + /** + * Convert current object to asn1js object and set correct values + * @returns {Object} asn1js object + */ + toSchema() + { + //region Create array of output sequence + const outputArray = []; + + outputArray.push(this.signatureAlgorithm.toSchema()); + outputArray.push(this.signature); + + if("certs" in this) + { + outputArray.push(new asn1js.Constructed({ + optional: true, + idBlock: { + tagClass: 3, // CONTEXT-SPECIFIC + tagNumber: 0 // [0] + }, + value: [ + new asn1js.Sequence({ + value: Array.from(this.certs, element => element.toSchema()) + }) + ] + })); + } + //endregion + + //region Construct and return new ASN.1 schema for this object + return (new asn1js.Sequence({ + value: outputArray + })); + //endregion + } + //********************************************************************************** + /** + * Convertion for the class to JSON object + * @returns {Object} + */ + toJSON() + { + const _object = { + signatureAlgorithm: this.signatureAlgorithm.toJSON(), + signature: this.signature.toJSON() + }; + + if("certs" in this) + _object.certs = Array.from(this.certs, element => element.toJSON()); + + return _object; + } + //********************************************************************************** +} +//************************************************************************************** diff --git a/core/third-party/pkijs/SignedAndUnsignedAttributes.js b/core/third-party/pkijs/SignedAndUnsignedAttributes.js new file mode 100644 index 0000000..9ee770c --- /dev/null +++ b/core/third-party/pkijs/SignedAndUnsignedAttributes.js @@ -0,0 +1,205 @@ +import * as asn1js from "./asn1.js"; +import { getParametersValue, clearProps } from "./pvutils.js"; +import Attribute from "./Attribute.js"; +//************************************************************************************** +/** + * Class from RFC5652 + */ +export default class SignedAndUnsignedAttributes +{ + //********************************************************************************** + /** + * Constructor for SignedAndUnsignedAttributes class + * @param {Object} [parameters={}] + * @param {Object} [parameters.schema] asn1js parsed value to initialize the class from + */ + constructor(parameters = {}) + { + //region Internal properties of the object + /** + * @type {number} + * @desc type + */ + this.type = getParametersValue(parameters, "type", SignedAndUnsignedAttributes.defaultValues("type")); + /** + * @type {Array} + * @desc attributes + */ + this.attributes = getParametersValue(parameters, "attributes", SignedAndUnsignedAttributes.defaultValues("attributes")); + /** + * @type {ArrayBuffer} + * @desc encodedValue Need to have it in order to successfully process with signature verification + */ + this.encodedValue = getParametersValue(parameters, "encodedValue", SignedAndUnsignedAttributes.defaultValues("encodedValue")); + //endregion + + //region If input argument array contains "schema" for this object + if("schema" in parameters) + this.fromSchema(parameters.schema); + //endregion + } + //********************************************************************************** + /** + * Return default values for all class members + * @param {string} memberName String name for a class member + */ + static defaultValues(memberName) + { + switch(memberName) + { + case "type": + return (-1); + case "attributes": + return []; + case "encodedValue": + return new ArrayBuffer(0); + default: + throw new Error(`Invalid member name for SignedAndUnsignedAttributes class: ${memberName}`); + } + } + //********************************************************************************** + /** + * Compare values with default values for all class members + * @param {string} memberName String name for a class member + * @param {*} memberValue Value to compare with default value + */ + static compareWithDefault(memberName, memberValue) + { + switch(memberName) + { + case "type": + return (memberValue === SignedAndUnsignedAttributes.defaultValues("type")); + case "attributes": + return (memberValue.length === 0); + case "encodedValue": + return (memberValue.byteLength === 0); + default: + throw new Error(`Invalid member name for SignedAndUnsignedAttributes class: ${memberName}`); + } + } + //********************************************************************************** + /** + * Return value of pre-defined ASN.1 schema for current class + * + * ASN.1 schema: + * ```asn1 + * SignedAttributes ::= SET SIZE (1..MAX) OF Attribute + * + * UnsignedAttributes ::= SET SIZE (1..MAX) OF Attribute + * ``` + * + * @param {Object} parameters Input parameters for the schema + * @returns {Object} asn1js schema object + */ + static schema(parameters = {}) + { + /** + * @type {Object} + * @property {string} [blockName] + * @property {number} [tagNumber] + * @property {string} [attributes] + */ + const names = getParametersValue(parameters, "names", {}); + + return (new asn1js.Constructed({ + name: (names.blockName || ""), + optional: true, + idBlock: { + tagClass: 3, // CONTEXT-SPECIFIC + tagNumber: names.tagNumber // "SignedAttributes" = 0, "UnsignedAttributes" = 1 + }, + value: [ + new asn1js.Repeated({ + name: (names.attributes || ""), + value: Attribute.schema() + }) + ] + })); + } + //********************************************************************************** + /** + * Convert parsed asn1js object into current class + * @param {!Object} schema + */ + fromSchema(schema) + { + //region Clear input data first + clearProps(schema, [ + "attributes" + ]); + //endregion + + //region Check the schema is valid + const asn1 = asn1js.compareSchema(schema, + schema, + SignedAndUnsignedAttributes.schema({ + names: { + tagNumber: this.type, + attributes: "attributes" + } + }) + ); + + if(asn1.verified === false) + throw new Error("Object's schema was not verified against input data for SignedAndUnsignedAttributes"); + //endregion + + //region Get internal properties from parsed schema + this.type = asn1.result.idBlock.tagNumber; + this.encodedValue = asn1.result.valueBeforeDecode; + + //region Change type from "[0]" to "SET" accordingly to standard + const encodedView = new Uint8Array(this.encodedValue); + encodedView[0] = 0x31; + //endregion + + if(("attributes" in asn1.result) === false) + { + if(this.type === 0) + throw new Error("Wrong structure of SignedUnsignedAttributes"); + else + return; // Not so important in case of "UnsignedAttributes" + } + + this.attributes = Array.from(asn1.result.attributes, element => new Attribute({ schema: element })); + //endregion + } + //********************************************************************************** + /** + * Convert current object to asn1js object and set correct values + * @returns {Object} asn1js object + */ + toSchema() + { + if(SignedAndUnsignedAttributes.compareWithDefault("type", this.type) || SignedAndUnsignedAttributes.compareWithDefault("attributes", this.attributes)) + throw new Error("Incorrectly initialized \"SignedAndUnsignedAttributes\" class"); + + //region Construct and return new ASN.1 schema for this object + return (new asn1js.Constructed({ + optional: true, + idBlock: { + tagClass: 3, // CONTEXT-SPECIFIC + tagNumber: this.type // "SignedAttributes" = 0, "UnsignedAttributes" = 1 + }, + value: Array.from(this.attributes, element => element.toSchema()) + })); + //endregion + } + //********************************************************************************** + /** + * Convertion for the class to JSON object + * @returns {Object} + */ + toJSON() + { + if(SignedAndUnsignedAttributes.compareWithDefault("type", this.type) || SignedAndUnsignedAttributes.compareWithDefault("attributes", this.attributes)) + throw new Error("Incorrectly initialized \"SignedAndUnsignedAttributes\" class"); + + return { + type: this.type, + attributes: Array.from(this.attributes, element => element.toJSON()) + }; + } + //********************************************************************************** +} +//************************************************************************************** diff --git a/core/third-party/pkijs/SignedCertificateTimestampList.js b/core/third-party/pkijs/SignedCertificateTimestampList.js new file mode 100644 index 0000000..53c2d3a --- /dev/null +++ b/core/third-party/pkijs/SignedCertificateTimestampList.js @@ -0,0 +1,634 @@ +import * as asn1js from "./asn1.js"; +import { getParametersValue, utilFromBase, utilToBase, bufferToHexCodes, toBase64, fromBase64, arrayBufferToString, stringToArrayBuffer } from "./pvutils.js"; +import { ByteStream, SeqStream } from "./bytestream.js"; +import { getCrypto, getEngine } from "./common.js"; +import PublicKeyInfo from "./PublicKeyInfo.js"; +//************************************************************************************** +export class SignedCertificateTimestamp +{ + //********************************************************************************** + /** + * Constructor for SignedCertificateTimestamp class + * @param {Object} [parameters={}] + * @param {Object} [parameters.schema] asn1js parsed value to initialize the class from + */ + constructor(parameters = {}) + { + //region Internal properties of the object + /** + * @type {number} + * @desc version + */ + this.version = getParametersValue(parameters, "version", SignedCertificateTimestamp.defaultValues("version")); + /** + * @type {ArrayBuffer} + * @desc logID + */ + this.logID = getParametersValue(parameters, "logID", SignedCertificateTimestamp.defaultValues("logID")); + /** + * @type {Date} + * @desc timestamp + */ + this.timestamp = getParametersValue(parameters, "timestamp", SignedCertificateTimestamp.defaultValues("timestamp")); + /** + * @type {ArrayBuffer} + * @desc extensions + */ + this.extensions = getParametersValue(parameters, "extensions", SignedCertificateTimestamp.defaultValues("extensions")); + /** + * @type {string} + * @desc hashAlgorithm + */ + this.hashAlgorithm = getParametersValue(parameters, "hashAlgorithm", SignedCertificateTimestamp.defaultValues("hashAlgorithm")); + /** + * @type {string} + * @desc signatureAlgorithm + */ + this.signatureAlgorithm = getParametersValue(parameters, "signatureAlgorithm", SignedCertificateTimestamp.defaultValues("signatureAlgorithm")); + /** + * @type {Object} + * @desc signature + */ + this.signature = getParametersValue(parameters, "signature", SignedCertificateTimestamp.defaultValues("signature")); + //endregion + + //region If input argument array contains "schema" for this object + if("schema" in parameters) + this.fromSchema(parameters.schema); + //endregion + + //region If input argument array contains "stream" + if("stream" in parameters) + this.fromStream(parameters.stream); + //endregion + } + //********************************************************************************** + /** + * Return default values for all class members + * @param {string} memberName String name for a class member + */ + static defaultValues(memberName) + { + switch(memberName) + { + case "version": + return 0; + case "logID": + case "extensions": + return new ArrayBuffer(0); + case "timestamp": + return new Date(0); + case "hashAlgorithm": + case "signatureAlgorithm": + return ""; + case "signature": + return new asn1js.Any(); + default: + throw new Error(`Invalid member name for SignedCertificateTimestamp class: ${memberName}`); + } + } + //********************************************************************************** + /** + * Convert parsed asn1js object into current class + * @param {!Object} schema + */ + fromSchema(schema) + { + if((schema instanceof asn1js.RawData) === false) + throw new Error("Object's schema was not verified against input data for SignedCertificateTimestamp"); + + const seqStream = new SeqStream({ + stream: new ByteStream({ + buffer: schema.data + }) + }); + + this.fromStream(seqStream); + } + //********************************************************************************** + /** + * Convert SeqStream data into current class + * @param {!SeqStream} stream + */ + fromStream(stream) + { + const blockLength = stream.getUint16(); + + this.version = (stream.getBlock(1))[0]; + + if(this.version === 0) + { + this.logID = (new Uint8Array(stream.getBlock(32))).buffer.slice(0); + this.timestamp = new Date(utilFromBase(new Uint8Array(stream.getBlock(8)), 8)); + + //region Extensions + const extensionsLength = stream.getUint16(); + this.extensions = (new Uint8Array(stream.getBlock(extensionsLength))).buffer.slice(0); + //endregion + + //region Hash algorithm + switch((stream.getBlock(1))[0]) + { + case 0: + this.hashAlgorithm = "none"; + break; + case 1: + this.hashAlgorithm = "md5"; + break; + case 2: + this.hashAlgorithm = "sha1"; + break; + case 3: + this.hashAlgorithm = "sha224"; + break; + case 4: + this.hashAlgorithm = "sha256"; + break; + case 5: + this.hashAlgorithm = "sha384"; + break; + case 6: + this.hashAlgorithm = "sha512"; + break; + default: + throw new Error("Object's stream was not correct for SignedCertificateTimestamp"); + } + //endregion + + //region Signature algorithm + switch((stream.getBlock(1))[0]) + { + case 0: + this.signatureAlgorithm = "anonymous"; + break; + case 1: + this.signatureAlgorithm = "rsa"; + break; + case 2: + this.signatureAlgorithm = "dsa"; + break; + case 3: + this.signatureAlgorithm = "ecdsa"; + break; + default: + throw new Error("Object's stream was not correct for SignedCertificateTimestamp"); + } + //endregion + + //region Signature + const signatureLength = stream.getUint16(); + const signatureData = (new Uint8Array(stream.getBlock(signatureLength))).buffer.slice(0); + + const asn1 = asn1js.fromBER(signatureData); + if(asn1.offset === (-1)) + throw new Error("Object's stream was not correct for SignedCertificateTimestamp"); + + this.signature = asn1.result; + //endregion + + if(blockLength !== (47 + extensionsLength + signatureLength)) + throw new Error("Object's stream was not correct for SignedCertificateTimestamp"); + } + } + //********************************************************************************** + /** + * Convert current object to asn1js object and set correct values + * @returns {Object} asn1js object + */ + toSchema() + { + const stream = this.toStream(); + + return new asn1js.RawData({ data: stream.stream.buffer }); + } + //********************************************************************************** + /** + * Convert current object to SeqStream data + * @returns {SeqStream} SeqStream object + */ + toStream() + { + const stream = new SeqStream(); + + stream.appendUint16(47 + this.extensions.byteLength + this.signature.valueBeforeDecode.byteLength); + stream.appendChar(this.version); + stream.appendView(new Uint8Array(this.logID)); + + const timeBuffer = new ArrayBuffer(8); + const timeView = new Uint8Array(timeBuffer); + + const baseArray = utilToBase(this.timestamp.valueOf(), 8); + timeView.set(new Uint8Array(baseArray), 8 - baseArray.byteLength); + + stream.appendView(timeView); + stream.appendUint16(this.extensions.byteLength); + + if(this.extensions.byteLength) + stream.appendView(new Uint8Array(this.extensions)); + + let _hashAlgorithm; + + switch(this.hashAlgorithm.toLowerCase()) + { + case "none": + _hashAlgorithm = 0; + break; + case "md5": + _hashAlgorithm = 1; + break; + case "sha1": + _hashAlgorithm = 2; + break; + case "sha224": + _hashAlgorithm = 3; + break; + case "sha256": + _hashAlgorithm = 4; + break; + case "sha384": + _hashAlgorithm = 5; + break; + case "sha512": + _hashAlgorithm = 6; + break; + default: + throw new Error(`Incorrect data for hashAlgorithm: ${this.hashAlgorithm}`); + } + + stream.appendChar(_hashAlgorithm); + + let _signatureAlgorithm; + + switch(this.signatureAlgorithm.toLowerCase()) + { + case "anonymous": + _signatureAlgorithm = 0; + break; + case "rsa": + _signatureAlgorithm = 1; + break; + case "dsa": + _signatureAlgorithm = 2; + break; + case "ecdsa": + _signatureAlgorithm = 3; + break; + default: + throw new Error(`Incorrect data for signatureAlgorithm: ${this.signatureAlgorithm}`); + } + + stream.appendChar(_signatureAlgorithm); + + const _signature = this.signature.toBER(false); + + stream.appendUint16(_signature.byteLength); + stream.appendView(new Uint8Array(_signature)); + + return stream; + } + //********************************************************************************** + /** + * Convertion for the class to JSON object + * @returns {Object} + */ + toJSON() + { + return { + version: this.version, + logID: bufferToHexCodes(this.logID), + timestamp: this.timestamp, + extensions: bufferToHexCodes(this.extensions), + hashAlgorithm: this.hashAlgorithm, + signatureAlgorithm: this.signatureAlgorithm, + signature: this.signature.toJSON() + }; + } + //********************************************************************************** + /** + * Verify SignedCertificateTimestamp for specific input data + * @param {Object[]} logs Array of objects with information about each CT Log (like here: https://ct.grahamedgecombe.com/logs.json) + * @param {String} logs.log_id Identifier of the CT Log encoded in BASE-64 format + * @param {String} logs.key Public key of the CT Log encoded in BASE-64 format + * @param {ArrayBuffer} data Data to verify signature against. Could be encoded Certificate or encoded PreCert + * @param {Number} [dataType=0] Type = 0 (data is encoded Certificate), type = 1 (data is encoded PreCert) + * @return {Promise} + */ + async verify(logs, data, dataType = 0) + { + //region Initial variables + let logId = toBase64(arrayBufferToString(this.logID)); + + let publicKeyBase64 = null; + let publicKeyInfo; + + let stream = new SeqStream(); + //endregion + + //region Found and init public key + for(const log of logs) + { + if(log.log_id === logId) + { + publicKeyBase64 = log.key; + break; + } + } + + if(publicKeyBase64 === null) + throw new Error(`Public key not found for CT with logId: ${logId}`); + + const asn1 = asn1js.fromBER(stringToArrayBuffer(fromBase64(publicKeyBase64))); + if(asn1.offset === (-1)) + throw new Error(`Incorrect key value for CT Log with logId: ${logId}`); + + publicKeyInfo = new PublicKeyInfo({ schema: asn1.result }); + //endregion + + //region Initialize signed data block + stream.appendChar(0x00); // sct_version + stream.appendChar(0x00); // signature_type = certificate_timestamp + + const timeBuffer = new ArrayBuffer(8); + const timeView = new Uint8Array(timeBuffer); + + const baseArray = utilToBase(this.timestamp.valueOf(), 8); + timeView.set(new Uint8Array(baseArray), 8 - baseArray.byteLength); + + stream.appendView(timeView); + + stream.appendUint16(dataType); + + if(dataType === 0) + stream.appendUint24(data.byteLength); + + stream.appendView(new Uint8Array(data)); + + stream.appendUint16(this.extensions.byteLength); + + if(this.extensions.byteLength !== 0) + stream.appendView(new Uint8Array(this.extensions)); + //endregion + + //region Perform verification + return getEngine().subtle.verifyWithPublicKey( + stream._stream._buffer.slice(0, stream._length), + { valueBlock: { valueHex: this.signature.toBER(false) } }, + publicKeyInfo, + { algorithmId: "" }, + "SHA-256" + ); + //endregion + } + //********************************************************************************** +} +//************************************************************************************** +/** + * Class from RFC6962 + */ +export default class SignedCertificateTimestampList +{ + //********************************************************************************** + /** + * Constructor for SignedCertificateTimestampList class + * @param {Object} [parameters={}] + * @param {Object} [parameters.schema] asn1js parsed value to initialize the class from + */ + constructor(parameters = {}) + { + //region Internal properties of the object + /** + * @type {Array.} + * @desc timestamps + */ + this.timestamps = getParametersValue(parameters, "timestamps", SignedCertificateTimestampList.defaultValues("timestamps")); + //endregion + + //region If input argument array contains "schema" for this object + if("schema" in parameters) + this.fromSchema(parameters.schema); + //endregion + } + //********************************************************************************** + /** + * Return default values for all class members + * @param {string} memberName String name for a class member + */ + static defaultValues(memberName) + { + switch(memberName) + { + case "timestamps": + return []; + default: + throw new Error(`Invalid member name for SignedCertificateTimestampList class: ${memberName}`); + } + } + //********************************************************************************** + /** + * Compare values with default values for all class members + * @param {string} memberName String name for a class member + * @param {*} memberValue Value to compare with default value + */ + static compareWithDefault(memberName, memberValue) + { + switch(memberName) + { + case "timestamps": + return (memberValue.length === 0); + default: + throw new Error(`Invalid member name for SignedCertificateTimestampList class: ${memberName}`); + } + } + //********************************************************************************** + /** + * Return value of pre-defined ASN.1 schema for current class + * + * ASN.1 schema: + * ```asn1 + * SignedCertificateTimestampList ::= OCTET STRING + * ``` + * + * @param {Object} parameters Input parameters for the schema + * @returns {Object} asn1js schema object + */ + static schema(parameters = {}) + { + /** + * @type {Object} + * @property {string} [blockName] + * @property {string} [optional] + */ + const names = getParametersValue(parameters, "names", {}); + + if(("optional" in names) === false) + names.optional = false; + + return (new asn1js.OctetString({ + name: (names.blockName || "SignedCertificateTimestampList"), + optional: names.optional + })); + } + //********************************************************************************** + /** + * Convert parsed asn1js object into current class + * @param {!Object} schema + */ + fromSchema(schema) + { + //region Check the schema is valid + if((schema instanceof asn1js.OctetString) === false) + throw new Error("Object's schema was not verified against input data for SignedCertificateTimestampList"); + //endregion + + //region Get internal properties from parsed schema + const seqStream = new SeqStream({ + stream: new ByteStream({ + buffer: schema.valueBlock.valueHex + }) + }); + + let dataLength = seqStream.getUint16(); + if(dataLength !== seqStream.length) + throw new Error("Object's schema was not verified against input data for SignedCertificateTimestampList"); + + while(seqStream.length) + this.timestamps.push(new SignedCertificateTimestamp({ stream: seqStream })); + //endregion + } + //********************************************************************************** + /** + * Convert current object to asn1js object and set correct values + * @returns {Object} asn1js object + */ + toSchema() + { + //region Initial variables + const stream = new SeqStream(); + + let overallLength = 0; + + const timestampsData = []; + //endregion + + //region Get overall length + for(const timestamp of this.timestamps) + { + const timestampStream = timestamp.toStream(); + timestampsData.push(timestampStream); + overallLength += timestampStream.stream.buffer.byteLength; + } + //endregion + + stream.appendUint16(overallLength); + + //region Set data from all timestamps + for(const timestamp of timestampsData) + stream.appendView(timestamp.stream.view); + //endregion + + return new asn1js.OctetString({ valueHex: stream.stream.buffer.slice(0) }); + } + //********************************************************************************** + /** + * Convertion for the class to JSON object + * @returns {Object} + */ + toJSON() + { + return { + timestamps: Array.from(this.timestamps, element => element.toJSON()) + }; + } + //********************************************************************************** +} +//************************************************************************************** +/** + * Verify SignedCertificateTimestamp for specific certificate content + * @param {Certificate} certificate Certificate for which verification would be performed + * @param {Certificate} issuerCertificate Certificate of the issuer of target certificate + * @param {Object[]} logs Array of objects with information about each CT Log (like here: https://ct.grahamedgecombe.com/logs.json) + * @param {String} logs.log_id Identifier of the CT Log encoded in BASE-64 format + * @param {String} logs.key Public key of the CT Log encoded in BASE-64 format + * @param {Number} [index=-1] Index of SignedCertificateTimestamp inside SignedCertificateTimestampList (for -1 would verify all) + * @return {Array} Array of verification results + */ +export async function verifySCTsForCertificate(certificate, issuerCertificate, logs, index = (-1)) +{ + //region Initial variables + let parsedValue = null; + let tbs; + let issuerId; + + const stream = new SeqStream(); + + let preCert; + //endregion + + //region Get a "crypto" extension + const crypto = getCrypto(); + if(typeof crypto === "undefined") + return Promise.reject("Unable to create WebCrypto object"); + //endregion + + //region Remove certificate extension + for(let i = 0; i < certificate.extensions.length; i++) + { + switch(certificate.extensions[i].extnID) + { + case "1.3.6.1.4.1.11129.2.4.2": + { + parsedValue = certificate.extensions[i].parsedValue; + + if(parsedValue.timestamps.length === 0) + throw new Error("Nothing to verify in the certificate"); + + certificate.extensions.splice(i, 1); + } + break; + default: + } + } + //endregion + + //region Check we do have what to verify + if(parsedValue === null) + throw new Error("No SignedCertificateTimestampList extension in the specified certificate"); + //endregion + + //region Prepare modifier TBS value + tbs = certificate.encodeTBS().toBER(false); + //endregion + + //region Initialize "issuer_key_hash" value + issuerId = await crypto.digest({ name: "SHA-256" }, new Uint8Array(issuerCertificate.subjectPublicKeyInfo.toSchema().toBER(false))); + //endregion + + //region Make final "PreCert" value + stream.appendView(new Uint8Array(issuerId)); + stream.appendUint24(tbs.byteLength); + stream.appendView(new Uint8Array(tbs)); + + preCert = stream._stream._buffer.slice(0, stream._length); + //endregion + + //region Call verification function for specified index + if(index === (-1)) + { + const verifyArray = []; + + for(const timestamp of parsedValue.timestamps) + { + const verifyResult = await timestamp.verify(logs, preCert, 1); + verifyArray.push(verifyResult); + } + + return verifyArray; + } + + if(index >= parsedValue.timestamps.length) + index = (parsedValue.timestamps.length - 1); + + return [await parsedValue.timestamps[index].verify(logs, preCert, 1)]; + //endregion +} +//********************************************************************************** diff --git a/core/third-party/pkijs/SignedData.js b/core/third-party/pkijs/SignedData.js new file mode 100644 index 0000000..2621cea --- /dev/null +++ b/core/third-party/pkijs/SignedData.js @@ -0,0 +1,1067 @@ +import * as asn1js from "./asn1.js"; +import { getParametersValue, utilConcatBuf, isEqualBuffer, clearProps } from "./pvutils.js"; +import { getCrypto, getEngine, getOIDByAlgorithm, getAlgorithmByOID } from "./common.js"; +import AlgorithmIdentifier from "./AlgorithmIdentifier.js"; +import EncapsulatedContentInfo from "./EncapsulatedContentInfo.js"; +import Certificate from "./Certificate.js"; +import CertificateRevocationList from "./CertificateRevocationList.js"; +import OtherRevocationInfoFormat from "./OtherRevocationInfoFormat.js"; +import SignerInfo from "./SignerInfo.js"; +import CertificateSet from "./CertificateSet.js"; +import RevocationInfoChoices from "./RevocationInfoChoices.js"; +import IssuerAndSerialNumber from "./IssuerAndSerialNumber.js"; +import TSTInfo from "./TSTInfo.js"; +import CertificateChainValidationEngine from "./CertificateChainValidationEngine.js"; +import BasicOCSPResponse from "./BasicOCSPResponse.js"; +//************************************************************************************** +/** + * Class from RFC5652 + */ +export default class SignedData +{ + //********************************************************************************** + /** + * Constructor for SignedData class + * @param {Object} [parameters={}] + * @param {Object} [parameters.schema] asn1js parsed value to initialize the class from + */ + constructor(parameters = {}) + { + //region Internal properties of the object + /** + * @type {number} + * @desc version + */ + this.version = getParametersValue(parameters, "version", SignedData.defaultValues("version")); + /** + * @type {Array.} + * @desc digestAlgorithms + */ + this.digestAlgorithms = getParametersValue(parameters, "digestAlgorithms", SignedData.defaultValues("digestAlgorithms")); + /** + * @type {EncapsulatedContentInfo} + * @desc encapContentInfo + */ + this.encapContentInfo = getParametersValue(parameters, "encapContentInfo", SignedData.defaultValues("encapContentInfo")); + + if("certificates" in parameters) + /** + * @type {Array.} + * @desc certificates + */ + this.certificates = getParametersValue(parameters, "certificates", SignedData.defaultValues("certificates")); + + if("crls" in parameters) + /** + * @type {Array.} + * @desc crls + */ + this.crls = getParametersValue(parameters, "crls", SignedData.defaultValues("crls")); + + if("ocsps" in parameters) + /** + * @type {Array.} + * @desc crls + */ + this.ocsps = getParametersValue(parameters, "ocsps", SignedData.defaultValues("ocsps")); + + /** + * @type {Array.} + * @desc signerInfos + */ + this.signerInfos = getParametersValue(parameters, "signerInfos", SignedData.defaultValues("signerInfos")); + //endregion + + //region If input argument array contains "schema" for this object + if("schema" in parameters) + this.fromSchema(parameters.schema); + //endregion + } + //********************************************************************************** + /** + * Return default values for all class members + * @param {string} memberName String name for a class member + */ + static defaultValues(memberName) + { + switch(memberName) + { + case "version": + return 0; + case "digestAlgorithms": + return []; + case "encapContentInfo": + return new EncapsulatedContentInfo(); + case "certificates": + return []; + case "crls": + return []; + case "ocsps": + return []; + case "signerInfos": + return []; + default: + throw new Error(`Invalid member name for SignedData class: ${memberName}`); + } + } + //********************************************************************************** + /** + * Compare values with default values for all class members + * @param {string} memberName String name for a class member + * @param {*} memberValue Value to compare with default value + */ + static compareWithDefault(memberName, memberValue) + { + switch(memberName) + { + case "version": + return (memberValue === SignedData.defaultValues("version")); + case "encapContentInfo": + return new EncapsulatedContentInfo(); + case "digestAlgorithms": + case "certificates": + case "crls": + case "ocsps": + case "signerInfos": + return (memberValue.length === 0); + default: + throw new Error(`Invalid member name for SignedData class: ${memberName}`); + } + } + //********************************************************************************** + /** + * Return value of pre-defined ASN.1 schema for current class + * + * ASN.1 schema: + * ```asn1 + * SignedData ::= SEQUENCE { + * version CMSVersion, + * digestAlgorithms DigestAlgorithmIdentifiers, + * encapContentInfo EncapsulatedContentInfo, + * certificates [0] IMPLICIT CertificateSet OPTIONAL, + * crls [1] IMPLICIT RevocationInfoChoices OPTIONAL, + * signerInfos SignerInfos } + * ``` + * + * @param {Object} parameters Input parameters for the schema + * @returns {Object} asn1js schema object + */ + static schema(parameters = {}) + { + /** + * @type {Object} + * @property {string} [blockName] + * @property {string} [optional] + * @property {string} [digestAlgorithms] + * @property {string} [encapContentInfo] + * @property {string} [certificates] + * @property {string} [crls] + * @property {string} [signerInfos] + */ + const names = getParametersValue(parameters, "names", {}); + + if(("optional" in names) === false) + names.optional = false; + + return (new asn1js.Sequence({ + name: (names.blockName || "SignedData"), + optional: names.optional, + value: [ + new asn1js.Integer({ name: (names.version || "SignedData.version") }), + new asn1js.Set({ + value: [ + new asn1js.Repeated({ + name: (names.digestAlgorithms || "SignedData.digestAlgorithms"), + value: AlgorithmIdentifier.schema() + }) + ] + }), + EncapsulatedContentInfo.schema(names.encapContentInfo || { + names: { + blockName: "SignedData.encapContentInfo" + } + }), + new asn1js.Constructed({ + name: (names.certificates || "SignedData.certificates"), + optional: true, + idBlock: { + tagClass: 3, // CONTEXT-SPECIFIC + tagNumber: 0 // [0] + }, + value: CertificateSet.schema().valueBlock.value + }), // IMPLICIT CertificateSet + new asn1js.Constructed({ + optional: true, + idBlock: { + tagClass: 3, // CONTEXT-SPECIFIC + tagNumber: 1 // [1] + }, + value: RevocationInfoChoices.schema(names.crls || { + names: { + crls: "SignedData.crls" + } + }).valueBlock.value + }), // IMPLICIT RevocationInfoChoices + new asn1js.Set({ + value: [ + new asn1js.Repeated({ + name: (names.signerInfos || "SignedData.signerInfos"), + value: SignerInfo.schema() + }) + ] + }) + ] + })); + } + //********************************************************************************** + /** + * Convert parsed asn1js object into current class + * @param {!Object} schema + */ + fromSchema(schema) + { + //region Clear input data first + clearProps(schema, [ + "SignedData.version", + "SignedData.digestAlgorithms", + "SignedData.encapContentInfo", + "SignedData.certificates", + "SignedData.crls", + "SignedData.signerInfos" + ]); + //endregion + + //region Check the schema is valid + const asn1 = asn1js.compareSchema(schema, + schema, + SignedData.schema() + ); + + if(asn1.verified === false) + throw new Error("Object's schema was not verified against input data for SignedData"); + //endregion + + //region Get internal properties from parsed schema + this.version = asn1.result["SignedData.version"].valueBlock.valueDec; + + if("SignedData.digestAlgorithms" in asn1.result) // Could be empty SET of digest algorithms + this.digestAlgorithms = Array.from(asn1.result["SignedData.digestAlgorithms"], algorithm => new AlgorithmIdentifier({ schema: algorithm })); + + this.encapContentInfo = new EncapsulatedContentInfo({ schema: asn1.result["SignedData.encapContentInfo"] }); + + if("SignedData.certificates" in asn1.result) + { + const certificateSet = new CertificateSet({ + schema: new asn1js.Set({ + value: asn1.result["SignedData.certificates"].valueBlock.value + }) + }); + this.certificates = certificateSet.certificates.slice(0); // Copy all just for making comfortable access + } + + if("SignedData.crls" in asn1.result) + { + this.crls = Array.from(asn1.result["SignedData.crls"], crl => + { + if(crl.idBlock.tagClass === 1) + return new CertificateRevocationList({ schema: crl }); + + //region Create SEQUENCE from [1] + crl.idBlock.tagClass = 1; // UNIVERSAL + crl.idBlock.tagNumber = 16; // SEQUENCE + //endregion + + return new OtherRevocationInfoFormat({ schema: crl }); + }); + } + + if("SignedData.signerInfos" in asn1.result) // Could be empty SET SignerInfos + this.signerInfos = Array.from(asn1.result["SignedData.signerInfos"], signerInfoSchema => new SignerInfo({ schema: signerInfoSchema })); + //endregion + } + //********************************************************************************** + /** + * Convert current object to asn1js object and set correct values + * @returns {Object} asn1js object + */ + toSchema(encodeFlag = false) + { + //region Create array for output sequence + const outputArray = []; + + outputArray.push(new asn1js.Integer({ value: this.version })); + + //region Create array of digest algorithms + outputArray.push(new asn1js.Set({ + value: Array.from(this.digestAlgorithms, algorithm => algorithm.toSchema(encodeFlag)) + })); + //endregion + + outputArray.push(this.encapContentInfo.toSchema()); + + if("certificates" in this) + { + const certificateSet = new CertificateSet({ certificates: this.certificates }); + const certificateSetSchema = certificateSet.toSchema(); + + outputArray.push(new asn1js.Constructed({ + idBlock: { + tagClass: 3, + tagNumber: 0 + }, + value: certificateSetSchema.valueBlock.value + })); + } + + if("crls" in this) + { + outputArray.push(new asn1js.Constructed({ + idBlock: { + tagClass: 3, // CONTEXT-SPECIFIC + tagNumber: 1 // [1] + }, + value: Array.from(this.crls, crl => + { + if(crl instanceof OtherRevocationInfoFormat) + { + const crlSchema = crl.toSchema(encodeFlag); + + crlSchema.idBlock.tagClass = 3; + crlSchema.idBlock.tagNumber = 1; + + return crlSchema; + } + + return crl.toSchema(encodeFlag); + }) + })); + } + + //region Create array of signer infos + outputArray.push(new asn1js.Set({ + value: Array.from(this.signerInfos, signerInfo => signerInfo.toSchema(encodeFlag)) + })); + //endregion + //endregion + + //region Construct and return new ASN.1 schema for this object + return (new asn1js.Sequence({ + value: outputArray + })); + //endregion + } + //********************************************************************************** + /** + * Convertion for the class to JSON object + * @returns {Object} + */ + toJSON() + { + const _object = { + version: this.version, + digestAlgorithms: Array.from(this.digestAlgorithms, algorithm => algorithm.toJSON()), + encapContentInfo: this.encapContentInfo.toJSON() + }; + + if("certificates" in this) + _object.certificates = Array.from(this.certificates, certificate => certificate.toJSON()); + + if("crls" in this) + _object.crls = Array.from(this.crls, crl => crl.toJSON()); + + _object.signerInfos = Array.from(this.signerInfos, signerInfo => signerInfo.toJSON()); + + return _object; + } + //********************************************************************************** + /** + * Verify current SignedData value + * @param {Object} [param={}] + * @param {Number} [param.signer = -1] Index of the signer which information we need to verify + * @param {ArrayBuffer} [param.data=new ArrayBuffer(0)] + * @param {Array.} [param.trustedCerts=[]] + * @param {Date} [param.checkDate=new Date()] + * @param {Boolean} [param.checkChain=false] + * @param {Boolean} [param.extendedMode=false] + * @param {?Function} [findOrigin=null] + * @param {?Function} [findIssuer=null] + */ + verify({ + signer = (-1), + data = (new ArrayBuffer(0)), + trustedCerts = [], + checkDate = (new Date()), + checkChain = false, + extendedMode = false, + passedWhenNotRevValues = false, + findOrigin = null, + findIssuer = null + } = {}) + { + //region Global variables + let sequence = Promise.resolve(); + + let messageDigestValue = new ArrayBuffer(0); + + let shaAlgorithm = ""; + + let signerCertificate = {}; + + let timestampSerial = null; + + let certificatePath = []; + + const engine = getEngine(); + //endregion + + //region Get a "crypto" extension + const crypto = getCrypto(); + if(typeof crypto === "undefined") + return Promise.reject("Unable to create WebCrypto object"); + //endregion + + //region Get a signer number + if(signer === (-1)) + { + if(extendedMode) + { + return Promise.reject({ + date: checkDate, + code: 1, + message: "Unable to get signer index from input parameters", + signatureVerified: null, + signerCertificate: null, + signerCertificateVerified: null + }); + } + + return Promise.reject("Unable to get signer index from input parameters"); + } + //endregion + + //region Check that certificates field was included in signed data + if(("certificates" in this) === false) + { + if(extendedMode) + { + return Promise.reject({ + date: checkDate, + code: 2, + message: "No certificates attached to this signed data", + signatureVerified: null, + signerCertificate: null, + signerCertificateVerified: null + }); + } + + return Promise.reject("No certificates attached to this signed data"); + } + //endregion + + //region Find a certificate for specified signer + if(this.signerInfos[signer].sid instanceof IssuerAndSerialNumber) + { + sequence = sequence.then(() => + { + for(const certificate of this.certificates) + { + if((certificate instanceof Certificate) === false) + continue; + + if((certificate.issuer.isEqual(this.signerInfos[signer].sid.issuer)) && + (certificate.serialNumber.isEqual(this.signerInfos[signer].sid.serialNumber))) + { + signerCertificate = certificate; + return Promise.resolve(); + } + } + + if(extendedMode) + { + return Promise.reject({ + date: checkDate, + code: 3, + message: "Unable to find signer certificate", + signatureVerified: null, + signerCertificate: null, + signerCertificateVerified: null + }); + } + + return Promise.reject("Unable to find signer certificate"); + }); + } + else // Find by SubjectKeyIdentifier + { + sequence = sequence.then(() => + Promise.all(Array.from(this.certificates.filter(certificate => (certificate instanceof Certificate)), certificate => + crypto.digest({ name: "sha-1" }, new Uint8Array(certificate.subjectPublicKeyInfo.subjectPublicKey.valueBlock.valueHex))) + ).then(results => + { + for(const [index, certificate] of this.certificates.entries()) + { + if((certificate instanceof Certificate) === false) + continue; + + if(isEqualBuffer(results[index], this.signerInfos[signer].sid.valueBlock.valueHex)) + { + signerCertificate = certificate; + return Promise.resolve(); + } + } + + if(extendedMode) + { + return Promise.reject({ + date: checkDate, + code: 3, + message: "Unable to find signer certificate", + signatureVerified: null, + signerCertificate: null, + signerCertificateVerified: null + }); + } + + return Promise.reject("Unable to find signer certificate"); + }, () => + { + if(extendedMode) + { + return Promise.reject({ + date: checkDate, + code: 3, + message: "Unable to find signer certificate", + signatureVerified: null, + signerCertificate: null, + signerCertificateVerified: null + }); + } + + return Promise.reject("Unable to find signer certificate"); + }) + ); + } + //endregion + + //region Verify internal digest in case of "tSTInfo" content type + sequence = sequence.then(() => + { + if(this.encapContentInfo.eContentType === "1.2.840.113549.1.9.16.1.4") + { + //region Check "eContent" precense + if(("eContent" in this.encapContentInfo) === false) + return false; + //endregion + + //region Initialize TST_INFO value + const asn1 = asn1js.fromBER(this.encapContentInfo.eContent.valueBlock.valueHex); + let tstInfo; + + try + { + tstInfo = new TSTInfo({ schema: asn1.result }); + } + catch(ex) + { + return false; + } + //endregion + + //region Change "checkDate" and append "timestampSerial" + checkDate = tstInfo.genTime; + timestampSerial = tstInfo.serialNumber.valueBlock.valueHex; + //endregion + + //region Check that we do have detached data content + if(data.byteLength === 0) + { + if(extendedMode) + { + return Promise.reject({ + date: checkDate, + code: 4, + message: "Missed detached data input array", + signatureVerified: null, + signerCertificate, + signerCertificateVerified: null + }); + } + + return Promise.reject("Missed detached data input array"); + } + //endregion + + return tstInfo.verify({ data }); + } + + return true; + }); + //endregion + + //region Make additional verification for signer's certificate + function checkCA(cert) + { + /// Certificate to find CA flag for + + //region Do not include signer's certificate + if((cert.issuer.isEqual(signerCertificate.issuer) === true) && (cert.serialNumber.isEqual(signerCertificate.serialNumber) === true)) + return null; + //endregion + + let isCA = false; + + if("extensions" in cert) + { + for(const extension of cert.extensions) + { + if(extension.extnID === "2.5.29.19") // BasicConstraints + { + if("cA" in extension.parsedValue) + { + if(extension.parsedValue.cA === true) + isCA = true; + } + } + } + } + + if(isCA) + return cert; + + return null; + } + + if(checkChain) + { + sequence = sequence.then(result => + { + //region Verify result of previous operation + if(result === false) + return false; + //endregion + + const promiseResults = Array.from(this.certificates.filter(certificate => (certificate instanceof Certificate)), certificate => checkCA(certificate)); + + const certificateChainValidationEngineParameters = { + checkDate, + certs: Array.from(promiseResults.filter(_result => (_result !== null))), + trustedCerts + }; + + if(findIssuer !== null) + certificateChainValidationEngineParameters.findIssuer = findIssuer; + + if(findOrigin !== null) + certificateChainValidationEngineParameters.findOrigin = findOrigin; + + const certificateChainEngine = new CertificateChainValidationEngine(certificateChainValidationEngineParameters); + + certificateChainEngine.certs.push(signerCertificate); + + if("crls" in this) + { + for(const crl of this.crls) + { + if("thisUpdate" in crl) + certificateChainEngine.crls.push(crl); + else // Assumed "revocation value" has "OtherRevocationInfoFormat" + { + if(crl.otherRevInfoFormat === "1.3.6.1.5.5.7.48.1.1") // Basic OCSP response + certificateChainEngine.ocsps.push(new BasicOCSPResponse({ schema: crl.otherRevInfo })); + } + } + } + + if("ocsps" in this) + certificateChainEngine.ocsps.push(...(this.ocsps)); + + return certificateChainEngine.verify({ passedWhenNotRevValues }).then(verificationResult => + { + if("certificatePath" in verificationResult) + certificatePath = verificationResult.certificatePath; + + if(verificationResult.result === true) + return Promise.resolve(true); + + if(extendedMode) + { + return Promise.reject({ + date: checkDate, + code: 5, + message: `Validation of signer's certificate failed: ${verificationResult.resultMessage}`, + signatureVerified: null, + signerCertificate, + signerCertificateVerified: false + }); + } + + return Promise.reject("Validation of signer's certificate failed"); + }, error => + { + if(extendedMode) + { + return Promise.reject({ + date: checkDate, + code: 5, + message: `Validation of signer's certificate failed with error: ${((error instanceof Object) ? error.resultMessage : error)}`, + signatureVerified: null, + signerCertificate, + signerCertificateVerified: false + }); + } + + return Promise.reject(`Validation of signer's certificate failed with error: ${((error instanceof Object) ? error.resultMessage : error)}`); + }); + }); + } + //endregion + + //region Find signer's hashing algorithm + sequence = sequence.then(result => + { + //region Verify result of previous operation + if(result === false) + return false; + //endregion + + const signerInfoHashAlgorithm = getAlgorithmByOID(this.signerInfos[signer].digestAlgorithm.algorithmId); + if(("name" in signerInfoHashAlgorithm) === false) + { + if(extendedMode) + { + return Promise.reject({ + date: checkDate, + code: 7, + message: `Unsupported signature algorithm: ${this.signerInfos[signer].digestAlgorithm.algorithmId}`, + signatureVerified: null, + signerCertificate, + signerCertificateVerified: true + }); + } + + return Promise.reject(`Unsupported signature algorithm: ${this.signerInfos[signer].digestAlgorithm.algorithmId}`); + } + + shaAlgorithm = signerInfoHashAlgorithm.name; + + return true; + }); + //endregion + + //region Create correct data block for verification + sequence = sequence.then(result => + { + //region Verify result of previous operation + if(result === false) + return false; + //endregion + + if("eContent" in this.encapContentInfo) // Attached data + { + if((this.encapContentInfo.eContent.idBlock.tagClass === 1) && + (this.encapContentInfo.eContent.idBlock.tagNumber === 4)) + { + if(this.encapContentInfo.eContent.idBlock.isConstructed === false) + data = this.encapContentInfo.eContent.valueBlock.valueHex; + else + { + for(const contentValue of this.encapContentInfo.eContent.valueBlock.value) + data = utilConcatBuf(data, contentValue.valueBlock.valueHex); + } + } + else + data = this.encapContentInfo.eContent.valueBlock.valueBeforeDecode; + } + else // Detached data + { + if(data.byteLength === 0) // Check that "data" already provided by function parameter + { + if(extendedMode) + { + return Promise.reject({ + date: checkDate, + code: 8, + message: "Missed detached data input array", + signatureVerified: null, + signerCertificate, + signerCertificateVerified: true + }); + } + + return Promise.reject("Missed detached data input array"); + } + } + + if("signedAttrs" in this.signerInfos[signer]) + { + //region Check mandatory attributes + let foundContentType = false; + let foundMessageDigest = false; + + for(const attribute of this.signerInfos[signer].signedAttrs.attributes) + { + //region Check that "content-type" attribute exists + if(attribute.type === "1.2.840.113549.1.9.3") + foundContentType = true; + //endregion + + //region Check that "message-digest" attribute exists + if(attribute.type === "1.2.840.113549.1.9.4") + { + foundMessageDigest = true; + messageDigestValue = attribute.values[0].valueBlock.valueHex; + } + //endregion + + //region Speed-up searching + if(foundContentType && foundMessageDigest) + break; + //endregion + } + + if(foundContentType === false) + { + if(extendedMode) + { + return Promise.reject({ + date: checkDate, + code: 9, + message: "Attribute \"content-type\" is a mandatory attribute for \"signed attributes\"", + signatureVerified: null, + signerCertificate, + signerCertificateVerified: true + }); + } + + return Promise.reject("Attribute \"content-type\" is a mandatory attribute for \"signed attributes\""); + } + + if(foundMessageDigest === false) + { + if(extendedMode) + { + return Promise.reject({ + date: checkDate, + code: 10, + message: "Attribute \"message-digest\" is a mandatory attribute for \"signed attributes\"", + signatureVerified: null, + signerCertificate, + signerCertificateVerified: true + }); + } + + return Promise.reject("Attribute \"message-digest\" is a mandatory attribute for \"signed attributes\""); + } + //endregion + } + + return true; + }); + //endregion + + //region Verify "message-digest" attribute in case of "signedAttrs" + sequence = sequence.then(result => + { + //region Verify result of previous operation + if(result === false) + return false; + //endregion + + if("signedAttrs" in this.signerInfos[signer]) + return crypto.digest(shaAlgorithm, new Uint8Array(data)); + + return true; + }).then( + /** + * @param {ArrayBuffer} result + */ + result => + { + //region Verify result of previous operation + if(result === false) + return false; + //endregion + + if("signedAttrs" in this.signerInfos[signer]) + { + if(isEqualBuffer(result, messageDigestValue)) + { + data = this.signerInfos[signer].signedAttrs.encodedValue; + return true; + } + + return false; + } + + return true; + }); + //endregion + + sequence = sequence.then(result => + { + //region Verify result of previous operation + if(result === false) + return false; + //endregion + + return engine.subtle.verifyWithPublicKey(data, this.signerInfos[signer].signature, signerCertificate.subjectPublicKeyInfo, signerCertificate.signatureAlgorithm, shaAlgorithm); + }); + + //region Make a final result + sequence = sequence.then(result => + { + if(extendedMode) + { + return { + date: checkDate, + code: 14, + message: "", + signatureVerified: result, + signerCertificate, + timestampSerial, + signerCertificateVerified: true, + certificatePath + }; + } + + return result; + }, error => + { + if(extendedMode) + { + if("code" in error) + return Promise.reject(error); + + return Promise.reject({ + date: checkDate, + code: 15, + message: `Error during verification: ${error.message}`, + signatureVerified: null, + signerCertificate, + timestampSerial, + signerCertificateVerified: true + }); + } + + return Promise.reject(error); + }); + //endregion + + return sequence; + } + //********************************************************************************** + /** + * Signing current SignedData + * @param {key} privateKey Private key for "subjectPublicKeyInfo" structure + * @param {number} signerIndex Index number (starting from 0) of signer index to make signature for + * @param {string} [hashAlgorithm="SHA-1"] Hashing algorithm. Default SHA-1 + * @param {ArrayBuffer} [data] Detached data + * @returns {*} + */ + sign(privateKey, signerIndex, hashAlgorithm = "SHA-1", data = (new ArrayBuffer(0))) + { + //region Initial checking + if(typeof privateKey === "undefined") + return Promise.reject("Need to provide a private key for signing"); + //endregion + + //region Initial variables + let sequence = Promise.resolve(); + let parameters; + + const engine = getEngine(); + //endregion + + //region Simple check for supported algorithm + const hashAlgorithmOID = getOIDByAlgorithm({ name: hashAlgorithm }); + if(hashAlgorithmOID === "") + return Promise.reject(`Unsupported hash algorithm: ${hashAlgorithm}`); + //endregion + + //region Append information about hash algorithm + if((this.digestAlgorithms.filter(algorithm => algorithm.algorithmId === hashAlgorithmOID)).length === 0) + { + this.digestAlgorithms.push(new AlgorithmIdentifier({ + algorithmId: hashAlgorithmOID, + algorithmParams: new asn1js.Null() + })); + } + + this.signerInfos[signerIndex].digestAlgorithm = new AlgorithmIdentifier({ + algorithmId: hashAlgorithmOID, + algorithmParams: new asn1js.Null() + }); + //endregion + + //region Get a "default parameters" for current algorithm and set correct signature algorithm + sequence = sequence.then(() => engine.subtle.getSignatureParameters(privateKey, hashAlgorithm)); + + sequence = sequence.then(result => + { + parameters = result.parameters; + this.signerInfos[signerIndex].signatureAlgorithm = result.signatureAlgorithm; + }); + //endregion + + //region Create TBS data for signing + sequence = sequence.then(() => + { + if("signedAttrs" in this.signerInfos[signerIndex]) + { + if(this.signerInfos[signerIndex].signedAttrs.encodedValue.byteLength !== 0) + data = this.signerInfos[signerIndex].signedAttrs.encodedValue; + else + { + data = this.signerInfos[signerIndex].signedAttrs.toSchema(true).toBER(false); + + //region Change type from "[0]" to "SET" acordingly to standard + const view = new Uint8Array(data); + view[0] = 0x31; + //endregion + } + } + else + { + if("eContent" in this.encapContentInfo) // Attached data + { + if((this.encapContentInfo.eContent.idBlock.tagClass === 1) && + (this.encapContentInfo.eContent.idBlock.tagNumber === 4)) + { + if(this.encapContentInfo.eContent.idBlock.isConstructed === false) + data = this.encapContentInfo.eContent.valueBlock.valueHex; + else + { + for(const content of this.encapContentInfo.eContent.valueBlock.value) + data = utilConcatBuf(data, content.valueBlock.valueHex); + } + } + else + data = this.encapContentInfo.eContent.valueBlock.valueBeforeDecode; + } + else // Detached data + { + if(data.byteLength === 0) // Check that "data" already provided by function parameter + return Promise.reject("Missed detached data input array"); + } + } + + return Promise.resolve(); + }); + //endregion + + //region Signing TBS data on provided private key + sequence = sequence.then(() => engine.subtle.signWithPrivateKey(data, privateKey, parameters)); + + sequence = sequence.then(result => + { + this.signerInfos[signerIndex].signature = new asn1js.OctetString({ valueHex: result }); + + return result; + }); + //endregion + + return sequence; + } + //********************************************************************************** +} +//************************************************************************************** diff --git a/core/third-party/pkijs/SignerInfo.js b/core/third-party/pkijs/SignerInfo.js new file mode 100644 index 0000000..d4b2bad --- /dev/null +++ b/core/third-party/pkijs/SignerInfo.js @@ -0,0 +1,347 @@ +import * as asn1js from "./asn1.js"; +import { getParametersValue, clearProps } from "./pvutils.js"; +import AlgorithmIdentifier from "./AlgorithmIdentifier.js"; +import SignedAndUnsignedAttributes from "./SignedAndUnsignedAttributes.js"; +import IssuerAndSerialNumber from "./IssuerAndSerialNumber.js"; +//************************************************************************************** +/** + * Class from RFC5652 + */ +export default class SignerInfo +{ + //********************************************************************************** + /** + * Constructor for SignerInfo class + * @param {Object} [parameters={}] + * @param {Object} [parameters.schema] asn1js parsed value to initialize the class from + */ + constructor(parameters = {}) + { + //region Internal properties of the object + /** + * @type {string} + * @desc version + */ + this.version = getParametersValue(parameters, "version", SignerInfo.defaultValues("version")); + /** + * @type {Object} + * @desc sid + */ + this.sid = getParametersValue(parameters, "sid", SignerInfo.defaultValues("sid")); + /** + * @type {AlgorithmIdentifier} + * @desc digestAlgorithm + */ + this.digestAlgorithm = getParametersValue(parameters, "digestAlgorithm", SignerInfo.defaultValues("digestAlgorithm")); + + if("signedAttrs" in parameters) + /** + * @type {SignedAndUnsignedAttributes} + * @desc signedAttrs + */ + this.signedAttrs = getParametersValue(parameters, "signedAttrs", SignerInfo.defaultValues("signedAttrs")); + + /** + * @type {AlgorithmIdentifier} + * @desc digestAlgorithm + */ + this.signatureAlgorithm = getParametersValue(parameters, "signatureAlgorithm", SignerInfo.defaultValues("signatureAlgorithm")); + /** + * @type {OctetString} + * @desc signature + */ + this.signature = getParametersValue(parameters, "signature", SignerInfo.defaultValues("signature")); + + if("unsignedAttrs" in parameters) + /** + * @type {SignedAndUnsignedAttributes} + * @desc unsignedAttrs + */ + this.unsignedAttrs = getParametersValue(parameters, "unsignedAttrs", SignerInfo.defaultValues("unsignedAttrs")); + //endregion + + //region If input argument array contains "schema" for this object + if("schema" in parameters) + this.fromSchema(parameters.schema); + //endregion + } + //********************************************************************************** + /** + * Return default values for all class members + * @param {string} memberName String name for a class member + */ + static defaultValues(memberName) + { + switch(memberName) + { + case "version": + return 0; + case "sid": + return new asn1js.Any(); + case "digestAlgorithm": + return new AlgorithmIdentifier(); + case "signedAttrs": + return new SignedAndUnsignedAttributes({ type: 0 }); + case "signatureAlgorithm": + return new AlgorithmIdentifier(); + case "signature": + return new asn1js.OctetString(); + case "unsignedAttrs": + return new SignedAndUnsignedAttributes({ type: 1 }); + default: + throw new Error(`Invalid member name for SignerInfo class: ${memberName}`); + } + } + //********************************************************************************** + /** + * Compare values with default values for all class members + * @param {string} memberName String name for a class member + * @param {*} memberValue Value to compare with default value + */ + static compareWithDefault(memberName, memberValue) + { + switch(memberName) + { + case "version": + return (SignerInfo.defaultValues("version") === memberValue); + case "sid": + return (memberValue instanceof asn1js.Any); + case "digestAlgorithm": + if((memberValue instanceof AlgorithmIdentifier) === false) + return false; + + return memberValue.isEqual(SignerInfo.defaultValues("digestAlgorithm")); + case "signedAttrs": + return ((SignedAndUnsignedAttributes.compareWithDefault("type", memberValue.type)) + && (SignedAndUnsignedAttributes.compareWithDefault("attributes", memberValue.attributes)) + && (SignedAndUnsignedAttributes.compareWithDefault("encodedValue", memberValue.encodedValue))); + case "signatureAlgorithm": + if((memberValue instanceof AlgorithmIdentifier) === false) + return false; + + return memberValue.isEqual(SignerInfo.defaultValues("signatureAlgorithm")); + case "signature": + case "unsignedAttrs": + return ((SignedAndUnsignedAttributes.compareWithDefault("type", memberValue.type)) + && (SignedAndUnsignedAttributes.compareWithDefault("attributes", memberValue.attributes)) + && (SignedAndUnsignedAttributes.compareWithDefault("encodedValue", memberValue.encodedValue))); + default: + throw new Error(`Invalid member name for SignerInfo class: ${memberName}`); + } + } + //********************************************************************************** + /** + * Return value of pre-defined ASN.1 schema for current class + * + * ASN.1 schema: + * ```asn1 + * SignerInfo ::= SEQUENCE { + * version CMSVersion, + * sid SignerIdentifier, + * digestAlgorithm DigestAlgorithmIdentifier, + * signedAttrs [0] IMPLICIT SignedAttributes OPTIONAL, + * signatureAlgorithm SignatureAlgorithmIdentifier, + * signature SignatureValue, + * unsignedAttrs [1] IMPLICIT UnsignedAttributes OPTIONAL } + * + * SignerIdentifier ::= CHOICE { + * issuerAndSerialNumber IssuerAndSerialNumber, + * subjectKeyIdentifier [0] SubjectKeyIdentifier } + * + * SubjectKeyIdentifier ::= OCTET STRING + * ``` + * + * @param {Object} parameters Input parameters for the schema + * @returns {Object} asn1js schema object + */ + static schema(parameters = {}) + { + + /** + * @type {Object} + * @property {string} [blockName] + * @property {string} [version] + * @property {string} [sid] + * @property {string} [digestAlgorithm] + * @property {string} [signedAttrs] + * @property {string} [signatureAlgorithm] + * @property {string} [signature] + * @property {string} [unsignedAttrs] + */ + const names = getParametersValue(parameters, "names", {}); + + return ( + new asn1js.Sequence({ + name: "SignerInfo", + value: [ + new asn1js.Integer({ name: (names.version || "SignerInfo.version") }), + new asn1js.Choice({ + value: [ + IssuerAndSerialNumber.schema(names.sid || { + names: { + blockName: "SignerInfo.sid" + } + }), + new asn1js.Constructed({ + optional: true, + name: (names.sid || "SignerInfo.sid"), + idBlock: { + tagClass: 3, // CONTEXT-SPECIFIC + tagNumber: 0 // [0] + }, + value: [new asn1js.OctetString()] + }) + ] + }), + AlgorithmIdentifier.schema(names.digestAlgorithm || { + names: { + blockName: "SignerInfo.digestAlgorithm" + } + }), + SignedAndUnsignedAttributes.schema(names.signedAttrs || { + names: { + blockName: "SignerInfo.signedAttrs", + tagNumber: 0 + } + }), + AlgorithmIdentifier.schema(names.signatureAlgorithm || { + names: { + blockName: "SignerInfo.signatureAlgorithm" + } + }), + new asn1js.OctetString({ name: (names.signature || "SignerInfo.signature") }), + SignedAndUnsignedAttributes.schema(names.unsignedAttrs || { + names: { + blockName: "SignerInfo.unsignedAttrs", + tagNumber: 1 + } + }) + ] + }) + ); + } + //********************************************************************************** + /** + * Convert parsed asn1js object into current class + * @param {!Object} schema + */ + fromSchema(schema) + { + //region Clear input data first + clearProps(schema, [ + "SignerInfo.version", + "SignerInfo.sid", + "SignerInfo.digestAlgorithm", + "SignerInfo.signedAttrs", + "SignerInfo.signatureAlgorithm", + "SignerInfo.signature", + "SignerInfo.unsignedAttrs" + ]); + //endregion + + //region Check the schema is valid + const asn1 = asn1js.compareSchema(schema, + schema, + SignerInfo.schema() + ); + + if(asn1.verified === false) + throw new Error("Object's schema was not verified against input data for SignerInfo"); + //endregion + + //region Get internal properties from parsed schema + this.version = asn1.result["SignerInfo.version"].valueBlock.valueDec; + + const currentSid = asn1.result["SignerInfo.sid"]; + if(currentSid.idBlock.tagClass === 1) + this.sid = new IssuerAndSerialNumber({ schema: currentSid }); + else + this.sid = currentSid; + + this.digestAlgorithm = new AlgorithmIdentifier({ schema: asn1.result["SignerInfo.digestAlgorithm"] }); + if("SignerInfo.signedAttrs" in asn1.result) + this.signedAttrs = new SignedAndUnsignedAttributes({ type: 0, schema: asn1.result["SignerInfo.signedAttrs"] }); + + this.signatureAlgorithm = new AlgorithmIdentifier({ schema: asn1.result["SignerInfo.signatureAlgorithm"] }); + this.signature = asn1.result["SignerInfo.signature"]; + if("SignerInfo.unsignedAttrs" in asn1.result) + this.unsignedAttrs = new SignedAndUnsignedAttributes({ type: 1, schema: asn1.result["SignerInfo.unsignedAttrs"] }); + //endregion + } + //********************************************************************************** + /** + * Convert current object to asn1js object and set correct values + * @returns {Object} asn1js object + */ + toSchema() + { + if(SignerInfo.compareWithDefault("sid", this.sid)) + throw new Error("Incorrectly initialized \"SignerInfo\" class"); + + //region Create array for output sequence + const outputArray = []; + + outputArray.push(new asn1js.Integer({ value: this.version })); + + if(this.sid instanceof IssuerAndSerialNumber) + outputArray.push(this.sid.toSchema()); + else + outputArray.push(this.sid); + + outputArray.push(this.digestAlgorithm.toSchema()); + + if("signedAttrs" in this) + { + if(SignerInfo.compareWithDefault("signedAttrs", this.signedAttrs) === false) + outputArray.push(this.signedAttrs.toSchema()); + } + + outputArray.push(this.signatureAlgorithm.toSchema()); + outputArray.push(this.signature); + + if("unsignedAttrs" in this) + { + if(SignerInfo.compareWithDefault("unsignedAttrs", this.unsignedAttrs) === false) + outputArray.push(this.unsignedAttrs.toSchema()); + } + //endregion + + //region Construct and return new ASN.1 schema for this object + return (new asn1js.Sequence({ + value: outputArray + })); + //endregion + } + //********************************************************************************** + /** + * Convertion for the class to JSON object + * @returns {Object} + */ + toJSON() + { + if(SignerInfo.compareWithDefault("sid", this.sid)) + throw new Error("Incorrectly initialized \"SignerInfo\" class"); + + const _object = { + version: this.version + }; + + if(!(this.sid instanceof asn1js.Any)) + _object.sid = this.sid.toJSON(); + + _object.digestAlgorithm = this.digestAlgorithm.toJSON(); + + if(SignerInfo.compareWithDefault("signedAttrs", this.signedAttrs) === false) + _object.signedAttrs = this.signedAttrs.toJSON(); + + _object.signatureAlgorithm = this.signatureAlgorithm.toJSON(); + _object.signature = this.signature.toJSON(); + + if(SignerInfo.compareWithDefault("unsignedAttrs", this.unsignedAttrs) === false) + _object.unsignedAttrs = this.unsignedAttrs.toJSON(); + + return _object; + } + //********************************************************************************** +} +//************************************************************************************** diff --git a/core/third-party/pkijs/SingleResponse.js b/core/third-party/pkijs/SingleResponse.js new file mode 100644 index 0000000..587e7f6 --- /dev/null +++ b/core/third-party/pkijs/SingleResponse.js @@ -0,0 +1,323 @@ +import * as asn1js from "./asn1.js"; +import { getParametersValue, clearProps } from "./pvutils.js"; +import CertID from "./CertID.js"; +import Extension from "./Extension.js"; +import Extensions from "./Extensions.js"; +//************************************************************************************** +/** + * Class from RFC6960 + */ +export default class SingleResponse +{ + //********************************************************************************** + /** + * Constructor for SingleResponse class + * @param {Object} [parameters={}] + * @param {Object} [parameters.schema] asn1js parsed value to initialize the class from + */ + constructor(parameters = {}) + { + //region Internal properties of the object + /** + * @type {CertID} + * @desc certID + */ + this.certID = getParametersValue(parameters, "certID", SingleResponse.defaultValues("certID")); + /** + * @type {Object} + * @desc certStatus + */ + this.certStatus = getParametersValue(parameters, "certStatus", SingleResponse.defaultValues("certStatus")); + /** + * @type {Date} + * @desc thisUpdate + */ + this.thisUpdate = getParametersValue(parameters, "thisUpdate", SingleResponse.defaultValues("thisUpdate")); + + if("nextUpdate" in parameters) + /** + * @type {Date} + * @desc nextUpdate + */ + this.nextUpdate = getParametersValue(parameters, "nextUpdate", SingleResponse.defaultValues("nextUpdate")); + + if("singleExtensions" in parameters) + /** + * @type {Array.} + * @desc singleExtensions + */ + this.singleExtensions = getParametersValue(parameters, "singleExtensions", SingleResponse.defaultValues("singleExtensions")); + //endregion + + //region If input argument array contains "schema" for this object + if("schema" in parameters) + this.fromSchema(parameters.schema); + //endregion + } + //********************************************************************************** + /** + * Return default values for all class members + * @param {string} memberName String name for a class member + */ + static defaultValues(memberName) + { + switch(memberName) + { + case "certID": + return new CertID(); + case "certStatus": + return {}; + case "thisUpdate": + case "nextUpdate": + return new Date(0, 0, 0); + case "singleExtensions": + return []; + default: + throw new Error(`Invalid member name for SingleResponse class: ${memberName}`); + } + } + //********************************************************************************** + /** + * Compare values with default values for all class members + * @param {string} memberName String name for a class member + * @param {*} memberValue Value to compare with default value + */ + static compareWithDefault(memberName, memberValue) + { + switch(memberName) + { + case "certID": + // noinspection OverlyComplexBooleanExpressionJS + return ((CertID.compareWithDefault("hashAlgorithm", memberValue.hashAlgorithm)) && + (CertID.compareWithDefault("issuerNameHash", memberValue.issuerNameHash)) && + (CertID.compareWithDefault("issuerKeyHash", memberValue.issuerKeyHash)) && + (CertID.compareWithDefault("serialNumber", memberValue.serialNumber))); + case "certStatus": + return (Object.keys(memberValue).length === 0); + case "thisUpdate": + case "nextUpdate": + return (memberValue === SingleResponse.defaultValues(memberName)); + default: + throw new Error(`Invalid member name for SingleResponse class: ${memberName}`); + } + } + //********************************************************************************** + /** + * Return value of pre-defined ASN.1 schema for current class + * + * ASN.1 schema: + * ```asn1 + * SingleResponse ::= SEQUENCE { + * certID CertID, + * certStatus CertStatus, + * thisUpdate GeneralizedTime, + * nextUpdate [0] EXPLICIT GeneralizedTime OPTIONAL, + * singleExtensions [1] EXPLICIT Extensions OPTIONAL } + * + * CertStatus ::= CHOICE { + * good [0] IMPLICIT NULL, + * revoked [1] IMPLICIT RevokedInfo, + * unknown [2] IMPLICIT UnknownInfo } + * + * RevokedInfo ::= SEQUENCE { + * revocationTime GeneralizedTime, + * revocationReason [0] EXPLICIT CRLReason OPTIONAL } + * + * UnknownInfo ::= NULL + * ``` + * + * @param {Object} parameters Input parameters for the schema + * @returns {Object} asn1js schema object + */ + static schema(parameters = {}) + { + /** + * @type {Object} + * @property {string} [blockName] + * @property {string} [certID] + * @property {string} [certStatus] + * @property {string} [thisUpdate] + * @property {string} [nextUpdate] + * @property {string} [singleExtensions] + */ + const names = getParametersValue(parameters, "names", {}); + + return (new asn1js.Sequence({ + name: (names.blockName || ""), + value: [ + CertID.schema(names.certID || {}), + new asn1js.Choice({ + value: [ + new asn1js.Primitive({ + name: (names.certStatus || ""), + idBlock: { + tagClass: 3, // CONTEXT-SPECIFIC + tagNumber: 0 // [0] + }, + lenBlockLength: 1 // The length contains one byte 0x00 + }), // IMPLICIT NULL (no "valueBlock") + new asn1js.Constructed({ + name: (names.certStatus || ""), + idBlock: { + tagClass: 3, // CONTEXT-SPECIFIC + tagNumber: 1 // [1] + }, + value: [ + new asn1js.GeneralizedTime(), + new asn1js.Constructed({ + optional: true, + idBlock: { + tagClass: 3, // CONTEXT-SPECIFIC + tagNumber: 0 // [0] + }, + value: [new asn1js.Enumerated()] + }) + ] + }), + new asn1js.Primitive({ + name: (names.certStatus || ""), + idBlock: { + tagClass: 3, // CONTEXT-SPECIFIC + tagNumber: 2 // [2] + }, + lenBlock: { length: 1 } + }) // IMPLICIT NULL (no "valueBlock") + ] + }), + new asn1js.GeneralizedTime({ name: (names.thisUpdate || "") }), + new asn1js.Constructed({ + optional: true, + idBlock: { + tagClass: 3, // CONTEXT-SPECIFIC + tagNumber: 0 // [0] + }, + value: [new asn1js.GeneralizedTime({ name: (names.nextUpdate || "") })] + }), + new asn1js.Constructed({ + optional: true, + idBlock: { + tagClass: 3, // CONTEXT-SPECIFIC + tagNumber: 1 // [1] + }, + value: [Extensions.schema(names.singleExtensions || {})] + }) // EXPLICIT SEQUENCE value + ] + })); + } + //********************************************************************************** + /** + * Convert parsed asn1js object into current class + * @param {!Object} schema + */ + fromSchema(schema) + { + //region Clear input data first + clearProps(schema, [ + "certID", + "certStatus", + "thisUpdate", + "nextUpdate", + "singleExtensions" + ]); + //endregion + + //region Check the schema is valid + const asn1 = asn1js.compareSchema(schema, + schema, + SingleResponse.schema({ + names: { + certID: { + names: { + blockName: "certID" + } + }, + certStatus: "certStatus", + thisUpdate: "thisUpdate", + nextUpdate: "nextUpdate", + singleExtensions: { + names: { + blockName: + "singleExtensions" + } + } + } + }) + ); + + if(asn1.verified === false) + throw new Error("Object's schema was not verified against input data for SingleResponse"); + //endregion + + //region Get internal properties from parsed schema + this.certID = new CertID({ schema: asn1.result.certID }); + this.certStatus = asn1.result.certStatus; + this.thisUpdate = asn1.result.thisUpdate.toDate(); + if("nextUpdate" in asn1.result) + this.nextUpdate = asn1.result.nextUpdate.toDate(); + + if("singleExtensions" in asn1.result) + this.singleExtensions = Array.from(asn1.result.singleExtensions.valueBlock.value, element => new Extension({ schema: element })); + //endregion + } + //********************************************************************************** + /** + * Convert current object to asn1js object and set correct values + * @returns {Object} asn1js object + */ + toSchema() + { + //region Create value array for output sequence + const outputArray = []; + + outputArray.push(this.certID.toSchema()); + outputArray.push(this.certStatus); + outputArray.push(new asn1js.GeneralizedTime({ valueDate: this.thisUpdate })); + if("nextUpdate" in this) + { + outputArray.push(new asn1js.Constructed({ + idBlock: { + tagClass: 3, // CONTEXT-SPECIFIC + tagNumber: 0 // [0] + }, + value: [new asn1js.GeneralizedTime({ valueDate: this.nextUpdate })] + })); + } + + if("singleExtensions" in this) + { + outputArray.push(new asn1js.Sequence({ + value: Array.from(this.singleExtensions, element => element.toSchema()) + })); + } + //endregion + + //region Construct and return new ASN.1 schema for this object + return (new asn1js.Sequence({ + value: outputArray + })); + //endregion + } + //********************************************************************************** + /** + * Convertion for the class to JSON object + * @returns {Object} + */ + toJSON() + { + const _object = { + certID: this.certID.toJSON(), + certStatus: this.certStatus.toJSON(), + thisUpdate: this.thisUpdate + }; + + if("nextUpdate" in this) + _object.nextUpdate = this.nextUpdate; + + if("singleExtensions" in this) + _object.singleExtensions = Array.from(this.singleExtensions, element => element.toJSON()); + + return _object; + } + //********************************************************************************** +} +//************************************************************************************** diff --git a/core/third-party/pkijs/SubjectDirectoryAttributes.js b/core/third-party/pkijs/SubjectDirectoryAttributes.js new file mode 100644 index 0000000..d1d9887 --- /dev/null +++ b/core/third-party/pkijs/SubjectDirectoryAttributes.js @@ -0,0 +1,135 @@ +import * as asn1js from "./asn1.js"; +import { getParametersValue, clearProps } from "./pvutils.js"; +import Attribute from "./Attribute.js"; +//************************************************************************************** +/** + * Class from RFC5280 + */ +export default class SubjectDirectoryAttributes +{ + //********************************************************************************** + /** + * Constructor for SubjectDirectoryAttributes class + * @param {Object} [parameters={}] + * @param {Object} [parameters.schema] asn1js parsed value to initialize the class from + */ + constructor(parameters = {}) + { + //region Internal properties of the object + /** + * @type {Array.} + * @desc attributes + */ + this.attributes = getParametersValue(parameters, "attributes", SubjectDirectoryAttributes.defaultValues("attributes")); + //endregion + + //region If input argument array contains "schema" for this object + if("schema" in parameters) + this.fromSchema(parameters.schema); + //endregion + } + //********************************************************************************** + /** + * Return default values for all class members + * @param {string} memberName String name for a class member + */ + static defaultValues(memberName) + { + switch(memberName) + { + case "attributes": + return []; + default: + throw new Error(`Invalid member name for SubjectDirectoryAttributes class: ${memberName}`); + } + } + //********************************************************************************** + /** + * Return value of pre-defined ASN.1 schema for current class + * + * ASN.1 schema: + * ```asn1 + * SubjectDirectoryAttributes ::= SEQUENCE SIZE (1..MAX) OF Attribute + * ``` + * + * @param {Object} parameters Input parameters for the schema + * @returns {Object} asn1js schema object + */ + static schema(parameters = {}) + { + /** + * @type {Object} + * @property {string} [blockName] + * @property {string} [utcTimeName] Name for "utcTimeName" choice + * @property {string} [generalTimeName] Name for "generalTimeName" choice + */ + const names = getParametersValue(parameters, "names", {}); + + return (new asn1js.Sequence({ + name: (names.blockName || ""), + value: [ + new asn1js.Repeated({ + name: (names.attributes || ""), + value: Attribute.schema() + }) + ] + })); + } + //********************************************************************************** + /** + * Convert parsed asn1js object into current class + * @param {!Object} schema + */ + fromSchema(schema) + { + //region Clear input data first + clearProps(schema, [ + "attributes" + ]); + //endregion + + //region Check the schema is valid + const asn1 = asn1js.compareSchema(schema, + schema, + SubjectDirectoryAttributes.schema({ + names: { + attributes: "attributes" + } + }) + ); + + if(asn1.verified === false) + throw new Error("Object's schema was not verified against input data for SubjectDirectoryAttributes"); + //endregion + + //region Get internal properties from parsed schema + this.attributes = Array.from(asn1.result.attributes, element => new Attribute({ schema: element })); + //endregion + } + //********************************************************************************** + /** + * Convert current object to asn1js object and set correct values + * @returns {Object} asn1js object + */ + toSchema() + { + //region Construct and return new ASN.1 schema for this object + return (new asn1js.Sequence({ + value: Array.from(this.attributes, element => element.toSchema()) + })); + //endregion + } + //********************************************************************************** + /** + * Convertion for the class to JSON object + * @returns {Object} + */ + toJSON() + { + return { + attributes: Array.from(this.attributes, element => element.toJSON()) + }; + } + //********************************************************************************** +} +//************************************************************************************** diff --git a/core/third-party/pkijs/TBSRequest.js b/core/third-party/pkijs/TBSRequest.js new file mode 100644 index 0000000..c008ef9 --- /dev/null +++ b/core/third-party/pkijs/TBSRequest.js @@ -0,0 +1,324 @@ +import * as asn1js from "./asn1.js"; +import { getParametersValue, clearProps } from "./pvutils.js"; +import GeneralName from "./GeneralName.js"; +import Request from "./Request.js"; +import Extension from "./Extension.js"; +import Extensions from "./Extensions.js"; +//************************************************************************************** +/** + * Class from RFC6960 + */ +export default class TBSRequest +{ + //********************************************************************************** + /** + * Constructor for TBSRequest class + * @param {Object} [parameters={}] + * @param {Object} [parameters.schema] asn1js parsed value to initialize the class from + */ + constructor(parameters = {}) + { + //region Internal properties of the object + /** + * @type {ArrayBuffer} + * @desc tbs + */ + this.tbs = getParametersValue(parameters, "tbs", TBSRequest.defaultValues("tbs")); + + if("version" in parameters) + /** + * @type {number} + * @desc version + */ + this.version = getParametersValue(parameters, "version", TBSRequest.defaultValues("version")); + + if("requestorName" in parameters) + /** + * @type {GeneralName} + * @desc requestorName + */ + this.requestorName = getParametersValue(parameters, "requestorName", TBSRequest.defaultValues("requestorName")); + + /** + * @type {Array.} + * @desc requestList + */ + this.requestList = getParametersValue(parameters, "requestList", TBSRequest.defaultValues("requestList")); + + if("requestExtensions" in parameters) + /** + * @type {Array.} + * @desc requestExtensions + */ + this.requestExtensions = getParametersValue(parameters, "requestExtensions", TBSRequest.defaultValues("requestExtensions")); + //endregion + + //region If input argument array contains "schema" for this object + if("schema" in parameters) + this.fromSchema(parameters.schema); + //endregion + } + //********************************************************************************** + /** + * Return default values for all class members + * @param {string} memberName String name for a class member + */ + static defaultValues(memberName) + { + switch(memberName) + { + case "tbs": + return new ArrayBuffer(0); + case "version": + return 0; + case "requestorName": + return new GeneralName(); + case "requestList": + case "requestExtensions": + return []; + default: + throw new Error(`Invalid member name for TBSRequest class: ${memberName}`); + } + } + //********************************************************************************** + /** + * Compare values with default values for all class members + * @param {string} memberName String name for a class member + * @param {*} memberValue Value to compare with default value + */ + static compareWithDefault(memberName, memberValue) + { + switch(memberName) + { + case "tbs": + return (memberValue.byteLength === 0); + case "version": + return (memberValue === TBSRequest.defaultValues(memberName)); + case "requestorName": + return ((memberValue.type === GeneralName.defaultValues("type")) && (Object.keys(memberValue.value).length === 0)); + case "requestList": + case "requestExtensions": + return (memberValue.length === 0); + default: + throw new Error(`Invalid member name for TBSRequest class: ${memberName}`); + } + } + //********************************************************************************** + /** + * Return value of pre-defined ASN.1 schema for current class + * + * ASN.1 schema: + * ```asn1 + * TBSRequest ::= SEQUENCE { + * version [0] EXPLICIT Version DEFAULT v1, + * requestorName [1] EXPLICIT GeneralName OPTIONAL, + * requestList SEQUENCE OF Request, + * requestExtensions [2] EXPLICIT Extensions OPTIONAL } + * ``` + * + * @param {Object} parameters Input parameters for the schema + * @returns {Object} asn1js schema object + */ + static schema(parameters = {}) + { + /** + * @type {Object} + * @property {string} [blockName] + * @property {string} [TBSRequestVersion] + * @property {string} [requestorName] + * @property {string} [requestList] + * @property {string} [requests] + * @property {string} [requestNames] + * @property {string} [extensions] + * @property {string} [requestExtensions] + */ + const names = getParametersValue(parameters, "names", {}); + + return (new asn1js.Sequence({ + name: (names.blockName || "TBSRequest"), + value: [ + new asn1js.Constructed({ + optional: true, + idBlock: { + tagClass: 3, // CONTEXT-SPECIFIC + tagNumber: 0 // [0] + }, + value: [new asn1js.Integer({ name: (names.TBSRequestVersion || "TBSRequest.version") })] + }), + new asn1js.Constructed({ + optional: true, + idBlock: { + tagClass: 3, // CONTEXT-SPECIFIC + tagNumber: 1 // [1] + }, + value: [GeneralName.schema(names.requestorName || { + names: { + blockName: "TBSRequest.requestorName" + } + })] + }), + new asn1js.Sequence({ + name: (names.requestList || "TBSRequest.requestList"), + value: [ + new asn1js.Repeated({ + name: (names.requests || "TBSRequest.requests"), + value: Request.schema(names.requestNames || {}) + }) + ] + }), + new asn1js.Constructed({ + optional: true, + idBlock: { + tagClass: 3, // CONTEXT-SPECIFIC + tagNumber: 2 // [2] + }, + value: [Extensions.schema(names.extensions || { + names: { + blockName: (names.requestExtensions || "TBSRequest.requestExtensions") + } + })] + }) + ] + })); + } + //********************************************************************************** + /** + * Convert parsed asn1js object into current class + * @param {!Object} schema + */ + fromSchema(schema) + { + //region Clear input data first + clearProps(schema, [ + "TBSRequest", + "TBSRequest.version", + "TBSRequest.requestorName", + "TBSRequest.requests", + "TBSRequest.requestExtensions" + ]); + //endregion + + //region Check the schema is valid + const asn1 = asn1js.compareSchema(schema, + schema, + TBSRequest.schema() + ); + + if(asn1.verified === false) + throw new Error("Object's schema was not verified against input data for TBSRequest"); + //endregion + + //region Get internal properties from parsed schema + this.tbs = asn1.result.TBSRequest.valueBeforeDecode; + + if("TBSRequest.version" in asn1.result) + this.version = asn1.result["TBSRequest.version"].valueBlock.valueDec; + if("TBSRequest.requestorName" in asn1.result) + this.requestorName = new GeneralName({ schema: asn1.result["TBSRequest.requestorName"] }); + + this.requestList = Array.from(asn1.result["TBSRequest.requests"], element => new Request({ schema: element })); + + if("TBSRequest.requestExtensions" in asn1.result) + this.requestExtensions = Array.from(asn1.result["TBSRequest.requestExtensions"].valueBlock.value, element => new Extension({ schema: element })); + //endregion + } + //********************************************************************************** + /** + * Convert current object to asn1js object and set correct values + * @param {boolean} encodeFlag If param equal to false then create TBS schema via decoding stored value. In othe case create TBS schema via assembling from TBS parts. + * @returns {Object} asn1js object + */ + toSchema(encodeFlag = false) + { + //region Decode stored TBS value + let tbsSchema; + + if(encodeFlag === false) + { + if(this.tbs.byteLength === 0) // No stored TBS part + return TBSRequest.schema(); + + tbsSchema = asn1js.fromBER(this.tbs).result; + } + //endregion + //region Create TBS schema via assembling from TBS parts + else + { + const outputArray = []; + + if("version" in this) + { + outputArray.push(new asn1js.Constructed({ + idBlock: { + tagClass: 3, // CONTEXT-SPECIFIC + tagNumber: 0 // [0] + }, + value: [new asn1js.Integer({ value: this.version })] + })); + } + + if("requestorName" in this) + { + outputArray.push(new asn1js.Constructed({ + idBlock: { + tagClass: 3, // CONTEXT-SPECIFIC + tagNumber: 1 // [1] + }, + value: [this.requestorName.toSchema()] + })); + } + + outputArray.push(new asn1js.Sequence({ + value: Array.from(this.requestList, element => element.toSchema()) + })); + + if("requestExtensions" in this) + { + outputArray.push(new asn1js.Constructed({ + idBlock: { + tagClass: 3, // CONTEXT-SPECIFIC + tagNumber: 2 // [2] + }, + value: [ + new asn1js.Sequence({ + value: Array.from(this.requestExtensions, element => element.toSchema()) + }) + ] + })); + } + + tbsSchema = new asn1js.Sequence({ + value: outputArray + }); + } + //endregion + + //region Construct and return new ASN.1 schema for this object + return tbsSchema; + //endregion + } + //********************************************************************************** + /** + * Convertion for the class to JSON object + * @returns {Object} + */ + toJSON() + { + const _object = {}; + + if("version" in this) + _object.version = this.version; + + if("requestorName" in this) + _object.requestorName = this.requestorName.toJSON(); + + _object.requestList = Array.from(this.requestList, element => element.toJSON()); + + if("requestExtensions" in this) + _object.requestExtensions = Array.from(this.requestExtensions, element => element.toJSON()); + + return _object; + } + //********************************************************************************** +} +//************************************************************************************** diff --git a/core/third-party/pkijs/TSTInfo.js b/core/third-party/pkijs/TSTInfo.js new file mode 100644 index 0000000..c5795d2 --- /dev/null +++ b/core/third-party/pkijs/TSTInfo.js @@ -0,0 +1,455 @@ +import * as asn1js from "./asn1.js"; +import { getParametersValue, isEqualBuffer, clearProps } from "./pvutils.js"; +import { getCrypto, getAlgorithmByOID } from "./common.js"; +import MessageImprint from "./MessageImprint.js"; +import Accuracy from "./Accuracy.js"; +import GeneralName from "./GeneralName.js"; +import Extension from "./Extension.js"; +//************************************************************************************** +/** + * Class from RFC3161 + */ +export default class TSTInfo +{ + //********************************************************************************** + /** + * Constructor for TSTInfo class + * @param {Object} [parameters={}] + * @param {Object} [parameters.schema] asn1js parsed value to initialize the class from + */ + constructor(parameters = {}) + { + //region Internal properties of the object + /** + * @type {number} + * @desc version + */ + this.version = getParametersValue(parameters, "version", TSTInfo.defaultValues("version")); + /** + * @type {string} + * @desc policy + */ + this.policy = getParametersValue(parameters, "policy", TSTInfo.defaultValues("policy")); + /** + * @type {MessageImprint} + * @desc messageImprint + */ + this.messageImprint = getParametersValue(parameters, "messageImprint", TSTInfo.defaultValues("messageImprint")); + /** + * @type {Integer} + * @desc serialNumber + */ + this.serialNumber = getParametersValue(parameters, "serialNumber", TSTInfo.defaultValues("serialNumber")); + /** + * @type {Date} + * @desc genTime + */ + this.genTime = getParametersValue(parameters, "genTime", TSTInfo.defaultValues("genTime")); + + if("accuracy" in parameters) + /** + * @type {Accuracy} + * @desc accuracy + */ + this.accuracy = getParametersValue(parameters, "accuracy", TSTInfo.defaultValues("accuracy")); + + if("ordering" in parameters) + /** + * @type {boolean} + * @desc ordering + */ + this.ordering = getParametersValue(parameters, "ordering", TSTInfo.defaultValues("ordering")); + + if("nonce" in parameters) + /** + * @type {Integer} + * @desc nonce + */ + this.nonce = getParametersValue(parameters, "nonce", TSTInfo.defaultValues("nonce")); + + if("tsa" in parameters) + /** + * @type {GeneralName} + * @desc tsa + */ + this.tsa = getParametersValue(parameters, "tsa", TSTInfo.defaultValues("tsa")); + + if("extensions" in parameters) + /** + * @type {Array.} + * @desc extensions + */ + this.extensions = getParametersValue(parameters, "extensions", TSTInfo.defaultValues("extensions")); + //endregion + + //region If input argument array contains "schema" for this object + if("schema" in parameters) + this.fromSchema(parameters.schema); + //endregion + } + //********************************************************************************** + /** + * Return default values for all class members + * @param {string} memberName String name for a class member + */ + static defaultValues(memberName) + { + switch(memberName) + { + case "version": + return 0; + case "policy": + return ""; + case "messageImprint": + return new MessageImprint(); + case "serialNumber": + return new asn1js.Integer(); + case "genTime": + return new Date(0, 0, 0); + case "accuracy": + return new Accuracy(); + case "ordering": + return false; + case "nonce": + return new asn1js.Integer(); + case "tsa": + return new GeneralName(); + case "extensions": + return []; + default: + throw new Error(`Invalid member name for TSTInfo class: ${memberName}`); + } + } + //********************************************************************************** + /** + * Compare values with default values for all class members + * @param {string} memberName String name for a class member + * @param {*} memberValue Value to compare with default value + */ + static compareWithDefault(memberName, memberValue) + { + switch(memberName) + { + case "version": + case "policy": + case "genTime": + case "ordering": + return (memberValue === TSTInfo.defaultValues(memberName)); + case "messageImprint": + return ((MessageImprint.compareWithDefault("hashAlgorithm", memberValue.hashAlgorithm)) && + (MessageImprint.compareWithDefault("hashedMessage", memberValue.hashedMessage))); + case "serialNumber": + case "nonce": + return (memberValue.isEqual(TSTInfo.defaultValues(memberName))); + case "accuracy": + return ((Accuracy.compareWithDefault("seconds", memberValue.seconds)) && + (Accuracy.compareWithDefault("millis", memberValue.millis)) && + (Accuracy.compareWithDefault("micros", memberValue.micros))); + case "tsa": + return ((GeneralName.compareWithDefault("type", memberValue.type)) && + (GeneralName.compareWithDefault("value", memberValue.value))); + case "extensions": + return (memberValue.length === 0); + default: + throw new Error(`Invalid member name for TSTInfo class: ${memberName}`); + } + } + //********************************************************************************** + /** + * Return value of pre-defined ASN.1 schema for current class + * + * ASN.1 schema: + * ```asn1 + * TSTInfo ::= SEQUENCE { + * version INTEGER { v1(1) }, + * policy TSAPolicyId, + * messageImprint MessageImprint, + * serialNumber INTEGER, + * genTime GeneralizedTime, + * accuracy Accuracy OPTIONAL, + * ordering BOOLEAN DEFAULT FALSE, + * nonce INTEGER OPTIONAL, + * tsa [0] GeneralName OPTIONAL, + * extensions [1] IMPLICIT Extensions OPTIONAL } + * ``` + * + * @param {Object} parameters Input parameters for the schema + * @returns {Object} asn1js schema object + */ + static schema(parameters = {}) + { + /** + * @type {Object} + * @property {string} [blockName] + * @property {string} [version] + * @property {string} [policy] + * @property {string} [messageImprint] + * @property {string} [serialNumber] + * @property {string} [genTime] + * @property {string} [accuracy] + * @property {string} [ordering] + * @property {string} [nonce] + * @property {string} [tsa] + * @property {string} [extensions] + */ + const names = getParametersValue(parameters, "names", {}); + + return (new asn1js.Sequence({ + name: (names.blockName || "TSTInfo"), + value: [ + new asn1js.Integer({ name: (names.version || "TSTInfo.version") }), + new asn1js.ObjectIdentifier({ name: (names.policy || "TSTInfo.policy") }), + MessageImprint.schema(names.messageImprint || { + names: { + blockName: "TSTInfo.messageImprint" + } + }), + new asn1js.Integer({ name: (names.serialNumber || "TSTInfo.serialNumber") }), + new asn1js.GeneralizedTime({ name: (names.genTime || "TSTInfo.genTime") }), + Accuracy.schema(names.accuracy || { + names: { + blockName: "TSTInfo.accuracy" + } + }), + new asn1js.Boolean({ + name: (names.ordering || "TSTInfo.ordering"), + optional: true + }), + new asn1js.Integer({ + name: (names.nonce || "TSTInfo.nonce"), + optional: true + }), + new asn1js.Constructed({ + optional: true, + idBlock: { + tagClass: 3, // CONTEXT-SPECIFIC + tagNumber: 0 // [0] + }, + value: [GeneralName.schema(names.tsa || { + names: { + blockName: "TSTInfo.tsa" + } + })] + }), + new asn1js.Constructed({ + optional: true, + idBlock: { + tagClass: 3, // CONTEXT-SPECIFIC + tagNumber: 1 // [1] + }, + value: [ + new asn1js.Repeated({ + name: (names.extensions || "TSTInfo.extensions"), + value: Extension.schema(names.extension || {}) + }) + ] + }) // IMPLICIT Extensions + ] + })); + } + //********************************************************************************** + /** + * Convert parsed asn1js object into current class + * @param {!Object} schema + */ + fromSchema(schema) + { + //region Clear input data first + clearProps(schema, [ + "TSTInfo.version", + "TSTInfo.policy", + "TSTInfo.messageImprint", + "TSTInfo.serialNumber", + "TSTInfo.genTime", + "TSTInfo.accuracy", + "TSTInfo.ordering", + "TSTInfo.nonce", + "TSTInfo.tsa", + "TSTInfo.extensions" + ]); + //endregion + + //region Check the schema is valid + const asn1 = asn1js.compareSchema(schema, + schema, + TSTInfo.schema() + ); + + if(asn1.verified === false) + throw new Error("Object's schema was not verified against input data for TSTInfo"); + //endregion + + //region Get internal properties from parsed schema + this.version = asn1.result["TSTInfo.version"].valueBlock.valueDec; + this.policy = asn1.result["TSTInfo.policy"].valueBlock.toString(); + this.messageImprint = new MessageImprint({ schema: asn1.result["TSTInfo.messageImprint"] }); + this.serialNumber = asn1.result["TSTInfo.serialNumber"]; + this.genTime = asn1.result["TSTInfo.genTime"].toDate(); + if("TSTInfo.accuracy" in asn1.result) + this.accuracy = new Accuracy({ schema: asn1.result["TSTInfo.accuracy"] }); + if("TSTInfo.ordering" in asn1.result) + this.ordering = asn1.result["TSTInfo.ordering"].valueBlock.value; + if("TSTInfo.nonce" in asn1.result) + this.nonce = asn1.result["TSTInfo.nonce"]; + if("TSTInfo.tsa" in asn1.result) + this.tsa = new GeneralName({ schema: asn1.result["TSTInfo.tsa"] }); + if("TSTInfo.extensions" in asn1.result) + this.extensions = Array.from(asn1.result["TSTInfo.extensions"], element => new Extension({ schema: element })); + //endregion + } + //********************************************************************************** + /** + * Convert current object to asn1js object and set correct values + * @returns {Object} asn1js object + */ + toSchema() + { + //region Create array for output sequence + const outputArray = []; + + outputArray.push(new asn1js.Integer({ value: this.version })); + outputArray.push(new asn1js.ObjectIdentifier({ value: this.policy })); + outputArray.push(this.messageImprint.toSchema()); + outputArray.push(this.serialNumber); + outputArray.push(new asn1js.GeneralizedTime({ valueDate: this.genTime })); + if("accuracy" in this) + outputArray.push(this.accuracy.toSchema()); + if("ordering" in this) + outputArray.push(new asn1js.Boolean({ value: this.ordering })); + if("nonce" in this) + outputArray.push(this.nonce); + if("tsa" in this) + { + outputArray.push(new asn1js.Constructed({ + optional: true, + idBlock: { + tagClass: 3, // CONTEXT-SPECIFIC + tagNumber: 0 // [0] + }, + value: [this.tsa.toSchema()] + })); + } + + //region Create array of extensions + if("extensions" in this) + { + outputArray.push(new asn1js.Constructed({ + optional: true, + idBlock: { + tagClass: 3, // CONTEXT-SPECIFIC + tagNumber: 1 // [1] + }, + value: Array.from(this.extensions, element => element.toSchema()) + })); + } + //endregion + //endregion + + //region Construct and return new ASN.1 schema for this object + return (new asn1js.Sequence({ + value: outputArray + })); + //endregion + } + //********************************************************************************** + /** + * Convertion for the class to JSON object + * @returns {Object} + */ + toJSON() + { + const _object = { + version: this.version, + policy: this.policy, + messageImprint: this.messageImprint.toJSON(), + serialNumber: this.serialNumber.toJSON(), + genTime: this.genTime + }; + + if("accuracy" in this) + _object.accuracy = this.accuracy.toJSON(); + + if("ordering" in this) + _object.ordering = this.ordering; + + if("nonce" in this) + _object.nonce = this.nonce.toJSON(); + + if("tsa" in this) + _object.tsa = this.tsa.toJSON(); + + if("extensions" in this) + _object.extensions = Array.from(this.extensions, element => element.toJSON()); + + return _object; + } + //********************************************************************************** + /** + * Verify current TST Info value + * @param {{data: ArrayBuffer, notBefore: Date, notAfter: Date}} parameters Input parameters + * @returns {Promise} + */ + verify(parameters = {}) + { + //region Initial variables + let sequence = Promise.resolve(); + + let data; + + let notBefore = null; + let notAfter = null; + //endregion + + //region Get a "crypto" extension + const crypto = getCrypto(); + if(typeof crypto === "undefined") + return Promise.reject("Unable to create WebCrypto object"); + //endregion + + //region Get initial parameters + if("data" in parameters) + data = parameters.data; + else + return Promise.reject("\"data\" is a mandatory attribute for TST_INFO verification"); + + if("notBefore" in parameters) + notBefore = parameters.notBefore; + + if("notAfter" in parameters) + notAfter = parameters.notAfter; + //endregion + + //region Check date + if(notBefore !== null) + { + if(this.genTime < notBefore) + return Promise.reject("Generation time for TSTInfo object is less than notBefore value"); + } + + if(notAfter !== null) + { + if(this.genTime > notAfter) + return Promise.reject("Generation time for TSTInfo object is more than notAfter value"); + } + //endregion + + //region Find hashing algorithm + const shaAlgorithm = getAlgorithmByOID(this.messageImprint.hashAlgorithm.algorithmId); + if(("name" in shaAlgorithm) === false) + return Promise.reject(`Unsupported signature algorithm: ${this.messageImprint.hashAlgorithm.algorithmId}`); + //endregion + + //region Calculate message digest for input "data" buffer + // noinspection JSCheckFunctionSignatures + sequence = sequence.then(() => + crypto.digest(shaAlgorithm.name, new Uint8Array(data)) + ).then( + result => isEqualBuffer(result, this.messageImprint.hashedMessage.valueBlock.valueHex) + ); + //endregion + + return sequence; + } + //********************************************************************************** +} +//************************************************************************************** diff --git a/core/third-party/pkijs/Time.js b/core/third-party/pkijs/Time.js new file mode 100644 index 0000000..6a4a29b --- /dev/null +++ b/core/third-party/pkijs/Time.js @@ -0,0 +1,158 @@ +import * as asn1js from "./asn1.js"; +import { getParametersValue, clearProps } from "./pvutils.js"; +//************************************************************************************** +/** + * Class from RFC5280 + */ +export default class Time +{ + //********************************************************************************** + /** + * Constructor for Time class + * @param {Object} [parameters={}] + * @param {Object} [parameters.schema] asn1js parsed value to initialize the class from + * @property {number} [type] 0 - UTCTime; 1 - GeneralizedTime; 2 - empty value + * @property {Date} [value] Value of the TIME class + */ + constructor(parameters = {}) + { + //region Internal properties of the object + /** + * @type {number} + * @desc 0 - UTCTime; 1 - GeneralizedTime; 2 - empty value + */ + this.type = getParametersValue(parameters, "type", Time.defaultValues("type")); + /** + * @type {Date} + * @desc Value of the TIME class + */ + this.value = getParametersValue(parameters, "value", Time.defaultValues("value")); + //endregion + + //region If input argument array contains "schema" for this object + if("schema" in parameters) + this.fromSchema(parameters.schema); + //endregion + } + //********************************************************************************** + /** + * Return default values for all class members + * @param {string} memberName String name for a class member + */ + static defaultValues(memberName) + { + switch(memberName) + { + case "type": + return 0; + case "value": + return new Date(0, 0, 0); + default: + throw new Error(`Invalid member name for Time class: ${memberName}`); + } + } + //********************************************************************************** + /** + * Return value of pre-defined ASN.1 schema for current class + * + * ASN.1 schema: + * ```asn1 + * Time ::= CHOICE { + * utcTime UTCTime, + * generalTime GeneralizedTime } + * ``` + * + * @param {Object} parameters Input parameters for the schema + * @param {boolean} optional Flag that current schema should be optional + * @returns {Object} asn1js schema object + */ + static schema(parameters = {}, optional = false) + { + /** + * @type {Object} + * @property {string} [blockName] + * @property {string} [utcTimeName] Name for "utcTimeName" choice + * @property {string} [generalTimeName] Name for "generalTimeName" choice + */ + const names = getParametersValue(parameters, "names", {}); + + return (new asn1js.Choice({ + optional, + value: [ + new asn1js.UTCTime({ name: (names.utcTimeName || "") }), + new asn1js.GeneralizedTime({ name: (names.generalTimeName || "") }) + ] + })); + } + //********************************************************************************** + /** + * Convert parsed asn1js object into current class + * @param {!Object} schema + */ + fromSchema(schema) + { + //region Clear input data first + clearProps(schema, [ + "utcTimeName", + "generalTimeName" + ]); + //endregion + + //region Check the schema is valid + const asn1 = asn1js.compareSchema(schema, schema, Time.schema({ + names: { + utcTimeName: "utcTimeName", + generalTimeName: "generalTimeName" + } + })); + + if(asn1.verified === false) + throw new Error("Object's schema was not verified against input data for Time"); + //endregion + + //region Get internal properties from parsed schema + if("utcTimeName" in asn1.result) + { + this.type = 0; + this.value = asn1.result.utcTimeName.toDate(); + } + if("generalTimeName" in asn1.result) + { + this.type = 1; + this.value = asn1.result.generalTimeName.toDate(); + } + //endregion + } + //********************************************************************************** + /** + * Convert current object to asn1js object and set correct values + * @returns {Object} asn1js object + */ + toSchema() + { + //region Construct and return new ASN.1 schema for this object + let result = {}; + + if(this.type === 0) + result = new asn1js.UTCTime({ valueDate: this.value }); + if(this.type === 1) + result = new asn1js.GeneralizedTime({ valueDate: this.value }); + + return result; + //endregion + } + //********************************************************************************** + /** + * Convertion for the class to JSON object + * @returns {Object} + */ + toJSON() + { + return { + type: this.type, + value: this.value + }; + } + //********************************************************************************** +} +//************************************************************************************** diff --git a/core/third-party/pkijs/TimeStampReq.js b/core/third-party/pkijs/TimeStampReq.js new file mode 100644 index 0000000..b895b1a --- /dev/null +++ b/core/third-party/pkijs/TimeStampReq.js @@ -0,0 +1,289 @@ +import * as asn1js from "./asn1.js"; +import { getParametersValue, clearProps } from "./pvutils.js"; +import MessageImprint from "./MessageImprint.js"; +import Extension from "./Extension.js"; +//************************************************************************************** +/** + * Class from RFC3161 + */ +export default class TimeStampReq +{ + //********************************************************************************** + /** + * Constructor for TimeStampReq class + * @param {Object} [parameters={}] + * @param {Object} [parameters.schema] asn1js parsed value to initialize the class from + */ + constructor(parameters = {}) + { + //region Internal properties of the object + /** + * @type {number} + * @desc version + */ + this.version = getParametersValue(parameters, "version", TimeStampReq.defaultValues("version")); + /** + * @type {MessageImprint} + * @desc messageImprint + */ + this.messageImprint = getParametersValue(parameters, "messageImprint", TimeStampReq.defaultValues("messageImprint")); + + if("reqPolicy" in parameters) + /** + * @type {string} + * @desc reqPolicy + */ + this.reqPolicy = getParametersValue(parameters, "reqPolicy", TimeStampReq.defaultValues("reqPolicy")); + + if("nonce" in parameters) + /** + * @type {Integer} + * @desc nonce + */ + this.nonce = getParametersValue(parameters, "nonce", TimeStampReq.defaultValues("nonce")); + + if("certReq" in parameters) + /** + * @type {boolean} + * @desc certReq + */ + this.certReq = getParametersValue(parameters, "certReq", TimeStampReq.defaultValues("certReq")); + + if("extensions" in parameters) + /** + * @type {Array.} + * @desc extensions + */ + this.extensions = getParametersValue(parameters, "extensions", TimeStampReq.defaultValues("extensions")); + //endregion + + //region If input argument array contains "schema" for this object + if("schema" in parameters) + this.fromSchema(parameters.schema); + //endregion + } + //********************************************************************************** + /** + * Return default values for all class members + * @param {string} memberName String name for a class member + */ + static defaultValues(memberName) + { + switch(memberName) + { + case "version": + return 0; + case "messageImprint": + return new MessageImprint(); + case "reqPolicy": + return ""; + case "nonce": + return new asn1js.Integer(); + case "certReq": + return false; + case "extensions": + return []; + default: + throw new Error(`Invalid member name for TimeStampReq class: ${memberName}`); + } + } + //********************************************************************************** + /** + * Compare values with default values for all class members + * @param {string} memberName String name for a class member + * @param {*} memberValue Value to compare with default value + */ + static compareWithDefault(memberName, memberValue) + { + switch(memberName) + { + case "version": + case "reqPolicy": + case "certReq": + return (memberValue === TimeStampReq.defaultValues(memberName)); + case "messageImprint": + return ((MessageImprint.compareWithDefault("hashAlgorithm", memberValue.hashAlgorithm)) && + (MessageImprint.compareWithDefault("hashedMessage", memberValue.hashedMessage))); + case "nonce": + return (memberValue.isEqual(TimeStampReq.defaultValues(memberName))); + case "extensions": + return (memberValue.length === 0); + default: + throw new Error(`Invalid member name for TimeStampReq class: ${memberName}`); + } + } + //********************************************************************************** + /** + * Return value of pre-defined ASN.1 schema for current class + * + * ASN.1 schema: + * ```asn1 + * TimeStampReq ::= SEQUENCE { + * version INTEGER { v1(1) }, + * messageImprint MessageImprint, + * reqPolicy TSAPolicyId OPTIONAL, + * nonce INTEGER OPTIONAL, + * certReq BOOLEAN DEFAULT FALSE, + * extensions [0] IMPLICIT Extensions OPTIONAL } + * + * TSAPolicyId ::= OBJECT IDENTIFIER + * ``` + * + * @param {Object} parameters Input parameters for the schema + * @returns {Object} asn1js schema object + */ + static schema(parameters = {}) + { + /** + * @type {Object} + * @property {string} [blockName] + * @property {string} [type] + * @property {string} [setName] + * @property {string} [values] + */ + const names = getParametersValue(parameters, "names", {}); + + return (new asn1js.Sequence({ + name: (names.blockName || "TimeStampReq"), + value: [ + new asn1js.Integer({ name: (names.version || "TimeStampReq.version") }), + MessageImprint.schema(names.messageImprint || { + names: { + blockName: "TimeStampReq.messageImprint" + } + }), + new asn1js.ObjectIdentifier({ + name: (names.reqPolicy || "TimeStampReq.reqPolicy"), + optional: true + }), + new asn1js.Integer({ + name: (names.nonce || "TimeStampReq.nonce"), + optional: true + }), + new asn1js.Boolean({ + name: (names.certReq || "TimeStampReq.certReq"), + optional: true + }), + new asn1js.Constructed({ + optional: true, + idBlock: { + tagClass: 3, // CONTEXT-SPECIFIC + tagNumber: 0 // [0] + }, + value: [new asn1js.Repeated({ + name: (names.extensions || "TimeStampReq.extensions"), + value: Extension.schema() + })] + }) // IMPLICIT SEQUENCE value + ] + })); + } + //********************************************************************************** + /** + * Convert parsed asn1js object into current class + * @param {!Object} schema + */ + fromSchema(schema) + { + //region Clear input data first + clearProps(schema, [ + "TimeStampReq.version", + "TimeStampReq.messageImprint", + "TimeStampReq.reqPolicy", + "TimeStampReq.nonce", + "TimeStampReq.certReq", + "TimeStampReq.extensions" + ]); + //endregion + + //region Check the schema is valid + const asn1 = asn1js.compareSchema(schema, + schema, + TimeStampReq.schema() + ); + + if(asn1.verified === false) + throw new Error("Object's schema was not verified against input data for TimeStampReq"); + //endregion + + //region Get internal properties from parsed schema + this.version = asn1.result["TimeStampReq.version"].valueBlock.valueDec; + this.messageImprint = new MessageImprint({ schema: asn1.result["TimeStampReq.messageImprint"] }); + if("TimeStampReq.reqPolicy" in asn1.result) + this.reqPolicy = asn1.result["TimeStampReq.reqPolicy"].valueBlock.toString(); + if("TimeStampReq.nonce" in asn1.result) + this.nonce = asn1.result["TimeStampReq.nonce"]; + if("TimeStampReq.certReq" in asn1.result) + this.certReq = asn1.result["TimeStampReq.certReq"].valueBlock.value; + if("TimeStampReq.extensions" in asn1.result) + this.extensions = Array.from(asn1.result["TimeStampReq.extensions"], element => new Extension({ schema: element })); + //endregion + } + //********************************************************************************** + /** + * Convert current object to asn1js object and set correct values + * @returns {Object} asn1js object + */ + toSchema() + { + //region Create array for output sequence + const outputArray = []; + + outputArray.push(new asn1js.Integer({ value: this.version })); + outputArray.push(this.messageImprint.toSchema()); + if("reqPolicy" in this) + outputArray.push(new asn1js.ObjectIdentifier({ value: this.reqPolicy })); + if("nonce" in this) + outputArray.push(this.nonce); + if(("certReq" in this) && (TimeStampReq.compareWithDefault("certReq", this.certReq) === false)) + outputArray.push(new asn1js.Boolean({ value: this.certReq })); + + //region Create array of extensions + if("extensions" in this) + { + outputArray.push(new asn1js.Constructed({ + idBlock: { + tagClass: 3, // CONTEXT-SPECIFIC + tagNumber: 0 // [0] + }, + value: Array.from(this.extensions, element => element.toSchema()) + })); + } + //endregion + //endregion + + //region Construct and return new ASN.1 schema for this object + return (new asn1js.Sequence({ + value: outputArray + })); + //endregion + } + //********************************************************************************** + /** + * Convertion for the class to JSON object + * @returns {Object} + */ + toJSON() + { + const _object = { + version: this.version, + messageImprint: this.messageImprint.toJSON() + }; + + if("reqPolicy" in this) + _object.reqPolicy = this.reqPolicy; + + if("nonce" in this) + _object.nonce = this.nonce.toJSON(); + + if(("certReq" in this) && (TimeStampReq.compareWithDefault("certReq", this.certReq) === false)) + _object.certReq = this.certReq; + + if("extensions" in this) + _object.extensions = Array.from(this.extensions, element => element.toJSON()); + + return _object; + } + //********************************************************************************** +} +//************************************************************************************** diff --git a/core/third-party/pkijs/TimeStampResp.js b/core/third-party/pkijs/TimeStampResp.js new file mode 100644 index 0000000..030b6c1 --- /dev/null +++ b/core/third-party/pkijs/TimeStampResp.js @@ -0,0 +1,237 @@ +import * as asn1js from "./asn1.js"; +import { getParametersValue, clearProps } from "./pvutils.js"; +import PKIStatusInfo from "./PKIStatusInfo.js"; +import ContentInfo from "./ContentInfo.js"; +import SignedData from "./SignedData.js"; +//************************************************************************************** +/** + * Class from RFC3161 + */ +export default class TimeStampResp +{ + //********************************************************************************** + /** + * Constructor for TimeStampResp class + * @param {Object} [parameters={}] + * @param {Object} [parameters.schema] asn1js parsed value to initialize the class from + */ + constructor(parameters = {}) + { + //region Internal properties of the object + /** + * @type {PKIStatusInfo} + * @desc status + */ + this.status = getParametersValue(parameters, "status", TimeStampResp.defaultValues("status")); + + if("timeStampToken" in parameters) + /** + * @type {ContentInfo} + * @desc timeStampToken + */ + this.timeStampToken = getParametersValue(parameters, "timeStampToken", TimeStampResp.defaultValues("timeStampToken")); + //endregion + + //region If input argument array contains "schema" for this object + if("schema" in parameters) + this.fromSchema(parameters.schema); + //endregion + } + //********************************************************************************** + /** + * Return default values for all class members + * @param {string} memberName String name for a class member + */ + static defaultValues(memberName) + { + switch(memberName) + { + case "status": + return new PKIStatusInfo(); + case "timeStampToken": + return new ContentInfo(); + default: + throw new Error(`Invalid member name for TimeStampResp class: ${memberName}`); + } + } + //********************************************************************************** + /** + * Compare values with default values for all class members + * @param {string} memberName String name for a class member + * @param {*} memberValue Value to compare with default value + */ + static compareWithDefault(memberName, memberValue) + { + switch(memberName) + { + case "status": + return ((PKIStatusInfo.compareWithDefault("status", memberValue.status)) && + (("statusStrings" in memberValue) === false) && + (("failInfo" in memberValue) === false)); + case "timeStampToken": + return ((memberValue.contentType === "") && + (memberValue.content instanceof asn1js.Any)); + default: + throw new Error(`Invalid member name for TimeStampResp class: ${memberName}`); + } + } + //********************************************************************************** + /** + * Return value of pre-defined ASN.1 schema for current class + * + * ASN.1 schema: + * ```asn1 + * TimeStampResp ::= SEQUENCE { + * status PKIStatusInfo, + * timeStampToken TimeStampToken OPTIONAL } + * ``` + * + * @param {Object} parameters Input parameters for the schema + * @returns {Object} asn1js schema object + */ + static schema(parameters = {}) + { + /** + * @type {Object} + * @property {string} [blockName] + * @property {string} [status] + * @property {string} [timeStampToken] + */ + const names = getParametersValue(parameters, "names", {}); + + return (new asn1js.Sequence({ + name: (names.blockName || "TimeStampResp"), + value: [ + PKIStatusInfo.schema(names.status || { + names: { + blockName: "TimeStampResp.status" + } + }), + ContentInfo.schema(names.timeStampToken || { + names: { + blockName: "TimeStampResp.timeStampToken", + optional: true + } + }) + ] + })); + } + //********************************************************************************** + /** + * Convert parsed asn1js object into current class + * @param {!Object} schema + */ + fromSchema(schema) + { + //region Clear input data first + clearProps(schema, [ + "TimeStampResp.status", + "TimeStampResp.timeStampToken" + ]); + //endregion + + //region Check the schema is valid + const asn1 = asn1js.compareSchema(schema, + schema, + TimeStampResp.schema() + ); + + if(asn1.verified === false) + throw new Error("Object's schema was not verified against input data for TimeStampResp"); + //endregion + + //region Get internal properties from parsed schema + this.status = new PKIStatusInfo({ schema: asn1.result["TimeStampResp.status"] }); + if("TimeStampResp.timeStampToken" in asn1.result) + this.timeStampToken = new ContentInfo({ schema: asn1.result["TimeStampResp.timeStampToken"] }); + //endregion + } + //********************************************************************************** + /** + * Convert current object to asn1js object and set correct values + * @returns {Object} asn1js object + */ + toSchema() + { + //region Create array for output sequence + const outputArray = []; + + outputArray.push(this.status.toSchema()); + if("timeStampToken" in this) + outputArray.push(this.timeStampToken.toSchema()); + //endregion + + //region Construct and return new ASN.1 schema for this object + return (new asn1js.Sequence({ + value: outputArray + })); + //endregion + } + //********************************************************************************** + /** + * Convertion for the class to JSON object + * @returns {Object} + */ + toJSON() + { + const _object = { + status: this.status + }; + + if("timeStampToken" in this) + _object.timeStampToken = this.timeStampToken.toJSON(); + + return _object; + } + //********************************************************************************** + /** + * Sign current TSP Response + * @param {Object} privateKey Private key for "subjectPublicKeyInfo" structure + * @param {string} [hashAlgorithm] Hashing algorithm. Default SHA-1 + * @returns {Promise} + */ + sign(privateKey, hashAlgorithm) + { + //region Check that "timeStampToken" exists + if(("timeStampToken" in this) === false) + return Promise.reject("timeStampToken is absent in TSP response"); + //endregion + + //region Check that "timeStampToken" has a right internal format + if(this.timeStampToken.contentType !== "1.2.840.113549.1.7.2") // Must be a CMS signed data + return Promise.reject(`Wrong format of timeStampToken: ${this.timeStampToken.contentType}`); + //endregion + + //region Sign internal signed data value + const signed = new ContentInfo({ schema: this.timeStampToken.content }); + + return signed.sign(privateKey, 0, hashAlgorithm); + //endregion + } + //********************************************************************************** + /** + * Verify current TSP Response + * @param {Object} verificationParameters Input parameters for verification + * @returns {Promise} + */ + verify(verificationParameters = { signer: 0, trustedCerts: [], data: new ArrayBuffer(0) }) + { + //region Check that "timeStampToken" exists + if(("timeStampToken" in this) === false) + return Promise.reject("timeStampToken is absent in TSP response"); + //endregion + + //region Check that "timeStampToken" has a right internal format + if(this.timeStampToken.contentType !== "1.2.840.113549.1.7.2") // Must be a CMS signed data + return Promise.reject(`Wrong format of timeStampToken: ${this.timeStampToken.contentType}`); + //endregion + + //region Verify internal signed data value + const signed = new SignedData({ schema: this.timeStampToken.content }); + + return signed.verify(verificationParameters); + //endregion + } + //********************************************************************************** +} +//************************************************************************************** diff --git a/core/third-party/pkijs/asn1.js b/core/third-party/pkijs/asn1.js new file mode 100644 index 0000000..48bd810 --- /dev/null +++ b/core/third-party/pkijs/asn1.js @@ -0,0 +1,6137 @@ +/* eslint-disable indent */ +/* + * Copyright (c) 2016-2018, Peculiar Ventures + * All rights reserved. + * + * Author 2016-2018, Yury Strozhevsky . + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its contributors + * may be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + */ +//************************************************************************************** +import { getParametersValue, padNumber, isEqualBuffer, bufferToHexCodes, checkBufferParams, utilToBase, utilFromBase, utilEncodeTC, utilDecodeTC, utilConcatBuf, utilConcatView } from "./pvutils.js"; +//************************************************************************************** +//region Declaration of global variables +//************************************************************************************** +const powers2 = [new Uint8Array([1])]; +const digitsString = "0123456789"; +//************************************************************************************** +//endregion +//************************************************************************************** +//region Declaration for "LocalBaseBlock" class +//************************************************************************************** +/** + * Class used as a base block for all remaining ASN.1 classes + * @typedef LocalBaseBlock + * @interface + * @property {number} blockLength + * @property {string} error + * @property {Array.} warnings + * @property {ArrayBuffer} valueBeforeDecode + */ +class LocalBaseBlock +{ + //********************************************************************************** + /** + * Constructor for "LocalBaseBlock" class + * @param {Object} [parameters={}] + * @property {ArrayBuffer} [valueBeforeDecode] + */ + constructor(parameters = {}) + { + /** + * @type {number} blockLength + */ + this.blockLength = getParametersValue(parameters, "blockLength", 0); + /** + * @type {string} error + */ + this.error = getParametersValue(parameters, "error", ""); + /** + * @type {Array.} warnings + */ + this.warnings = getParametersValue(parameters, "warnings", []); + //noinspection JSCheckFunctionSignatures + /** + * @type {ArrayBuffer} valueBeforeDecode + */ + if("valueBeforeDecode" in parameters) + this.valueBeforeDecode = parameters.valueBeforeDecode.slice(0); + else + this.valueBeforeDecode = new ArrayBuffer(0); + } + //********************************************************************************** + /** + * Aux function, need to get a block name. Need to have it here for inhiritence + * @returns {string} + */ + static blockName() + { + return "baseBlock"; + } + //********************************************************************************** + /** + * Convertion for the block to JSON object + * @returns {{blockName: string, blockLength: number, error: string, warnings: Array., valueBeforeDecode: string}} + */ + toJSON() + { + return { + blockName: this.constructor.blockName(), + blockLength: this.blockLength, + error: this.error, + warnings: this.warnings, + valueBeforeDecode: bufferToHexCodes(this.valueBeforeDecode, 0, this.valueBeforeDecode.byteLength) + }; + } + //********************************************************************************** +} +//************************************************************************************** +//endregion +//************************************************************************************** +//region Description for "HexBlock" class +//************************************************************************************** +/** + * Class used as a base block for all remaining ASN.1 classes + * @extends LocalBaseBlock + * @typedef HexBlock + * @property {number} blockLength + * @property {string} error + * @property {Array.} warnings + * @property {ArrayBuffer} valueBeforeDecode + * @property {boolean} isHexOnly + * @property {ArrayBuffer} valueHex + */ +//noinspection JSUnusedLocalSymbols +export const HexBlock = BaseClass => class LocalHexBlockMixin extends BaseClass +{ + //********************************************************************************** + //noinspection JSUnusedGlobalSymbols + /** + * Constructor for "HexBlock" class + * @param {Object} [parameters={}] + * @property {ArrayBuffer} [valueHex] + */ + constructor(parameters = {}) + { + super(parameters); + + /** + * @type {boolean} + */ + this.isHexOnly = getParametersValue(parameters, "isHexOnly", false); + /** + * @type {ArrayBuffer} + */ + if("valueHex" in parameters) + this.valueHex = parameters.valueHex.slice(0); + else + this.valueHex = new ArrayBuffer(0); + } + //********************************************************************************** + /** + * Aux function, need to get a block name. Need to have it here for inhiritence + * @returns {string} + */ + static blockName() + { + return "hexBlock"; + } + //********************************************************************************** + /** + * Base function for converting block from BER encoded array of bytes + * @param {!ArrayBuffer} inputBuffer ASN.1 BER encoded array + * @param {!number} inputOffset Offset in ASN.1 BER encoded array where decoding should be started + * @param {!number} inputLength Maximum length of array of bytes which can be using in this function + * @returns {number} Offset after least decoded byte + */ + fromBER(inputBuffer, inputOffset, inputLength) + { + //region Basic check for parameters + //noinspection JSCheckFunctionSignatures + if(checkBufferParams(this, inputBuffer, inputOffset, inputLength) === false) + return (-1); + //endregion + + //region Getting Uint8Array from ArrayBuffer + const intBuffer = new Uint8Array(inputBuffer, inputOffset, inputLength); + //endregion + + //region Initial checks + if(intBuffer.length === 0) + { + this.warnings.push("Zero buffer length"); + return inputOffset; + } + //endregion + + //region Copy input buffer to internal buffer + this.valueHex = inputBuffer.slice(inputOffset, inputOffset + inputLength); + //endregion + + this.blockLength = inputLength; + + return (inputOffset + inputLength); + } + //********************************************************************************** + /** + * Encoding of current ASN.1 block into ASN.1 encoded array (BER rules) + * @param {boolean} [sizeOnly=false] Flag that we need only a size of encoding, not a real array of bytes + * @returns {ArrayBuffer} + */ + toBER(sizeOnly = false) + { + if(this.isHexOnly !== true) + { + this.error = "Flag \"isHexOnly\" is not set, abort"; + return new ArrayBuffer(0); + } + + if(sizeOnly === true) + return new ArrayBuffer(this.valueHex.byteLength); + + //noinspection JSCheckFunctionSignatures + return this.valueHex.slice(0); + } + //********************************************************************************** + /** + * Convertion for the block to JSON object + * @returns {Object} + */ + toJSON() + { + let object = {}; + + //region Seems at the moment (Sep 2016) there is no way how to check method is supported in "super" object + try + { + object = super.toJSON(); + } + catch(ex){} + //endregion + + object.blockName = this.constructor.blockName(); + object.isHexOnly = this.isHexOnly; + object.valueHex = bufferToHexCodes(this.valueHex, 0, this.valueHex.byteLength); + + return object; + } + //********************************************************************************** +}; +//************************************************************************************** +//endregion +//************************************************************************************** +//region Declaration of identification block class +//************************************************************************************** +class LocalIdentificationBlock extends HexBlock(LocalBaseBlock) +{ + //********************************************************************************** + /** + * Constructor for "LocalBaseBlock" class + * @param {Object} [parameters={}] + * @property {Object} [idBlock] + */ + constructor(parameters = {}) + { + super(); + + if("idBlock" in parameters) + { + //region Properties from hexBlock class + this.isHexOnly = getParametersValue(parameters.idBlock, "isHexOnly", false); + this.valueHex = getParametersValue(parameters.idBlock, "valueHex", new ArrayBuffer(0)); + //endregion + + this.tagClass = getParametersValue(parameters.idBlock, "tagClass", (-1)); + this.tagNumber = getParametersValue(parameters.idBlock, "tagNumber", (-1)); + this.isConstructed = getParametersValue(parameters.idBlock, "isConstructed", false); + } + else + { + this.tagClass = (-1); + this.tagNumber = (-1); + this.isConstructed = false; + } + } + //********************************************************************************** + /** + * Aux function, need to get a block name. Need to have it here for inhiritence + * @returns {string} + */ + static blockName() + { + return "identificationBlock"; + } + //********************************************************************************** + /** + * Encoding of current ASN.1 block into ASN.1 encoded array (BER rules) + * @param {boolean} [sizeOnly=false] Flag that we need only a size of encoding, not a real array of bytes + * @returns {ArrayBuffer} + */ + toBER(sizeOnly = false) + { + //region Initial variables + let firstOctet = 0; + let retBuf; + let retView; + //endregion + + switch(this.tagClass) + { + case 1: + firstOctet |= 0x00; // UNIVERSAL + break; + case 2: + firstOctet |= 0x40; // APPLICATION + break; + case 3: + firstOctet |= 0x80; // CONTEXT-SPECIFIC + break; + case 4: + firstOctet |= 0xC0; // PRIVATE + break; + default: + this.error = "Unknown tag class"; + return (new ArrayBuffer(0)); + } + + if(this.isConstructed) + firstOctet |= 0x20; + + if((this.tagNumber < 31) && (!this.isHexOnly)) + { + retBuf = new ArrayBuffer(1); + retView = new Uint8Array(retBuf); + + if(!sizeOnly) + { + let number = this.tagNumber; + number &= 0x1F; + firstOctet |= number; + + retView[0] = firstOctet; + } + + return retBuf; + } + + if(this.isHexOnly === false) + { + const encodedBuf = utilToBase(this.tagNumber, 7); + const encodedView = new Uint8Array(encodedBuf); + const size = encodedBuf.byteLength; + + retBuf = new ArrayBuffer(size + 1); + retView = new Uint8Array(retBuf); + retView[0] = (firstOctet | 0x1F); + + if(!sizeOnly) + { + for(let i = 0; i < (size - 1); i++) + retView[i + 1] = encodedView[i] | 0x80; + + retView[size] = encodedView[size - 1]; + } + + return retBuf; + } + + retBuf = new ArrayBuffer(this.valueHex.byteLength + 1); + retView = new Uint8Array(retBuf); + + retView[0] = (firstOctet | 0x1F); + + if(sizeOnly === false) + { + const curView = new Uint8Array(this.valueHex); + + for(let i = 0; i < (curView.length - 1); i++) + retView[i + 1] = curView[i] | 0x80; + + retView[this.valueHex.byteLength] = curView[curView.length - 1]; + } + + return retBuf; + } + //********************************************************************************** + /** + * Base function for converting block from BER encoded array of bytes + * @param {!ArrayBuffer} inputBuffer ASN.1 BER encoded array + * @param {!number} inputOffset Offset in ASN.1 BER encoded array where decoding should be started + * @param {!number} inputLength Maximum length of array of bytes which can be using in this function + * @returns {number} + */ + fromBER(inputBuffer, inputOffset, inputLength) + { + //region Basic check for parameters + //noinspection JSCheckFunctionSignatures + if(checkBufferParams(this, inputBuffer, inputOffset, inputLength) === false) + return (-1); + //endregion + + //region Getting Uint8Array from ArrayBuffer + const intBuffer = new Uint8Array(inputBuffer, inputOffset, inputLength); + //endregion + + //region Initial checks + if(intBuffer.length === 0) + { + this.error = "Zero buffer length"; + return (-1); + } + //endregion + + //region Find tag class + const tagClassMask = intBuffer[0] & 0xC0; + + switch(tagClassMask) + { + case 0x00: + this.tagClass = (1); // UNIVERSAL + break; + case 0x40: + this.tagClass = (2); // APPLICATION + break; + case 0x80: + this.tagClass = (3); // CONTEXT-SPECIFIC + break; + case 0xC0: + this.tagClass = (4); // PRIVATE + break; + default: + this.error = "Unknown tag class"; + return (-1); + } + //endregion + + //region Find it's constructed or not + this.isConstructed = (intBuffer[0] & 0x20) === 0x20; + //endregion + + //region Find tag number + this.isHexOnly = false; + + const tagNumberMask = intBuffer[0] & 0x1F; + + //region Simple case (tag number < 31) + if(tagNumberMask !== 0x1F) + { + this.tagNumber = (tagNumberMask); + this.blockLength = 1; + } + //endregion + //region Tag number bigger or equal to 31 + else + { + let count = 1; + + this.valueHex = new ArrayBuffer(255); + let tagNumberBufferMaxLength = 255; + let intTagNumberBuffer = new Uint8Array(this.valueHex); + + //noinspection JSBitwiseOperatorUsage + while(intBuffer[count] & 0x80) + { + intTagNumberBuffer[count - 1] = intBuffer[count] & 0x7F; + count++; + + if(count >= intBuffer.length) + { + this.error = "End of input reached before message was fully decoded"; + return (-1); + } + + //region In case if tag number length is greater than 255 bytes (rare but possible case) + if(count === tagNumberBufferMaxLength) + { + tagNumberBufferMaxLength += 255; + + const tempBuffer = new ArrayBuffer(tagNumberBufferMaxLength); + const tempBufferView = new Uint8Array(tempBuffer); + + for(let i = 0; i < intTagNumberBuffer.length; i++) + tempBufferView[i] = intTagNumberBuffer[i]; + + this.valueHex = new ArrayBuffer(tagNumberBufferMaxLength); + intTagNumberBuffer = new Uint8Array(this.valueHex); + } + //endregion + } + + this.blockLength = (count + 1); + intTagNumberBuffer[count - 1] = intBuffer[count] & 0x7F; // Write last byte to buffer + + //region Cut buffer + const tempBuffer = new ArrayBuffer(count); + const tempBufferView = new Uint8Array(tempBuffer); + + for(let i = 0; i < count; i++) + tempBufferView[i] = intTagNumberBuffer[i]; + + this.valueHex = new ArrayBuffer(count); + intTagNumberBuffer = new Uint8Array(this.valueHex); + intTagNumberBuffer.set(tempBufferView); + //endregion + + //region Try to convert long tag number to short form + if(this.blockLength <= 9) + this.tagNumber = utilFromBase(intTagNumberBuffer, 7); + else + { + this.isHexOnly = true; + this.warnings.push("Tag too long, represented as hex-coded"); + } + //endregion + } + //endregion + //endregion + + //region Check if constructed encoding was using for primitive type + if(((this.tagClass === 1)) && + (this.isConstructed)) + { + switch(this.tagNumber) + { + case 1: // Boolean + case 2: // REAL + case 5: // Null + case 6: // OBJECT IDENTIFIER + case 9: // REAL + case 13: // RELATIVE OBJECT IDENTIFIER + case 14: // Time + case 23: + case 24: + case 31: + case 32: + case 33: + case 34: + this.error = "Constructed encoding used for primitive type"; + return (-1); + default: + } + } + //endregion + + return (inputOffset + this.blockLength); // Return current offset in input buffer + } + //********************************************************************************** + /** + * Convertion for the block to JSON object + * @returns {{blockName: string, + * tagClass: number, + * tagNumber: number, + * isConstructed: boolean, + * isHexOnly: boolean, + * valueHex: ArrayBuffer, + * blockLength: number, + * error: string, warnings: Array., + * valueBeforeDecode: string}} + */ + toJSON() + { + let object = {}; + + //region Seems at the moment (Sep 2016) there is no way how to check method is supported in "super" object + try + { + object = super.toJSON(); + } + catch(ex){} + //endregion + + object.blockName = this.constructor.blockName(); + object.tagClass = this.tagClass; + object.tagNumber = this.tagNumber; + object.isConstructed = this.isConstructed; + + return object; + } + //********************************************************************************** +} +//************************************************************************************** +//endregion +//************************************************************************************** +//region Declaration of length block class +//************************************************************************************** +class LocalLengthBlock extends LocalBaseBlock +{ + //********************************************************************************** + /** + * Constructor for "LocalLengthBlock" class + * @param {Object} [parameters={}] + * @property {Object} [lenBlock] + */ + constructor(parameters = {}) + { + super(); + + if("lenBlock" in parameters) + { + this.isIndefiniteForm = getParametersValue(parameters.lenBlock, "isIndefiniteForm", false); + this.longFormUsed = getParametersValue(parameters.lenBlock, "longFormUsed", false); + this.length = getParametersValue(parameters.lenBlock, "length", 0); + } + else + { + this.isIndefiniteForm = false; + this.longFormUsed = false; + this.length = 0; + } + } + //********************************************************************************** + /** + * Aux function, need to get a block name. Need to have it here for inhiritence + * @returns {string} + */ + static blockName() + { + return "lengthBlock"; + } + //********************************************************************************** + /** + * Base function for converting block from BER encoded array of bytes + * @param {!ArrayBuffer} inputBuffer ASN.1 BER encoded array + * @param {!number} inputOffset Offset in ASN.1 BER encoded array where decoding should be started + * @param {!number} inputLength Maximum length of array of bytes which can be using in this function + * @returns {number} + */ + fromBER(inputBuffer, inputOffset, inputLength) + { + //region Basic check for parameters + //noinspection JSCheckFunctionSignatures + if(checkBufferParams(this, inputBuffer, inputOffset, inputLength) === false) + return (-1); + //endregion + + //region Getting Uint8Array from ArrayBuffer + const intBuffer = new Uint8Array(inputBuffer, inputOffset, inputLength); + //endregion + + //region Initial checks + if(intBuffer.length === 0) + { + this.error = "Zero buffer length"; + return (-1); + } + + if(intBuffer[0] === 0xFF) + { + this.error = "Length block 0xFF is reserved by standard"; + return (-1); + } + //endregion + + //region Check for length form type + this.isIndefiniteForm = intBuffer[0] === 0x80; + //endregion + + //region Stop working in case of indefinite length form + if(this.isIndefiniteForm === true) + { + this.blockLength = 1; + return (inputOffset + this.blockLength); + } + //endregion + + //region Check is long form of length encoding using + this.longFormUsed = !!(intBuffer[0] & 0x80); + //endregion + + //region Stop working in case of short form of length value + if(this.longFormUsed === false) + { + this.length = (intBuffer[0]); + this.blockLength = 1; + return (inputOffset + this.blockLength); + } + //endregion + + //region Calculate length value in case of long form + const count = intBuffer[0] & 0x7F; + + if(count > 8) // Too big length value + { + this.error = "Too big integer"; + return (-1); + } + + if((count + 1) > intBuffer.length) + { + this.error = "End of input reached before message was fully decoded"; + return (-1); + } + + const lengthBufferView = new Uint8Array(count); + + for(let i = 0; i < count; i++) + lengthBufferView[i] = intBuffer[i + 1]; + + if(lengthBufferView[count - 1] === 0x00) + this.warnings.push("Needlessly long encoded length"); + + this.length = utilFromBase(lengthBufferView, 8); + + if(this.longFormUsed && (this.length <= 127)) + this.warnings.push("Unneccesary usage of long length form"); + + this.blockLength = count + 1; + //endregion + + return (inputOffset + this.blockLength); // Return current offset in input buffer + } + //********************************************************************************** + /** + * Encoding of current ASN.1 block into ASN.1 encoded array (BER rules) + * @param {boolean} [sizeOnly=false] Flag that we need only a size of encoding, not a real array of bytes + * @returns {ArrayBuffer} + */ + toBER(sizeOnly = false) + { + //region Initial variables + let retBuf; + let retView; + //endregion + + if(this.length > 127) + this.longFormUsed = true; + + if(this.isIndefiniteForm) + { + retBuf = new ArrayBuffer(1); + + if(sizeOnly === false) + { + retView = new Uint8Array(retBuf); + retView[0] = 0x80; + } + + return retBuf; + } + + if(this.longFormUsed === true) + { + const encodedBuf = utilToBase(this.length, 8); + + if(encodedBuf.byteLength > 127) + { + this.error = "Too big length"; + return (new ArrayBuffer(0)); + } + + retBuf = new ArrayBuffer(encodedBuf.byteLength + 1); + + if(sizeOnly === true) + return retBuf; + + const encodedView = new Uint8Array(encodedBuf); + retView = new Uint8Array(retBuf); + + retView[0] = encodedBuf.byteLength | 0x80; + + for(let i = 0; i < encodedBuf.byteLength; i++) + retView[i + 1] = encodedView[i]; + + return retBuf; + } + + retBuf = new ArrayBuffer(1); + + if(sizeOnly === false) + { + retView = new Uint8Array(retBuf); + + retView[0] = this.length; + } + + return retBuf; + } + //********************************************************************************** + /** + * Convertion for the block to JSON object + * @returns {{blockName, blockLength, error, warnings, valueBeforeDecode}|{blockName: string, blockLength: number, error: string, warnings: Array., valueBeforeDecode: string}} + */ + toJSON() + { + let object = {}; + + //region Seems at the moment (Sep 2016) there is no way how to check method is supported in "super" object + try + { + object = super.toJSON(); + } + catch(ex){} + //endregion + + object.blockName = this.constructor.blockName(); + object.isIndefiniteForm = this.isIndefiniteForm; + object.longFormUsed = this.longFormUsed; + object.length = this.length; + + return object; + } + //********************************************************************************** +} +//************************************************************************************** +//endregion +//************************************************************************************** +//region Declaration of value block class +//************************************************************************************** +export class ValueBlock extends LocalBaseBlock +{ + //********************************************************************************** + /** + * Constructor for "ValueBlock" class + * @param {Object} [parameters={}] + */ + constructor(parameters = {}) + { + super(parameters); + } + //********************************************************************************** + /** + * Aux function, need to get a block name. Need to have it here for inhiritence + * @returns {string} + */ + static blockName() + { + return "valueBlock"; + } + //********************************************************************************** + //noinspection JSUnusedLocalSymbols,JSUnusedLocalSymbols,JSUnusedLocalSymbols + /** + * Base function for converting block from BER encoded array of bytes + * @param {!ArrayBuffer} inputBuffer ASN.1 BER encoded array + * @param {!number} inputOffset Offset in ASN.1 BER encoded array where decoding should be started + * @param {!number} inputLength Maximum length of array of bytes which can be using in this function + * @returns {number} + */ + fromBER(inputBuffer, inputOffset, inputLength) + { + //region Throw an exception for a function which needs to be specified in extended classes + throw TypeError("User need to make a specific function in a class which extends \"ValueBlock\""); + //endregion + } + //********************************************************************************** + //noinspection JSUnusedLocalSymbols + /** + * Encoding of current ASN.1 block into ASN.1 encoded array (BER rules) + * @param {boolean} [sizeOnly=false] Flag that we need only a size of encoding, not a real array of bytes + * @returns {ArrayBuffer} + */ + toBER(sizeOnly = false) + { + //region Throw an exception for a function which needs to be specified in extended classes + throw TypeError("User need to make a specific function in a class which extends \"ValueBlock\""); + //endregion + } + //********************************************************************************** +} +//************************************************************************************** +//endregion +//************************************************************************************** +//region Declaration of basic ASN.1 block class +//************************************************************************************** +export class BaseBlock extends LocalBaseBlock +{ + //********************************************************************************** + /** + * Constructor for "BaseBlock" class + * @param {Object} [parameters={}] + * @property {Object} [primitiveSchema] + * @property {string} [name] + * @property {boolean} [optional] + * @param valueBlockType Type of value block + */ + constructor(parameters = {}, valueBlockType = ValueBlock) + { + super(parameters); + + if("name" in parameters) + this.name = parameters.name; + if("optional" in parameters) + this.optional = parameters.optional; + if("primitiveSchema" in parameters) + this.primitiveSchema = parameters.primitiveSchema; + + this.idBlock = new LocalIdentificationBlock(parameters); + this.lenBlock = new LocalLengthBlock(parameters); + this.valueBlock = new valueBlockType(parameters); + } + //********************************************************************************** + /** + * Aux function, need to get a block name. Need to have it here for inhiritence + * @returns {string} + */ + static blockName() + { + return "BaseBlock"; + } + //********************************************************************************** + /** + * Base function for converting block from BER encoded array of bytes + * @param {!ArrayBuffer} inputBuffer ASN.1 BER encoded array + * @param {!number} inputOffset Offset in ASN.1 BER encoded array where decoding should be started + * @param {!number} inputLength Maximum length of array of bytes which can be using in this function + * @returns {number} + */ + fromBER(inputBuffer, inputOffset, inputLength) + { + const resultOffset = this.valueBlock.fromBER(inputBuffer, inputOffset, (this.lenBlock.isIndefiniteForm === true) ? inputLength : this.lenBlock.length); + if(resultOffset === (-1)) + { + this.error = this.valueBlock.error; + return resultOffset; + } + + if(this.idBlock.error.length === 0) + this.blockLength += this.idBlock.blockLength; + + if(this.lenBlock.error.length === 0) + this.blockLength += this.lenBlock.blockLength; + + if(this.valueBlock.error.length === 0) + this.blockLength += this.valueBlock.blockLength; + + return resultOffset; + } + //********************************************************************************** + /** + * Encoding of current ASN.1 block into ASN.1 encoded array (BER rules) + * @param {boolean} [sizeOnly=false] Flag that we need only a size of encoding, not a real array of bytes + * @returns {ArrayBuffer} + */ + toBER(sizeOnly = false) + { + let retBuf; + + const idBlockBuf = this.idBlock.toBER(sizeOnly); + const valueBlockSizeBuf = this.valueBlock.toBER(true); + + this.lenBlock.length = valueBlockSizeBuf.byteLength; + const lenBlockBuf = this.lenBlock.toBER(sizeOnly); + + retBuf = utilConcatBuf(idBlockBuf, lenBlockBuf); + + let valueBlockBuf; + + if(sizeOnly === false) + valueBlockBuf = this.valueBlock.toBER(sizeOnly); + else + valueBlockBuf = new ArrayBuffer(this.lenBlock.length); + + retBuf = utilConcatBuf(retBuf, valueBlockBuf); + + if(this.lenBlock.isIndefiniteForm === true) + { + const indefBuf = new ArrayBuffer(2); + + if(sizeOnly === false) + { + const indefView = new Uint8Array(indefBuf); + + indefView[0] = 0x00; + indefView[1] = 0x00; + } + + retBuf = utilConcatBuf(retBuf, indefBuf); + } + + return retBuf; + } + //********************************************************************************** + /** + * Convertion for the block to JSON object + * @returns {{blockName, blockLength, error, warnings, valueBeforeDecode}|{blockName: string, blockLength: number, error: string, warnings: Array., valueBeforeDecode: string}} + */ + toJSON() + { + let object = {}; + + //region Seems at the moment (Sep 2016) there is no way how to check method is supported in "super" object + try + { + object = super.toJSON(); + } + catch(ex){} + //endregion + + object.idBlock = this.idBlock.toJSON(); + object.lenBlock = this.lenBlock.toJSON(); + object.valueBlock = this.valueBlock.toJSON(); + + if("name" in this) + object.name = this.name; + if("optional" in this) + object.optional = this.optional; + if("primitiveSchema" in this) + object.primitiveSchema = this.primitiveSchema.toJSON(); + + return object; + } + //********************************************************************************** +} +//************************************************************************************** +//endregion +//************************************************************************************** +//region Declaration of basic block for all PRIMITIVE types +//************************************************************************************** +class LocalPrimitiveValueBlock extends ValueBlock +{ + //********************************************************************************** + /** + * Constructor for "LocalPrimitiveValueBlock" class + * @param {Object} [parameters={}] + * @property {ArrayBuffer} [valueBeforeDecode] + */ + constructor(parameters = {}) + { + super(parameters); + + //region Variables from "hexBlock" class + if("valueHex" in parameters) + this.valueHex = parameters.valueHex.slice(0); + else + this.valueHex = new ArrayBuffer(0); + + this.isHexOnly = getParametersValue(parameters, "isHexOnly", true); + //endregion + } + //********************************************************************************** + /** + * Base function for converting block from BER encoded array of bytes + * @param {!ArrayBuffer} inputBuffer ASN.1 BER encoded array + * @param {!number} inputOffset Offset in ASN.1 BER encoded array where decoding should be started + * @param {!number} inputLength Maximum length of array of bytes which can be using in this function + * @returns {number} + */ + fromBER(inputBuffer, inputOffset, inputLength) + { + //region Basic check for parameters + //noinspection JSCheckFunctionSignatures + if(checkBufferParams(this, inputBuffer, inputOffset, inputLength) === false) + return (-1); + //endregion + + //region Getting Uint8Array from ArrayBuffer + const intBuffer = new Uint8Array(inputBuffer, inputOffset, inputLength); + //endregion + + //region Initial checks + if(intBuffer.length === 0) + { + this.warnings.push("Zero buffer length"); + return inputOffset; + } + //endregion + + //region Copy input buffer into internal buffer + this.valueHex = new ArrayBuffer(intBuffer.length); + const valueHexView = new Uint8Array(this.valueHex); + + for(let i = 0; i < intBuffer.length; i++) + valueHexView[i] = intBuffer[i]; + //endregion + + this.blockLength = inputLength; + + return (inputOffset + inputLength); + } + //********************************************************************************** + //noinspection JSUnusedLocalSymbols + /** + * Encoding of current ASN.1 block into ASN.1 encoded array (BER rules) + * @param {boolean} [sizeOnly=false] Flag that we need only a size of encoding, not a real array of bytes + * @returns {ArrayBuffer} + */ + toBER(sizeOnly = false) + { + return this.valueHex.slice(0); + } + //********************************************************************************** + /** + * Aux function, need to get a block name. Need to have it here for inhiritence + * @returns {string} + */ + static blockName() + { + return "PrimitiveValueBlock"; + } + //********************************************************************************** + /** + * Convertion for the block to JSON object + * @returns {{blockName, blockLength, error, warnings, valueBeforeDecode}|{blockName: string, blockLength: number, error: string, warnings: Array., valueBeforeDecode: string}} + */ + toJSON() + { + let object = {}; + + //region Seems at the moment (Sep 2016) there is no way how to check method is supported in "super" object + try + { + object = super.toJSON(); + } + catch(ex){} + //endregion + + object.valueHex = bufferToHexCodes(this.valueHex, 0, this.valueHex.byteLength); + object.isHexOnly = this.isHexOnly; + + return object; + } + //********************************************************************************** +} +//************************************************************************************** +export class Primitive extends BaseBlock +{ + //********************************************************************************** + /** + * Constructor for "Primitive" class + * @param {Object} [parameters={}] + * @property {ArrayBuffer} [valueHex] + */ + constructor(parameters = {}) + { + super(parameters, LocalPrimitiveValueBlock); + + this.idBlock.isConstructed = false; + } + //********************************************************************************** + /** + * Aux function, need to get a block name. Need to have it here for inhiritence + * @returns {string} + */ + static blockName() + { + return "PRIMITIVE"; + } + //********************************************************************************** +} +//************************************************************************************** +//endregion +//************************************************************************************** +//region Declaration of basic block for all CONSTRUCTED types +//************************************************************************************** +class LocalConstructedValueBlock extends ValueBlock +{ + //********************************************************************************** + /** + * Constructor for "LocalConstructedValueBlock" class + * @param {Object} [parameters={}] + */ + constructor(parameters = {}) + { + super(parameters); + + this.value = getParametersValue(parameters, "value", []); + this.isIndefiniteForm = getParametersValue(parameters, "isIndefiniteForm", false); + } + //********************************************************************************** + /** + * Base function for converting block from BER encoded array of bytes + * @param {!ArrayBuffer} inputBuffer ASN.1 BER encoded array + * @param {!number} inputOffset Offset in ASN.1 BER encoded array where decoding should be started + * @param {!number} inputLength Maximum length of array of bytes which can be using in this function + * @returns {number} + */ + fromBER(inputBuffer, inputOffset, inputLength) + { + //region Store initial offset and length + const initialOffset = inputOffset; + const initialLength = inputLength; + //endregion + + //region Basic check for parameters + //noinspection JSCheckFunctionSignatures + if(checkBufferParams(this, inputBuffer, inputOffset, inputLength) === false) + return (-1); + //endregion + + //region Getting Uint8Array from ArrayBuffer + const intBuffer = new Uint8Array(inputBuffer, inputOffset, inputLength); + //endregion + + //region Initial checks + if(intBuffer.length === 0) + { + this.warnings.push("Zero buffer length"); + return inputOffset; + } + //endregion + + //region Aux function + function checkLen(indefiniteLength, length) + { + if(indefiniteLength === true) + return 1; + + return length; + } + //endregion + + let currentOffset = inputOffset; + + while(checkLen(this.isIndefiniteForm, inputLength) > 0) + { + const returnObject = LocalFromBER(inputBuffer, currentOffset, inputLength); + if(returnObject.offset === (-1)) + { + this.error = returnObject.result.error; + this.warnings.concat(returnObject.result.warnings); + return (-1); + } + + currentOffset = returnObject.offset; + + this.blockLength += returnObject.result.blockLength; + inputLength -= returnObject.result.blockLength; + + this.value.push(returnObject.result); + + if((this.isIndefiniteForm === true) && (returnObject.result.constructor.blockName() === EndOfContent.blockName())) + break; + } + + if(this.isIndefiniteForm === true) + { + if(this.value[this.value.length - 1].constructor.blockName() === EndOfContent.blockName()) + this.value.pop(); + else + this.warnings.push("No EndOfContent block encoded"); + } + + //region Copy "inputBuffer" to "valueBeforeDecode" + this.valueBeforeDecode = inputBuffer.slice(initialOffset, initialOffset + initialLength); + //endregion + + return currentOffset; + } + //********************************************************************************** + /** + * Encoding of current ASN.1 block into ASN.1 encoded array (BER rules) + * @param {boolean} [sizeOnly=false] Flag that we need only a size of encoding, not a real array of bytes + * @returns {ArrayBuffer} + */ + toBER(sizeOnly = false) + { + let retBuf = new ArrayBuffer(0); + + for(let i = 0; i < this.value.length; i++) + { + const valueBuf = this.value[i].toBER(sizeOnly); + retBuf = utilConcatBuf(retBuf, valueBuf); + } + + return retBuf; + } + //********************************************************************************** + /** + * Aux function, need to get a block name. Need to have it here for inhiritence + * @returns {string} + */ + static blockName() + { + return "ConstructedValueBlock"; + } + //********************************************************************************** + /** + * Convertion for the block to JSON object + * @returns {{blockName, blockLength, error, warnings, valueBeforeDecode}|{blockName: string, blockLength: number, error: string, warnings: Array., valueBeforeDecode: string}} + */ + toJSON() + { + let object = {}; + + //region Seems at the moment (Sep 2016) there is no way how to check method is supported in "super" object + try + { + object = super.toJSON(); + } + catch(ex){} + //endregion + + object.isIndefiniteForm = this.isIndefiniteForm; + object.value = []; + for(let i = 0; i < this.value.length; i++) + object.value.push(this.value[i].toJSON()); + + return object; + } + //********************************************************************************** +} +//************************************************************************************** +export class Constructed extends BaseBlock +{ + //********************************************************************************** + /** + * Constructor for "Constructed" class + * @param {Object} [parameters={}] + */ + constructor(parameters = {}) + { + super(parameters, LocalConstructedValueBlock); + + this.idBlock.isConstructed = true; + } + //********************************************************************************** + /** + * Aux function, need to get a block name. Need to have it here for inhiritence + * @returns {string} + */ + static blockName() + { + return "CONSTRUCTED"; + } + //********************************************************************************** + /** + * Base function for converting block from BER encoded array of bytes + * @param {!ArrayBuffer} inputBuffer ASN.1 BER encoded array + * @param {!number} inputOffset Offset in ASN.1 BER encoded array where decoding should be started + * @param {!number} inputLength Maximum length of array of bytes which can be using in this function + * @returns {number} + */ + fromBER(inputBuffer, inputOffset, inputLength) + { + this.valueBlock.isIndefiniteForm = this.lenBlock.isIndefiniteForm; + + const resultOffset = this.valueBlock.fromBER(inputBuffer, inputOffset, (this.lenBlock.isIndefiniteForm === true) ? inputLength : this.lenBlock.length); + if(resultOffset === (-1)) + { + this.error = this.valueBlock.error; + return resultOffset; + } + + if(this.idBlock.error.length === 0) + this.blockLength += this.idBlock.blockLength; + + if(this.lenBlock.error.length === 0) + this.blockLength += this.lenBlock.blockLength; + + if(this.valueBlock.error.length === 0) + this.blockLength += this.valueBlock.blockLength; + + return resultOffset; + } + //********************************************************************************** +} +//************************************************************************************** +//endregion +//************************************************************************************** +//region Declaration of ASN.1 EndOfContent type class +//************************************************************************************** +class LocalEndOfContentValueBlock extends ValueBlock +{ + //********************************************************************************** + /** + * Constructor for "LocalEndOfContentValueBlock" class + * @param {Object} [parameters={}] + */ + constructor(parameters = {}) + { + super(parameters); + } + //********************************************************************************** + //noinspection JSUnusedLocalSymbols,JSUnusedLocalSymbols + /** + * Base function for converting block from BER encoded array of bytes + * @param {!ArrayBuffer} inputBuffer ASN.1 BER encoded array + * @param {!number} inputOffset Offset in ASN.1 BER encoded array where decoding should be started + * @param {!number} inputLength Maximum length of array of bytes which can be using in this function + * @returns {number} + */ + fromBER(inputBuffer, inputOffset, inputLength) + { + //region There is no "value block" for EndOfContent type and we need to return the same offset + return inputOffset; + //endregion + } + //********************************************************************************** + //noinspection JSUnusedLocalSymbols + /** + * Encoding of current ASN.1 block into ASN.1 encoded array (BER rules) + * @param {boolean} [sizeOnly=false] Flag that we need only a size of encoding, not a real array of bytes + * @returns {ArrayBuffer} + */ + toBER(sizeOnly = false) + { + return new ArrayBuffer(0); + } + //********************************************************************************** + /** + * Aux function, need to get a block name. Need to have it here for inhiritence + * @returns {string} + */ + static blockName() + { + return "EndOfContentValueBlock"; + } + //********************************************************************************** +} +//************************************************************************************** +export class EndOfContent extends BaseBlock +{ + //********************************************************************************** + constructor(paramaters = {}) + { + super(paramaters, LocalEndOfContentValueBlock); + + this.idBlock.tagClass = 1; // UNIVERSAL + this.idBlock.tagNumber = 0; // EndOfContent + } + //********************************************************************************** + /** + * Aux function, need to get a block name. Need to have it here for inhiritence + * @returns {string} + */ + static blockName() + { + return "EndOfContent"; + } + //********************************************************************************** +} +//************************************************************************************** +//endregion +//************************************************************************************** +//region Declaration of ASN.1 Boolean type class +//************************************************************************************** +class LocalBooleanValueBlock extends ValueBlock +{ + //********************************************************************************** + /** + * Constructor for "LocalBooleanValueBlock" class + * @param {Object} [parameters={}] + */ + constructor(parameters = {}) + { + super(parameters); + + this.value = getParametersValue(parameters, "value", false); + this.isHexOnly = getParametersValue(parameters, "isHexOnly", false); + + if("valueHex" in parameters) + this.valueHex = parameters.valueHex.slice(0); + else + { + this.valueHex = new ArrayBuffer(1); + if(this.value === true) + { + const view = new Uint8Array(this.valueHex); + view[0] = 0xFF; + } + } + } + //********************************************************************************** + /** + * Base function for converting block from BER encoded array of bytes + * @param {!ArrayBuffer} inputBuffer ASN.1 BER encoded array + * @param {!number} inputOffset Offset in ASN.1 BER encoded array where decoding should be started + * @param {!number} inputLength Maximum length of array of bytes which can be using in this function + * @returns {number} Offset after least decoded byte + */ + fromBER(inputBuffer, inputOffset, inputLength) + { + //region Basic check for parameters + //noinspection JSCheckFunctionSignatures + if(checkBufferParams(this, inputBuffer, inputOffset, inputLength) === false) + return (-1); + //endregion + + //region Getting Uint8Array from ArrayBuffer + const intBuffer = new Uint8Array(inputBuffer, inputOffset, inputLength); + //endregion + + if(inputLength > 1) + this.warnings.push("Boolean value encoded in more then 1 octet"); + + this.isHexOnly = true; + + //region Copy input buffer to internal array + this.valueHex = new ArrayBuffer(intBuffer.length); + const view = new Uint8Array(this.valueHex); + + for(let i = 0; i < intBuffer.length; i++) + view[i] = intBuffer[i]; + //endregion + + if(utilDecodeTC.call(this) !== 0 ) + this.value = true; + else + this.value = false; + + this.blockLength = inputLength; + + return (inputOffset + inputLength); + } + //********************************************************************************** + //noinspection JSUnusedLocalSymbols + /** + * Encoding of current ASN.1 block into ASN.1 encoded array (BER rules) + * @param {boolean} [sizeOnly=false] Flag that we need only a size of encoding, not a real array of bytes + * @returns {ArrayBuffer} + */ + toBER(sizeOnly = false) + { + return this.valueHex; + } + //********************************************************************************** + /** + * Aux function, need to get a block name. Need to have it here for inhiritence + * @returns {string} + */ + static blockName() + { + return "BooleanValueBlock"; + } + //********************************************************************************** + /** + * Convertion for the block to JSON object + * @returns {{blockName, blockLength, error, warnings, valueBeforeDecode}|{blockName: string, blockLength: number, error: string, warnings: Array., valueBeforeDecode: string}} + */ + toJSON() + { + let object = {}; + + //region Seems at the moment (Sep 2016) there is no way how to check method is supported in "super" object + try + { + object = super.toJSON(); + } + catch(ex){} + //endregion + + object.value = this.value; + object.isHexOnly = this.isHexOnly; + object.valueHex = bufferToHexCodes(this.valueHex, 0, this.valueHex.byteLength); + + return object; + } + //********************************************************************************** +} +//************************************************************************************** +export class Boolean extends BaseBlock +{ + //********************************************************************************** + /** + * Constructor for "Boolean" class + * @param {Object} [parameters={}] + */ + constructor(parameters = {}) + { + super(parameters, LocalBooleanValueBlock); + + this.idBlock.tagClass = 1; // UNIVERSAL + this.idBlock.tagNumber = 1; // Boolean + } + //********************************************************************************** + /** + * Aux function, need to get a block name. Need to have it here for inhiritence + * @returns {string} + */ + static blockName() + { + return "Boolean"; + } + //********************************************************************************** +} +//************************************************************************************** +//endregion +//************************************************************************************** +//region Declaration of ASN.1 Sequence and Set type classes +//************************************************************************************** +export class Sequence extends Constructed +{ + //********************************************************************************** + /** + * Constructor for "Sequence" class + * @param {Object} [parameters={}] + */ + constructor(parameters = {}) + { + super(parameters); + + this.idBlock.tagClass = 1; // UNIVERSAL + this.idBlock.tagNumber = 16; // Sequence + } + //********************************************************************************** + /** + * Aux function, need to get a block name. Need to have it here for inhiritence + * @returns {string} + */ + static blockName() + { + return "Sequence"; + } + //********************************************************************************** +} +//************************************************************************************** +export class Set extends Constructed +{ + //********************************************************************************** + /** + * Constructor for "Set" class + * @param {Object} [parameters={}] + */ + constructor(parameters = {}) + { + super(parameters); + + this.idBlock.tagClass = 1; // UNIVERSAL + this.idBlock.tagNumber = 17; // Set + } + //********************************************************************************** + /** + * Aux function, need to get a block name. Need to have it here for inhiritence + * @returns {string} + */ + static blockName() + { + return "Set"; + } + //********************************************************************************** +} +//************************************************************************************** +//endregion +//************************************************************************************** +//region Declaration of ASN.1 Null type class +//************************************************************************************** +export class Null extends BaseBlock +{ + //********************************************************************************** + /** + * Constructor for "Null" class + * @param {Object} [parameters={}] + */ + constructor(parameters = {}) + { + super(parameters, LocalBaseBlock); // We will not have a call to "Null value block" because of specified "fromBER" and "toBER" functions + + this.idBlock.tagClass = 1; // UNIVERSAL + this.idBlock.tagNumber = 5; // Null + } + //********************************************************************************** + /** + * Aux function, need to get a block name. Need to have it here for inhiritence + * @returns {string} + */ + static blockName() + { + return "Null"; + } + //********************************************************************************** + //noinspection JSUnusedLocalSymbols + /** + * Base function for converting block from BER encoded array of bytes + * @param {!ArrayBuffer} inputBuffer ASN.1 BER encoded array + * @param {!number} inputOffset Offset in ASN.1 BER encoded array where decoding should be started + * @param {!number} inputLength Maximum length of array of bytes which can be using in this function + * @returns {number} Offset after least decoded byte + */ + fromBER(inputBuffer, inputOffset, inputLength) + { + if(this.lenBlock.length > 0) + this.warnings.push("Non-zero length of value block for Null type"); + + if(this.idBlock.error.length === 0) + this.blockLength += this.idBlock.blockLength; + + if(this.lenBlock.error.length === 0) + this.blockLength += this.lenBlock.blockLength; + + this.blockLength += inputLength; + + if((inputOffset + inputLength) > inputBuffer.byteLength) + { + this.error = "End of input reached before message was fully decoded (inconsistent offset and length values)"; + return (-1); + } + + return (inputOffset + inputLength); + } + //********************************************************************************** + /** + * Encoding of current ASN.1 block into ASN.1 encoded array (BER rules) + * @param {boolean} [sizeOnly=false] Flag that we need only a size of encoding, not a real array of bytes + * @returns {ArrayBuffer} + */ + toBER(sizeOnly = false) + { + const retBuf = new ArrayBuffer(2); + + if(sizeOnly === true) + return retBuf; + + const retView = new Uint8Array(retBuf); + retView[0] = 0x05; + retView[1] = 0x00; + + return retBuf; + } + //********************************************************************************** +} +//************************************************************************************** +//endregion +//************************************************************************************** +//region Declaration of ASN.1 OctetString type class +//************************************************************************************** +class LocalOctetStringValueBlock extends HexBlock(LocalConstructedValueBlock) +{ + //********************************************************************************** + /** + * Constructor for "LocalOctetStringValueBlock" class + * @param {Object} [parameters={}] + * @property {ArrayBuffer} [valueHex] + */ + constructor(parameters = {}) + { + super(parameters); + + this.isConstructed = getParametersValue(parameters, "isConstructed", false); + } + //********************************************************************************** + /** + * Base function for converting block from BER encoded array of bytes + * @param {!ArrayBuffer} inputBuffer ASN.1 BER encoded array + * @param {!number} inputOffset Offset in ASN.1 BER encoded array where decoding should be started + * @param {!number} inputLength Maximum length of array of bytes which can be using in this function + * @returns {number} Offset after least decoded byte + */ + fromBER(inputBuffer, inputOffset, inputLength) + { + let resultOffset = 0; + + if(this.isConstructed === true) + { + this.isHexOnly = false; + + resultOffset = LocalConstructedValueBlock.prototype.fromBER.call(this, inputBuffer, inputOffset, inputLength); + if(resultOffset === (-1)) + return resultOffset; + + for(let i = 0; i < this.value.length; i++) + { + const currentBlockName = this.value[i].constructor.blockName(); + + if(currentBlockName === EndOfContent.blockName()) + { + if(this.isIndefiniteForm === true) + break; + else + { + this.error = "EndOfContent is unexpected, OCTET STRING may consists of OCTET STRINGs only"; + return (-1); + } + } + + if(currentBlockName !== OctetString.blockName()) + { + this.error = "OCTET STRING may consists of OCTET STRINGs only"; + return (-1); + } + } + } + else + { + this.isHexOnly = true; + + resultOffset = super.fromBER(inputBuffer, inputOffset, inputLength); + this.blockLength = inputLength; + } + + return resultOffset; + } + //********************************************************************************** + /** + * Encoding of current ASN.1 block into ASN.1 encoded array (BER rules) + * @param {boolean} [sizeOnly=false] Flag that we need only a size of encoding, not a real array of bytes + * @returns {ArrayBuffer} + */ + toBER(sizeOnly = false) + { + if(this.isConstructed === true) + return LocalConstructedValueBlock.prototype.toBER.call(this, sizeOnly); + + let retBuf = new ArrayBuffer(this.valueHex.byteLength); + + if(sizeOnly === true) + return retBuf; + + if(this.valueHex.byteLength === 0) + return retBuf; + + retBuf = this.valueHex.slice(0); + + return retBuf; + } + //********************************************************************************** + /** + * Aux function, need to get a block name. Need to have it here for inhiritence + * @returns {string} + */ + static blockName() + { + return "OctetStringValueBlock"; + } + //********************************************************************************** + toJSON() + { + let object = {}; + + //region Seems at the moment (Sep 2016) there is no way how to check method is supported in "super" object + try + { + object = super.toJSON(); + } + catch(ex){} + //endregion + + object.isConstructed = this.isConstructed; + object.isHexOnly = this.isHexOnly; + object.valueHex = bufferToHexCodes(this.valueHex, 0, this.valueHex.byteLength); + + return object; + } + //********************************************************************************** +} +//************************************************************************************** +export class OctetString extends BaseBlock +{ + //********************************************************************************** + /** + * Constructor for "OctetString" class + * @param {Object} [parameters={}] + */ + constructor(parameters = {}) + { + super(parameters, LocalOctetStringValueBlock); + + this.idBlock.tagClass = 1; // UNIVERSAL + this.idBlock.tagNumber = 4; // OctetString + } + //********************************************************************************** + /** + * Base function for converting block from BER encoded array of bytes + * @param {!ArrayBuffer} inputBuffer ASN.1 BER encoded array + * @param {!number} inputOffset Offset in ASN.1 BER encoded array where decoding should be started + * @param {!number} inputLength Maximum length of array of bytes which can be using in this function + * @returns {number} Offset after least decoded byte + */ + fromBER(inputBuffer, inputOffset, inputLength) + { + this.valueBlock.isConstructed = this.idBlock.isConstructed; + this.valueBlock.isIndefiniteForm = this.lenBlock.isIndefiniteForm; + + //region Ability to encode empty OCTET STRING + if(inputLength === 0) + { + if(this.idBlock.error.length === 0) + this.blockLength += this.idBlock.blockLength; + + if(this.lenBlock.error.length === 0) + this.blockLength += this.lenBlock.blockLength; + + return inputOffset; + } + //endregion + + return super.fromBER(inputBuffer, inputOffset, inputLength); + } + //********************************************************************************** + /** + * Aux function, need to get a block name. Need to have it here for inhiritence + * @returns {string} + */ + static blockName() + { + return "OctetString"; + } + //********************************************************************************** + //noinspection JSUnusedGlobalSymbols + /** + * Checking that two OCTETSTRINGs are equal + * @param {OctetString} octetString + */ + isEqual(octetString) + { + //region Check input type + if((octetString instanceof OctetString) === false) + return false; + //endregion + + //region Compare two JSON strings + if(JSON.stringify(this) !== JSON.stringify(octetString)) + return false; + //endregion + + return true; + } + //********************************************************************************** +} +//************************************************************************************** +//endregion +//************************************************************************************** +//region Declaration of ASN.1 BitString type class +//************************************************************************************** +class LocalBitStringValueBlock extends HexBlock(LocalConstructedValueBlock) +{ + //********************************************************************************** + /** + * Constructor for "LocalBitStringValueBlock" class + * @param {Object} [parameters={}] + * @property {ArrayBuffer} [valueHex] + */ + constructor(parameters = {}) + { + super(parameters); + + this.unusedBits = getParametersValue(parameters, "unusedBits", 0); + this.isConstructed = getParametersValue(parameters, "isConstructed", false); + this.blockLength = this.valueHex.byteLength; + } + //********************************************************************************** + /** + * Base function for converting block from BER encoded array of bytes + * @param {!ArrayBuffer} inputBuffer ASN.1 BER encoded array + * @param {!number} inputOffset Offset in ASN.1 BER encoded array where decoding should be started + * @param {!number} inputLength Maximum length of array of bytes which can be using in this function + * @returns {number} Offset after least decoded byte + */ + fromBER(inputBuffer, inputOffset, inputLength) + { + //region Ability to decode zero-length BitString value + if(inputLength === 0) + return inputOffset; + //endregion + + let resultOffset = (-1); + + //region If the BISTRING supposed to be a constructed value + if(this.isConstructed === true) + { + resultOffset = LocalConstructedValueBlock.prototype.fromBER.call(this, inputBuffer, inputOffset, inputLength); + if(resultOffset === (-1)) + return resultOffset; + + for(let i = 0; i < this.value.length; i++) + { + const currentBlockName = this.value[i].constructor.blockName(); + + if(currentBlockName === EndOfContent.blockName()) + { + if(this.isIndefiniteForm === true) + break; + else + { + this.error = "EndOfContent is unexpected, BIT STRING may consists of BIT STRINGs only"; + return (-1); + } + } + + if(currentBlockName !== BitString.blockName()) + { + this.error = "BIT STRING may consists of BIT STRINGs only"; + return (-1); + } + + if((this.unusedBits > 0) && (this.value[i].valueBlock.unusedBits > 0)) + { + this.error = "Usign of \"unused bits\" inside constructive BIT STRING allowed for least one only"; + return (-1); + } + + this.unusedBits = this.value[i].valueBlock.unusedBits; + if(this.unusedBits > 7) + { + this.error = "Unused bits for BitString must be in range 0-7"; + return (-1); + } + } + + return resultOffset; + } + //endregion + //region If the BitString supposed to be a primitive value + //region Basic check for parameters + //noinspection JSCheckFunctionSignatures + if(checkBufferParams(this, inputBuffer, inputOffset, inputLength) === false) + return (-1); + //endregion + + const intBuffer = new Uint8Array(inputBuffer, inputOffset, inputLength); + + this.unusedBits = intBuffer[0]; + + if(this.unusedBits > 7) + { + this.error = "Unused bits for BitString must be in range 0-7"; + return (-1); + } + + //region Copy input buffer to internal buffer + this.valueHex = new ArrayBuffer(intBuffer.length - 1); + const view = new Uint8Array(this.valueHex); + for(let i = 0; i < (inputLength - 1); i++) + view[i] = intBuffer[i + 1]; + //endregion + + this.blockLength = intBuffer.length; + + return (inputOffset + inputLength); + //endregion + } + //********************************************************************************** + /** + * Encoding of current ASN.1 block into ASN.1 encoded array (BER rules) + * @param {boolean} [sizeOnly=false] Flag that we need only a size of encoding, not a real array of bytes + * @returns {ArrayBuffer} + */ + toBER(sizeOnly = false) + { + if(this.isConstructed === true) + return LocalConstructedValueBlock.prototype.toBER.call(this, sizeOnly); + + if(sizeOnly === true) + return (new ArrayBuffer(this.valueHex.byteLength + 1)); + + if(this.valueHex.byteLength === 0) + return (new ArrayBuffer(0)); + + const curView = new Uint8Array(this.valueHex); + + const retBuf = new ArrayBuffer(this.valueHex.byteLength + 1); + const retView = new Uint8Array(retBuf); + + retView[0] = this.unusedBits; + + for(let i = 0; i < this.valueHex.byteLength; i++) + retView[i + 1] = curView[i]; + + return retBuf; + } + //********************************************************************************** + /** + * Aux function, need to get a block name. Need to have it here for inhiritence + * @returns {string} + */ + static blockName() + { + return "BitStringValueBlock"; + } + //********************************************************************************** + /** + * Convertion for the block to JSON object + * @returns {{blockName, blockLength, error, warnings, valueBeforeDecode}|{blockName: string, blockLength: number, error: string, warnings: Array., valueBeforeDecode: string}} + */ + toJSON() + { + let object = {}; + + //region Seems at the moment (Sep 2016) there is no way how to check method is supported in "super" object + try + { + object = super.toJSON(); + } + catch(ex){} + //endregion + + object.unusedBits = this.unusedBits; + object.isConstructed = this.isConstructed; + object.isHexOnly = this.isHexOnly; + object.valueHex = bufferToHexCodes(this.valueHex, 0, this.valueHex.byteLength); + + return object; + } + //********************************************************************************** +} +//************************************************************************************** +export class BitString extends BaseBlock +{ + //********************************************************************************** + /** + * Constructor for "BitString" class + * @param {Object} [parameters={}] + */ + constructor(parameters = {}) + { + super(parameters, LocalBitStringValueBlock); + + this.idBlock.tagClass = 1; // UNIVERSAL + this.idBlock.tagNumber = 3; // BitString + } + //********************************************************************************** + /** + * Aux function, need to get a block name. Need to have it here for inhiritence + * @returns {string} + */ + static blockName() + { + return "BitString"; + } + //********************************************************************************** + /** + * Base function for converting block from BER encoded array of bytes + * @param {!ArrayBuffer} inputBuffer ASN.1 BER encoded array + * @param {!number} inputOffset Offset in ASN.1 BER encoded array where decoding should be started + * @param {!number} inputLength Maximum length of array of bytes which can be using in this function + * @returns {number} Offset after least decoded byte + */ + fromBER(inputBuffer, inputOffset, inputLength) + { + //region Ability to encode empty BitString + if(inputLength === 0) + return inputOffset; + //endregion + + this.valueBlock.isConstructed = this.idBlock.isConstructed; + this.valueBlock.isIndefiniteForm = this.lenBlock.isIndefiniteForm; + + return super.fromBER(inputBuffer, inputOffset, inputLength); + } + //********************************************************************************** + /** + * Checking that two BITSTRINGs are equal + * @param {BitString} bitString + */ + isEqual(bitString) + { + //region Check input type + if((bitString instanceof BitString) === false) + return false; + //endregion + + //region Compare two JSON strings + if(JSON.stringify(this) !== JSON.stringify(bitString)) + return false; + //endregion + + return true; + } + //********************************************************************************** +} +//************************************************************************************** +//endregion +//************************************************************************************** +//region Declaration of ASN.1 Integer type class +//************************************************************************************** +/** + * @extends ValueBlock + */ +class LocalIntegerValueBlock extends HexBlock(ValueBlock) +{ + //********************************************************************************** + /** + * Constructor for "LocalIntegerValueBlock" class + * @param {Object} [parameters={}] + * @property {ArrayBuffer} [valueHex] + */ + constructor(parameters = {}) + { + super(parameters); + + if("value" in parameters) + this.valueDec = parameters.value; + } + //********************************************************************************** + /** + * Setter for "valueHex" + * @param {ArrayBuffer} _value + */ + set valueHex(_value) + { + this._valueHex = _value.slice(0); + + if(_value.byteLength >= 4) + { + this.warnings.push("Too big Integer for decoding, hex only"); + this.isHexOnly = true; + this._valueDec = 0; + } + else + { + this.isHexOnly = false; + + if(_value.byteLength > 0) + this._valueDec = utilDecodeTC.call(this); + } + } + //********************************************************************************** + /** + * Getter for "valueHex" + * @returns {ArrayBuffer} + */ + get valueHex() + { + return this._valueHex; + } + //********************************************************************************** + /** + * Getter for "valueDec" + * @param {number} _value + */ + set valueDec(_value) + { + this._valueDec = _value; + + this.isHexOnly = false; + this._valueHex = utilEncodeTC(_value); + } + //********************************************************************************** + /** + * Getter for "valueDec" + * @returns {number} + */ + get valueDec() + { + return this._valueDec; + } + //********************************************************************************** + /** + * Base function for converting block from DER encoded array of bytes + * @param {!ArrayBuffer} inputBuffer ASN.1 DER encoded array + * @param {!number} inputOffset Offset in ASN.1 DER encoded array where decoding should be started + * @param {!number} inputLength Maximum length of array of bytes which can be using in this function + * @param {number} [expectedLength=0] Expected length of converted "valueHex" buffer + * @returns {number} Offset after least decoded byte + */ + fromDER(inputBuffer, inputOffset, inputLength, expectedLength = 0) + { + const offset = this.fromBER(inputBuffer, inputOffset, inputLength); + if(offset === (-1)) + return offset; + + const view = new Uint8Array(this._valueHex); + + if((view[0] === 0x00) && ((view[1] & 0x80) !== 0)) + { + const updatedValueHex = new ArrayBuffer(this._valueHex.byteLength - 1); + const updatedView = new Uint8Array(updatedValueHex); + + updatedView.set(new Uint8Array(this._valueHex, 1, this._valueHex.byteLength - 1)); + + this._valueHex = updatedValueHex.slice(0); + } + else + { + if(expectedLength !== 0) + { + if(this._valueHex.byteLength < expectedLength) + { + if((expectedLength - this._valueHex.byteLength) > 1) + expectedLength = this._valueHex.byteLength + 1; + + const updatedValueHex = new ArrayBuffer(expectedLength); + const updatedView = new Uint8Array(updatedValueHex); + + updatedView.set(view, expectedLength - this._valueHex.byteLength); + + this._valueHex = updatedValueHex.slice(0); + } + } + } + + return offset; + } + //********************************************************************************** + /** + * Encoding of current ASN.1 block into ASN.1 encoded array (DER rules) + * @param {boolean} [sizeOnly=false] Flag that we need only a size of encoding, not a real array of bytes + * @returns {ArrayBuffer} + */ + toDER(sizeOnly = false) + { + const view = new Uint8Array(this._valueHex); + + switch(true) + { + case ((view[0] & 0x80) !== 0): + { + const updatedValueHex = new ArrayBuffer(this._valueHex.byteLength + 1); + const updatedView = new Uint8Array(updatedValueHex); + + updatedView[0] = 0x00; + updatedView.set(view, 1); + + this._valueHex = updatedValueHex.slice(0); + } + break; + case ((view[0] === 0x00) && ((view[1] & 0x80) === 0)): + { + const updatedValueHex = new ArrayBuffer(this._valueHex.byteLength - 1); + const updatedView = new Uint8Array(updatedValueHex); + + updatedView.set(new Uint8Array(this._valueHex, 1, this._valueHex.byteLength - 1)); + + this._valueHex = updatedValueHex.slice(0); + } + break; + default: + } + + return this.toBER(sizeOnly); + } + //********************************************************************************** + /** + * Base function for converting block from BER encoded array of bytes + * @param {!ArrayBuffer} inputBuffer ASN.1 BER encoded array + * @param {!number} inputOffset Offset in ASN.1 BER encoded array where decoding should be started + * @param {!number} inputLength Maximum length of array of bytes which can be using in this function + * @returns {number} Offset after least decoded byte + */ + fromBER(inputBuffer, inputOffset, inputLength) + { + const resultOffset = super.fromBER(inputBuffer, inputOffset, inputLength); + if(resultOffset === (-1)) + return resultOffset; + + this.blockLength = inputLength; + + return (inputOffset + inputLength); + } + //********************************************************************************** + /** + * Encoding of current ASN.1 block into ASN.1 encoded array (BER rules) + * @param {boolean} [sizeOnly=false] Flag that we need only a size of encoding, not a real array of bytes + * @returns {ArrayBuffer} + */ + toBER(sizeOnly = false) + { + //noinspection JSCheckFunctionSignatures + return this.valueHex.slice(0); + } + //********************************************************************************** + /** + * Aux function, need to get a block name. Need to have it here for inhiritence + * @returns {string} + */ + static blockName() + { + return "IntegerValueBlock"; + } + //********************************************************************************** + //noinspection JSUnusedGlobalSymbols + /** + * Convertion for the block to JSON object + * @returns {Object} + */ + toJSON() + { + let object = {}; + + //region Seems at the moment (Sep 2016) there is no way how to check method is supported in "super" object + try + { + object = super.toJSON(); + } + catch(ex){} + //endregion + + object.valueDec = this.valueDec; + + return object; + } + //********************************************************************************** + /** + * Convert current value to decimal string representation + */ + toString() + { + //region Aux functions + function viewAdd(first, second) + { + //region Initial variables + const c = new Uint8Array([0]); + + let firstView = new Uint8Array(first); + let secondView = new Uint8Array(second); + + let firstViewCopy = firstView.slice(0); + const firstViewCopyLength = firstViewCopy.length - 1; + let secondViewCopy = secondView.slice(0); + const secondViewCopyLength = secondViewCopy.length - 1; + + let value = 0; + + const max = (secondViewCopyLength < firstViewCopyLength) ? firstViewCopyLength : secondViewCopyLength; + + let counter = 0; + //endregion + + for(let i = max; i >= 0; i--, counter++) + { + switch(true) + { + case (counter < secondViewCopy.length): + value = firstViewCopy[firstViewCopyLength - counter] + secondViewCopy[secondViewCopyLength - counter] + c[0]; + break; + default: + value = firstViewCopy[firstViewCopyLength - counter] + c[0]; + } + + c[0] = value / 10; + + switch(true) + { + case (counter >= firstViewCopy.length): + firstViewCopy = utilConcatView(new Uint8Array([value % 10]), firstViewCopy); + break; + default: + firstViewCopy[firstViewCopyLength - counter] = value % 10; + } + } + + if(c[0] > 0) + firstViewCopy = utilConcatView(c, firstViewCopy); + + return firstViewCopy.slice(0); + } + + function power2(n) + { + if(n >= powers2.length) + { + for(let p = powers2.length; p <= n; p++) + { + const c = new Uint8Array([0]); + let digits = (powers2[p - 1]).slice(0); + + for(let i = (digits.length - 1); i >=0; i--) + { + const newValue = new Uint8Array([(digits[i] << 1) + c[0]]); + c[0] = newValue[0] / 10; + digits[i] = newValue[0] % 10; + } + + if (c[0] > 0) + digits = utilConcatView(c, digits); + + powers2.push(digits); + } + } + + return powers2[n]; + } + + function viewSub(first, second) + { + //region Initial variables + let b = 0; + + let firstView = new Uint8Array(first); + let secondView = new Uint8Array(second); + + let firstViewCopy = firstView.slice(0); + const firstViewCopyLength = firstViewCopy.length - 1; + let secondViewCopy = secondView.slice(0); + const secondViewCopyLength = secondViewCopy.length - 1; + + let value; + + let counter = 0; + //endregion + + for(let i = secondViewCopyLength; i >= 0; i--, counter++) + { + value = firstViewCopy[firstViewCopyLength - counter] - secondViewCopy[secondViewCopyLength - counter] - b; + + switch(true) + { + case (value < 0): + b = 1; + firstViewCopy[firstViewCopyLength - counter] = value + 10; + break; + default: + b = 0; + firstViewCopy[firstViewCopyLength - counter] = value; + } + } + + if(b > 0) + { + for(let i = (firstViewCopyLength - secondViewCopyLength + 1); i >= 0; i--, counter++) + { + value = firstViewCopy[firstViewCopyLength - counter] - b; + + if(value < 0) + { + b = 1; + firstViewCopy[firstViewCopyLength - counter] = value + 10; + } + else + { + b = 0; + firstViewCopy[firstViewCopyLength - counter] = value; + break; + } + } + } + + return firstViewCopy.slice(); + } + //endregion + + //region Initial variables + const firstBit = (this._valueHex.byteLength * 8) - 1; + + let digits = new Uint8Array((this._valueHex.byteLength * 8) / 3); + let bitNumber = 0; + let currentByte; + + const asn1View = new Uint8Array(this._valueHex); + + let result = ""; + + let flag = false; + //endregion + + //region Calculate number + for(let byteNumber = (this._valueHex.byteLength - 1); byteNumber >= 0; byteNumber--) + { + currentByte = asn1View[byteNumber]; + + for(let i = 0; i < 8; i++) + { + if((currentByte & 1) === 1) + { + switch(bitNumber) + { + case firstBit: + digits = viewSub(power2(bitNumber), digits); + result = "-"; + break; + default: + digits = viewAdd(digits, power2(bitNumber)); + } + } + + bitNumber++; + currentByte >>= 1; + } + } + //endregion + + //region Print number + for(let i = 0; i < digits.length; i++) + { + if(digits[i]) + flag = true; + + if(flag) + result += digitsString.charAt(digits[i]); + } + + if(flag === false) + result += digitsString.charAt(0); + //endregion + + return result; + } + //********************************************************************************** +} +//************************************************************************************** +export class Integer extends BaseBlock +{ + //********************************************************************************** + /** + * Constructor for "Integer" class + * @param {Object} [parameters={}] + */ + constructor(parameters = {}) + { + super(parameters, LocalIntegerValueBlock); + + this.idBlock.tagClass = 1; // UNIVERSAL + this.idBlock.tagNumber = 2; // Integer + } + //********************************************************************************** + /** + * Aux function, need to get a block name. Need to have it here for inhiritence + * @returns {string} + */ + static blockName() + { + return "Integer"; + } + //********************************************************************************** + //noinspection JSUnusedGlobalSymbols + /** + * Compare two Integer object, or Integer and ArrayBuffer objects + * @param {!Integer|ArrayBuffer} otherValue + * @returns {boolean} + */ + isEqual(otherValue) + { + if(otherValue instanceof Integer) + { + if(this.valueBlock.isHexOnly && otherValue.valueBlock.isHexOnly) // Compare two ArrayBuffers + return isEqualBuffer(this.valueBlock.valueHex, otherValue.valueBlock.valueHex); + + if(this.valueBlock.isHexOnly === otherValue.valueBlock.isHexOnly) + return (this.valueBlock.valueDec === otherValue.valueBlock.valueDec); + + return false; + } + + if(otherValue instanceof ArrayBuffer) + return isEqualBuffer(this.valueBlock.valueHex, otherValue); + + return false; + } + //********************************************************************************** + /** + * Convert current Integer value from BER into DER format + * @returns {Integer} + */ + convertToDER() + { + const integer = new Integer({ valueHex: this.valueBlock.valueHex }); + integer.valueBlock.toDER(); + + return integer; + } + //********************************************************************************** + /** + * Convert current Integer value from DER to BER format + * @returns {Integer} + */ + convertFromDER() + { + const expectedLength = (this.valueBlock.valueHex.byteLength % 2) ? (this.valueBlock.valueHex.byteLength + 1) : this.valueBlock.valueHex.byteLength; + const integer = new Integer({ valueHex: this.valueBlock.valueHex }); + integer.valueBlock.fromDER(integer.valueBlock.valueHex, 0, integer.valueBlock.valueHex.byteLength, expectedLength); + + return integer; + } + //********************************************************************************** +} +//************************************************************************************** +//endregion +//************************************************************************************** +//region Declaration of ASN.1 Enumerated type class +//************************************************************************************** +export class Enumerated extends Integer +{ + //********************************************************************************** + /** + * Constructor for "Enumerated" class + * @param {Object} [parameters={}] + */ + constructor(parameters = {}) + { + super(parameters); + + this.idBlock.tagClass = 1; // UNIVERSAL + this.idBlock.tagNumber = 10; // Enumerated + } + //********************************************************************************** + /** + * Aux function, need to get a block name. Need to have it here for inhiritence + * @returns {string} + */ + static blockName() + { + return "Enumerated"; + } + //********************************************************************************** +} +//************************************************************************************** +//endregion +//************************************************************************************** +//region Declaration of ASN.1 ObjectIdentifier type class +//************************************************************************************** +class LocalSidValueBlock extends HexBlock(LocalBaseBlock) +{ + //********************************************************************************** + /** + * Constructor for "LocalSidValueBlock" class + * @param {Object} [parameters={}] + * @property {number} [valueDec] + * @property {boolean} [isFirstSid] + */ + constructor(parameters = {}) + { + super(parameters); + + this.valueDec = getParametersValue(parameters, "valueDec", -1); + this.isFirstSid = getParametersValue(parameters, "isFirstSid", false); + } + //********************************************************************************** + /** + * Aux function, need to get a block name. Need to have it here for inhiritence + * @returns {string} + */ + static blockName() + { + return "sidBlock"; + } + //********************************************************************************** + /** + * Base function for converting block from BER encoded array of bytes + * @param {!ArrayBuffer} inputBuffer ASN.1 BER encoded array + * @param {!number} inputOffset Offset in ASN.1 BER encoded array where decoding should be started + * @param {!number} inputLength Maximum length of array of bytes which can be using in this function + * @returns {number} Offset after least decoded byte + */ + fromBER(inputBuffer, inputOffset, inputLength) + { + if(inputLength === 0) + return inputOffset; + + //region Basic check for parameters + //noinspection JSCheckFunctionSignatures + if(checkBufferParams(this, inputBuffer, inputOffset, inputLength) === false) + return (-1); + //endregion + + const intBuffer = new Uint8Array(inputBuffer, inputOffset, inputLength); + + this.valueHex = new ArrayBuffer(inputLength); + let view = new Uint8Array(this.valueHex); + + for(let i = 0; i < inputLength; i++) + { + view[i] = intBuffer[i] & 0x7F; + + this.blockLength++; + + if((intBuffer[i] & 0x80) === 0x00) + break; + } + + //region Ajust size of valueHex buffer + const tempValueHex = new ArrayBuffer(this.blockLength); + const tempView = new Uint8Array(tempValueHex); + + for(let i = 0; i < this.blockLength; i++) + tempView[i] = view[i]; + + //noinspection JSCheckFunctionSignatures + this.valueHex = tempValueHex.slice(0); + view = new Uint8Array(this.valueHex); + //endregion + + if((intBuffer[this.blockLength - 1] & 0x80) !== 0x00) + { + this.error = "End of input reached before message was fully decoded"; + return (-1); + } + + if(view[0] === 0x00) + this.warnings.push("Needlessly long format of SID encoding"); + + if(this.blockLength <= 8) + this.valueDec = utilFromBase(view, 7); + else + { + this.isHexOnly = true; + this.warnings.push("Too big SID for decoding, hex only"); + } + + return (inputOffset + this.blockLength); + } + //********************************************************************************** + /** + * Encoding of current ASN.1 block into ASN.1 encoded array (BER rules) + * @param {boolean} [sizeOnly=false] Flag that we need only a size of encoding, not a real array of bytes + * @returns {ArrayBuffer} + */ + toBER(sizeOnly = false) + { + //region Initial variables + let retBuf; + let retView; + //endregion + + if(this.isHexOnly) + { + if(sizeOnly === true) + return (new ArrayBuffer(this.valueHex.byteLength)); + + const curView = new Uint8Array(this.valueHex); + + retBuf = new ArrayBuffer(this.blockLength); + retView = new Uint8Array(retBuf); + + for(let i = 0; i < (this.blockLength - 1); i++) + retView[i] = curView[i] | 0x80; + + retView[this.blockLength - 1] = curView[this.blockLength - 1]; + + return retBuf; + } + + const encodedBuf = utilToBase(this.valueDec, 7); + if(encodedBuf.byteLength === 0) + { + this.error = "Error during encoding SID value"; + return (new ArrayBuffer(0)); + } + + retBuf = new ArrayBuffer(encodedBuf.byteLength); + + if(sizeOnly === false) + { + const encodedView = new Uint8Array(encodedBuf); + retView = new Uint8Array(retBuf); + + for(let i = 0; i < (encodedBuf.byteLength - 1); i++) + retView[i] = encodedView[i] | 0x80; + + retView[encodedBuf.byteLength - 1] = encodedView[encodedBuf.byteLength - 1]; + } + + return retBuf; + } + //********************************************************************************** + /** + * Create string representation of current SID block + * @returns {string} + */ + toString() + { + let result = ""; + + if(this.isHexOnly === true) + result = bufferToHexCodes(this.valueHex, 0, this.valueHex.byteLength); + else + { + if(this.isFirstSid) + { + let sidValue = this.valueDec; + + if(this.valueDec <= 39) + result = "0."; + else + { + if(this.valueDec <= 79) + { + result = "1."; + sidValue -= 40; + } + else + { + result = "2."; + sidValue -= 80; + } + } + + result += sidValue.toString(); + } + else + result = this.valueDec.toString(); + } + + return result; + } + //********************************************************************************** + //noinspection JSUnusedGlobalSymbols + /** + * Convertion for the block to JSON object + * @returns {Object} + */ + toJSON() + { + let object = {}; + + //region Seems at the moment (Sep 2016) there is no way how to check method is supported in "super" object + try + { + object = super.toJSON(); + } + catch(ex){} + //endregion + + object.valueDec = this.valueDec; + object.isFirstSid = this.isFirstSid; + + return object; + } + //********************************************************************************** +} +//************************************************************************************** +class LocalObjectIdentifierValueBlock extends ValueBlock +{ + //********************************************************************************** + /** + * Constructor for "LocalObjectIdentifierValueBlock" class + * @param {Object} [parameters={}] + * @property {ArrayBuffer} [valueHex] + */ + constructor(parameters = {}) + { + super(parameters); + + this.fromString(getParametersValue(parameters, "value", "")); + } + //********************************************************************************** + /** + * Base function for converting block from BER encoded array of bytes + * @param {!ArrayBuffer} inputBuffer ASN.1 BER encoded array + * @param {!number} inputOffset Offset in ASN.1 BER encoded array where decoding should be started + * @param {!number} inputLength Maximum length of array of bytes which can be using in this function + * @returns {number} Offset after least decoded byte + */ + fromBER(inputBuffer, inputOffset, inputLength) + { + let resultOffset = inputOffset; + + while(inputLength > 0) + { + const sidBlock = new LocalSidValueBlock(); + resultOffset = sidBlock.fromBER(inputBuffer, resultOffset, inputLength); + if(resultOffset === (-1)) + { + this.blockLength = 0; + this.error = sidBlock.error; + return resultOffset; + } + + if(this.value.length === 0) + sidBlock.isFirstSid = true; + + this.blockLength += sidBlock.blockLength; + inputLength -= sidBlock.blockLength; + + this.value.push(sidBlock); + } + + return resultOffset; + } + //********************************************************************************** + /** + * Encoding of current ASN.1 block into ASN.1 encoded array (BER rules) + * @param {boolean} [sizeOnly=false] Flag that we need only a size of encoding, not a real array of bytes + * @returns {ArrayBuffer} + */ + toBER(sizeOnly = false) + { + let retBuf = new ArrayBuffer(0); + + for(let i = 0; i < this.value.length; i++) + { + const valueBuf = this.value[i].toBER(sizeOnly); + if(valueBuf.byteLength === 0) + { + this.error = this.value[i].error; + return (new ArrayBuffer(0)); + } + + retBuf = utilConcatBuf(retBuf, valueBuf); + } + + return retBuf; + } + //********************************************************************************** + /** + * Create "LocalObjectIdentifierValueBlock" class from string + * @param {string} string Input string to convert from + * @returns {boolean} + */ + fromString(string) + { + this.value = []; // Clear existing SID values + + let pos1 = 0; + let pos2 = 0; + + let sid = ""; + + let flag = false; + + do + { + pos2 = string.indexOf(".", pos1); + if(pos2 === (-1)) + sid = string.substr(pos1); + else + sid = string.substr(pos1, pos2 - pos1); + + pos1 = pos2 + 1; + + if(flag) + { + const sidBlock = this.value[0]; + + let plus = 0; + + switch(sidBlock.valueDec) + { + case 0: + break; + case 1: + plus = 40; + break; + case 2: + plus = 80; + break; + default: + this.value = []; // clear SID array + return false; // ??? + } + + const parsedSID = parseInt(sid, 10); + if(isNaN(parsedSID)) + return true; + + sidBlock.valueDec = parsedSID + plus; + + flag = false; + } + else + { + const sidBlock = new LocalSidValueBlock(); + sidBlock.valueDec = parseInt(sid, 10); + if(isNaN(sidBlock.valueDec)) + return true; + + if(this.value.length === 0) + { + sidBlock.isFirstSid = true; + flag = true; + } + + this.value.push(sidBlock); + } + } while(pos2 !== (-1)); + + return true; + } + //********************************************************************************** + /** + * Converts "LocalObjectIdentifierValueBlock" class to string + * @returns {string} + */ + toString() + { + let result = ""; + let isHexOnly = false; + + for(let i = 0; i < this.value.length; i++) + { + isHexOnly = this.value[i].isHexOnly; + + let sidStr = this.value[i].toString(); + + if(i !== 0) + result = `${result}.`; + + if(isHexOnly) + { + sidStr = `{${sidStr}}`; + + if(this.value[i].isFirstSid) + result = `2.{${sidStr} - 80}`; + else + result += sidStr; + } + else + result += sidStr; + } + + return result; + } + //********************************************************************************** + /** + * Aux function, need to get a block name. Need to have it here for inhiritence + * @returns {string} + */ + static blockName() + { + return "ObjectIdentifierValueBlock"; + } + //********************************************************************************** + /** + * Convertion for the block to JSON object + * @returns {Object} + */ + toJSON() + { + let object = {}; + + //region Seems at the moment (Sep 2016) there is no way how to check method is supported in "super" object + try + { + object = super.toJSON(); + } + catch(ex){} + //endregion + + object.value = this.toString(); + object.sidArray = []; + for(let i = 0; i < this.value.length; i++) + object.sidArray.push(this.value[i].toJSON()); + + return object; + } + //********************************************************************************** +} +//************************************************************************************** +/** + * @extends BaseBlock + */ +export class ObjectIdentifier extends BaseBlock +{ + //********************************************************************************** + /** + * Constructor for "ObjectIdentifier" class + * @param {Object} [parameters={}] + * @property {ArrayBuffer} [valueHex] + */ + constructor(parameters = {}) + { + super(parameters, LocalObjectIdentifierValueBlock); + + this.idBlock.tagClass = 1; // UNIVERSAL + this.idBlock.tagNumber = 6; // OBJECT IDENTIFIER + } + //********************************************************************************** + /** + * Aux function, need to get a block name. Need to have it here for inhiritence + * @returns {string} + */ + static blockName() + { + return "ObjectIdentifier"; + } + //********************************************************************************** +} +//************************************************************************************** +//endregion +//************************************************************************************** +//region Declaration of all string's classes +//************************************************************************************** +class LocalUtf8StringValueBlock extends HexBlock(LocalBaseBlock) +{ + //********************************************************************************** + //noinspection JSUnusedGlobalSymbols + /** + * Constructor for "LocalUtf8StringValueBlock" class + * @param {Object} [parameters={}] + */ + constructor(parameters = {}) + { + super(parameters); + + this.isHexOnly = true; + this.value = ""; // String representation of decoded ArrayBuffer + } + //********************************************************************************** + /** + * Aux function, need to get a block name. Need to have it here for inhiritence + * @returns {string} + */ + static blockName() + { + return "Utf8StringValueBlock"; + } + //********************************************************************************** + //noinspection JSUnusedGlobalSymbols + /** + * Convertion for the block to JSON object + * @returns {Object} + */ + toJSON() + { + let object = {}; + + //region Seems at the moment (Sep 2016) there is no way how to check method is supported in "super" object + try + { + object = super.toJSON(); + } + catch(ex){} + //endregion + + object.value = this.value; + + return object; + } + //********************************************************************************** +} +//************************************************************************************** +/** + * @extends BaseBlock + */ +export class Utf8String extends BaseBlock +{ + //********************************************************************************** + /** + * Constructor for "Utf8String" class + * @param {Object} [parameters={}] + * @property {ArrayBuffer} [valueHex] + */ + constructor(parameters = {}) + { + super(parameters, LocalUtf8StringValueBlock); + + if("value" in parameters) + this.fromString(parameters.value); + + this.idBlock.tagClass = 1; // UNIVERSAL + this.idBlock.tagNumber = 12; // Utf8String + } + //********************************************************************************** + /** + * Aux function, need to get a block name. Need to have it here for inhiritence + * @returns {string} + */ + static blockName() + { + return "Utf8String"; + } + //********************************************************************************** + /** + * Base function for converting block from BER encoded array of bytes + * @param {!ArrayBuffer} inputBuffer ASN.1 BER encoded array + * @param {!number} inputOffset Offset in ASN.1 BER encoded array where decoding should be started + * @param {!number} inputLength Maximum length of array of bytes which can be using in this function + * @returns {number} Offset after least decoded byte + */ + fromBER(inputBuffer, inputOffset, inputLength) + { + const resultOffset = this.valueBlock.fromBER(inputBuffer, inputOffset, (this.lenBlock.isIndefiniteForm === true) ? inputLength : this.lenBlock.length); + if(resultOffset === (-1)) + { + this.error = this.valueBlock.error; + return resultOffset; + } + + this.fromBuffer(this.valueBlock.valueHex); + + if(this.idBlock.error.length === 0) + this.blockLength += this.idBlock.blockLength; + + if(this.lenBlock.error.length === 0) + this.blockLength += this.lenBlock.blockLength; + + if(this.valueBlock.error.length === 0) + this.blockLength += this.valueBlock.blockLength; + + return resultOffset; + } + //********************************************************************************** + /** + * Function converting ArrayBuffer into ASN.1 internal string + * @param {!ArrayBuffer} inputBuffer ASN.1 BER encoded array + */ + fromBuffer(inputBuffer) + { + this.valueBlock.value = String.fromCharCode.apply(null, new Uint8Array(inputBuffer)); + + try + { + //noinspection JSDeprecatedSymbols + this.valueBlock.value = decodeURIComponent(escape(this.valueBlock.value)); + } + catch(ex) + { + this.warnings.push(`Error during "decodeURIComponent": ${ex}, using raw string`); + } + } + //********************************************************************************** + /** + * Function converting JavaScript string into ASN.1 internal class + * @param {!string} inputString ASN.1 BER encoded array + */ + fromString(inputString) + { + //noinspection JSDeprecatedSymbols + const str = unescape(encodeURIComponent(inputString)); + const strLen = str.length; + + this.valueBlock.valueHex = new ArrayBuffer(strLen); + const view = new Uint8Array(this.valueBlock.valueHex); + + for(let i = 0; i < strLen; i++) + view[i] = str.charCodeAt(i); + + this.valueBlock.value = inputString; + } + //********************************************************************************** +} +//************************************************************************************** +//region Declaration of ASN.1 RelativeObjectIdentifier type class +//************************************************************************************** +class LocalRelativeSidValueBlock extends HexBlock(LocalBaseBlock) +{ + //********************************************************************************** + /** + * Constructor for "LocalRelativeSidValueBlock" class + * @param {Object} [parameters={}] + * @property {number} [valueDec] + */ + constructor(parameters = {}) + { + super(parameters); + + this.valueDec = getParametersValue(parameters, "valueDec", -1); + } + //********************************************************************************** + /** + * Aux function, need to get a block name. Need to have it here for inhiritence + * @returns {string} + */ + static blockName() + { + return "relativeSidBlock"; + } + //********************************************************************************** + /** + * Base function for converting block from BER encoded array of bytes + * @param {!ArrayBuffer} inputBuffer ASN.1 BER encoded array + * @param {!number} inputOffset Offset in ASN.1 BER encoded array where decoding should be started + * @param {!number} inputLength Maximum length of array of bytes which can be using in this function + * @returns {number} Offset after least decoded byte + */ + fromBER(inputBuffer, inputOffset, inputLength) + { + if (inputLength === 0) + return inputOffset; + + //region Basic check for parameters + //noinspection JSCheckFunctionSignatures + if (checkBufferParams(this, inputBuffer, inputOffset, inputLength) === false) + return (-1); + //endregion + + const intBuffer = new Uint8Array(inputBuffer, inputOffset, inputLength); + + this.valueHex = new ArrayBuffer(inputLength); + let view = new Uint8Array(this.valueHex); + + for (let i = 0; i < inputLength; i++) + { + view[i] = intBuffer[i] & 0x7F; + + this.blockLength++; + + if ((intBuffer[i] & 0x80) === 0x00) + break; + } + + //region Ajust size of valueHex buffer + const tempValueHex = new ArrayBuffer(this.blockLength); + const tempView = new Uint8Array(tempValueHex); + + for (let i = 0; i < this.blockLength; i++) + tempView[i] = view[i]; + + //noinspection JSCheckFunctionSignatures + this.valueHex = tempValueHex.slice(0); + view = new Uint8Array(this.valueHex); + //endregion + + if ((intBuffer[this.blockLength - 1] & 0x80) !== 0x00) + { + this.error = "End of input reached before message was fully decoded"; + return (-1); + } + + if (view[0] === 0x00) + this.warnings.push("Needlessly long format of SID encoding"); + + if (this.blockLength <= 8) + this.valueDec = utilFromBase(view, 7); + else + { + this.isHexOnly = true; + this.warnings.push("Too big SID for decoding, hex only"); + } + + return (inputOffset + this.blockLength); + } + //********************************************************************************** + /** + * Encoding of current ASN.1 block into ASN.1 encoded array (BER rules) + * @param {boolean} [sizeOnly=false] Flag that we need only a size of encoding, not a real array of bytes + * @returns {ArrayBuffer} + */ + toBER(sizeOnly = false) + { + //region Initial variables + let retBuf; + let retView; + //endregion + + if (this.isHexOnly) + { + if (sizeOnly === true) + return (new ArrayBuffer(this.valueHex.byteLength)); + + const curView = new Uint8Array(this.valueHex); + + retBuf = new ArrayBuffer(this.blockLength); + retView = new Uint8Array(retBuf); + + for (let i = 0; i < (this.blockLength - 1); i++) + retView[i] = curView[i] | 0x80; + + retView[this.blockLength - 1] = curView[this.blockLength - 1]; + + return retBuf; + } + + const encodedBuf = utilToBase(this.valueDec, 7); + if (encodedBuf.byteLength === 0) + { + this.error = "Error during encoding SID value"; + return (new ArrayBuffer(0)); + } + + retBuf = new ArrayBuffer(encodedBuf.byteLength); + + if (sizeOnly === false) + { + const encodedView = new Uint8Array(encodedBuf); + retView = new Uint8Array(retBuf); + + for (let i = 0; i < (encodedBuf.byteLength - 1); i++) + retView[i] = encodedView[i] | 0x80; + + retView[encodedBuf.byteLength - 1] = encodedView[encodedBuf.byteLength - 1]; + } + + return retBuf; + } + //********************************************************************************** + /** + * Create string representation of current SID block + * @returns {string} + */ + toString() + { + let result = ""; + + if (this.isHexOnly === true) + result = bufferToHexCodes(this.valueHex, 0, this.valueHex.byteLength); + else { + result = this.valueDec.toString(); + } + + return result; + } + //********************************************************************************** + //noinspection JSUnusedGlobalSymbols + /** + * Convertion for the block to JSON object + * @returns {Object} + */ + toJSON() + { + let object = {}; + + //region Seems at the moment (Sep 2016) there is no way how to check method is supported in "super" object + try { + object = super.toJSON(); + } catch (ex) {} + //endregion + + object.valueDec = this.valueDec; + + return object; + } + //********************************************************************************** +} +//************************************************************************************** +class LocalRelativeObjectIdentifierValueBlock extends ValueBlock { + //********************************************************************************** + /** + * Constructor for "LocalRelativeObjectIdentifierValueBlock" class + * @param {Object} [parameters={}] + * @property {ArrayBuffer} [valueHex] + */ + constructor(parameters = {}) + { + super(parameters); + + this.fromString(getParametersValue(parameters, "value", "")); + } + //********************************************************************************** + /** + * Base function for converting block from BER encoded array of bytes + * @param {!ArrayBuffer} inputBuffer ASN.1 BER encoded array + * @param {!number} inputOffset Offset in ASN.1 BER encoded array where decoding should be started + * @param {!number} inputLength Maximum length of array of bytes which can be using in this function + * @returns {number} Offset after least decoded byte + */ + fromBER(inputBuffer, inputOffset, inputLength) + { + let resultOffset = inputOffset; + + while (inputLength > 0) + { + const sidBlock = new LocalRelativeSidValueBlock(); + resultOffset = sidBlock.fromBER(inputBuffer, resultOffset, inputLength); + if (resultOffset === (-1)) + { + this.blockLength = 0; + this.error = sidBlock.error; + return resultOffset; + } + + this.blockLength += sidBlock.blockLength; + inputLength -= sidBlock.blockLength; + + this.value.push(sidBlock); + } + + return resultOffset; + } + //********************************************************************************** + /** + * Encoding of current ASN.1 block into ASN.1 encoded array (BER rules) + * @param {boolean} [sizeOnly=false] Flag that we need only a size of encoding, not a real array of bytes + * @returns {ArrayBuffer} + */ + toBER(sizeOnly = false) + { + let retBuf = new ArrayBuffer(0); + + for (let i = 0; i < this.value.length; i++) + { + const valueBuf = this.value[i].toBER(sizeOnly); + if (valueBuf.byteLength === 0) + { + this.error = this.value[i].error; + return (new ArrayBuffer(0)); + } + + retBuf = utilConcatBuf(retBuf, valueBuf); + } + + return retBuf; + } + //********************************************************************************** + /** + * Create "LocalRelativeObjectIdentifierValueBlock" class from string + * @param {string} string Input string to convert from + * @returns {boolean} + */ + fromString(string) + { + this.value = []; // Clear existing SID values + + let pos1 = 0; + let pos2 = 0; + + let sid = ""; + + do + { + pos2 = string.indexOf(".", pos1); + if (pos2 === (-1)) + sid = string.substr(pos1); + else + sid = string.substr(pos1, pos2 - pos1); + + pos1 = pos2 + 1; + + const sidBlock = new LocalRelativeSidValueBlock(); + sidBlock.valueDec = parseInt(sid, 10); + if (isNaN(sidBlock.valueDec)) + return true; + + this.value.push(sidBlock); + + } while (pos2 !== (-1)); + + return true; + } + //********************************************************************************** + /** + * Converts "LocalRelativeObjectIdentifierValueBlock" class to string + * @returns {string} + */ + toString() + { + let result = ""; + let isHexOnly = false; + + for (let i = 0; i < this.value.length; i++) + { + isHexOnly = this.value[i].isHexOnly; + + let sidStr = this.value[i].toString(); + + if (i !== 0) + result = `${result}.`; + + if (isHexOnly) + { + sidStr = `{${sidStr}}`; + result += sidStr; + } else + result += sidStr; + } + + return result; + } + //********************************************************************************** + /** + * Aux function, need to get a block name. Need to have it here for inhiritence + * @returns {string} + */ + static blockName() + { + return "RelativeObjectIdentifierValueBlock"; + } + //********************************************************************************** + /** + * Convertion for the block to JSON object + * @returns {Object} + */ + toJSON() + { + let object = {}; + + //region Seems at the moment (Sep 2016) there is no way how to check method is supported in "super" object + try + { + object = super.toJSON(); + } catch (ex) {} + //endregion + + object.value = this.toString(); + object.sidArray = []; + for (let i = 0; i < this.value.length; i++) + object.sidArray.push(this.value[i].toJSON()); + + return object; + } + //********************************************************************************** +} +//************************************************************************************** +/** + * @extends BaseBlock + */ +export class RelativeObjectIdentifier extends BaseBlock +{ + //********************************************************************************** + /** + * Constructor for "RelativeObjectIdentifier" class + * @param {Object} [parameters={}] + * @property {ArrayBuffer} [valueHex] + */ + constructor(parameters = {}) + { + super(parameters, LocalRelativeObjectIdentifierValueBlock); + + this.idBlock.tagClass = 1; // UNIVERSAL + this.idBlock.tagNumber = 13; // RELATIVE OBJECT IDENTIFIER + } + //********************************************************************************** + /** + * Aux function, need to get a block name. Need to have it here for inhiritence + * @returns {string} + */ + static blockName() + { + return "RelativeObjectIdentifier"; + } + //********************************************************************************** +} +//************************************************************************************** +//endregion +//************************************************************************************** +/** + * @extends LocalBaseBlock + * @extends HexBlock + */ +class LocalBmpStringValueBlock extends HexBlock(LocalBaseBlock) +{ + //********************************************************************************** + /** + * Constructor for "LocalBmpStringValueBlock" class + * @param {Object} [parameters={}] + */ + constructor(parameters = {}) + { + super(parameters); + + this.isHexOnly = true; + this.value = ""; + } + //********************************************************************************** + /** + * Aux function, need to get a block name. Need to have it here for inhiritence + * @returns {string} + */ + static blockName() + { + return "BmpStringValueBlock"; + } + //********************************************************************************** + //noinspection JSUnusedGlobalSymbols + /** + * Convertion for the block to JSON object + * @returns {Object} + */ + toJSON() + { + let object = {}; + + //region Seems at the moment (Sep 2016) there is no way how to check method is supported in "super" object + try + { + object = super.toJSON(); + } + catch(ex){} + //endregion + + object.value = this.value; + + return object; + } + //********************************************************************************** +} +//************************************************************************************** +/** + * @extends BaseBlock + */ +export class BmpString extends BaseBlock +{ + //********************************************************************************** + /** + * Constructor for "BmpString" class + * @param {Object} [parameters={}] + */ + constructor(parameters = {}) + { + super(parameters, LocalBmpStringValueBlock); + + if("value" in parameters) + this.fromString(parameters.value); + + this.idBlock.tagClass = 1; // UNIVERSAL + this.idBlock.tagNumber = 30; // BmpString + } + //********************************************************************************** + /** + * Aux function, need to get a block name. Need to have it here for inhiritence + * @returns {string} + */ + static blockName() + { + return "BmpString"; + } + //********************************************************************************** + /** + * Base function for converting block from BER encoded array of bytes + * @param {!ArrayBuffer} inputBuffer ASN.1 BER encoded array + * @param {!number} inputOffset Offset in ASN.1 BER encoded array where decoding should be started + * @param {!number} inputLength Maximum length of array of bytes which can be using in this function + * @returns {number} Offset after least decoded byte + */ + fromBER(inputBuffer, inputOffset, inputLength) + { + const resultOffset = this.valueBlock.fromBER(inputBuffer, inputOffset, (this.lenBlock.isIndefiniteForm === true) ? inputLength : this.lenBlock.length); + if(resultOffset === (-1)) + { + this.error = this.valueBlock.error; + return resultOffset; + } + + this.fromBuffer(this.valueBlock.valueHex); + + if(this.idBlock.error.length === 0) + this.blockLength += this.idBlock.blockLength; + + if(this.lenBlock.error.length === 0) + this.blockLength += this.lenBlock.blockLength; + + if(this.valueBlock.error.length === 0) + this.blockLength += this.valueBlock.blockLength; + + return resultOffset; + } + //********************************************************************************** + /** + * Function converting ArrayBuffer into ASN.1 internal string + * @param {!ArrayBuffer} inputBuffer ASN.1 BER encoded array + */ + fromBuffer(inputBuffer) + { + //noinspection JSCheckFunctionSignatures + const copyBuffer = inputBuffer.slice(0); + const valueView = new Uint8Array(copyBuffer); + + for(let i = 0; i < valueView.length; i += 2) + { + const temp = valueView[i]; + + valueView[i] = valueView[i + 1]; + valueView[i + 1] = temp; + } + + this.valueBlock.value = String.fromCharCode.apply(null, new Uint16Array(copyBuffer)); + } + //********************************************************************************** + /** + * Function converting JavaScript string into ASN.1 internal class + * @param {!string} inputString ASN.1 BER encoded array + */ + fromString(inputString) + { + const strLength = inputString.length; + + this.valueBlock.valueHex = new ArrayBuffer(strLength * 2); + const valueHexView = new Uint8Array(this.valueBlock.valueHex); + + for(let i = 0; i < strLength; i++) + { + const codeBuf = utilToBase(inputString.charCodeAt(i), 8); + const codeView = new Uint8Array(codeBuf); + if(codeView.length > 2) + continue; + + const dif = 2 - codeView.length; + + for(let j = (codeView.length - 1); j >= 0; j--) + valueHexView[i * 2 + j + dif] = codeView[j]; + } + + this.valueBlock.value = inputString; + } + //********************************************************************************** +} +//************************************************************************************** +class LocalUniversalStringValueBlock extends HexBlock(LocalBaseBlock) +{ + //********************************************************************************** + /** + * Constructor for "LocalUniversalStringValueBlock" class + * @param {Object} [parameters={}] + */ + constructor(parameters = {}) + { + super(parameters); + + this.isHexOnly = true; + this.value = ""; + } + //********************************************************************************** + /** + * Aux function, need to get a block name. Need to have it here for inhiritence + * @returns {string} + */ + static blockName() + { + return "UniversalStringValueBlock"; + } + //********************************************************************************** + //noinspection JSUnusedGlobalSymbols + /** + * Convertion for the block to JSON object + * @returns {Object} + */ + toJSON() + { + let object = {}; + + //region Seems at the moment (Sep 2016) there is no way how to check method is supported in "super" object + try + { + object = super.toJSON(); + } + catch(ex){} + //endregion + + object.value = this.value; + + return object; + } + //********************************************************************************** +} +//************************************************************************************** +/** + * @extends BaseBlock + */ +export class UniversalString extends BaseBlock +{ + //********************************************************************************** + /** + * Constructor for "UniversalString" class + * @param {Object} [parameters={}] + */ + constructor(parameters = {}) + { + super(parameters, LocalUniversalStringValueBlock); + + if("value" in parameters) + this.fromString(parameters.value); + + this.idBlock.tagClass = 1; // UNIVERSAL + this.idBlock.tagNumber = 28; // UniversalString + } + //********************************************************************************** + /** + * Aux function, need to get a block name. Need to have it here for inhiritence + * @returns {string} + */ + static blockName() + { + return "UniversalString"; + } + //********************************************************************************** + /** + * Base function for converting block from BER encoded array of bytes + * @param {!ArrayBuffer} inputBuffer ASN.1 BER encoded array + * @param {!number} inputOffset Offset in ASN.1 BER encoded array where decoding should be started + * @param {!number} inputLength Maximum length of array of bytes which can be using in this function + * @returns {number} Offset after least decoded byte + */ + fromBER(inputBuffer, inputOffset, inputLength) + { + const resultOffset = this.valueBlock.fromBER(inputBuffer, inputOffset, (this.lenBlock.isIndefiniteForm === true) ? inputLength : this.lenBlock.length); + if(resultOffset === (-1)) + { + this.error = this.valueBlock.error; + return resultOffset; + } + + this.fromBuffer(this.valueBlock.valueHex); + + if(this.idBlock.error.length === 0) + this.blockLength += this.idBlock.blockLength; + + if(this.lenBlock.error.length === 0) + this.blockLength += this.lenBlock.blockLength; + + if(this.valueBlock.error.length === 0) + this.blockLength += this.valueBlock.blockLength; + + return resultOffset; + } + //********************************************************************************** + /** + * Function converting ArrayBuffer into ASN.1 internal string + * @param {!ArrayBuffer} inputBuffer ASN.1 BER encoded array + */ + fromBuffer(inputBuffer) + { + //noinspection JSCheckFunctionSignatures + const copyBuffer = inputBuffer.slice(0); + const valueView = new Uint8Array(copyBuffer); + + for(let i = 0; i < valueView.length; i += 4) + { + valueView[i] = valueView[i + 3]; + valueView[i + 1] = valueView[i + 2]; + valueView[i + 2] = 0x00; + valueView[i + 3] = 0x00; + } + + this.valueBlock.value = String.fromCharCode.apply(null, new Uint32Array(copyBuffer)); + } + //********************************************************************************** + /** + * Function converting JavaScript string into ASN.1 internal class + * @param {!string} inputString ASN.1 BER encoded array + */ + fromString(inputString) + { + const strLength = inputString.length; + + this.valueBlock.valueHex = new ArrayBuffer(strLength * 4); + const valueHexView = new Uint8Array(this.valueBlock.valueHex); + + for(let i = 0; i < strLength; i++) + { + const codeBuf = utilToBase(inputString.charCodeAt(i), 8); + const codeView = new Uint8Array(codeBuf); + if(codeView.length > 4) + continue; + + const dif = 4 - codeView.length; + + for(let j = (codeView.length - 1); j >= 0; j--) + valueHexView[i * 4 + j + dif] = codeView[j]; + } + + this.valueBlock.value = inputString; + } + //********************************************************************************** +} +//************************************************************************************** +class LocalSimpleStringValueBlock extends HexBlock(LocalBaseBlock) +{ + //********************************************************************************** + /** + * Constructor for "LocalSimpleStringValueBlock" class + * @param {Object} [parameters={}] + */ + constructor(parameters = {}) + { + super(parameters); + + this.value = ""; + this.isHexOnly = true; + } + //********************************************************************************** + /** + * Aux function, need to get a block name. Need to have it here for inhiritence + * @returns {string} + */ + static blockName() + { + return "SimpleStringValueBlock"; + } + //********************************************************************************** + //noinspection JSUnusedGlobalSymbols + /** + * Convertion for the block to JSON object + * @returns {Object} + */ + toJSON() + { + let object = {}; + + //region Seems at the moment (Sep 2016) there is no way how to check method is supported in "super" object + try + { + object = super.toJSON(); + } + catch(ex){} + //endregion + + object.value = this.value; + + return object; + } + //********************************************************************************** +} +//************************************************************************************** +/** + * @extends BaseBlock + */ +class LocalSimpleStringBlock extends BaseBlock +{ + //********************************************************************************** + /** + * Constructor for "LocalSimpleStringBlock" class + * @param {Object} [parameters={}] + */ + constructor(parameters = {}) + { + super(parameters, LocalSimpleStringValueBlock); + + if("value" in parameters) + this.fromString(parameters.value); + } + //********************************************************************************** + /** + * Aux function, need to get a block name. Need to have it here for inhiritence + * @returns {string} + */ + static blockName() + { + return "SIMPLESTRING"; + } + //********************************************************************************** + /** + * Base function for converting block from BER encoded array of bytes + * @param {!ArrayBuffer} inputBuffer ASN.1 BER encoded array + * @param {!number} inputOffset Offset in ASN.1 BER encoded array where decoding should be started + * @param {!number} inputLength Maximum length of array of bytes which can be using in this function + * @returns {number} Offset after least decoded byte + */ + fromBER(inputBuffer, inputOffset, inputLength) + { + const resultOffset = this.valueBlock.fromBER(inputBuffer, inputOffset, (this.lenBlock.isIndefiniteForm === true) ? inputLength : this.lenBlock.length); + if(resultOffset === (-1)) + { + this.error = this.valueBlock.error; + return resultOffset; + } + + this.fromBuffer(this.valueBlock.valueHex); + + if(this.idBlock.error.length === 0) + this.blockLength += this.idBlock.blockLength; + + if(this.lenBlock.error.length === 0) + this.blockLength += this.lenBlock.blockLength; + + if(this.valueBlock.error.length === 0) + this.blockLength += this.valueBlock.blockLength; + + return resultOffset; + } + //********************************************************************************** + /** + * Function converting ArrayBuffer into ASN.1 internal string + * @param {!ArrayBuffer} inputBuffer ASN.1 BER encoded array + */ + fromBuffer(inputBuffer) + { + this.valueBlock.value = String.fromCharCode.apply(null, new Uint8Array(inputBuffer)); + } + //********************************************************************************** + /** + * Function converting JavaScript string into ASN.1 internal class + * @param {!string} inputString ASN.1 BER encoded array + */ + fromString(inputString) + { + const strLen = inputString.length; + + this.valueBlock.valueHex = new ArrayBuffer(strLen); + const view = new Uint8Array(this.valueBlock.valueHex); + + for(let i = 0; i < strLen; i++) + view[i] = inputString.charCodeAt(i); + + this.valueBlock.value = inputString; + } + //********************************************************************************** +} +//************************************************************************************** +/** + * @extends LocalSimpleStringBlock + */ +export class NumericString extends LocalSimpleStringBlock +{ + //********************************************************************************** + /** + * Constructor for "NumericString" class + * @param {Object} [parameters={}] + */ + constructor(parameters = {}) + { + super(parameters); + + this.idBlock.tagClass = 1; // UNIVERSAL + this.idBlock.tagNumber = 18; // NumericString + } + //********************************************************************************** + /** + * Aux function, need to get a block name. Need to have it here for inhiritence + * @returns {string} + */ + static blockName() + { + return "NumericString"; + } + //********************************************************************************** +} +//************************************************************************************** +/** + * @extends LocalSimpleStringBlock + */ +export class PrintableString extends LocalSimpleStringBlock +{ + //********************************************************************************** + /** + * Constructor for "PrintableString" class + * @param {Object} [parameters={}] + */ + constructor(parameters = {}) + { + super(parameters); + + this.idBlock.tagClass = 1; // UNIVERSAL + this.idBlock.tagNumber = 19; // PrintableString + } + //********************************************************************************** + /** + * Aux function, need to get a block name. Need to have it here for inhiritence + * @returns {string} + */ + static blockName() + { + return "PrintableString"; + } + //********************************************************************************** +} +//************************************************************************************** +/** + * @extends LocalSimpleStringBlock + */ +export class TeletexString extends LocalSimpleStringBlock +{ + //********************************************************************************** + /** + * Constructor for "TeletexString" class + * @param {Object} [parameters={}] + */ + constructor(parameters = {}) + { + super(parameters); + + this.idBlock.tagClass = 1; // UNIVERSAL + this.idBlock.tagNumber = 20; // TeletexString + } + //********************************************************************************** + /** + * Aux function, need to get a block name. Need to have it here for inhiritence + * @returns {string} + */ + static blockName() + { + return "TeletexString"; + } + //********************************************************************************** +} +//************************************************************************************** +/** + * @extends LocalSimpleStringBlock + */ +export class VideotexString extends LocalSimpleStringBlock +{ + //********************************************************************************** + /** + * Constructor for "VideotexString" class + * @param {Object} [parameters={}] + */ + constructor(parameters = {}) + { + super(parameters); + + this.idBlock.tagClass = 1; // UNIVERSAL + this.idBlock.tagNumber = 21; // VideotexString + } + //********************************************************************************** + /** + * Aux function, need to get a block name. Need to have it here for inhiritence + * @returns {string} + */ + static blockName() + { + return "VideotexString"; + } + //********************************************************************************** +} +//************************************************************************************** +/** + * @extends LocalSimpleStringBlock + */ +export class IA5String extends LocalSimpleStringBlock +{ + //********************************************************************************** + /** + * Constructor for "IA5String" class + * @param {Object} [parameters={}] + */ + constructor(parameters = {}) + { + super(parameters); + + this.idBlock.tagClass = 1; // UNIVERSAL + this.idBlock.tagNumber = 22; // IA5String + } + //********************************************************************************** + /** + * Aux function, need to get a block name. Need to have it here for inhiritence + * @returns {string} + */ + static blockName() + { + return "IA5String"; + } + //********************************************************************************** +} +//************************************************************************************** +/** + * @extends LocalSimpleStringBlock + */ +export class GraphicString extends LocalSimpleStringBlock +{ + //********************************************************************************** + /** + * Constructor for "GraphicString" class + * @param {Object} [parameters={}] + */ + constructor(parameters = {}) + { + super(parameters); + + this.idBlock.tagClass = 1; // UNIVERSAL + this.idBlock.tagNumber = 25; // GraphicString + } + //********************************************************************************** + /** + * Aux function, need to get a block name. Need to have it here for inhiritence + * @returns {string} + */ + static blockName() + { + return "GraphicString"; + } + //********************************************************************************** +} +//************************************************************************************** +/** + * @extends LocalSimpleStringBlock + */ +export class VisibleString extends LocalSimpleStringBlock +{ + //********************************************************************************** + /** + * Constructor for "VisibleString" class + * @param {Object} [parameters={}] + */ + constructor(parameters = {}) + { + super(parameters); + + this.idBlock.tagClass = 1; // UNIVERSAL + this.idBlock.tagNumber = 26; // VisibleString + } + //********************************************************************************** + /** + * Aux function, need to get a block name. Need to have it here for inhiritence + * @returns {string} + */ + static blockName() + { + return "VisibleString"; + } + //********************************************************************************** +} +//************************************************************************************** +/** + * @extends LocalSimpleStringBlock + */ +export class GeneralString extends LocalSimpleStringBlock +{ + //********************************************************************************** + /** + * Constructor for "GeneralString" class + * @param {Object} [parameters={}] + */ + constructor(parameters = {}) + { + super(parameters); + + this.idBlock.tagClass = 1; // UNIVERSAL + this.idBlock.tagNumber = 27; // GeneralString + } + //********************************************************************************** + /** + * Aux function, need to get a block name. Need to have it here for inhiritence + * @returns {string} + */ + static blockName() + { + return "GeneralString"; + } + //********************************************************************************** +} +//************************************************************************************** +/** + * @extends LocalSimpleStringBlock + */ +export class CharacterString extends LocalSimpleStringBlock +{ + //********************************************************************************** + /** + * Constructor for "CharacterString" class + * @param {Object} [parameters={}] + */ + constructor(parameters = {}) + { + super(parameters); + + this.idBlock.tagClass = 1; // UNIVERSAL + this.idBlock.tagNumber = 29; // CharacterString + } + //********************************************************************************** + /** + * Aux function, need to get a block name. Need to have it here for inhiritence + * @returns {string} + */ + static blockName() + { + return "CharacterString"; + } + //********************************************************************************** +} +//************************************************************************************** +//endregion +//************************************************************************************** +//region Declaration of all date and time classes +//************************************************************************************** +/** + * @extends VisibleString + */ +export class UTCTime extends VisibleString +{ + //********************************************************************************** + /** + * Constructor for "UTCTime" class + * @param {Object} [parameters={}] + * @property {string} [value] String representatio of the date + * @property {Date} [valueDate] JavaScript "Date" object + */ + constructor(parameters = {}) + { + super(parameters); + + this.year = 0; + this.month = 0; + this.day = 0; + this.hour = 0; + this.minute = 0; + this.second = 0; + + //region Create UTCTime from ASN.1 UTC string value + if("value" in parameters) + { + this.fromString(parameters.value); + + this.valueBlock.valueHex = new ArrayBuffer(parameters.value.length); + const view = new Uint8Array(this.valueBlock.valueHex); + + for(let i = 0; i < parameters.value.length; i++) + view[i] = parameters.value.charCodeAt(i); + } + //endregion + //region Create GeneralizedTime from JavaScript Date type + if("valueDate" in parameters) + { + this.fromDate(parameters.valueDate); + this.valueBlock.valueHex = this.toBuffer(); + } + //endregion + + this.idBlock.tagClass = 1; // UNIVERSAL + this.idBlock.tagNumber = 23; // UTCTime + } + //********************************************************************************** + /** + * Base function for converting block from BER encoded array of bytes + * @param {!ArrayBuffer} inputBuffer ASN.1 BER encoded array + * @param {!number} inputOffset Offset in ASN.1 BER encoded array where decoding should be started + * @param {!number} inputLength Maximum length of array of bytes which can be using in this function + * @returns {number} Offset after least decoded byte + */ + fromBER(inputBuffer, inputOffset, inputLength) + { + const resultOffset = this.valueBlock.fromBER(inputBuffer, inputOffset, (this.lenBlock.isIndefiniteForm === true) ? inputLength : this.lenBlock.length); + if(resultOffset === (-1)) + { + this.error = this.valueBlock.error; + return resultOffset; + } + + this.fromBuffer(this.valueBlock.valueHex); + + if(this.idBlock.error.length === 0) + this.blockLength += this.idBlock.blockLength; + + if(this.lenBlock.error.length === 0) + this.blockLength += this.lenBlock.blockLength; + + if(this.valueBlock.error.length === 0) + this.blockLength += this.valueBlock.blockLength; + + return resultOffset; + } + //********************************************************************************** + /** + * Function converting ArrayBuffer into ASN.1 internal string + * @param {!ArrayBuffer} inputBuffer ASN.1 BER encoded array + */ + fromBuffer(inputBuffer) + { + this.fromString(String.fromCharCode.apply(null, new Uint8Array(inputBuffer))); + } + //********************************************************************************** + /** + * Function converting ASN.1 internal string into ArrayBuffer + * @returns {ArrayBuffer} + */ + toBuffer() + { + const str = this.toString(); + + const buffer = new ArrayBuffer(str.length); + const view = new Uint8Array(buffer); + + for(let i = 0; i < str.length; i++) + view[i] = str.charCodeAt(i); + + return buffer; + } + //********************************************************************************** + /** + * Function converting "Date" object into ASN.1 internal string + * @param {!Date} inputDate JavaScript "Date" object + */ + fromDate(inputDate) + { + this.year = inputDate.getUTCFullYear(); + this.month = inputDate.getUTCMonth() + 1; + this.day = inputDate.getUTCDate(); + this.hour = inputDate.getUTCHours(); + this.minute = inputDate.getUTCMinutes(); + this.second = inputDate.getUTCSeconds(); + } + //********************************************************************************** + //noinspection JSUnusedGlobalSymbols + /** + * Function converting ASN.1 internal string into "Date" object + * @returns {Date} + */ + toDate() + { + return (new Date(Date.UTC(this.year, this.month - 1, this.day, this.hour, this.minute, this.second))); + } + //********************************************************************************** + /** + * Function converting JavaScript string into ASN.1 internal class + * @param {!string} inputString ASN.1 BER encoded array + */ + fromString(inputString) + { + //region Parse input string + const parser = /(\d{2})(\d{2})(\d{2})(\d{2})(\d{2})(\d{2})Z/ig; + const parserArray = parser.exec(inputString); + if(parserArray === null) + { + this.error = "Wrong input string for convertion"; + return; + } + //endregion + + //region Store parsed values + const year = parseInt(parserArray[1], 10); + if(year >= 50) + this.year = 1900 + year; + else + this.year = 2000 + year; + + this.month = parseInt(parserArray[2], 10); + this.day = parseInt(parserArray[3], 10); + this.hour = parseInt(parserArray[4], 10); + this.minute = parseInt(parserArray[5], 10); + this.second = parseInt(parserArray[6], 10); + //endregion + } + //********************************************************************************** + /** + * Function converting ASN.1 internal class into JavaScript string + * @returns {string} + */ + toString() + { + const outputArray = new Array(7); + + outputArray[0] = padNumber(((this.year < 2000) ? (this.year - 1900) : (this.year - 2000)), 2); + outputArray[1] = padNumber(this.month, 2); + outputArray[2] = padNumber(this.day, 2); + outputArray[3] = padNumber(this.hour, 2); + outputArray[4] = padNumber(this.minute, 2); + outputArray[5] = padNumber(this.second, 2); + outputArray[6] = "Z"; + + return outputArray.join(""); + } + //********************************************************************************** + /** + * Aux function, need to get a block name. Need to have it here for inhiritence + * @returns {string} + */ + static blockName() + { + return "UTCTime"; + } + //********************************************************************************** + /** + * Convertion for the block to JSON object + * @returns {Object} + */ + toJSON() + { + let object = {}; + + //region Seems at the moment (Sep 2016) there is no way how to check method is supported in "super" object + try + { + object = super.toJSON(); + } + catch(ex){} + //endregion + + object.year = this.year; + object.month = this.month; + object.day = this.day; + object.hour = this.hour; + object.minute = this.minute; + object.second = this.second; + + return object; + } + //********************************************************************************** +} +//************************************************************************************** +/** + * @extends VisibleString + */ +export class GeneralizedTime extends VisibleString +{ + //********************************************************************************** + /** + * Constructor for "GeneralizedTime" class + * @param {Object} [parameters={}] + * @property {string} [value] String representatio of the date + * @property {Date} [valueDate] JavaScript "Date" object + */ + constructor(parameters = {}) + { + super(parameters); + + this.year = 0; + this.month = 0; + this.day = 0; + this.hour = 0; + this.minute = 0; + this.second = 0; + this.millisecond = 0; + + //region Create UTCTime from ASN.1 UTC string value + if("value" in parameters) + { + this.fromString(parameters.value); + + this.valueBlock.valueHex = new ArrayBuffer(parameters.value.length); + const view = new Uint8Array(this.valueBlock.valueHex); + + for(let i = 0; i < parameters.value.length; i++) + view[i] = parameters.value.charCodeAt(i); + } + //endregion + //region Create GeneralizedTime from JavaScript Date type + if("valueDate" in parameters) + { + this.fromDate(parameters.valueDate); + this.valueBlock.valueHex = this.toBuffer(); + } + //endregion + + this.idBlock.tagClass = 1; // UNIVERSAL + this.idBlock.tagNumber = 24; // GeneralizedTime + } + //********************************************************************************** + /** + * Base function for converting block from BER encoded array of bytes + * @param {!ArrayBuffer} inputBuffer ASN.1 BER encoded array + * @param {!number} inputOffset Offset in ASN.1 BER encoded array where decoding should be started + * @param {!number} inputLength Maximum length of array of bytes which can be using in this function + * @returns {number} Offset after least decoded byte + */ + fromBER(inputBuffer, inputOffset, inputLength) + { + const resultOffset = this.valueBlock.fromBER(inputBuffer, inputOffset, (this.lenBlock.isIndefiniteForm === true) ? inputLength : this.lenBlock.length); + if(resultOffset === (-1)) + { + this.error = this.valueBlock.error; + return resultOffset; + } + + this.fromBuffer(this.valueBlock.valueHex); + + if(this.idBlock.error.length === 0) + this.blockLength += this.idBlock.blockLength; + + if(this.lenBlock.error.length === 0) + this.blockLength += this.lenBlock.blockLength; + + if(this.valueBlock.error.length === 0) + this.blockLength += this.valueBlock.blockLength; + + return resultOffset; + } + //********************************************************************************** + /** + * Function converting ArrayBuffer into ASN.1 internal string + * @param {!ArrayBuffer} inputBuffer ASN.1 BER encoded array + */ + fromBuffer(inputBuffer) + { + this.fromString(String.fromCharCode.apply(null, new Uint8Array(inputBuffer))); + } + //********************************************************************************** + /** + * Function converting ASN.1 internal string into ArrayBuffer + * @returns {ArrayBuffer} + */ + toBuffer() + { + const str = this.toString(); + + const buffer = new ArrayBuffer(str.length); + const view = new Uint8Array(buffer); + + for(let i = 0; i < str.length; i++) + view[i] = str.charCodeAt(i); + + return buffer; + } + //********************************************************************************** + /** + * Function converting "Date" object into ASN.1 internal string + * @param {!Date} inputDate JavaScript "Date" object + */ + fromDate(inputDate) + { + this.year = inputDate.getUTCFullYear(); + this.month = inputDate.getUTCMonth() + 1; + this.day = inputDate.getUTCDate(); + this.hour = inputDate.getUTCHours(); + this.minute = inputDate.getUTCMinutes(); + this.second = inputDate.getUTCSeconds(); + this.millisecond = inputDate.getUTCMilliseconds(); + } + //********************************************************************************** + //noinspection JSUnusedGlobalSymbols + /** + * Function converting ASN.1 internal string into "Date" object + * @returns {Date} + */ + toDate() + { + return (new Date(Date.UTC(this.year, this.month - 1, this.day, this.hour, this.minute, this.second, this.millisecond))); + } + //********************************************************************************** + /** + * Function converting JavaScript string into ASN.1 internal class + * @param {!string} inputString ASN.1 BER encoded array + */ + fromString(inputString) + { + //region Initial variables + let isUTC = false; + + let timeString = ""; + let dateTimeString = ""; + let fractionPart = 0; + + let parser; + + let hourDifference = 0; + let minuteDifference = 0; + //endregion + + //region Convert as UTC time + if(inputString[inputString.length - 1] === "Z") + { + timeString = inputString.substr(0, inputString.length - 1); + + isUTC = true; + } + //endregion + //region Convert as local time + else + { + //noinspection JSPrimitiveTypeWrapperUsage + const number = new Number(inputString[inputString.length - 1]); + + if(isNaN(number.valueOf())) + throw new Error("Wrong input string for convertion"); + + timeString = inputString; + } + //endregion + + //region Check that we do not have a "+" and "-" symbols inside UTC time + if(isUTC) + { + if(timeString.indexOf("+") !== (-1)) + throw new Error("Wrong input string for convertion"); + + if(timeString.indexOf("-") !== (-1)) + throw new Error("Wrong input string for convertion"); + } + //endregion + //region Get "UTC time difference" in case of local time + else + { + let multiplier = 1; + let differencePosition = timeString.indexOf("+"); + let differenceString = ""; + + if(differencePosition === (-1)) + { + differencePosition = timeString.indexOf("-"); + multiplier = (-1); + } + + if(differencePosition !== (-1)) + { + differenceString = timeString.substr(differencePosition + 1); + timeString = timeString.substr(0, differencePosition); + + if((differenceString.length !== 2) && (differenceString.length !== 4)) + throw new Error("Wrong input string for convertion"); + + //noinspection JSPrimitiveTypeWrapperUsage + let number = new Number(differenceString.substr(0, 2)); + + if(isNaN(number.valueOf())) + throw new Error("Wrong input string for convertion"); + + hourDifference = multiplier * number; + + if(differenceString.length === 4) + { + //noinspection JSPrimitiveTypeWrapperUsage + number = new Number(differenceString.substr(2, 2)); + + if(isNaN(number.valueOf())) + throw new Error("Wrong input string for convertion"); + + minuteDifference = multiplier * number; + } + } + } + //endregion + + //region Get position of fraction point + let fractionPointPosition = timeString.indexOf("."); // Check for "full stop" symbol + if(fractionPointPosition === (-1)) + fractionPointPosition = timeString.indexOf(","); // Check for "comma" symbol + //endregion + + //region Get fraction part + if(fractionPointPosition !== (-1)) + { + //noinspection JSPrimitiveTypeWrapperUsage + const fractionPartCheck = new Number(`0${timeString.substr(fractionPointPosition)}`); + + if(isNaN(fractionPartCheck.valueOf())) + throw new Error("Wrong input string for convertion"); + + fractionPart = fractionPartCheck.valueOf(); + + dateTimeString = timeString.substr(0, fractionPointPosition); + } + else + dateTimeString = timeString; + //endregion + + //region Parse internal date + switch(true) + { + case (dateTimeString.length === 8): // "YYYYMMDD" + parser = /(\d{4})(\d{2})(\d{2})/ig; + if(fractionPointPosition !== (-1)) + throw new Error("Wrong input string for convertion"); // Here we should not have a "fraction point" + break; + case (dateTimeString.length === 10): // "YYYYMMDDHH" + parser = /(\d{4})(\d{2})(\d{2})(\d{2})/ig; + + if(fractionPointPosition !== (-1)) + { + let fractionResult = 60 * fractionPart; + this.minute = Math.floor(fractionResult); + + fractionResult = 60 * (fractionResult - this.minute); + this.second = Math.floor(fractionResult); + + fractionResult = 1000 * (fractionResult - this.second); + this.millisecond = Math.floor(fractionResult); + } + break; + case (dateTimeString.length === 12): // "YYYYMMDDHHMM" + parser = /(\d{4})(\d{2})(\d{2})(\d{2})(\d{2})/ig; + + if(fractionPointPosition !== (-1)) + { + let fractionResult = 60 * fractionPart; + this.second = Math.floor(fractionResult); + + fractionResult = 1000 * (fractionResult - this.second); + this.millisecond = Math.floor(fractionResult); + } + break; + case (dateTimeString.length === 14): // "YYYYMMDDHHMMSS" + parser = /(\d{4})(\d{2})(\d{2})(\d{2})(\d{2})(\d{2})/ig; + + if(fractionPointPosition !== (-1)) + { + const fractionResult = 1000 * fractionPart; + this.millisecond = Math.floor(fractionResult); + } + break; + default: + throw new Error("Wrong input string for convertion"); + } + //endregion + + //region Put parsed values at right places + const parserArray = parser.exec(dateTimeString); + if(parserArray === null) + throw new Error("Wrong input string for convertion"); + + for(let j = 1; j < parserArray.length; j++) + { + switch(j) + { + case 1: + this.year = parseInt(parserArray[j], 10); + break; + case 2: + this.month = parseInt(parserArray[j], 10); + break; + case 3: + this.day = parseInt(parserArray[j], 10); + break; + case 4: + this.hour = parseInt(parserArray[j], 10) + hourDifference; + break; + case 5: + this.minute = parseInt(parserArray[j], 10) + minuteDifference; + break; + case 6: + this.second = parseInt(parserArray[j], 10); + break; + default: + throw new Error("Wrong input string for convertion"); + } + } + //endregion + + //region Get final date + if(isUTC === false) + { + const tempDate = new Date(this.year, this.month, this.day, this.hour, this.minute, this.second, this.millisecond); + + this.year = tempDate.getUTCFullYear(); + this.month = tempDate.getUTCMonth(); + this.day = tempDate.getUTCDay(); + this.hour = tempDate.getUTCHours(); + this.minute = tempDate.getUTCMinutes(); + this.second = tempDate.getUTCSeconds(); + this.millisecond = tempDate.getUTCMilliseconds(); + } + //endregion + } + //********************************************************************************** + /** + * Function converting ASN.1 internal class into JavaScript string + * @returns {string} + */ + toString() + { + const outputArray = []; + + outputArray.push(padNumber(this.year, 4)); + outputArray.push(padNumber(this.month, 2)); + outputArray.push(padNumber(this.day, 2)); + outputArray.push(padNumber(this.hour, 2)); + outputArray.push(padNumber(this.minute, 2)); + outputArray.push(padNumber(this.second, 2)); + if(this.millisecond !== 0) + { + outputArray.push("."); + outputArray.push(padNumber(this.millisecond, 3)); + } + outputArray.push("Z"); + + return outputArray.join(""); + } + //********************************************************************************** + /** + * Aux function, need to get a block name. Need to have it here for inhiritence + * @returns {string} + */ + static blockName() + { + return "GeneralizedTime"; + } + //********************************************************************************** + /** + * Convertion for the block to JSON object + * @returns {Object} + */ + toJSON() + { + let object = {}; + + //region Seems at the moment (Sep 2016) there is no way how to check method is supported in "super" object + try + { + object = super.toJSON(); + } + catch(ex){} + //endregion + + object.year = this.year; + object.month = this.month; + object.day = this.day; + object.hour = this.hour; + object.minute = this.minute; + object.second = this.second; + object.millisecond = this.millisecond; + + return object; + } + //********************************************************************************** +} +//************************************************************************************** +/** + * @extends Utf8String + */ +export class DATE extends Utf8String +{ + //********************************************************************************** + /** + * Constructor for "DATE" class + * @param {Object} [parameters={}] + */ + constructor(parameters = {}) + { + super(parameters); + + this.idBlock.tagClass = 1; // UNIVERSAL + this.idBlock.tagNumber = 31; // DATE + } + //********************************************************************************** + /** + * Aux function, need to get a block name. Need to have it here for inhiritence + * @returns {string} + */ + static blockName() + { + return "DATE"; + } + //********************************************************************************** +} +//************************************************************************************** +/** + * @extends Utf8String + */ +export class TimeOfDay extends Utf8String +{ + //********************************************************************************** + /** + * Constructor for "TimeOfDay" class + * @param {Object} [parameters={}] + */ + constructor(parameters = {}) + { + super(parameters); + + this.idBlock.tagClass = 1; // UNIVERSAL + this.idBlock.tagNumber = 32; // TimeOfDay + } + //********************************************************************************** + /** + * Aux function, need to get a block name. Need to have it here for inhiritence + * @returns {string} + */ + static blockName() + { + return "TimeOfDay"; + } + //********************************************************************************** +} +//************************************************************************************** +/** + * @extends Utf8String + */ +export class DateTime extends Utf8String +{ + //********************************************************************************** + /** + * Constructor for "DateTime" class + * @param {Object} [parameters={}] + */ + constructor(parameters = {}) + { + super(parameters); + + this.idBlock.tagClass = 1; // UNIVERSAL + this.idBlock.tagNumber = 33; // DateTime + } + //********************************************************************************** + /** + * Aux function, need to get a block name. Need to have it here for inhiritence + * @returns {string} + */ + static blockName() + { + return "DateTime"; + } + //********************************************************************************** +} +//************************************************************************************** +/** + * @extends Utf8String + */ +export class Duration extends Utf8String +{ + //********************************************************************************** + /** + * Constructor for "Duration" class + * @param {Object} [parameters={}] + */ + constructor(parameters = {}) + { + super(parameters); + + this.idBlock.tagClass = 1; // UNIVERSAL + this.idBlock.tagNumber = 34; // Duration + } + //********************************************************************************** + /** + * Aux function, need to get a block name. Need to have it here for inhiritence + * @returns {string} + */ + static blockName() + { + return "Duration"; + } + //********************************************************************************** +} +//************************************************************************************** +/** + * @extends Utf8String + */ +export class TIME extends Utf8String +{ + //********************************************************************************** + /** + * Constructor for "Time" class + * @param {Object} [parameters={}] + */ + constructor(parameters = {}) + { + super(parameters); + + this.idBlock.tagClass = 1; // UNIVERSAL + this.idBlock.tagNumber = 14; // Time + } + //********************************************************************************** + /** + * Aux function, need to get a block name. Need to have it here for inhiritence + * @returns {string} + */ + static blockName() + { + return "TIME"; + } + //********************************************************************************** +} +//************************************************************************************** +//endregion +//************************************************************************************** +//region Declaration of special ASN.1 schema type Choice +//************************************************************************************** +export class Choice +{ + //********************************************************************************** + /** + * Constructor for "Choice" class + * @param {Object} [parameters={}] + * @property {Array} [value] Array of ASN.1 types for make a choice from + * @property {boolean} [optional] + */ + constructor(parameters = {}) + { + this.value = getParametersValue(parameters, "value", []); + this.optional = getParametersValue(parameters, "optional", false); + } + //********************************************************************************** +} +//************************************************************************************** +//endregion +//************************************************************************************** +//region Declaration of special ASN.1 schema type Any +//************************************************************************************** +export class Any +{ + //********************************************************************************** + /** + * Constructor for "Any" class + * @param {Object} [parameters={}] + * @property {string} [name] + * @property {boolean} [optional] + */ + constructor(parameters = {}) + { + this.name = getParametersValue(parameters, "name", ""); + this.optional = getParametersValue(parameters, "optional", false); + } + //********************************************************************************** +} +//************************************************************************************** +//endregion +//************************************************************************************** +//region Declaration of special ASN.1 schema type Repeated +//************************************************************************************** +export class Repeated +{ + //********************************************************************************** + /** + * Constructor for "Repeated" class + * @param {Object} [parameters={}] + * @property {string} [name] + * @property {boolean} [optional] + */ + constructor(parameters = {}) + { + this.name = getParametersValue(parameters, "name", ""); + this.optional = getParametersValue(parameters, "optional", false); + this.value = getParametersValue(parameters, "value", new Any()); + this.local = getParametersValue(parameters, "local", false); // Could local or global array to store elements + } + //********************************************************************************** +} +//************************************************************************************** +//endregion +//************************************************************************************** +//region Declaration of special ASN.1 schema type RawData +//************************************************************************************** +/** + * @description Special class providing ability to have "toBER/fromBER" for raw ArrayBuffer + */ +export class RawData +{ + //********************************************************************************** + /** + * Constructor for "Repeated" class + * @param {Object} [parameters={}] + * @property {string} [name] + * @property {boolean} [optional] + */ + constructor(parameters = {}) + { + this.data = getParametersValue(parameters, "data", new ArrayBuffer(0)); + } + //********************************************************************************** + /** + * Base function for converting block from BER encoded array of bytes + * @param {!ArrayBuffer} inputBuffer ASN.1 BER encoded array + * @param {!number} inputOffset Offset in ASN.1 BER encoded array where decoding should be started + * @param {!number} inputLength Maximum length of array of bytes which can be using in this function + * @returns {number} Offset after least decoded byte + */ + fromBER(inputBuffer, inputOffset, inputLength) + { + this.data = inputBuffer.slice(inputOffset, inputLength); + return (inputOffset + inputLength); + } + //********************************************************************************** + /** + * Encoding of current ASN.1 block into ASN.1 encoded array (BER rules) + * @param {boolean} [sizeOnly=false] Flag that we need only a size of encoding, not a real array of bytes + * @returns {ArrayBuffer} + */ + toBER(sizeOnly = false) + { + return this.data; + } + //********************************************************************************** +} +//************************************************************************************** +//endregion +//************************************************************************************** +//region Major ASN.1 BER decoding function +//************************************************************************************** +/** + * Internal library function for decoding ASN.1 BER + * @param {!ArrayBuffer} inputBuffer ASN.1 BER encoded array + * @param {!number} inputOffset Offset in ASN.1 BER encoded array where decoding should be started + * @param {!number} inputLength Maximum length of array of bytes which can be using in this function + * @returns {{offset: number, result: Object}} + */ +function LocalFromBER(inputBuffer, inputOffset, inputLength) +{ + const incomingOffset = inputOffset; // Need to store initial offset since "inputOffset" is changing in the function + + //region Local function changing a type for ASN.1 classes + function localChangeType(inputObject, newType) + { + if(inputObject instanceof newType) + return inputObject; + + const newObject = new newType(); + newObject.idBlock = inputObject.idBlock; + newObject.lenBlock = inputObject.lenBlock; + newObject.warnings = inputObject.warnings; + //noinspection JSCheckFunctionSignatures + newObject.valueBeforeDecode = inputObject.valueBeforeDecode.slice(0); + + return newObject; + } + //endregion + + //region Create a basic ASN.1 type since we need to return errors and warnings from the function + let returnObject = new BaseBlock({}, Object); + //endregion + + //region Basic check for parameters + const baseBlock = new LocalBaseBlock(); + if(checkBufferParams(baseBlock, inputBuffer, inputOffset, inputLength) === false) + { + returnObject.error = baseBlock.error; + return { + offset: (-1), + result: returnObject + }; + } + //endregion + + //region Getting Uint8Array from ArrayBuffer + const intBuffer = new Uint8Array(inputBuffer, inputOffset, inputLength); + //endregion + + //region Initial checks + if(intBuffer.length === 0) + { + returnObject.error = "Zero buffer length"; + return { + offset: (-1), + result: returnObject + }; + } + //endregion + + //region Decode indentifcation block of ASN.1 BER structure + let resultOffset = returnObject.idBlock.fromBER(inputBuffer, inputOffset, inputLength); + returnObject.warnings.concat(returnObject.idBlock.warnings); + if(resultOffset === (-1)) + { + returnObject.error = returnObject.idBlock.error; + return { + offset: (-1), + result: returnObject + }; + } + + inputOffset = resultOffset; + inputLength -= returnObject.idBlock.blockLength; + //endregion + + //region Decode length block of ASN.1 BER structure + resultOffset = returnObject.lenBlock.fromBER(inputBuffer, inputOffset, inputLength); + returnObject.warnings.concat(returnObject.lenBlock.warnings); + if(resultOffset === (-1)) + { + returnObject.error = returnObject.lenBlock.error; + return { + offset: (-1), + result: returnObject + }; + } + + inputOffset = resultOffset; + inputLength -= returnObject.lenBlock.blockLength; + //endregion + + //region Check for usign indefinite length form in encoding for primitive types + if((returnObject.idBlock.isConstructed === false) && + (returnObject.lenBlock.isIndefiniteForm === true)) + { + returnObject.error = "Indefinite length form used for primitive encoding form"; + return { + offset: (-1), + result: returnObject + }; + } + //endregion + + //region Switch ASN.1 block type + let newASN1Type = BaseBlock; + + switch(returnObject.idBlock.tagClass) + { + //region UNIVERSAL + case 1: + //region Check for reserved tag numbers + if((returnObject.idBlock.tagNumber >= 37) && + (returnObject.idBlock.isHexOnly === false)) + { + returnObject.error = "UNIVERSAL 37 and upper tags are reserved by ASN.1 standard"; + return { + offset: (-1), + result: returnObject + }; + } + //endregion + + switch(returnObject.idBlock.tagNumber) + { + //region EndOfContent type + case 0: + //region Check for EndOfContent type + if((returnObject.idBlock.isConstructed === true) && + (returnObject.lenBlock.length > 0)) + { + returnObject.error = "Type [UNIVERSAL 0] is reserved"; + return { + offset: (-1), + result: returnObject + }; + } + //endregion + + newASN1Type = EndOfContent; + + break; + //endregion + //region Boolean type + case 1: + newASN1Type = Boolean; + break; + //endregion + //region Integer type + case 2: + newASN1Type = Integer; + break; + //endregion + //region BitString type + case 3: + newASN1Type = BitString; + break; + //endregion + //region OctetString type + case 4: + newASN1Type = OctetString; + break; + //endregion + //region Null type + case 5: + newASN1Type = Null; + break; + //endregion + //region OBJECT IDENTIFIER type + case 6: + newASN1Type = ObjectIdentifier; + break; + //endregion + //region Enumerated type + case 10: + newASN1Type = Enumerated; + break; + //endregion + //region Utf8String type + case 12: + newASN1Type = Utf8String; + break; + //endregion + //region Time type + //region RELATIVE OBJECT IDENTIFIER type + case 13: + newASN1Type = RelativeObjectIdentifier; + break; + //endregion + case 14: + newASN1Type = TIME; + break; + //endregion + //region ASN.1 reserved type + case 15: + returnObject.error = "[UNIVERSAL 15] is reserved by ASN.1 standard"; + return { + offset: (-1), + result: returnObject + }; + //endregion + //region Sequence type + case 16: + newASN1Type = Sequence; + break; + //endregion + //region Set type + case 17: + newASN1Type = Set; + break; + //endregion + //region NumericString type + case 18: + newASN1Type = NumericString; + break; + //endregion + //region PrintableString type + case 19: + newASN1Type = PrintableString; + break; + //endregion + //region TeletexString type + case 20: + newASN1Type = TeletexString; + break; + //endregion + //region VideotexString type + case 21: + newASN1Type = VideotexString; + break; + //endregion + //region IA5String type + case 22: + newASN1Type = IA5String; + break; + //endregion + //region UTCTime type + case 23: + newASN1Type = UTCTime; + break; + //endregion + //region GeneralizedTime type + case 24: + newASN1Type = GeneralizedTime; + break; + //endregion + //region GraphicString type + case 25: + newASN1Type = GraphicString; + break; + //endregion + //region VisibleString type + case 26: + newASN1Type = VisibleString; + break; + //endregion + //region GeneralString type + case 27: + newASN1Type = GeneralString; + break; + //endregion + //region UniversalString type + case 28: + newASN1Type = UniversalString; + break; + //endregion + //region CharacterString type + case 29: + newASN1Type = CharacterString; + break; + //endregion + //region BmpString type + case 30: + newASN1Type = BmpString; + break; + //endregion + //region DATE type + case 31: + newASN1Type = DATE; + break; + //endregion + //region TimeOfDay type + case 32: + newASN1Type = TimeOfDay; + break; + //endregion + //region Date-Time type + case 33: + newASN1Type = DateTime; + break; + //endregion + //region Duration type + case 34: + newASN1Type = Duration; + break; + //endregion + //region default + default: + { + let newObject; + + if(returnObject.idBlock.isConstructed === true) + newObject = new Constructed(); + else + newObject = new Primitive(); + + newObject.idBlock = returnObject.idBlock; + newObject.lenBlock = returnObject.lenBlock; + newObject.warnings = returnObject.warnings; + + returnObject = newObject; + } + //endregion + } + break; + //endregion + //region All other tag classes + case 2: // APPLICATION + case 3: // CONTEXT-SPECIFIC + case 4: // PRIVATE + default: + { + if(returnObject.idBlock.isConstructed === true) + newASN1Type = Constructed; + else + newASN1Type = Primitive; + } + //endregion + } + //endregion + + //region Change type and perform BER decoding + returnObject = localChangeType(returnObject, newASN1Type); + resultOffset = returnObject.fromBER(inputBuffer, inputOffset, (returnObject.lenBlock.isIndefiniteForm === true) ? inputLength : returnObject.lenBlock.length); + //endregion + + //region Coping incoming buffer for entire ASN.1 block + returnObject.valueBeforeDecode = inputBuffer.slice(incomingOffset, incomingOffset + returnObject.blockLength); + //endregion + + return { + offset: resultOffset, + result: returnObject + }; +} +//************************************************************************************** +/** + * Major function for decoding ASN.1 BER array into internal library structuries + * @param {!ArrayBuffer} inputBuffer ASN.1 BER encoded array of bytes + */ +export function fromBER(inputBuffer) +{ + if(inputBuffer.byteLength === 0) + { + const result = new BaseBlock({}, Object); + result.error = "Input buffer has zero length"; + + return { + offset: (-1), + result + }; + } + + return LocalFromBER(inputBuffer, 0, inputBuffer.byteLength); +} +//************************************************************************************** +//endregion +//************************************************************************************** +//region Major scheme verification function +//************************************************************************************** +/** + * Compare of two ASN.1 object trees + * @param {!Object} root Root of input ASN.1 object tree + * @param {!Object} inputData Input ASN.1 object tree + * @param {!Object} inputSchema Input ASN.1 schema to compare with + * @return {{verified: boolean}|{verified:boolean, result: Object}} + */ +export function compareSchema(root, inputData, inputSchema) +{ + //region Special case for Choice schema element type + if(inputSchema instanceof Choice) + { + const choiceResult = false; + + for(let j = 0; j < inputSchema.value.length; j++) + { + const result = compareSchema(root, inputData, inputSchema.value[j]); + if(result.verified === true) + { + return { + verified: true, + result: root + }; + } + } + + if(choiceResult === false) + { + const _result = { + verified: false, + result: { + error: "Wrong values for Choice type" + } + }; + + if(inputSchema.hasOwnProperty("name")) + _result.name = inputSchema.name; + + return _result; + } + } + //endregion + + //region Special case for Any schema element type + if(inputSchema instanceof Any) + { + //region Add named component of ASN.1 schema + if(inputSchema.hasOwnProperty("name")) + root[inputSchema.name] = inputData; + //endregion + + return { + verified: true, + result: root + }; + } + //endregion + + //region Initial check + if((root instanceof Object) === false) + { + return { + verified: false, + result: { error: "Wrong root object" } + }; + } + + if((inputData instanceof Object) === false) + { + return { + verified: false, + result: { error: "Wrong ASN.1 data" } + }; + } + + if((inputSchema instanceof Object) === false) + { + return { + verified: false, + result: { error: "Wrong ASN.1 schema" } + }; + } + + if(("idBlock" in inputSchema) === false) + { + return { + verified: false, + result: { error: "Wrong ASN.1 schema" } + }; + } + //endregion + + //region Comparing idBlock properties in ASN.1 data and ASN.1 schema + //region Encode and decode ASN.1 schema idBlock + /// This encoding/decoding is neccessary because could be an errors in schema definition + if(("fromBER" in inputSchema.idBlock) === false) + { + return { + verified: false, + result: { error: "Wrong ASN.1 schema" } + }; + } + + if(("toBER" in inputSchema.idBlock) === false) + { + return { + verified: false, + result: { error: "Wrong ASN.1 schema" } + }; + } + + const encodedId = inputSchema.idBlock.toBER(false); + if(encodedId.byteLength === 0) + { + return { + verified: false, + result: { error: "Error encoding idBlock for ASN.1 schema" } + }; + } + + const decodedOffset = inputSchema.idBlock.fromBER(encodedId, 0, encodedId.byteLength); + if(decodedOffset === (-1)) + { + return { + verified: false, + result: { error: "Error decoding idBlock for ASN.1 schema" } + }; + } + //endregion + + //region tagClass + if(inputSchema.idBlock.hasOwnProperty("tagClass") === false) + { + return { + verified: false, + result: { error: "Wrong ASN.1 schema" } + }; + } + + if(inputSchema.idBlock.tagClass !== inputData.idBlock.tagClass) + { + return { + verified: false, + result: root + }; + } + //endregion + //region tagNumber + if(inputSchema.idBlock.hasOwnProperty("tagNumber") === false) + { + return { + verified: false, + result: { error: "Wrong ASN.1 schema" } + }; + } + + if(inputSchema.idBlock.tagNumber !== inputData.idBlock.tagNumber) + { + return { + verified: false, + result: root + }; + } + //endregion + //region isConstructed + if(inputSchema.idBlock.hasOwnProperty("isConstructed") === false) + { + return { + verified: false, + result: { error: "Wrong ASN.1 schema" } + }; + } + + if(inputSchema.idBlock.isConstructed !== inputData.idBlock.isConstructed) + { + return { + verified: false, + result: root + }; + } + //endregion + //region isHexOnly + if(("isHexOnly" in inputSchema.idBlock) === false) // Since 'isHexOnly' is an inhirited property + { + return { + verified: false, + result: { error: "Wrong ASN.1 schema" } + }; + } + + if(inputSchema.idBlock.isHexOnly !== inputData.idBlock.isHexOnly) + { + return { + verified: false, + result: root + }; + } + //endregion + //region valueHex + if(inputSchema.idBlock.isHexOnly === true) + { + if(("valueHex" in inputSchema.idBlock) === false) // Since 'valueHex' is an inhirited property + { + return { + verified: false, + result: { error: "Wrong ASN.1 schema" } + }; + } + + const schemaView = new Uint8Array(inputSchema.idBlock.valueHex); + const asn1View = new Uint8Array(inputData.idBlock.valueHex); + + if(schemaView.length !== asn1View.length) + { + return { + verified: false, + result: root + }; + } + + for(let i = 0; i < schemaView.length; i++) + { + if(schemaView[i] !== asn1View[1]) + { + return { + verified: false, + result: root + }; + } + } + } + //endregion + //endregion + + //region Add named component of ASN.1 schema + if(inputSchema.hasOwnProperty("name")) + { + inputSchema.name = inputSchema.name.replace(/^\s+|\s+$/g, ""); + if(inputSchema.name !== "") + root[inputSchema.name] = inputData; + } + //endregion + + //region Getting next ASN.1 block for comparition + if(inputSchema.idBlock.isConstructed === true) + { + let admission = 0; + let result = { verified: false }; + + let maxLength = inputSchema.valueBlock.value.length; + + if(maxLength > 0) + { + if(inputSchema.valueBlock.value[0] instanceof Repeated) + maxLength = inputData.valueBlock.value.length; + } + + //region Special case when constructive value has no elements + if(maxLength === 0) + { + return { + verified: true, + result: root + }; + } + //endregion + + //region Special case when "inputData" has no values and "inputSchema" has all optional values + if((inputData.valueBlock.value.length === 0) && + (inputSchema.valueBlock.value.length !== 0)) + { + let _optional = true; + + for(let i = 0; i < inputSchema.valueBlock.value.length; i++) + _optional = _optional && (inputSchema.valueBlock.value[i].optional || false); + + if(_optional === true) + { + return { + verified: true, + result: root + }; + } + + //region Delete early added name of block + if(inputSchema.hasOwnProperty("name")) + { + inputSchema.name = inputSchema.name.replace(/^\s+|\s+$/g, ""); + if(inputSchema.name !== "") + delete root[inputSchema.name]; + } + //endregion + + root.error = "Inconsistent object length"; + + return { + verified: false, + result: root + }; + } + //endregion + + for(let i = 0; i < maxLength; i++) + { + //region Special case when there is an "optional" element of ASN.1 schema at the end + if((i - admission) >= inputData.valueBlock.value.length) + { + if(inputSchema.valueBlock.value[i].optional === false) + { + const _result = { + verified: false, + result: root + }; + + root.error = "Inconsistent length between ASN.1 data and schema"; + + //region Delete early added name of block + if(inputSchema.hasOwnProperty("name")) + { + inputSchema.name = inputSchema.name.replace(/^\s+|\s+$/g, ""); + if(inputSchema.name !== "") + { + delete root[inputSchema.name]; + _result.name = inputSchema.name; + } + } + //endregion + + return _result; + } + } + //endregion + else + { + //region Special case for Repeated type of ASN.1 schema element + if(inputSchema.valueBlock.value[0] instanceof Repeated) + { + result = compareSchema(root, inputData.valueBlock.value[i], inputSchema.valueBlock.value[0].value); + if(result.verified === false) + { + if(inputSchema.valueBlock.value[0].optional === true) + admission++; + else + { + //region Delete early added name of block + if(inputSchema.hasOwnProperty("name")) + { + inputSchema.name = inputSchema.name.replace(/^\s+|\s+$/g, ""); + if(inputSchema.name !== "") + delete root[inputSchema.name]; + } + //endregion + + return result; + } + } + + if(("name" in inputSchema.valueBlock.value[0]) && (inputSchema.valueBlock.value[0].name.length > 0)) + { + let arrayRoot = {}; + + if(("local" in inputSchema.valueBlock.value[0]) && (inputSchema.valueBlock.value[0].local === true)) + arrayRoot = inputData; + else + arrayRoot = root; + + if(typeof arrayRoot[inputSchema.valueBlock.value[0].name] === "undefined") + arrayRoot[inputSchema.valueBlock.value[0].name] = []; + + arrayRoot[inputSchema.valueBlock.value[0].name].push(inputData.valueBlock.value[i]); + } + } + //endregion + else + { + result = compareSchema(root, inputData.valueBlock.value[i - admission], inputSchema.valueBlock.value[i]); + if(result.verified === false) + { + if(inputSchema.valueBlock.value[i].optional === true) + admission++; + else + { + //region Delete early added name of block + if(inputSchema.hasOwnProperty("name")) + { + inputSchema.name = inputSchema.name.replace(/^\s+|\s+$/g, ""); + if(inputSchema.name !== "") + delete root[inputSchema.name]; + } + //endregion + + return result; + } + } + } + } + } + + if(result.verified === false) // The situation may take place if last element is "optional" and verification failed + { + const _result = { + verified: false, + result: root + }; + + //region Delete early added name of block + if(inputSchema.hasOwnProperty("name")) + { + inputSchema.name = inputSchema.name.replace(/^\s+|\s+$/g, ""); + if(inputSchema.name !== "") + { + delete root[inputSchema.name]; + _result.name = inputSchema.name; + } + } + //endregion + + return _result; + } + + return { + verified: true, + result: root + }; + } + //endregion + //region Ability to parse internal value for primitive-encoded value (value of OctetString, for example) + if(("primitiveSchema" in inputSchema) && + ("valueHex" in inputData.valueBlock)) + { + //region Decoding of raw ASN.1 data + const asn1 = fromBER(inputData.valueBlock.valueHex); + if(asn1.offset === (-1)) + { + const _result = { + verified: false, + result: asn1.result + }; + + //region Delete early added name of block + if(inputSchema.hasOwnProperty("name")) + { + inputSchema.name = inputSchema.name.replace(/^\s+|\s+$/g, ""); + if(inputSchema.name !== "") + { + delete root[inputSchema.name]; + _result.name = inputSchema.name; + } + } + //endregion + + return _result; + } + //endregion + + return compareSchema(root, asn1.result, inputSchema.primitiveSchema); + } + + return { + verified: true, + result: root + }; + //endregion +} +//************************************************************************************** +//noinspection JSUnusedGlobalSymbols +/** + * ASN.1 schema verification for ArrayBuffer data + * @param {!ArrayBuffer} inputBuffer Input BER-encoded ASN.1 data + * @param {!Object} inputSchema Input ASN.1 schema to verify against to + * @return {{verified: boolean}|{verified:boolean, result: Object}} + */ +export function verifySchema(inputBuffer, inputSchema) +{ + //region Initial check + if((inputSchema instanceof Object) === false) + { + return { + verified: false, + result: { error: "Wrong ASN.1 schema type" } + }; + } + //endregion + + //region Decoding of raw ASN.1 data + const asn1 = fromBER(inputBuffer); + if(asn1.offset === (-1)) + { + return { + verified: false, + result: asn1.result + }; + } + //endregion + + //region Compare ASN.1 struct with input schema + return compareSchema(asn1.result, asn1.result, inputSchema); + //endregion +} +//************************************************************************************** +//endregion +//************************************************************************************** +//region Major function converting JSON to ASN.1 objects +//************************************************************************************** +//noinspection JSUnusedGlobalSymbols +/** + * Converting from JSON to ASN.1 objects + * @param {string|Object} json JSON string or object to convert to ASN.1 objects + */ +export function fromJSON(json) +{ + // TODO Implement +} +//************************************************************************************** +//endregion +//************************************************************************************** diff --git a/core/third-party/pkijs/bytestream.js b/core/third-party/pkijs/bytestream.js new file mode 100644 index 0000000..ad57a86 --- /dev/null +++ b/core/third-party/pkijs/bytestream.js @@ -0,0 +1,4317 @@ +/* + * Copyright (c) 2016-2018, Peculiar Ventures + * All rights reserved. + * + * Author 2016-2018, Yury Strozhevsky . + * + */ +//************************************************************************************** +export class ByteStream +{ + //********************************************************************************** + // noinspection FunctionWithMultipleLoopsJS + /** + * Constructor for ByteStream class + * @param {{[length]: number, [stub]: number, [view]: Uint8Array, [buffer]: ArrayBuffer, [string]: string, [hexstring]: string}} parameters + */ + constructor(parameters = {}) + { + this.clear(); + + for(const key of Object.keys(parameters)) + { + switch(key) + { + case "length": + this.length = parameters.length; + break; + case "stub": + // noinspection NonBlockStatementBodyJS + for(let i = 0; i < this._view.length; i++) + this._view[i] = parameters.stub; + break; + case "view": + this.fromUint8Array(parameters.view); + break; + case "buffer": + this.fromArrayBuffer(parameters.buffer); + break; + case "string": + this.fromString(parameters.string); + break; + case "hexstring": + this.fromHexString(parameters.hexstring); + break; + default: + } + } + } + //********************************************************************************** + /** + * Setter for "buffer" + * @param {ArrayBuffer} value + */ + set buffer(value) + { + this._buffer = value.slice(0); + this._view = new Uint8Array(this._buffer); + } + //********************************************************************************** + /** + * Getter for "buffer" + * @returns {ArrayBuffer} + */ + get buffer() + { + return this._buffer; + } + //********************************************************************************** + /** + * Setter for "view" + * @param {Uint8Array} value + */ + set view(value) + { + this._buffer = new ArrayBuffer(value.length); + this._view = new Uint8Array(this._buffer); + + this._view.set(value); + } + //********************************************************************************** + /** + * Getter for "view" + * @returns {Uint8Array} + */ + get view() + { + return this._view; + } + //********************************************************************************** + /** + * Getter for "length" + * @returns {number} + */ + get length() + { + return this._buffer.byteLength; + } + //********************************************************************************** + /** + * Setter for "length" + * @param {number} value + */ + set length(value) + { + this._buffer = new ArrayBuffer(value); + this._view = new Uint8Array(this._buffer); + } + //********************************************************************************** + /** + * Clear existing stream + */ + clear() + { + this._buffer = new ArrayBuffer(0); + this._view = new Uint8Array(this._buffer); + } + //********************************************************************************** + /** + * Initialize "Stream" object from existing "ArrayBuffer" + * @param {!ArrayBuffer} array The ArrayBuffer to copy from + */ + fromArrayBuffer(array) + { + this.buffer = array; + } + //********************************************************************************** + // noinspection FunctionNamingConventionJS + /** + * Initialize "Stream" object from existing "Uint8Array" + * @param {!Uint8Array} array The Uint8Array to copy from + */ + fromUint8Array(array) + { + this._buffer = new ArrayBuffer(array.length); + this._view = new Uint8Array(this._buffer); + + this._view.set(array); + } + //********************************************************************************** + /** + * Initialize "Stream" object from existing string + * @param {string} string The string to initialize from + */ + fromString(string) + { + const stringLength = string.length; + + this.length = stringLength; + + // noinspection NonBlockStatementBodyJS + for(let i = 0; i < stringLength; i++) + this.view[i] = string.charCodeAt(i); + } + //********************************************************************************** + /** + * Represent "Stream" object content as a string + * @param {number} [start] Start position to convert to string + * @param {number} [length] Length of array to convert to string + * @returns {string} + */ + toString(start = 0, length = (this.view.length - start)) + { + //region Initial variables + let result = ""; + //endregion + + //region Check input parameters + // noinspection ConstantOnRightSideOfComparisonJS, ConstantOnLeftSideOfComparisonJS + if((start >= this.view.length) || (start < 0)) + { + // noinspection AssignmentToFunctionParameterJS + start = 0; + } + + // noinspection ConstantOnRightSideOfComparisonJS, ConstantOnLeftSideOfComparisonJS + if((length >= this.view.length) || (length < 0)) + { + // noinspection AssignmentToFunctionParameterJS + length = this.view.length - start; + } + //endregion + + //region Convert array of bytes to string + // noinspection NonBlockStatementBodyJS + for(let i = start; i < (start + length); i++) + result += String.fromCharCode(this.view[i]); + //endregion + + return result; + } + //********************************************************************************** + // noinspection FunctionTooLongJS + /** + * Initialize "Stream" object from existing hexdecimal string + * @param {string} hexString String to initialize from + */ + fromHexString(hexString) + { + //region Initial variables + const stringLength = hexString.length; + + this.buffer = new ArrayBuffer(stringLength >> 1); + this.view = new Uint8Array(this.buffer); + + const hexMap = new Map(); + + // noinspection MagicNumberJS + hexMap.set("0", 0x00); + // noinspection MagicNumberJS + hexMap.set("1", 0x01); + // noinspection MagicNumberJS + hexMap.set("2", 0x02); + // noinspection MagicNumberJS + hexMap.set("3", 0x03); + // noinspection MagicNumberJS + hexMap.set("4", 0x04); + // noinspection MagicNumberJS + hexMap.set("5", 0x05); + // noinspection MagicNumberJS + hexMap.set("6", 0x06); + // noinspection MagicNumberJS + hexMap.set("7", 0x07); + // noinspection MagicNumberJS + hexMap.set("8", 0x08); + // noinspection MagicNumberJS + hexMap.set("9", 0x09); + // noinspection MagicNumberJS + hexMap.set("A", 0x0A); + // noinspection MagicNumberJS + hexMap.set("a", 0x0A); + // noinspection MagicNumberJS + hexMap.set("B", 0x0B); + // noinspection MagicNumberJS + hexMap.set("b", 0x0B); + // noinspection MagicNumberJS + hexMap.set("C", 0x0C); + // noinspection MagicNumberJS + hexMap.set("c", 0x0C); + // noinspection MagicNumberJS + hexMap.set("D", 0x0D); + // noinspection MagicNumberJS + hexMap.set("d", 0x0D); + // noinspection MagicNumberJS + hexMap.set("E", 0x0E); + // noinspection MagicNumberJS + hexMap.set("e", 0x0E); + // noinspection MagicNumberJS + hexMap.set("F", 0x0F); + // noinspection MagicNumberJS + hexMap.set("f", 0x0F); + + let j = 0; + // noinspection MagicNumberJS + let temp = 0x00; + //endregion + + //region Convert char-by-char + for(let i = 0; i < stringLength; i++) + { + // noinspection NegatedIfStatementJS + if(!(i % 2)) + { + // noinspection NestedFunctionCallJS + temp = hexMap.get(hexString.charAt(i)) << 4; + } + else + { + // noinspection NestedFunctionCallJS + temp |= hexMap.get(hexString.charAt(i)); + + this.view[j] = temp; + j++; + } + } + //endregion + } + //********************************************************************************** + // noinspection JSUnusedGlobalSymbols + /** + * Represent "Stream" object content as a hexdecimal string + * @param {number} [start=0] Start position to convert to string + * @param {number} [length=(this.view.length - start)] Length of array to convert to string + * @returns {string} + */ + toHexString(start = 0, length = (this.view.length - start)) + { + //region Initial variables + let result = ""; + //endregion + + //region Check input parameters + // noinspection ConstantOnRightSideOfComparisonJS, ConstantOnLeftSideOfComparisonJS + if((start >= this.view.length) || (start < 0)) + { + // noinspection AssignmentToFunctionParameterJS + start = 0; + } + + // noinspection ConstantOnRightSideOfComparisonJS, ConstantOnLeftSideOfComparisonJS + if((length >= this.view.length) || (length < 0)) + { + // noinspection AssignmentToFunctionParameterJS + length = this.view.length - start; + } + //endregion + + for(let i = start; i < (start + length); i++) + { + // noinspection ChainedFunctionCallJS + const str = this.view[i].toString(16).toUpperCase(); + // noinspection ConstantOnRightSideOfComparisonJS, ConstantOnLeftSideOfComparisonJS, ConditionalExpressionJS, EqualityComparisonWithCoercionJS + result = result + ((str.length == 1) ? "0" : "") + str; + } + + return result; + } + //********************************************************************************** + // noinspection FunctionWithMultipleReturnPointsJS + /** + * Return copy of existing "Stream" + * @param {number} [start=0] Start position of the copy + * @param {number} [length=this.view.length] Length of the copy + * @returns {ByteStream} + */ + copy(start = 0, length = (this._buffer.byteLength - start)) + { + //region Check input parameters + // noinspection ConstantOnRightSideOfComparisonJS, ConstantOnLeftSideOfComparisonJS, NonBlockStatementBodyJS + if((start === 0) && (this._buffer.byteLength === 0)) + return new ByteStream(); + + // noinspection ConstantOnRightSideOfComparisonJS, ConstantOnLeftSideOfComparisonJS, NonBlockStatementBodyJS + if((start < 0) || (start > (this._buffer.byteLength - 1))) + throw new Error(`Wrong start position: ${start}`); + //endregion + + const stream = new ByteStream(); + + stream._buffer = this._buffer.slice(start, start + length); + stream._view = new Uint8Array(stream._buffer); + + return stream; + } + //********************************************************************************** + // noinspection JSUnusedGlobalSymbols, FunctionWithMultipleReturnPointsJS + /** + * Return slice of existing "Stream" + * @param {number} [start=0] Start position of the slice + * @param {number} [end=this._buffer.byteLength] End position of the slice + * @returns {ByteStream} + */ + slice(start = 0, end = this._buffer.byteLength) + { + //region Check input parameters + // noinspection ConstantOnRightSideOfComparisonJS, ConstantOnLeftSideOfComparisonJS, NonBlockStatementBodyJS + if((start === 0) && (this._buffer.byteLength === 0)) + return new ByteStream(); + + // noinspection ConstantOnRightSideOfComparisonJS, ConstantOnLeftSideOfComparisonJS, NonBlockStatementBodyJS + if((start < 0) || (start > (this._buffer.byteLength - 1))) + throw new Error(`Wrong start position: ${start}`); + //endregion + + const stream = new ByteStream(); + + stream._buffer = this._buffer.slice(start, end); + stream._view = new Uint8Array(stream._buffer); + + return stream; + } + //********************************************************************************** + /** + * Change size of existing "Stream" + * @param {!number} size Size for new "Stream" + */ + realloc(size) + { + //region Initial variables + const buffer = new ArrayBuffer(size); + const view = new Uint8Array(buffer); + //endregion + + //region Create a new ArrayBuffer content + // noinspection NonBlockStatementBodyJS + if(size > this._view.length) + view.set(this._view); + else + { + // noinspection NestedFunctionCallJS + view.set(new Uint8Array(this._buffer, 0, size)); + } + //endregion + + //region Initialize "Stream" with new "ArrayBuffer" + this._buffer = buffer.slice(0); + this._view = new Uint8Array(this._buffer); + //endregion + } + //********************************************************************************** + // noinspection JSUnusedGlobalSymbols + /** + * Append a new "Stream" content to the current "Stream" + * @param {ByteStream} stream A new "stream" to append to current "stream" + */ + append(stream) + { + //region Initial variables + const initialSize = this._buffer.byteLength; + const streamViewLength = stream._buffer.byteLength; + + const copyView = stream._view.slice(); + //endregion + + //region Re-allocate current internal buffer + this.realloc(initialSize + streamViewLength); + //endregion + + //region Copy input stream content to a new place + this._view.set(copyView, initialSize); + //endregion + } + //********************************************************************************** + // noinspection JSUnusedGlobalSymbols, FunctionWithMultipleReturnPointsJS + /** + * Insert "Stream" content to the current "Stream" at specific position + * @param {ByteStream} stream A new "stream" to insert to current "stream" + * @param {number} [start=0] Start position to insert to + * @param {number} [length] + * @returns {boolean} + */ + insert(stream, start = 0, length = (this._buffer.byteLength - start)) + { + //region Initial variables + // noinspection NonBlockStatementBodyJS + if(start > (this._buffer.byteLength - 1)) + return false; + + if(length > (this._buffer.byteLength - start)) + { + // noinspection AssignmentToFunctionParameterJS + length = this._buffer.byteLength - start; + } + //endregion + + //region Check input variables + if(length > stream._buffer.byteLength) + { + // noinspection AssignmentToFunctionParameterJS + length = stream._buffer.byteLength; + } + //endregion + + //region Update content of the current stream + // noinspection NonBlockStatementBodyJS, EqualityComparisonWithCoercionJS + if(length == stream._buffer.byteLength) + this._view.set(stream._view, start); + else + { + // noinspection NestedFunctionCallJS + this._view.set(stream._view.slice(0, length), start); + } + //endregion + + return true; + } + //********************************************************************************** + // noinspection FunctionWithMultipleReturnPointsJS + /** + * Check that two "Stream" objects has equal content + * @param {ByteStream} stream Stream to compare with + * @returns {boolean} + */ + isEqual(stream) + { + //region Check length of both buffers + // noinspection NonBlockStatementBodyJS, EqualityComparisonWithCoercionJS + if(this._buffer.byteLength != stream._buffer.byteLength) + return false; + //endregion + + //region Compare each byte of both buffers + for(let i = 0; i < stream._buffer.byteLength; i++) + { + // noinspection NonBlockStatementBodyJS, EqualityComparisonWithCoercionJS + if(this.view[i] != stream.view[i]) + return false; + } + //endregion + + return true; + } + //********************************************************************************** + // noinspection JSUnusedGlobalSymbols, FunctionWithMultipleReturnPointsJS + /** + * Check that current "Stream" objects has equal content with input "Uint8Array" + * @param {Uint8Array} view View to compare with + * @returns {boolean} + */ + isEqualView(view) + { + //region Check length of both buffers + // noinspection NonBlockStatementBodyJS, EqualityComparisonWithCoercionJS + if(view.length != this.view.length) + return false; + //endregion + + //region Compare each byte of both buffers + for(let i = 0; i < view.length; i++) + { + // noinspection NonBlockStatementBodyJS, EqualityComparisonWithCoercionJS + if(this.view[i] != view[i]) + return false; + } + //endregion + + return true; + } + //********************************************************************************** + // noinspection JSUnusedGlobalSymbols, FunctionWithMultipleLoopsJS, FunctionWithMultipleReturnPointsJS, OverlyComplexFunctionJS, FunctionTooLongJS + /** + * Find any byte pattern in "Stream" + * @param {ByteStream} pattern Stream having pattern value + * @param {?number} [start] Start position to search from + * @param {?number} [length] Length of byte block to search at + * @param {boolean} [backward] Flag to search in backward order + * @returns {number} + */ + findPattern(pattern, start = null, length = null, backward = false) + { + //region Check input variables + // noinspection ConstantOnRightSideOfComparisonJS, ConstantOnLeftSideOfComparisonJS + if(start == null) + { + // noinspection AssignmentToFunctionParameterJS, ConditionalExpressionJS + start = (backward) ? this.buffer.byteLength : 0; + } + + if(start > this.buffer.byteLength) + { + // noinspection AssignmentToFunctionParameterJS + start = this.buffer.byteLength; + } + + if(backward) + { + // noinspection ConstantOnRightSideOfComparisonJS, ConstantOnLeftSideOfComparisonJS + if(length == null) + { + // noinspection AssignmentToFunctionParameterJS + length = start; + } + + if(length > start) + { + // noinspection AssignmentToFunctionParameterJS + length = start; + } + } + else + { + // noinspection ConstantOnRightSideOfComparisonJS, ConstantOnLeftSideOfComparisonJS + if(length == null) + { + // noinspection AssignmentToFunctionParameterJS + length = this.buffer.byteLength - start; + } + + if(length > (this.buffer.byteLength - start)) + { + // noinspection AssignmentToFunctionParameterJS + length = this.buffer.byteLength - start; + } + } + //endregion + + //region Initial variables + const patternLength = pattern.buffer.byteLength; + // noinspection NonBlockStatementBodyJS + if(patternLength > length) + return (-1); + //endregion + + //region Make a "pre-read" array for pattern + const patternArray = []; + // noinspection NonBlockStatementBodyJS + for(let i = 0; i < patternLength; i++) + patternArray.push(pattern.view[i]); + //endregion + + //region Search for pattern + for(let i = 0; i <= (length - patternLength); i++) + { + let equal = true; + // noinspection ConditionalExpressionJS + const equalStart = (backward) ? (start - patternLength - i) : (start + i); + + for(let j = 0; j < patternLength; j++) + { + // noinspection EqualityComparisonWithCoercionJS + if(this.view[j + equalStart] != patternArray[j]) + { + equal = false; + // noinspection BreakStatementJS + break; + } + } + + if(equal) + { + // noinspection ConditionalExpressionJS + return (backward) ? (start - patternLength - i) : (start + patternLength + i); // Position after the pattern found + } + } + //endregion + + return (-1); + } + //********************************************************************************** + // noinspection OverlyComplexFunctionJS + /** + * Find first position of any pattern from input array + * @param {Array.} patterns Array with patterns which should be found + * @param {?number} [start] Start position to search from + * @param {?number} [length] Length of byte block to search at + * @param {boolean} [backward=false] Flag to search in backward order + * @returns {{id: number, position: number}} + */ + findFirstIn(patterns, start = null, length = null, backward = false) + { + //region Initial variables + // noinspection ConstantOnRightSideOfComparisonJS, ConstantOnLeftSideOfComparisonJS + if(start == null) + { + // noinspection AssignmentToFunctionParameterJS, ConditionalExpressionJS + start = (backward) ? this.buffer.byteLength : 0; + } + + if(start > this.buffer.byteLength) + { + // noinspection AssignmentToFunctionParameterJS + start = this.buffer.byteLength; + } + + if(backward) + { + // noinspection ConstantOnRightSideOfComparisonJS, ConstantOnLeftSideOfComparisonJS + if(length == null) + { + // noinspection AssignmentToFunctionParameterJS + length = start; + } + + if(length > start) + { + // noinspection AssignmentToFunctionParameterJS + length = start; + } + } + else + { + // noinspection ConstantOnRightSideOfComparisonJS, ConstantOnLeftSideOfComparisonJS + if(length == null) + { + // noinspection AssignmentToFunctionParameterJS + length = this.buffer.byteLength - start; + } + + if(length > (this.buffer.byteLength - start)) + { + // noinspection AssignmentToFunctionParameterJS + length = this.buffer.byteLength - start; + } + } + + // noinspection ConditionalExpressionJS + const result = { + id: (-1), + position: (backward) ? 0 : (start + length), + length: 0 + }; + //endregion + + for(let i = 0; i < patterns.length; i++) + { + const position = this.findPattern(patterns[i], start, length, backward); + // noinspection EqualityComparisonWithCoercionJS + if(position != (-1)) + { + let valid = false; + const patternLength = patterns[i].length; + + if(backward) + { + // noinspection NonBlockStatementBodyJS + if((position - patternLength) >= (result.position - result.length)) + valid = true; + } + else + { + // noinspection NonBlockStatementBodyJS + if((position - patternLength) <= (result.position - result.length)) + valid = true; + } + + if(valid) + { + result.position = position; + result.id = i; + result.length = patternLength; + } + } + } + + return result; + } + //********************************************************************************** + // noinspection FunctionWithMultipleReturnPointsJS + /** + * Find all positions of any pattern from input array + * @param {Array.} patterns Array with patterns which should be found + * @param {?number} [start] Start position to search from + * @param {?number} [length] Length of byte block to search at + * @returns {Array} + */ + findAllIn(patterns, start = 0, length = (this.buffer.byteLength - start)) + { + //region Initial variables + const result = []; + + // noinspection ConstantOnRightSideOfComparisonJS, ConstantOnLeftSideOfComparisonJS + if(start == null) + { + // noinspection AssignmentToFunctionParameterJS + start = 0; + } + + // noinspection NonBlockStatementBodyJS + if(start > (this.buffer.byteLength - 1)) + return result; + + // noinspection ConstantOnRightSideOfComparisonJS, ConstantOnLeftSideOfComparisonJS + if(length == null) + { + // noinspection AssignmentToFunctionParameterJS + length = this.buffer.byteLength - start; + } + + if(length > (this.buffer.byteLength - start)) + { + // noinspection AssignmentToFunctionParameterJS + length = this.buffer.byteLength - start; + } + + let patternFound = { + id: (-1), + position: start + }; + //endregion + + //region Find all accurences of patterns + do + { + const position = patternFound.position; + + patternFound = this.findFirstIn(patterns, patternFound.position, length); + + // noinspection EqualityComparisonWithCoercionJS + if(patternFound.id == (-1)) + { + // noinspection BreakStatementJS + break; + } + + // noinspection AssignmentToFunctionParameterJS + length -= (patternFound.position - position); + + result.push({ + id: patternFound.id, + position: patternFound.position + }); + } while(true); // eslint-disable-line + //endregion + + return result; + } + //********************************************************************************** + // noinspection FunctionWithMultipleLoopsJS, FunctionWithMultipleReturnPointsJS + /** + * Find all positions of a pattern + * @param {ByteStream} pattern Stream having pattern value + * @param {?number} [start] Start position to search from + * @param {?number} [length] Length of byte block to search at + * @returns {Array|number} Array with all pattern positions or (-1) if failed + */ + findAllPatternIn(pattern, start = 0, length = (this.buffer.byteLength - start)) + { + //region Check input variables + // noinspection ConstantOnRightSideOfComparisonJS, ConstantOnLeftSideOfComparisonJS + if(start == null) + { + // noinspection AssignmentToFunctionParameterJS + start = 0; + } + + if(start > this.buffer.byteLength) + { + // noinspection AssignmentToFunctionParameterJS + start = this.buffer.byteLength; + } + + // noinspection ConstantOnRightSideOfComparisonJS, ConstantOnLeftSideOfComparisonJS + if(length == null) + { + // noinspection AssignmentToFunctionParameterJS + length = this.buffer.byteLength - start; + } + + if(length > (this.buffer.byteLength - start)) + { + // noinspection AssignmentToFunctionParameterJS + length = this.buffer.byteLength - start; + } + //endregion + + //region Initial variables + const result = []; + + const patternLength = pattern.buffer.byteLength; + // noinspection NonBlockStatementBodyJS + if(patternLength > length) + return (-1); + //endregion + + //region Make a "pre-read" array for pattern + const patternArray = Array.from(pattern.view); + //endregion + + //region Search for pattern + for(let i = 0; i <= (length - patternLength); i++) + { + let equal = true; + const equalStart = start + i; + + for(let j = 0; j < patternLength; j++) + { + // noinspection EqualityComparisonWithCoercionJS + if(this.view[j + equalStart] != patternArray[j]) + { + equal = false; + // noinspection BreakStatementJS + break; + } + } + + if(equal) + { + result.push(start + patternLength + i); // Position after the pattern found + i += (patternLength - 1); // On next step of "for" we will have "i++" + } + } + //endregion + + return result; + } + //********************************************************************************** + // noinspection OverlyComplexFunctionJS, FunctionTooLongJS + /** + * Find first position of data, not included in patterns from input array + * @param {Array.} patterns Array with patterns which should be ommited + * @param {?number} [start] Start position to search from + * @param {?number} [length] Length of byte block to search at + * @param {boolean} [backward=false] Flag to search in backward order + * @returns {{left: {id: number, position: *}, right: {id: number, position: number}, value: ByteStream}} + */ + findFirstNotIn(patterns, start = null, length = null, backward = false) + { + //region Initial variables + // noinspection ConstantOnRightSideOfComparisonJS, ConstantOnLeftSideOfComparisonJS + if(start == null) + { + // noinspection AssignmentToFunctionParameterJS, ConditionalExpressionJS + start = (backward) ? this.buffer.byteLength : 0; + } + + if(start > this.buffer.byteLength) + { + // noinspection AssignmentToFunctionParameterJS + start = this.buffer.byteLength; + } + + if(backward) + { + // noinspection ConstantOnRightSideOfComparisonJS, ConstantOnLeftSideOfComparisonJS + if(length == null) + { + // noinspection AssignmentToFunctionParameterJS + length = start; + } + + if(length > start) + { + // noinspection AssignmentToFunctionParameterJS + length = start; + } + } + else + { + // noinspection ConstantOnRightSideOfComparisonJS, ConstantOnLeftSideOfComparisonJS + if(length == null) + { + // noinspection AssignmentToFunctionParameterJS + length = this.buffer.byteLength - start; + } + + if(length > (this.buffer.byteLength - start)) + { + // noinspection AssignmentToFunctionParameterJS + length = this.buffer.byteLength - start; + } + } + + const result = { + left: { + id: (-1), + position: start + }, + right: { + id: (-1), + position: 0 + }, + value: new ByteStream() + }; + + let currentLength = length; + //endregion + + // noinspection ConstantOnRightSideOfComparisonJS, ConstantOnLeftSideOfComparisonJS + while(currentLength > 0) + { + //region Search for nearest "pattern" + // noinspection ConditionalExpressionJS + result.right = this.findFirstIn(patterns, + (backward) ? (start - length + currentLength) : (start + length - currentLength), + currentLength, + backward); + //endregion + + //region No pattern at all + // noinspection EqualityComparisonWithCoercionJS + if(result.right.id == (-1)) + { + // noinspection AssignmentToFunctionParameterJS + length = currentLength; + + if(backward) + { + // noinspection AssignmentToFunctionParameterJS + start -= length; + } + else + { + // noinspection AssignmentToFunctionParameterJS + start = result.left.position; + } + + result.value = new ByteStream(); + + result.value._buffer = this._buffer.slice(start, start + length); + result.value._view = new Uint8Array(result.value._buffer); + + // noinspection BreakStatementJS + break; + } + //endregion + + //region Check distance between two patterns + // noinspection ConditionalExpressionJS, EqualityComparisonWithCoercionJS + if(result.right.position != ((backward) ? (result.left.position - patterns[result.right.id].buffer.byteLength) : (result.left.position + patterns[result.right.id].buffer.byteLength))) + { + if(backward) + { + // noinspection AssignmentToFunctionParameterJS + start = result.right.position + patterns[result.right.id].buffer.byteLength; + // noinspection AssignmentToFunctionParameterJS + length = result.left.position - result.right.position - patterns[result.right.id].buffer.byteLength; + } + else + { + // noinspection AssignmentToFunctionParameterJS + start = result.left.position; + // noinspection AssignmentToFunctionParameterJS + length = result.right.position - result.left.position - patterns[result.right.id].buffer.byteLength; + } + + result.value = new ByteStream(); + + result.value._buffer = this._buffer.slice(start, start + length); + result.value._view = new Uint8Array(result.value._buffer); + + // noinspection BreakStatementJS + break; + } + //endregion + + //region Store information about previous pattern + result.left = result.right; + //endregion + + //region Change current length + currentLength -= patterns[result.right.id]._buffer.byteLength; + //endregion + } + + //region Swap "patterns" in case of backward order + if(backward) + { + const temp = result.right; + result.right = result.left; + result.left = temp; + } + //endregion + + return result; + } + //********************************************************************************** + // noinspection FunctionWithMultipleReturnPointsJS + /** + * Find all positions of data, not included in patterns from input array + * @param {Array.} patterns Array with patterns which should be ommited + * @param {?number} [start] Start position to search from + * @param {?number} [length] Length of byte block to search at + * @returns {Array} + */ + findAllNotIn(patterns, start = null, length = null) + { + //region Initial variables + const result = []; + + // noinspection ConstantOnRightSideOfComparisonJS, ConstantOnLeftSideOfComparisonJS + if(start == null) + { + // noinspection AssignmentToFunctionParameterJS + start = 0; + } + + // noinspection NonBlockStatementBodyJS + if(start > (this.buffer.byteLength - 1)) + return result; + + // noinspection ConstantOnRightSideOfComparisonJS, ConstantOnLeftSideOfComparisonJS + if(length == null) + { + // noinspection AssignmentToFunctionParameterJS + length = this.buffer.byteLength - start; + } + + if(length > (this.buffer.byteLength - start)) + { + // noinspection AssignmentToFunctionParameterJS + length = this.buffer.byteLength - start; + } + + let patternFound = { + left: { + id: (-1), + position: start + }, + right: { + id: (-1), + position: start + }, + value: new ByteStream() + }; + //endregion + + //region Find all accurences of patterns + // noinspection EqualityComparisonWithCoercionJS + do + { + const position = patternFound.right.position; + + patternFound = this.findFirstNotIn(patterns, patternFound.right.position, length); + + // noinspection AssignmentToFunctionParameterJS + length -= (patternFound.right.position - position); + + result.push({ + left: { + id: patternFound.left.id, + position: patternFound.left.position + }, + right: { + id: patternFound.right.id, + position: patternFound.right.position + }, + value: patternFound.value + }); + } while(patternFound.right.id != (-1)); + //endregion + + return result; + } + //********************************************************************************** + // noinspection FunctionWithMultipleReturnPointsJS, OverlyComplexFunctionJS + /** + * Find position of a sequence of any patterns from input array + * @param {Array.} patterns Array of pattern to look for + * @param {?number} [start] Start position to search from + * @param {?number} [length] Length of byte block to search at + * @param {boolean} [backward=false] Flag to search in backward order + * @returns {*} + */ + findFirstSequence(patterns, start = null, length = null, backward = false) + { + //region Initial variables + // noinspection ConstantOnRightSideOfComparisonJS, ConstantOnLeftSideOfComparisonJS + if(start == null) + { + // noinspection AssignmentToFunctionParameterJS, ConditionalExpressionJS + start = (backward) ? this.buffer.byteLength : 0; + } + + if(start > this.buffer.byteLength) + { + // noinspection AssignmentToFunctionParameterJS + start = this.buffer.byteLength; + } + + if(backward) + { + // noinspection ConstantOnRightSideOfComparisonJS, ConstantOnLeftSideOfComparisonJS + if(length == null) + { + // noinspection AssignmentToFunctionParameterJS + length = start; + } + + if(length > start) + { + // noinspection AssignmentToFunctionParameterJS + length = start; + } + } + else + { + // noinspection ConstantOnRightSideOfComparisonJS, ConstantOnLeftSideOfComparisonJS + if(length == null) + { + // noinspection AssignmentToFunctionParameterJS + length = this.buffer.byteLength - start; + } + + if(length > (this.buffer.byteLength - start)) + { + // noinspection AssignmentToFunctionParameterJS + length = this.buffer.byteLength - start; + } + } + //endregion + + //region Find first byte from sequence + const firstIn = this.skipNotPatterns(patterns, start, length, backward); + // noinspection EqualityComparisonWithCoercionJS + if(firstIn == (-1)) + { + return { + position: (-1), + value: new ByteStream() + }; + } + //endregion + + //region Find first byte not in sequence + // noinspection ConditionalExpressionJS + const firstNotIn = this.skipPatterns(patterns, + firstIn, + length - ((backward) ? (start - firstIn) : (firstIn - start)), + backward); + //endregion + + //region Make output value + if(backward) + { + // noinspection AssignmentToFunctionParameterJS + start = firstNotIn; + // noinspection AssignmentToFunctionParameterJS + length = (firstIn - firstNotIn); + } + else + { + // noinspection AssignmentToFunctionParameterJS + start = firstIn; + // noinspection AssignmentToFunctionParameterJS + length = (firstNotIn - firstIn); + } + + const value = new ByteStream(); + + value._buffer = this._buffer.slice(start, start + length); + value._view = new Uint8Array(value._buffer); + //endregion + + return { + position: firstNotIn, + value + }; + } + //********************************************************************************** + // noinspection FunctionWithMultipleReturnPointsJS + /** + * Find all positions of a sequence of any patterns from input array + * @param {Array.} patterns Array of patterns to search for + * @param {?number} [start] Start position to search from + * @param {?number} [length] Length of byte block to search at + * @returns {Array} + */ + findAllSequences(patterns, start = null, length = null) + { + //region Initial variables + const result = []; + + // noinspection ConstantOnRightSideOfComparisonJS, ConstantOnLeftSideOfComparisonJS + if(start == null) + { + // noinspection AssignmentToFunctionParameterJS + start = 0; + } + + // noinspection NonBlockStatementBodyJS + if(start > (this.buffer.byteLength - 1)) + return result; + + // noinspection ConstantOnRightSideOfComparisonJS, ConstantOnLeftSideOfComparisonJS + if(length == null) + { + // noinspection AssignmentToFunctionParameterJS + length = this.buffer.byteLength - start; + } + + if(length > (this.buffer.byteLength - start)) + { + // noinspection AssignmentToFunctionParameterJS + length = this.buffer.byteLength - start; + } + + let patternFound = { + position: start, + value: new ByteStream() + }; + //endregion + + //region Find all accurences of patterns + // noinspection EqualityComparisonWithCoercionJS + do + { + const position = patternFound.position; + + patternFound = this.findFirstSequence(patterns, patternFound.position, length); + + // noinspection EqualityComparisonWithCoercionJS + if(patternFound.position != (-1)) + { + // noinspection AssignmentToFunctionParameterJS + length -= (patternFound.position - position); + + result.push({ + position: patternFound.position, + value: patternFound.value + }); + } + + } while(patternFound.position != (-1)); + //endregion + + return result; + } + //********************************************************************************** + // noinspection FunctionWithMultipleLoopsJS, FunctionWithMultipleReturnPointsJS, OverlyComplexFunctionJS, FunctionTooLongJS + /** + * Find all paired patterns in the stream + * @param {ByteStream} leftPattern Left pattern to search for + * @param {ByteStream} rightPattern Right pattern to search for + * @param {?number} [start=null] Start position to search from + * @param {?number} [length=null] Length of byte block to search at + * @returns {Array} + */ + findPairedPatterns(leftPattern, rightPattern, start = null, length = null) + { + //region Initial variables + const result = []; + + // noinspection NonBlockStatementBodyJS + if(leftPattern.isEqual(rightPattern)) + return result; + + // noinspection ConstantOnRightSideOfComparisonJS, ConstantOnLeftSideOfComparisonJS + if(start == null) + { + // noinspection AssignmentToFunctionParameterJS + start = 0; + } + + // noinspection NonBlockStatementBodyJS + if(start > (this.buffer.byteLength - 1)) + return result; + + // noinspection ConstantOnRightSideOfComparisonJS, ConstantOnLeftSideOfComparisonJS + if(length == null) + { + // noinspection AssignmentToFunctionParameterJS + length = this.buffer.byteLength - start; + } + + if(length > (this.buffer.byteLength - start)) + { + // noinspection AssignmentToFunctionParameterJS + length = this.buffer.byteLength - start; + } + + let currentPositionLeft = 0; + //endregion + + //region Find all "left patterns" as sorted array + const leftPatterns = this.findAllPatternIn(leftPattern, start, length); + // noinspection ConstantOnRightSideOfComparisonJS, ConstantOnLeftSideOfComparisonJS, NonBlockStatementBodyJS, EqualityComparisonWithCoercionJS + if(leftPatterns.length == 0) + return result; + //endregion + + //region Find all "right patterns" as sorted array + const rightPatterns = this.findAllPatternIn(rightPattern, start, length); + // noinspection ConstantOnRightSideOfComparisonJS, ConstantOnLeftSideOfComparisonJS, NonBlockStatementBodyJS, EqualityComparisonWithCoercionJS + if(rightPatterns.length == 0) + return result; + //endregion + + //region Combine patterns + while(currentPositionLeft < leftPatterns.length) + { + // noinspection ConstantOnRightSideOfComparisonJS, ConstantOnLeftSideOfComparisonJS, EqualityComparisonWithCoercionJS + if(rightPatterns.length == 0) + { + // noinspection BreakStatementJS + break; + } + + // noinspection EqualityComparisonWithCoercionJS + if(leftPatterns[0] == rightPatterns[0]) + { + // Possible situation when one pattern is a part of another + // For example "stream" and "endstream" + // In case when we have only "endstream" in fact "stream" will be also found at the same position + // (position of the pattern is an index AFTER the pattern) + + result.push({ + left: leftPatterns[0], + right: rightPatterns[0] + }); + + leftPatterns.splice(0, 1); + rightPatterns.splice(0, 1); + + // noinspection ContinueStatementJS + continue; + } + + if(leftPatterns[currentPositionLeft] > rightPatterns[0]) + { + // noinspection BreakStatementJS + break; + } + + while(leftPatterns[currentPositionLeft] < rightPatterns[0]) + { + currentPositionLeft++; + + if(currentPositionLeft >= leftPatterns.length) + { + // noinspection BreakStatementJS + break; + } + } + + result.push({ + left: leftPatterns[currentPositionLeft - 1], + right: rightPatterns[0] + }); + + leftPatterns.splice(currentPositionLeft - 1, 1); + rightPatterns.splice(0, 1); + + currentPositionLeft = 0; + } + //endregion + + //region Sort result + result.sort((a, b) => (a.left - b.left)); + //endregion + + return result; + } + //********************************************************************************** + // noinspection FunctionWithMultipleLoopsJS, FunctionWithMultipleReturnPointsJS, OverlyComplexFunctionJS, FunctionTooLongJS + /** + * Find all paired patterns in the stream + * @param {Array.} inputLeftPatterns Array of left patterns to search for + * @param {Array.} inputRightPatterns Array of right patterns to search for + * @param {?number} [start=null] Start position to search from + * @param {?number} [length=null] Length of byte block to search at + * @returns {Array} + */ + findPairedArrays(inputLeftPatterns, inputRightPatterns, start = null, length = null) + { + //region Initial variables + const result = []; + + // noinspection ConstantOnRightSideOfComparisonJS, ConstantOnLeftSideOfComparisonJS + if(start == null) + { + // noinspection AssignmentToFunctionParameterJS + start = 0; + } + + // noinspection NonBlockStatementBodyJS + if(start > (this.buffer.byteLength - 1)) + return result; + + // noinspection ConstantOnRightSideOfComparisonJS, ConstantOnLeftSideOfComparisonJS + if(length == null) + { + // noinspection AssignmentToFunctionParameterJS + length = this.buffer.byteLength - start; + } + + if(length > (this.buffer.byteLength - start)) + { + // noinspection AssignmentToFunctionParameterJS + length = this.buffer.byteLength - start; + } + + let currentPositionLeft = 0; + //endregion + + //region Find all "left patterns" as sorted array + const leftPatterns = this.findAllIn(inputLeftPatterns, start, length); + // noinspection ConstantOnRightSideOfComparisonJS, ConstantOnLeftSideOfComparisonJS, NonBlockStatementBodyJS, EqualityComparisonWithCoercionJS + if(leftPatterns.length == 0) + return result; + //endregion + + //region Find all "right patterns" as sorted array + const rightPatterns = this.findAllIn(inputRightPatterns, start, length); + // noinspection ConstantOnRightSideOfComparisonJS, ConstantOnLeftSideOfComparisonJS, NonBlockStatementBodyJS, EqualityComparisonWithCoercionJS + if(rightPatterns.length == 0) + return result; + //endregion + + //region Combine patterns + while(currentPositionLeft < leftPatterns.length) + { + // noinspection ConstantOnRightSideOfComparisonJS, ConstantOnLeftSideOfComparisonJS, EqualityComparisonWithCoercionJS + if(rightPatterns.length == 0) + { + // noinspection BreakStatementJS + break; + } + + // noinspection EqualityComparisonWithCoercionJS + if(leftPatterns[0].position == rightPatterns[0].position) + { + // Possible situation when one pattern is a part of another + // For example "stream" and "endstream" + // In case when we have only "endstream" in fact "stream" will be also found at the same position + // (position of the pattern is an index AFTER the pattern) + + result.push({ + left: leftPatterns[0], + right: rightPatterns[0] + }); + + leftPatterns.splice(0, 1); + rightPatterns.splice(0, 1); + + // noinspection ContinueStatementJS + continue; + } + + if(leftPatterns[currentPositionLeft].position > rightPatterns[0].position) + { + // noinspection BreakStatementJS + break; + } + + while(leftPatterns[currentPositionLeft].position < rightPatterns[0].position) + { + currentPositionLeft++; + + if(currentPositionLeft >= leftPatterns.length) + { + // noinspection BreakStatementJS + break; + } + } + + result.push({ + left: leftPatterns[currentPositionLeft - 1], + right: rightPatterns[0] + }); + + leftPatterns.splice(currentPositionLeft - 1, 1); + rightPatterns.splice(0, 1); + + currentPositionLeft = 0; + } + //endregion + + //region Sort result + result.sort((a, b) => (a.left.position - b.left.position)); + //endregion + + return result; + } + //********************************************************************************** + // noinspection FunctionWithMultipleReturnPointsJS, FunctionTooLongJS + /** + * Replace one patter with other + * @param {ByteStream} searchPattern The pattern to search for + * @param {ByteStream} replacePattern The pattern to replace initial pattern + * @param {?number} [start=null] Start position to search from + * @param {?number} [length=null] Length of byte block to search at + * @param {Array|null} [findAllResult=null] Pre-calculated results of "findAllIn" + * @returns {*} + */ + replacePattern(searchPattern, replacePattern, start = null, length = null, findAllResult = null) + { + //region Initial variables + let result; + + let i; + const output = { + status: (-1), + searchPatternPositions: [], + replacePatternPositions: [] + }; + + // noinspection ConstantOnRightSideOfComparisonJS, ConstantOnLeftSideOfComparisonJS + if(start == null) + { + // noinspection AssignmentToFunctionParameterJS + start = 0; + } + + // noinspection NonBlockStatementBodyJS + if(start > (this.buffer.byteLength - 1)) + return false; + + // noinspection ConstantOnRightSideOfComparisonJS, ConstantOnLeftSideOfComparisonJS + if(length == null) + { + // noinspection AssignmentToFunctionParameterJS + length = this.buffer.byteLength - start; + } + + if(length > (this.buffer.byteLength - start)) + { + // noinspection AssignmentToFunctionParameterJS + length = this.buffer.byteLength - start; + } + //endregion + + //region Find a pattern to search for + // noinspection ConstantOnRightSideOfComparisonJS, ConstantOnLeftSideOfComparisonJS, NonBlockStatementBodyJS + if(findAllResult == null) + { + result = this.findAllIn([searchPattern], start, length); + // noinspection ConstantOnRightSideOfComparisonJS, ConstantOnLeftSideOfComparisonJS, NonBlockStatementBodyJS, EqualityComparisonWithCoercionJS + if(result.length == 0) + return output; + } + else + result = findAllResult; + + // noinspection NestedFunctionCallJS + output.searchPatternPositions.push(...Array.from(result, element => element.position)); + //endregion + + //region Variables for new buffer initialization + const patternDifference = searchPattern.buffer.byteLength - replacePattern.buffer.byteLength; + + const changedBuffer = new ArrayBuffer(this.view.length - (result.length * patternDifference)); + const changedView = new Uint8Array(changedBuffer); + //endregion + + //region Copy data from 0 to start + // noinspection NestedFunctionCallJS + changedView.set(new Uint8Array(this.buffer, 0, start)); + //endregion + + //region Replace pattern + for(i = 0; i < result.length; i++) + { + //region Initial variables + // noinspection ConstantOnRightSideOfComparisonJS, ConstantOnLeftSideOfComparisonJS, ConditionalExpressionJS, EqualityComparisonWithCoercionJS + const currentPosition = (i == 0) ? start : result[i - 1].position; + //endregion + + //region Copy bytes other then search pattern + // noinspection NestedFunctionCallJS + changedView.set(new Uint8Array(this.buffer, currentPosition, result[i].position - searchPattern.buffer.byteLength - currentPosition), currentPosition - i * patternDifference); + //endregion + + //region Put replace pattern in a new buffer + changedView.set(replacePattern.view, result[i].position - searchPattern.buffer.byteLength - i * patternDifference); + + output.replacePatternPositions.push(result[i].position - searchPattern.buffer.byteLength - i * patternDifference); + //endregion + } + //endregion + + //region Copy data from the end of old buffer + i--; + // noinspection NestedFunctionCallJS + changedView.set(new Uint8Array(this.buffer, result[i].position, this.buffer.byteLength - result[i].position), result[i].position - searchPattern.buffer.byteLength + replacePattern.buffer.byteLength - i * patternDifference); + //endregion + + //region Re-initialize existing buffer + this.buffer = changedBuffer; + this.view = new Uint8Array(this.buffer); + //endregion + + output.status = 1; + + return output; + } + //********************************************************************************** + // noinspection FunctionWithMultipleLoopsJS, FunctionWithMultipleReturnPointsJS, OverlyComplexFunctionJS, FunctionTooLongJS + /** + * Skip any pattern from input array + * @param {Array.} patterns Array with patterns which should be ommited + * @param {?number} [start=null] Start position to search from + * @param {?number} [length=null] Length of byte block to search at + * @param {boolean} [backward=false] Flag to search in backward order + * @returns {*} + */ + skipPatterns(patterns, start = null, length = null, backward = false) + { + //region Initial variables + // noinspection ConstantOnRightSideOfComparisonJS, ConstantOnLeftSideOfComparisonJS + if(start == null) + { + // noinspection AssignmentToFunctionParameterJS, ConditionalExpressionJS + start = (backward) ? this.buffer.byteLength : 0; + } + + if(start > this.buffer.byteLength) + { + // noinspection AssignmentToFunctionParameterJS + start = this.buffer.byteLength; + } + + if(backward) + { + // noinspection ConstantOnRightSideOfComparisonJS, ConstantOnLeftSideOfComparisonJS + if(length == null) + { + // noinspection AssignmentToFunctionParameterJS + length = start; + } + + if(length > start) + { + // noinspection AssignmentToFunctionParameterJS + length = start; + } + } + else + { + // noinspection ConstantOnRightSideOfComparisonJS, ConstantOnLeftSideOfComparisonJS + if(length == null) + { + // noinspection AssignmentToFunctionParameterJS + length = this.buffer.byteLength - start; + } + + if(length > (this.buffer.byteLength - start)) + { + // noinspection AssignmentToFunctionParameterJS + length = this.buffer.byteLength - start; + } + } + + let result = start; + //endregion + + //region Search for pattern + for(let k = 0; k < patterns.length; k++) + { + const patternLength = patterns[k].buffer.byteLength; + // noinspection ConditionalExpressionJS + const equalStart = (backward) ? (result - patternLength) : (result); + let equal = true; + + for(let j = 0; j < patternLength; j++) + { + // noinspection EqualityComparisonWithCoercionJS + if(this.view[j + equalStart] != patterns[k].view[j]) + { + equal = false; + // noinspection BreakStatementJS + break; + } + } + + if(equal) + { + k = (-1); + + if(backward) + { + result -= patternLength; + // noinspection ConstantOnRightSideOfComparisonJS, ConstantOnLeftSideOfComparisonJS, NonBlockStatementBodyJS + if(result <= 0) + return result; + } + else + { + result += patternLength; + // noinspection NonBlockStatementBodyJS + if(result >= (start + length)) + return result; + } + } + } + //endregion + + return result; + } + //********************************************************************************** + // noinspection FunctionWithMultipleLoopsJS, OverlyComplexFunctionJS, FunctionTooLongJS + /** + * Skip any pattern not from input array + * @param {Array.} patterns Array with patterns which should not be ommited + * @param start + * @param length + * @param backward + * @returns {number} + */ + skipNotPatterns(patterns, start = null, length = null, backward = false) + { + //region Initial variables + // noinspection ConstantOnRightSideOfComparisonJS, ConstantOnLeftSideOfComparisonJS + if(start == null) + { + // noinspection AssignmentToFunctionParameterJS, ConditionalExpressionJS + start = (backward) ? this.buffer.byteLength : 0; + } + + if(start > this.buffer.byteLength) + { + // noinspection AssignmentToFunctionParameterJS + start = this.buffer.byteLength; + } + + if(backward) + { + // noinspection ConstantOnRightSideOfComparisonJS, ConstantOnLeftSideOfComparisonJS + if(length == null) + { + // noinspection AssignmentToFunctionParameterJS + length = start; + } + + if(length > start) + { + // noinspection AssignmentToFunctionParameterJS + length = start; + } + } + else + { + // noinspection ConstantOnRightSideOfComparisonJS, ConstantOnLeftSideOfComparisonJS + if(length == null) + { + // noinspection AssignmentToFunctionParameterJS + length = this.buffer.byteLength - start; + } + + if(length > (this.buffer.byteLength - start)) + { + // noinspection AssignmentToFunctionParameterJS + length = this.buffer.byteLength - start; + } + } + + let result = (-1); + //endregion + + //region Search for pattern + for(let i = 0; i < length; i++) + { + for(let k = 0; k < patterns.length; k++) + { + const patternLength = patterns[k].buffer.byteLength; + // noinspection ConditionalExpressionJS + const equalStart = (backward) ? (start - i - patternLength) : (start + i); + let equal = true; + + for(let j = 0; j < patternLength; j++) + { + // noinspection EqualityComparisonWithCoercionJS + if(this.view[j + equalStart] != patterns[k].view[j]) + { + equal = false; + // noinspection BreakStatementJS + break; + } + } + + if(equal) + { + // noinspection ConditionalExpressionJS + result = (backward) ? (start - i) : (start + i); // Exact position of pattern found + // noinspection BreakStatementJS + break; + } + } + + // noinspection EqualityComparisonWithCoercionJS + if(result != (-1)) + { + // noinspection BreakStatementJS + break; + } + } + //endregion + + return result; + } + //********************************************************************************** +} +//************************************************************************************** +export class SeqStream +{ + //********************************************************************************** + /** + * Constructor for "SeqStream" class + * @param {{[stream]: ByteStream, [length]: number, [backward]: boolean, [start]: number, [appendBlock]: number}} parameters + */ + constructor(parameters = {}) + { + /** + * Major stream + * @type {ByteStream} + */ + this.stream = new ByteStream(); + /** + * Length of the major stream + * @type {number} + */ + this._length = 0; + /** + * Flag to search in backward direction + * @type {boolean} + */ + this.backward = false; + /** + * Start position to search + * @type {number} + */ + this._start = 0; + /** + * Length of a block when append information to major stream + * @type {number} + */ + this.appendBlock = 0; + + this.prevLength = 0; + this.prevStart = 0; + + for(const key of Object.keys(parameters)) + { + switch(key) + { + case "stream": + this.stream = parameters.stream; + break; + case "backward": + this.backward = parameters.backward; + // noinspection JSUnusedGlobalSymbols + this._start = this.stream.buffer.byteLength; + break; + case "length": + // noinspection JSUnusedGlobalSymbols + this._length = parameters.length; + break; + case "start": + // noinspection JSUnusedGlobalSymbols + this._start = parameters.start; + break; + case "appendBlock": + this.appendBlock = parameters.appendBlock; + break; + case "view": + this.stream = new ByteStream({ view: parameters.view}); + break; + case "buffer": + this.stream = new ByteStream({ buffer: parameters.buffer}); + break; + case "string": + this.stream = new ByteStream({ string: parameters.string}); + break; + case "hexstring": + this.stream = new ByteStream({ hexstring: parameters.hexstring}); + break; + default: + } + } + } + //********************************************************************************** + /** + * Setter for "stream" property + * @param {ByteStream} value + */ + set stream(value) + { + this._stream = value; + + this.prevLength = this._length; + // noinspection JSUnusedGlobalSymbols + this._length = value._buffer.byteLength; + + this.prevStart = this._start; + // noinspection JSUnusedGlobalSymbols + this._start = 0; + } + //********************************************************************************** + /** + * Getter for "stream" property + * @returns {ByteStream} + */ + get stream() + { + return this._stream; + } + //********************************************************************************** + /** + * Setter for "length" property + * @param {number} value + */ + set length(value) + { + this.prevLength = this._length; + // noinspection JSUnusedGlobalSymbols + this._length = value; + } + //********************************************************************************** + // noinspection FunctionWithMultipleReturnPointsJS + /** + * Getter for "length" property + * @returns {number} + */ + get length() + { + // noinspection NonBlockStatementBodyJS + if(this.appendBlock) + return this.start; + + return this._length; + } + //********************************************************************************** + // noinspection FunctionWithMultipleReturnPointsJS + /** + * Setter for "start" property + * @param {number} value + */ + set start(value) + { + // noinspection NonBlockStatementBodyJS + if(value > this.stream.buffer.byteLength) + return; + + //region Initialization of "prev" internal variables + this.prevStart = this._start; + this.prevLength = this._length; + //endregion + + // noinspection JSUnusedGlobalSymbols, ConditionalExpressionJS + this._length -= ((this.backward) ? (this._start - value) : (value - this._start)); + // noinspection JSUnusedGlobalSymbols + this._start = value; + } + //********************************************************************************** + /** + * Getter for "start" property + * @returns {number} + */ + get start() + { + return this._start; + } + //********************************************************************************** + /** + * Return ArrayBuffer with having value of existing SeqStream length + * @return {ArrayBuffer} + */ + get buffer() + { + return this._stream._buffer.slice(0, this._length); + } + //********************************************************************************** + // noinspection JSUnusedGlobalSymbols + /** + * Reset current position of the "SeqStream" + */ + resetPosition() + { + // noinspection JSUnusedGlobalSymbols + this._start = this.prevStart; + // noinspection JSUnusedGlobalSymbols + this._length = this.prevLength; + } + //********************************************************************************** + // noinspection JSUnusedGlobalSymbols, FunctionWithMultipleReturnPointsJS + /** + * Find any byte pattern in "ByteStream" + * @param {ByteStream} pattern Stream having pattern value + * @param {?number} [gap] Maximum gap between start position and position of nearest object + * @returns {number} + */ + findPattern(pattern, gap = null) + { + //region Initial variables + // noinspection ConstantOnRightSideOfComparisonJS, ConstantOnLeftSideOfComparisonJS + if((gap == null) || (gap > this.length)) + { + // noinspection AssignmentToFunctionParameterJS + gap = this.length; + } + //endregion + + //region Find pattern + const result = this.stream.findPattern(pattern, this.start, this.length, this.backward); + // noinspection ConstantOnRightSideOfComparisonJS, ConstantOnLeftSideOfComparisonJS, NonBlockStatementBodyJS, EqualityComparisonWithCoercionJS + if(result == (-1)) + return result; + + if(this.backward) + { + // noinspection NonBlockStatementBodyJS + if(result < (this.start - pattern.buffer.byteLength - gap)) + return (-1); + } + else + { + // noinspection NonBlockStatementBodyJS + if(result > (this.start + pattern.buffer.byteLength + gap)) + return (-1); + } + //endregion + + //region Create new values + this.start = result; + //endregion ; + + return result; + } + //********************************************************************************** + // noinspection JSUnusedGlobalSymbols, FunctionWithMultipleReturnPointsJS + /** + * Find first position of any pattern from input array + * @param {Array.} patterns Array with patterns which should be found + * @param {?number} [gap] Maximum gap between start position and position of nearest object + * @returns {{id: number, position: number}} + */ + findFirstIn(patterns, gap = null) + { + //region Initial variables + // noinspection ConstantOnRightSideOfComparisonJS, ConstantOnLeftSideOfComparisonJS + if((gap == null) || (gap > this.length)) + { + // noinspection AssignmentToFunctionParameterJS + gap = this.length; + } + //endregion + + //region Search for patterns + const result = this.stream.findFirstIn(patterns, this.start, this.length, this.backward); + // noinspection NonBlockStatementBodyJS, EqualityComparisonWithCoercionJS + if(result.id == (-1)) + return result; + + if(this.backward) + { + if(result.position < (this.start - patterns[result.id].buffer.byteLength - gap)) + { + // noinspection ConditionalExpressionJS + return { + id: (-1), + position: (this.backward) ? 0 : (this.start + this.length) + }; + } + } + else + { + if(result.position > (this.start + patterns[result.id].buffer.byteLength + gap)) + { + // noinspection ConditionalExpressionJS + return { + id: (-1), + position: (this.backward) ? 0 : (this.start + this.length) + }; + } + } + //endregion + + //region Create new values + this.start = result.position; + //endregion ; + + return result; + } + //********************************************************************************** + // noinspection JSUnusedGlobalSymbols + /** + * Find all positions of any pattern from input array + * @param {Array.} patterns Array with patterns which should be found + * @returns {Array} + */ + findAllIn(patterns) + { + // In case of "backward order" the start position is at the end on stream. + // In case of "normal order" the start position is at the begging of the stream. + // But in fact for search for all patterns we need to have start position in "normal order". + // noinspection ConditionalExpressionJS + const start = (this.backward) ? (this.start - this.length) : this.start; + + return this.stream.findAllIn(patterns, start, this.length); + } + //********************************************************************************** + // noinspection JSUnusedGlobalSymbols, FunctionWithMultipleReturnPointsJS, OverlyComplexFunctionJS + /** + * Find first position of data, not included in patterns from input array + * @param {Array.} patterns Array with patterns which should be ommited + * @param {?number} gap Maximum gap between start position and position of nearest object + * @returns {*} + */ + findFirstNotIn(patterns, gap = null) + { + //region Initial variables + // noinspection ConstantOnRightSideOfComparisonJS, ConstantOnLeftSideOfComparisonJS + if((gap == null) || (gap > this._length)) + { + // noinspection AssignmentToFunctionParameterJS + gap = this._length; + } + //endregion + + //region Search for patterns + const result = this._stream.findFirstNotIn(patterns, this._start, this._length, this.backward); + // noinspection NonBlockStatementBodyJS, EqualityComparisonWithCoercionJS + if((result.left.id == (-1)) && (result.right.id == (-1))) + return result; + + if(this.backward) + { + // noinspection EqualityComparisonWithCoercionJS + if(result.right.id != (-1)) + { + if(result.right.position < (this._start - patterns[result.right.id]._buffer.byteLength - gap)) + { + return { + left: { + id: (-1), + position: this._start + }, + right: { + id: (-1), + position: 0 + }, + value: new ByteStream() + }; + } + } + } + else + { + // noinspection EqualityComparisonWithCoercionJS + if(result.left.id != (-1)) + { + if(result.left.position > (this._start + patterns[result.left.id]._buffer.byteLength + gap)) + { + return { + left: { + id: (-1), + position: this._start + }, + right: { + id: (-1), + position: 0 + }, + value: new ByteStream() + }; + } + } + } + //endregion + + //region Create new values + if(this.backward) + { + // noinspection NonBlockStatementBodyJS, EqualityComparisonWithCoercionJS + if(result.left.id == (-1)) + this.start = 0; + else + this.start = result.left.position; + } + else + { + // noinspection NonBlockStatementBodyJS, EqualityComparisonWithCoercionJS + if(result.right.id == (-1)) + this.start = (this._start + this._length); + else + this.start = result.right.position; + } + //endregion ; + + return result; + } + //********************************************************************************** + // noinspection JSUnusedGlobalSymbols + /** + * Find all positions of data, not included in patterns from input array + * @param {Array.} patterns Array with patterns which should be ommited + * @returns {Array} + */ + findAllNotIn(patterns) + { + // In case of "backward order" the start position is at the end on stream. + // In case of "normal order" the start position is at the begging of the stream. + // But in fact for search for all patterns we need to have start position in "normal order". + // noinspection ConditionalExpressionJS + const start = (this.backward) ? (this._start - this._length) : this._start; + + return this._stream.findAllNotIn(patterns, start, this._length); + } + //********************************************************************************** + // noinspection JSUnusedGlobalSymbols, FunctionWithMultipleReturnPointsJS + /** + * Find position of a sequence of any patterns from input array + * @param {Array.} patterns Array with patterns which should be ommited + * @param {?number} [length] Length to search sequence for + * @param {?number} [gap] Maximum gap between start position and position of nearest object + * @returns {*} + */ + findFirstSequence(patterns, length = null, gap = null) + { + //region Initial variables + // noinspection ConstantOnRightSideOfComparisonJS, ConstantOnLeftSideOfComparisonJS + if((length == null) || (length > this._length)) + { + // noinspection AssignmentToFunctionParameterJS + length = this._length; + } + + // noinspection ConstantOnRightSideOfComparisonJS, ConstantOnLeftSideOfComparisonJS + if((gap == null) || (gap > length)) + { + // noinspection AssignmentToFunctionParameterJS + gap = length; + } + //endregion + + //region Search for sequence + const result = this._stream.findFirstSequence(patterns, this._start, length, this.backward); + // noinspection ConstantOnRightSideOfComparisonJS, ConstantOnLeftSideOfComparisonJS, NonBlockStatementBodyJS, EqualityComparisonWithCoercionJS + if(result.value.buffer.byteLength == 0) + return result; + + if(this.backward) + { + if(result.position < (this._start - result.value._buffer.byteLength - gap)) + { + return { + position: (-1), + value: new ByteStream() + }; + } + } + else + { + if(result.position > (this._start + result.value._buffer.byteLength + gap)) + { + return { + position: (-1), + value: new ByteStream() + }; + } + } + //endregion + + //region Create new values + this.start = result.position; + //endregion ; + + return result; + } + //********************************************************************************** + // noinspection JSUnusedGlobalSymbols + /** + * Find position of a sequence of any patterns from input array + * @param {Array.} patterns Array with patterns which should be found + * @returns {Array} + */ + findAllSequences(patterns) + { + // In case of "backward order" the start position is at the end on stream. + // In case of "normal order" the start position is at the begging of the stream. + // But in fact for search for all patterns we need to have start position in "normal order". + // noinspection ConditionalExpressionJS + const start = (this.backward) ? (this.start - this.length) : this.start; + + return this.stream.findAllSequences(patterns, start, this.length); + } + //********************************************************************************** + // noinspection JSUnusedGlobalSymbols, FunctionWithMultipleReturnPointsJS + /** + * Find all paired patterns in the stream + * @param {ByteStream} leftPattern Left pattern to search for + * @param {ByteStream} rightPattern Right pattern to search for + * @param {?number} [gap] Maximum gap between start position and position of nearest object + * @returns {Array} + */ + findPairedPatterns(leftPattern, rightPattern, gap = null) + { + //region Initial variables + // noinspection ConstantOnRightSideOfComparisonJS, ConstantOnLeftSideOfComparisonJS + if((gap == null) || (gap > this.length)) + { + // noinspection AssignmentToFunctionParameterJS + gap = this.length; + } + //endregion + + // In case of "backward order" the start position is at the end on stream. + // In case of "normal order" the start position is at the begging of the stream. + // But in fact for search for all patterns we need to have start position in "normal order". + // noinspection ConditionalExpressionJS + const start = (this.backward) ? (this.start - this.length) : this.start; + + //region Search for patterns + const result = this.stream.findPairedPatterns(leftPattern, rightPattern, start, this.length); + if(result.length) + { + if(this.backward) + { + // noinspection NonBlockStatementBodyJS + if(result[0].right < (this.start - rightPattern.buffer.byteLength - gap)) + return []; + } + else + { + // noinspection NonBlockStatementBodyJS + if(result[0].left > (this.start + leftPattern.buffer.byteLength + gap)) + return []; + } + } + //endregion + + return result; + } + //********************************************************************************** + // noinspection JSUnusedGlobalSymbols, FunctionWithMultipleReturnPointsJS + /** + * Find all paired patterns in the stream + * @param {Array.} leftPatterns Array of left patterns to search for + * @param {Array.} rightPatterns Array of right patterns to search for + * @param {?number} [gap] Maximum gap between start position and position of nearest object + * @returns {Array} + */ + findPairedArrays(leftPatterns, rightPatterns, gap = null) + { + //region Initial variables + // noinspection ConstantOnRightSideOfComparisonJS, ConstantOnLeftSideOfComparisonJS + if((gap == null) || (gap > this.length)) + { + // noinspection AssignmentToFunctionParameterJS + gap = this.length; + } + //endregion + + // In case of "backward order" the start position is at the end on stream. + // In case of "normal order" the start position is at the begging of the stream. + // But in fact for search for all patterns we need to have start position in "normal order". + // noinspection ConditionalExpressionJS + const start = (this.backward) ? (this.start - this.length) : this.start; + + //region Search for patterns + const result = this.stream.findPairedArrays(leftPatterns, rightPatterns, start, this.length); + if(result.length) + { + if(this.backward) + { + // noinspection NonBlockStatementBodyJS + if(result[0].right.position < (this.start - rightPatterns[result[0].right.id].buffer.byteLength - gap)) + return []; + } + else + { + // noinspection NonBlockStatementBodyJS + if(result[0].left.position > (this.start + leftPatterns[result[0].left.id].buffer.byteLength + gap)) + return []; + } + } + //endregion + + return result; + } + //********************************************************************************** + // noinspection JSUnusedGlobalSymbols + /** + * Replace one patter with other + * @param {ByteStream} searchPattern The pattern to search for + * @param {ByteStream} replacePattern The pattern to replace initial pattern + * @returns {*} + */ + replacePattern(searchPattern, replacePattern) + { + // In case of "backward order" the start position is at the end on stream. + // In case of "normal order" the start position is at the begging of the stream. + // But in fact for search for all patterns we need to have start position in "normal order". + // noinspection ConditionalExpressionJS + const start = (this.backward) ? (this.start - this.length) : this.start; + + return this.stream.replacePattern(searchPattern, replacePattern, start, this.length); + } + //********************************************************************************** + // noinspection JSUnusedGlobalSymbols + /** + * Skip of any pattern from input array + * @param {Array.} patterns Array with patterns which should be ommited + * @returns {*} + */ + skipPatterns(patterns) + { + const result = this.stream.skipPatterns(patterns, this.start, this.length, this.backward); + + //region Create new values + this.start = result; + //endregion ; + + return result; + } + //********************************************************************************** + // noinspection JSUnusedGlobalSymbols, FunctionWithMultipleReturnPointsJS + /** + * Skip of any pattern from input array + * @param {Array.} patterns Array with patterns which should be ommited + * @returns {number} + */ + skipNotPatterns(patterns) + { + const result = this.stream.skipNotPatterns(patterns, this.start, this.length, this.backward); + // noinspection NonBlockStatementBodyJS, EqualityComparisonWithCoercionJS + if(result == (-1)) + return (-1); + + //region Create new values + this.start = result; + //endregion ; + + return result; + } + //********************************************************************************** + // noinspection JSUnusedGlobalSymbols + /** + * Append a new "Stream" content to the current "Stream" + * @param {ByteStream} stream A new "stream" to append to current "stream" + */ + append(stream) + { + if((this._start + stream._buffer.byteLength) > this._stream._buffer.byteLength) + { + if(stream._buffer.byteLength > this.appendBlock) + { + // noinspection MagicNumberJS + this.appendBlock = (stream._buffer.byteLength + 1000); + } + + this._stream.realloc(this._stream._buffer.byteLength + this.appendBlock); + } + + this._stream._view.set(stream._view, this._start); + + this._length += (stream._buffer.byteLength * 2); + this.start = (this._start + stream._buffer.byteLength); + this.prevLength -= (stream._buffer.byteLength * 2); + } + //********************************************************************************** + // noinspection JSUnusedGlobalSymbols + /** + * Append a "view" content to the current "Stream" + * @param {Uint8Array} view A new "view" to append to current "stream" + */ + appendView(view) + { + if((this._start + view.length) > this._stream._buffer.byteLength) + { + if(view.length > this.appendBlock) + { + // noinspection MagicNumberJS + this.appendBlock = (view.length + 1000); + } + + this._stream.realloc(this._stream._buffer.byteLength + this.appendBlock); + } + + this._stream._view.set(view, this._start); + + this._length += (view.length * 2); + this.start = (this._start + view.length); + this.prevLength -= (view.length * 2); + } + //********************************************************************************** + // noinspection JSUnusedGlobalSymbols + /** + * Append a new char to the current "Stream" + * @param {number} char A new char to append to current "stream" + */ + appendChar(char) + { + if((this._start + 1) > this._stream._buffer.byteLength) + { + // noinspection ConstantOnLefSideOfComparisonJS + if(1 > this.appendBlock) + { + // noinspection MagicNumberJS + this.appendBlock = 1000; + } + + this._stream.realloc(this._stream._buffer.byteLength + this.appendBlock); + } + + this._stream._view[this._start] = char; + + this._length += 2; + this.start = (this._start + 1); + this.prevLength -= 2; + } + //********************************************************************************** + // noinspection FunctionNamingConventionJS + /** + * Append a new number to the current "Stream" + * @param {number} number A new unsigned 16-bit integer to append to current "stream" + */ + appendUint16(number) + { + if((this._start + 2) > this._stream._buffer.byteLength) + { + // noinspection ConstantOnLefSideOfComparisonJS + if(2 > this.appendBlock) + { + // noinspection MagicNumberJS + this.appendBlock = 1000; + } + + this._stream.realloc(this._stream._buffer.byteLength + this.appendBlock); + } + + const value = new Uint16Array([number]); + const view = new Uint8Array(value.buffer); + + this._stream._view[this._start] = view[1]; + this._stream._view[this._start + 1] = view[0]; + + this._length += 4; + this.start = (this._start + 2); + this.prevLength -= 4; + } + //********************************************************************************** + // noinspection FunctionNamingConventionJS + /** + * Append a new number to the current "Stream" + * @param {number} number A new unsigned 24-bit integer to append to current "stream" + */ + appendUint24(number) + { + if((this._start + 3) > this._stream._buffer.byteLength) + { + // noinspection ConstantOnLefSideOfComparisonJS + if(3 > this.appendBlock) + { + // noinspection MagicNumberJS + this.appendBlock = 1000; + } + + this._stream.realloc(this._stream._buffer.byteLength + this.appendBlock); + } + + const value = new Uint32Array([number]); + const view = new Uint8Array(value.buffer); + + this._stream._view[this._start] = view[2]; + this._stream._view[this._start + 1] = view[1]; + this._stream._view[this._start + 2] = view[0]; + + this._length += 6; + this.start = (this._start + 3); + this.prevLength -= 6; + } + //********************************************************************************** + // noinspection FunctionNamingConventionJS + /** + * Append a new number to the current "Stream" + * @param {number} number A new unsigned 32-bit integer to append to current "stream" + */ + appendUint32(number) + { + if((this._start + 4) > this._stream._buffer.byteLength) + { + // noinspection ConstantOnLefSideOfComparisonJS + if(4 > this.appendBlock) + { + // noinspection MagicNumberJS + this.appendBlock = 1000; + } + + this._stream.realloc(this._stream._buffer.byteLength + this.appendBlock); + } + + const value = new Uint32Array([number]); + const view = new Uint8Array(value.buffer); + + this._stream._view[this._start] = view[3]; + this._stream._view[this._start + 1] = view[2]; + this._stream._view[this._start + 2] = view[1]; + this._stream._view[this._start + 3] = view[0]; + + this._length += 8; + this.start = (this._start + 4); + this.prevLength -= 8; + } + //********************************************************************************** + // noinspection FunctionWithMultipleReturnPointsJS + /** + * Get a block of data + * @param {number} size Size of the data block to get + * @param {boolean} [changeLength=true] Should we change "length" and "start" value after reading the data block + * @returns {Array} + */ + getBlock(size, changeLength = true) + { + //region Check input parameters + // noinspection ConstantOnRightSideOfComparisonJS, ConstantOnLeftSideOfComparisonJS, NonBlockStatementBodyJS + if(this._length <= 0) + return []; + + if(this._length < size) + { + // noinspection AssignmentToFunctionParameterJS + size = this._length; + } + //endregion + + //region Initial variables + let result; + //endregion + + //region Getting result depends on "backward" flag + if(this.backward) + { + const buffer = this._stream._buffer.slice(this._length - size, this._length); + const view = new Uint8Array(buffer); + + result = new Array(size); + + // noinspection NonBlockStatementBodyJS + for(let i = 0; i < size; i++) + result[size - 1 - i] = view[i]; + } + else + { + const buffer = this._stream._buffer.slice(this._start, this._start + size); + + // noinspection NestedFunctionCallJS + result = Array.from(new Uint8Array(buffer)); + } + //endregion + + //region Change "length" value if needed + if(changeLength) + { + // noinspection ConditionalExpressionJS + this.start += ((this.backward) ? ((-1) * size) : size); + } + //endregion + + return result; + } + //********************************************************************************** + // noinspection JSUnusedGlobalSymbols, FunctionWithMultipleReturnPointsJS, FunctionNamingConventionJS + /** + * Get 2-byte unsigned integer value + * @param {boolean} [changeLength=true] Should we change "length" and "start" value after reading the data block + * @returns {number} + */ + getUint16(changeLength = true) + { + const block = this.getBlock(2, changeLength); + + //region Check posibility for convertion + // noinspection ConstantOnRightSideOfComparisonJS, ConstantOnLeftSideOfComparisonJS, NonBlockStatementBodyJS + if(block.length < 2) + return 0; + //endregion + + //region Convert byte array to "Uint16Array" value + const value = new Uint16Array(1); + const view = new Uint8Array(value.buffer); + + view[0] = block[1]; + view[1] = block[0]; + //endregion + + return value[0]; + } + //********************************************************************************** + // noinspection JSUnusedGlobalSymbols, FunctionWithMultipleReturnPointsJS, FunctionNamingConventionJS + /** + * Get 2-byte signed integer value + * @param {boolean} [changeLength=true] Should we change "length" and "start" value after reading the data block + * @returns {number} + */ + getInt16(changeLength = true) + { + const block = this.getBlock(2, changeLength); + + //region Check posibility for convertion + // noinspection ConstantOnRightSideOfComparisonJS, ConstantOnLeftSideOfComparisonJS, NonBlockStatementBodyJS + if(block.length < 2) + return 0; + //endregion + + //region Convert byte array to "Int16Array" value + const value = new Int16Array(1); + const view = new Uint8Array(value.buffer); + + view[0] = block[1]; + view[1] = block[0]; + //endregion + + return value[0]; + } + //********************************************************************************** + // noinspection JSUnusedGlobalSymbols, FunctionWithMultipleReturnPointsJS, FunctionNamingConventionJS + /** + * Get 3-byte unsigned integer value + * @param {boolean} [changeLength=true] Should we change "length" and "start" value after reading the data block + * @returns {number} + */ + getUint24(changeLength = true) + { + const block = this.getBlock(3, changeLength); + + //region Check posibility for convertion + // noinspection ConstantOnRightSideOfComparisonJS, ConstantOnLeftSideOfComparisonJS, NonBlockStatementBodyJS + if(block.length < 3) + return 0; + //endregion + + //region Convert byte array to "Uint32Array" value + const value = new Uint32Array(1); + const view = new Uint8Array(value.buffer); + + // noinspection ConstantOnRightSideOfComparisonJS, ConstantOnLeftSideOfComparisonJS, NonBlockStatementBodyJS + for(let i = 3; i >= 1; i--) + view[3 - i] = block[i - 1]; + //endregion + + return value[0]; + } + //********************************************************************************** + // noinspection JSUnusedGlobalSymbols, FunctionWithMultipleReturnPointsJS, FunctionNamingConventionJS + /** + * Get 4-byte unsigned integer value + * @param {boolean} [changeLength=true] Should we change "length" and "start" value after reading the data block + * @returns {number} + */ + getUint32(changeLength = true) + { + const block = this.getBlock(4, changeLength); + + //region Check posibility for convertion + // noinspection ConstantOnRightSideOfComparisonJS, ConstantOnLeftSideOfComparisonJS, NonBlockStatementBodyJS + if(block.length < 4) + return 0; + //endregion + + //region Convert byte array to "Uint32Array" value + const value = new Uint32Array(1); + const view = new Uint8Array(value.buffer); + + // noinspection ConstantOnRightSideOfComparisonJS, ConstantOnLeftSideOfComparisonJS, NonBlockStatementBodyJS + for(let i = 3; i >= 0; i--) + view[3 - i] = block[i]; + //endregion + + return value[0]; + } + //********************************************************************************** + /** + * Get 4-byte signed integer value + * @param {boolean} [changeLength=true] Should we change "length" and "start" value after reading the data block + * @returns {number} + */ + getInt32(changeLength = true) + { + const block = this.getBlock(4, changeLength); + + //region Check posibility for convertion + // noinspection ConstantOnRightSideOfComparisonJS, ConstantOnLeftSideOfComparisonJS, NonBlockStatementBodyJS + if(block.length < 4) + return 0; + //endregion + + //region Convert byte array to "Int32Array" value + const value = new Int32Array(1); + const view = new Uint8Array(value.buffer); + + // noinspection ConstantOnRightSideOfComparisonJS, ConstantOnLeftSideOfComparisonJS, NonBlockStatementBodyJS + for(let i = 3; i >= 0; i--) + view[3 - i] = block[i]; + //endregion + + return value[0]; + } + //********************************************************************************** +} +//************************************************************************************** +// noinspection FunctionWithMultipleLoopsJS, FunctionWithMultipleReturnPointsJS, OverlyComplexFunctionJS, FunctionTooLongJS +/** + * Get parsed values from "byte map" + * @param {ByteStream} stream Stream to parse data from + * @param {Object} map Object with information how to parse "byte map" + * @param {number} elements Number of elements in parsing byte map + * @param {?number} [start=null] Start position to parse from + * @param {?number} [length=null] Length of byte block to parse from + * @returns {*} + */ +export function parseByteMap(stream, map, elements, start = null, length = null) +{ + /* + Map example: + + let map = [ + { + type: "string", + name: "type", + minlength: 1, + maxlength: 1, + func: function(array) + { + let result = { + status: (-1), + length: 1 + }; + + switch(array[0]) + { + case 0x6E: // "n" + result.value = "n"; + break; + case 0x66: // "f" + result.value = "f"; + break; + default: + return result; + } + + result.status = 1; + + return result; + } + }, + { + type: "check", + minlength: 1, + maxlength: 2, + func: function(array) + { + let position = (-1); + + if(array[0] == 0x0A) + position = 1; + if(array[1] == 0x0A) + position = 2; + + return { + status: (position > 0) ? 1 : (-1), + length: position + }; + } + } + ]; + */ + + //region Initial variables + // noinspection ConstantOnRightSideOfComparisonJS, ConstantOnLeftSideOfComparisonJS + if(start === null) + { + // noinspection AssignmentToFunctionParameterJS + start = 0; + } + + // noinspection NonBlockStatementBodyJS + if(start > (stream.buffer.byteLength - 1)) + return false; + + // noinspection ConstantOnRightSideOfComparisonJS, ConstantOnLeftSideOfComparisonJS + if(length === null) + { + // noinspection AssignmentToFunctionParameterJS + length = stream.buffer.byteLength - start; + } + + if(length > (stream.buffer.byteLength - start)) + { + // noinspection AssignmentToFunctionParameterJS + length = stream.buffer.byteLength - start; + } + + let dataView; + + // noinspection ConstantOnRightSideOfComparisonJS, ConstantOnLeftSideOfComparisonJS, EqualityComparisonWithCoercionJS, NonBlockStatementBodyJS + if((start == 0) && (length == stream.buffer.byteLength)) + dataView = stream.view; + else + dataView = new Uint8Array(stream.buffer, start, length); + + const resultArray = new Array(elements); + let elementsCount = 0; + + let count = 0; + const mapLength = map.length; + //endregion + + //region Parse all byte, structure by structure + while(count < length) + { + let structureLength = 0; + + resultArray[elementsCount] = {}; + + for(let i = 0; i < mapLength; i++) + { + // noinspection ConstantOnRightSideOfComparisonJS, ConstantOnLeftSideOfComparisonJS, JSUnresolvedVariable, EqualityComparisonWithCoercionJS + if(map[i].maxlength == 0) + { + // noinspection NonBlockStatementBodyJS + if("defaultValue" in map[i]) + (resultArray[elementsCount])[map[i].name] = map[i].defaultValue; + + // noinspection ContinueStatementJS + continue; + } + + // noinspection JSUnresolvedVariable + const array = new Array(map[i].maxlength); + + // noinspection JSUnresolvedVariable + for(let j = 0; j < map[i].maxlength; j++) + { + // noinspection IncrementDecrementResultUsedJS + array[j] = dataView[count++]; + } + + // noinspection JSUnresolvedVariable + const result = (map[i].func)(array); + // noinspection EqualityComparisonWithCoercionJS, NonBlockStatementBodyJS + if(result.status == (-1)) + { + // noinspection ConstantOnRightSideOfComparisonJS, ConstantOnLeftSideOfComparisonJS, NonBlockStatementBodyJS, EqualityComparisonWithCoercionJS + if(resultArray.length == 1) + return []; + + return resultArray.slice(0, resultArray.length - 1); + } + + // noinspection ConstantOnRightSideOfComparisonJS, ConstantOnLeftSideOfComparisonJS, EqualityComparisonWithCoercionJS, NonBlockStatementBodyJS + if(map[i].type != "check") + (resultArray[elementsCount])[map[i].name] = result.value; + + // noinspection JSUnresolvedVariable + count -= (map[i].maxlength - result.length); + structureLength += result.length; + } + + // noinspection IncrementDecrementResultUsedJS + (resultArray[elementsCount++]).structureLength = structureLength; + } + //endregion + + return resultArray; +} +//************************************************************************************** +//region "Bits-to-string" array +const bitsToStringArray = [ + "00000000", "00000001", "00000010", + "00000011", "00000100", "00000101", + "00000110", "00000111", "00001000", + "00001001", "00001010", "00001011", + "00001100", "00001101", "00001110", + "00001111", "00010000", "00010001", + "00010010", "00010011", "00010100", + "00010101", "00010110", "00010111", + "00011000", "00011001", "00011010", + "00011011", "00011100", "00011101", + "00011110", "00011111", "00100000", + "00100001", "00100010", "00100011", + "00100100", "00100101", "00100110", + "00100111", "00101000", "00101001", + "00101010", "00101011", "00101100", + "00101101", "00101110", "00101111", + "00110000", "00110001", "00110010", + "00110011", "00110100", "00110101", + "00110110", "00110111", "00111000", + "00111001", "00111010", "00111011", + "00111100", "00111101", "00111110", + "00111111", "01000000", "01000001", + "01000010", "01000011", "01000100", + "01000101", "01000110", "01000111", + "01001000", "01001001", "01001010", + "01001011", "01001100", "01001101", + "01001110", "01001111", "01010000", + "01010001", "01010010", "01010011", + "01010100", "01010101", "01010110", + "01010111", "01011000", "01011001", + "01011010", "01011011", "01011100", + "01011101", "01011110", "01011111", + "01100000", "01100001", "01100010", + "01100011", "01100100", "01100101", + "01100110", "01100111", "01101000", + "01101001", "01101010", "01101011", + "01101100", "01101101", "01101110", + "01101111", "01110000", "01110001", + "01110010", "01110011", "01110100", + "01110101", "01110110", "01110111", + "01111000", "01111001", "01111010", + "01111011", "01111100", "01111101", + "01111110", "01111111", "10000000", + "10000001", "10000010", "10000011", + "10000100", "10000101", "10000110", + "10000111", "10001000", "10001001", + "10001010", "10001011", "10001100", + "10001101", "10001110", "10001111", + "10010000", "10010001", "10010010", + "10010011", "10010100", "10010101", + "10010110", "10010111", "10011000", + "10011001", "10011010", "10011011", + "10011100", "10011101", "10011110", + "10011111", "10100000", "10100001", + "10100010", "10100011", "10100100", + "10100101", "10100110", "10100111", + "10101000", "10101001", "10101010", + "10101011", "10101100", "10101101", + "10101110", "10101111", "10110000", + "10110001", "10110010", "10110011", + "10110100", "10110101", "10110110", + "10110111", "10111000", "10111001", + "10111010", "10111011", "10111100", + "10111101", "10111110", "10111111", + "11000000", "11000001", "11000010", + "11000011", "11000100", "11000101", + "11000110", "11000111", "11001000", + "11001001", "11001010", "11001011", + "11001100", "11001101", "11001110", + "11001111", "11010000", "11010001", + "11010010", "11010011", "11010100", + "11010101", "11010110", "11010111", + "11011000", "11011001", "11011010", + "11011011", "11011100", "11011101", + "11011110", "11011111", "11100000", + "11100001", "11100010", "11100011", + "11100100", "11100101", "11100110", + "11100111", "11101000", "11101001", + "11101010", "11101011", "11101100", + "11101101", "11101110", "11101111", + "11110000", "11110001", "11110010", + "11110011", "11110100", "11110101", + "11110110", "11110111", "11111000", + "11111001", "11111010", "11111011", + "11111100", "11111101", "11111110", + "11111111" +]; +//endregion +//************************************************************************************** +export class BitStream +{ + //********************************************************************************** + /** + * Constructor for "BitStream" class + * @param {{[byteStream]: ByteStream, [view]: Uint8Array, [buffer]: ArrayBuffer, [string]: string, [bitsCount]: number}} parameters + */ + constructor(parameters = {}) + { + this.buffer = new ArrayBuffer(0); + this.view = new Uint8Array(this.buffer); + + this.bitsCount = 0; // Number of bits stored in current "BitStream" + + for(const key of Object.keys(parameters)) + { + switch(key) + { + case "byteStream": + this.fromByteStream(parameters.byteStream); + break; + case "view": + this.fromUint8Array(parameters.view); + break; + case "buffer": + this.fromArrayBuffer(parameters.buffer); + break; + case "string": + this.fromString(parameters.string); + break; + case "uint32": + this.fromUint32(parameters.uint32); + break; + case "bitsCount": + this.bitsCount = parameters.bitsCount; + break; + default: + } + } + } + //********************************************************************************** + /** + * Clear existing stream + */ + clear() + { + this.buffer = new ArrayBuffer(0); + this.view = new Uint8Array(this.buffer); + + this.bitsCount = 0; + } + //********************************************************************************** + /** + * Initialize "BitStream" by data from existing "ByteStream" + * @param {ByteStream} stream + */ + fromByteStream(stream) + { + this.buffer = stream.buffer.slice(0); + this.view = new Uint8Array(this.buffer); + + this.bitsCount = this.view.length << 3; + } + //********************************************************************************** + /** + * Initialize "BitStream" object from existing "ArrayBuffer" + * @param {ArrayBuffer} array The ArrayBuffer to copy from + */ + fromArrayBuffer(array) + { + this.buffer = array.slice(0); + this.view = new Uint8Array(this.buffer); + + this.bitsCount = this.view.length << 3; + } + //********************************************************************************** + // noinspection FunctionNamingConventionJS + /** + * Initialize "BitStream" object from existing "Uint8Array" + * @param {Uint8Array} array The Uint8Array to copy from + */ + fromUint8Array(array) + { + this.buffer = new ArrayBuffer(array.length); + this.view = new Uint8Array(this.buffer); + + this.view.set(array); + + this.bitsCount = this.view.length << 3; + } + //********************************************************************************** + /** + * Initialize "BitStream" object from existing bit string + * @param {string} string The string to initialize from + */ + fromString(string) + { + //region Initial variables + const stringLength = string.length; + + // noinspection ConditionalExpressionJS + this.buffer = new ArrayBuffer((stringLength >> 3) + ((stringLength % 8) ? 1 : 0)); + this.view = new Uint8Array(this.buffer); + + this.bitsCount = ((stringLength >> 3) + 1) << 3; // In order to handle correct shifting + + let byteIndex = 0; + //endregion + + //region Convert from "bit string" to bytes + for(let i = 0; i < stringLength; i++) + { + // noinspection ConstantOnRightSideOfComparisonJS, ConstantOnLeftSideOfComparisonJS, EqualityComparisonWithCoercionJS, NonBlockStatementBodyJS + if(string[i] == "1") + this.view[byteIndex] |= 1 << (7 - (i % 8)); + + // noinspection ConstantOnRightSideOfComparisonJS, ConstantOnLeftSideOfComparisonJS, EqualityComparisonWithCoercionJS, NonBlockStatementBodyJS + if(i && (((i + 1) % 8) == 0)) + byteIndex++; + } + //endregion + + //region Shift "BitStream" into correct position + // noinspection NonBlockStatementBodyJS + if(stringLength % 8) + this.shiftRight(8 - (stringLength % 8)); + //endregion + + //region Change "bitsCount" + this.bitsCount = stringLength; + //endregion + } + //********************************************************************************** + /** + * Initialize "BitStream" object from existing uint32 number + * @param {Number} number The string to initialize from + */ + fromUint32(uint32) + { + this.buffer = new ArrayBuffer(4); + this.view = new Uint8Array(this.buffer); + + const value = new Uint32Array([uint32]); + const view = new Uint8Array(value.buffer); + + for(let i = 3; i >= 0; i--) + this.view[i] = view[3 - i]; + + this.bitsCount = 32; + } + //********************************************************************************** + /** + * Represent "BitStream" object content as a string + * @param {?number} [start=null] Start number to convert to string from + * @param {?number} [length=null] Length of BitStream to convert to string + * @returns {string} + */ + toString(start = null, length = null) + { + //region Check input parameters + // noinspection ConstantOnRightSideOfComparisonJS, ConstantOnLeftSideOfComparisonJS + if(start == null) + { + // noinspection AssignmentToFunctionParameterJS + start = 0; + } + + // noinspection ConstantOnRightSideOfComparisonJS, ConstantOnLeftSideOfComparisonJS + if((start >= this.view.length) || (start < 0)) + { + // noinspection AssignmentToFunctionParameterJS + start = 0; + } + + // noinspection ConstantOnRightSideOfComparisonJS, ConstantOnLeftSideOfComparisonJS + if(length == null) + { + // noinspection AssignmentToFunctionParameterJS + length = this.view.length - start; + } + + // noinspection ConstantOnRightSideOfComparisonJS, ConstantOnLeftSideOfComparisonJS + if((length >= this.view.length) || (length < 0)) + { + // noinspection AssignmentToFunctionParameterJS + length = this.view.length - start; + } + //endregion + + //region Initial variables + const result = []; + //endregion + + //region Convert from bytes to "bit string" + // noinspection NonBlockStatementBodyJS + for(let i = start; i < (start + length); i++) + result.push(bitsToStringArray[this.view[i]]); + //endregion + + // noinspection ChainedFunctionCallJS + return result.join("").slice((this.view.length << 3) - this.bitsCount); + } + //********************************************************************************** + // noinspection FunctionWithMultipleReturnPointsJS + /** + * Shift entire "BitStream" value right to number of bits + * @param {number} shift Number of bits to shift value + * @param {boolean} [needShrink=true] Need to shrink result or not + */ + shiftRight(shift, needShrink = true) + { + //region Check parameters + // noinspection ConstantOnRightSideOfComparisonJS, ConstantOnLeftSideOfComparisonJS, EqualityComparisonWithCoercionJS, NonBlockStatementBodyJS + if(this.view.length == 0) + return; + + // noinspection ConstantOnRightSideOfComparisonJS, ConstantOnLeftSideOfComparisonJS, NonBlockStatementBodyJS + if((shift < 0) || (shift > 8)) + throw new Error("The \"shift\" parameter must be in range 0-8"); + + // noinspection NonBlockStatementBodyJS + if(shift > this.bitsCount) + throw new Error("The \"shift\" parameter can not be bigger than \"this.bitsCount\""); + //endregion + + //region Initial variables + // noinspection MagicNumberJS + const shiftMask = 0xFF >> (8 - shift); + this.view[this.view.length - 1] >>= shift; + //endregion + + //region Shift value + // noinspection ConstantOnRightSideOfComparisonJS, ConstantOnLeftSideOfComparisonJS + for(let i = (this.view.length - 2); i >= 0; i--) + { + // noinspection NonShortCircuitBooleanExpressionJS + this.view[i + 1] |= (this.view[i] & shiftMask) << (8 - shift); + this.view[i] >>= shift; + } + //endregion + + //region Decrease number of bits stored into value + this.bitsCount -= shift; + // noinspection ConstantOnRightSideOfComparisonJS, ConstantOnLeftSideOfComparisonJS, EqualityComparisonWithCoercionJS, NonBlockStatementBodyJS + if(this.bitsCount == 0) + this.clear(); + //endregion + + //region Change stream size if needed + // noinspection NonBlockStatementBodyJS + if(needShrink) + this.shrink(); + //endregion + } + //********************************************************************************** + // noinspection JSUnusedGlobalSymbols, FunctionWithMultipleReturnPointsJS + /** + * Shift entire "BitStream" value left to number of bits + * @param {number} shift Number of bits to shift value + */ + shiftLeft(shift) + { + /* + NOTE: We do not really shift value because of internal structure of "BitStream": + all bytes inside "BitStream" are aligned to right position. So, even if we will + really shift value to left after that we will need again shift it right to the + same number of bits. Thus all that we do here is hiding of left bits and descresing + the "bitsCount" number. + */ + + //region Check parameters + // noinspection ConstantOnRightSideOfComparisonJS, ConstantOnLeftSideOfComparisonJS, EqualityComparisonWithCoercionJS, NonBlockStatementBodyJS + if(this.view.length == 0) + return; + + // noinspection ConstantOnRightSideOfComparisonJS, ConstantOnLeftSideOfComparisonJS, NonBlockStatementBodyJS + if((shift < 0) || (shift > 8)) + throw new Error("The \"shift\" parameter must be in range 0-8"); + + // noinspection NonBlockStatementBodyJS + if(shift > this.bitsCount) + throw new Error("The \"shift\" parameter can not be bigger than \"this.bitsCount\""); + //endregion + + //region Remove shifted bits + // noinspection MagicNumberJS, NonShortCircuitBooleanExpressionJS + const bitsOffset = this.bitsCount & 0x07; + if(bitsOffset > shift) + { + // noinspection MagicNumberJS + this.view[0] &= 0xFF >> (bitsOffset + shift); + } + else + { + //region Change size of buffer + const buffer = new ArrayBuffer(this.buffer.byteLength - 1); + const view = new Uint8Array(buffer); + + // noinspection NestedFunctionCallJS + view.set(new Uint8Array(this.buffer, 1, this.buffer.byteLength - 1)); + //endregion + + //region Mask item with index 0 + // noinspection MagicNumberJS + view[0] &= 0xFF >> (shift - bitsOffset); + //endregion + + //region Store final array into current stream + this.buffer = buffer.slice(0); + this.view = new Uint8Array(this.buffer); + //endregion + } + //endregion + + //region Decrease number of bits stored into value + this.bitsCount -= shift; + // noinspection ConstantOnRightSideOfComparisonJS, ConstantOnLeftSideOfComparisonJS, EqualityComparisonWithCoercionJS, NonBlockStatementBodyJS + if(this.bitsCount == 0) + this.clear(); + //endregion + } + //********************************************************************************** + // noinspection FunctionWithMultipleReturnPointsJS, FunctionTooLongJS + /** + * Return slice of existing "BitStream" + * @param {?number} [start=null] Start position of the slice (in bits) + * @param {?number} [end=null] End position of the slice (in bits) + * @returns {BitStream} + */ + slice(start = null, end = null) + { + //region Make ability to pass non-value bits + let valueShift = 0; + // noinspection NonBlockStatementBodyJS + if(this.bitsCount % 8) + valueShift = (8 - (this.bitsCount % 8)); + + // noinspection AssignmentToFunctionParameterJS + start += valueShift; + // noinspection AssignmentToFunctionParameterJS + end += valueShift; + //endregion + + //region Initial variables + // noinspection ConstantOnRightSideOfComparisonJS, ConstantOnLeftSideOfComparisonJS + if(start == null) + { + // noinspection AssignmentToFunctionParameterJS + start = 0; + } + + // noinspection ConstantOnRightSideOfComparisonJS, ConstantOnLeftSideOfComparisonJS, NonBlockStatementBodyJS + if((start < 0) || (start > ((this.view.length << 3) - 1))) + return new BitStream(); //("Wrong start position: " + start); + + // noinspection ConstantOnRightSideOfComparisonJS, ConstantOnLeftSideOfComparisonJS + if(end == null) + { + // noinspection AssignmentToFunctionParameterJS + end = (this.view.length << 3) - 1; + } + + // noinspection ConstantOnRightSideOfComparisonJS, ConstantOnLeftSideOfComparisonJS, NonBlockStatementBodyJS + if((end < 0) || (end > ((this.view.length << 3) - 1))) + return new BitStream(); //("Wrong end position: " + end); + + // noinspection NonBlockStatementBodyJS + if((end - start + 1) > this.bitsCount) + return new BitStream(); //("Maximum length is " + this.bitsCount); + + const startIndex = start >> 3; + // noinspection MagicNumberJS, NonShortCircuitBooleanExpressionJS + const startOffset = start & 0x07; + + const endIndex = end >> 3; + // noinspection MagicNumberJS, NonShortCircuitBooleanExpressionJS + const endOffset = end & 0x07; + + // noinspection ConstantOnRightSideOfComparisonJS, ConstantOnLeftSideOfComparisonJS, ConditionalExpressionJS, EqualityComparisonWithCoercionJS + const bitsLength = ((endIndex - startIndex) == 0) ? 1 : (endIndex - startIndex + 1); + + const result = new BitStream(); + //endregion + + //region Store "primary bytes" + result.buffer = new ArrayBuffer(bitsLength); + result.view = new Uint8Array(result.buffer); + result.bitsCount = bitsLength << 3; + + // noinspection NestedFunctionCallJS + result.view.set(new Uint8Array(this.buffer, startIndex, bitsLength)); + //endregion + + //region Change "start byte" + // noinspection MagicNumberJS + result.view[0] &= (0xFF >> startOffset); + //endregion + + //region Change "end byte" + // noinspection MagicNumberJS + result.view[bitsLength] &= (0xFF << (7 - endOffset)); + //endregion + + //region Shift result array to right + // noinspection NonBlockStatementBodyJS + if(7 - endOffset) + result.shiftRight(7 - endOffset, false); + //endregion + + //region Set final number of bits + result.bitsCount = (end - start + 1); + //endregion + + //region Cut unnecessary bytes from result + result.shrink(); + //endregion + + return result; + } + //********************************************************************************** + // noinspection FunctionWithMultipleReturnPointsJS + /** + * Return copy of existing "BitStream" + * @param {?number} [start=null] Start position of the copy (in bits) + * @param {?number} [length=null] Length of the copy (in bits) + * @returns {BitStream} + */ + copy(start = null, length = null) + { + //region Check input parameters + // noinspection ConstantOnRightSideOfComparisonJS, ConstantOnLeftSideOfComparisonJS, NonBlockStatementBodyJS + if((start < 0) || (start > ((this.view.length << 3) - 1))) + return new BitStream(); //("Wrong start position: " + start); + + // noinspection ConstantOnRightSideOfComparisonJS, ConstantOnLeftSideOfComparisonJS + if(length === null) + { + // noinspection AssignmentToFunctionParameterJS + length = (this.view.length << 3) - start - 1; + } + + // noinspection NonBlockStatementBodyJS + if(length > this.bitsCount) + return new BitStream(); //("Maximum length is " + this.bitsCount); + //endregion + + return this.slice(start, start + length - 1); + } + //********************************************************************************** + /** + * Shrink unnecessary bytes in current stream accordingly to "bitsCount" value + */ + shrink() + { + // noinspection ConditionalExpressionJS + const currentLength = (this.bitsCount >> 3) + ((this.bitsCount % 8) ? 1 : 0); + if(currentLength < this.buffer.byteLength) + { + //region Change size of buffer + const buffer = new ArrayBuffer(currentLength); + const view = new Uint8Array(buffer); + + // noinspection NestedFunctionCallJS + view.set(new Uint8Array(this.buffer, this.buffer.byteLength - currentLength, currentLength)); + //endregion + + //region Store final array into current stream + this.buffer = buffer.slice(0); + this.view = new Uint8Array(this.buffer); + //endregion + } + } + //********************************************************************************** + // noinspection JSUnusedGlobalSymbols + /** + * Reverse bits order in each byte in the stream + * Got it from here: http://graphics.stanford.edu/~seander/bithacks.html#ReverseByteWith32Bits + */ + reverseBytes() + { + //region Reverse bits order in each byte in the stream + for(let i = 0; i < this.view.length; i++) + { + // noinspection MagicNumberJS, NonShortCircuitBooleanExpressionJS + this.view[i] = ((this.view[i] * 0x0802 & 0x22110) | (this.view[i] * 0x8020 & 0x88440)) * 0x10101 >> 16; + } + //endregion + + //region Shift "most significant" byte + if(this.bitsCount % 8) + { + // noinspection ConditionalExpressionJS + const currentLength = (this.bitsCount >> 3) + ((this.bitsCount % 8) ? 1 : 0); + // noinspection MagicNumberJS, NonShortCircuitBooleanExpressionJS + this.view[this.view.length - currentLength] >>= (8 - (this.bitsCount & 0x07)); + } + //endregion + } + //********************************************************************************** + // noinspection JSUnusedGlobalSymbols + /** + * Reverse all bits in entire "BitStream" + */ + reverseValue() + { + const initialValue = this.toString(); + const initialValueLength = initialValue.length; + + const reversedValue = new Array(initialValueLength); + + // noinspection NonBlockStatementBodyJS + for(let i = 0; i < initialValueLength; i++) + reversedValue[initialValueLength - 1 - i] = initialValue[i]; + + // noinspection NestedFunctionCallJS + this.fromString(reversedValue.join("")); + } + //********************************************************************************** + // noinspection JSUnusedGlobalSymbols, FunctionWithMultipleReturnPointsJS + /** + * Trying to represent entire "BitStream" as an unsigned integer. + * @return {number} + */ + getNumberValue() + { + //region Initial variables + const byteLength = (this.buffer.byteLength - 1); + //endregion + + //region Check posibility for convertion + // noinspection ConstantOnRightSideOfComparisonJS, ConstantOnLeftSideOfComparisonJS, NonBlockStatementBodyJS + if(byteLength > 3) + return (-1); + + // noinspection ConstantOnRightSideOfComparisonJS, ConstantOnLeftSideOfComparisonJS, EqualityComparisonWithCoercionJS, NonBlockStatementBodyJS + if(byteLength == (-1)) + return 0; + //endregion + + //region Convert byte array to "Uint32Array" value + const value = new Uint32Array(1); + const view = new Uint8Array(value.buffer); + + // noinspection ConstantOnRightSideOfComparisonJS, ConstantOnLeftSideOfComparisonJS, NonBlockStatementBodyJS + for(let i = byteLength; i >= 0; i--) + view[byteLength - i] = this.view[i]; + //endregion + + return value[0]; + } + //********************************************************************************** + // noinspection JSUnusedGlobalSymbols + /** + * Find any bit pattern in "BitStream" + * @param {BitStream} pattern Stream having pattern value + * @param {?number} [start=null] Start position to search from + * @param {?number} [length=null] Length of byte block to search at + * @param {boolean} [backward=false] Flag to search in backward order + * @returns {number} + */ + findPattern(pattern, start = null, length = null, backward = false) + { + //region Convert "BitStream" values to "ByteStream" + const stringStream = new ByteStream({ + string: this.toString() + }); + const stringPattern = new ByteStream({ + string: pattern.toString() + }); + //endregion + + return stringStream.findPattern(stringPattern, start, length, backward); + } + //********************************************************************************** + // noinspection JSUnusedGlobalSymbols + /** + * Find first position of any pattern from input array + * @param {Array.} patterns Array with patterns which should be found + * @param {?number} [start=null] Start position to search from + * @param {?number} [length=null] Length of byte block to search at + * @param {boolean} [backward=false] Flag to search in backward order + * @returns {{id: number, position: number}} + */ + findFirstIn(patterns, start = null, length = null, backward = false) + { + //region Convert "BitStream" values to "ByteStream" + const stringStream = new ByteStream({ + string: this.toString() + }); + + const stringPatterns = new Array(patterns.length); + + for(let i = 0; i < patterns.length; i++) + { + stringPatterns[i] = new ByteStream({ + string: patterns[i].toString() + }); + } + //endregion + + return stringStream.findFirstIn(stringPatterns, start, length, backward); + } + //********************************************************************************** + // noinspection JSUnusedGlobalSymbols + /** + * Find all positions of any pattern from input array + * @param {Array.} patterns Array with patterns which should be found + * @param {?number} [start=null] Start position to search from + * @param {?number} [length=null] Length of byte block to search at + * @returns {Array} + */ + findAllIn(patterns, start = null, length = null) + { + //region Convert "BitStream" values to "ByteStream" + const stringStream = new ByteStream({ + string: this.toString() + }); + + const stringPatterns = new Array(patterns.length); + + for(let i = 0; i < patterns.length; i++) + { + stringPatterns[i] = new ByteStream({ + string: patterns[i].toString() + }); + } + //endregion + + return stringStream.findAllIn(stringPatterns, start, length); + } + //********************************************************************************** + // noinspection JSUnusedGlobalSymbols + /** + * Find all positions of a pattern + * @param {BitStream} pattern Stream having pattern value + * @param {?number} [start=null] Start position to search from + * @param {?number} [length=null] Length of byte block to search at + * @returns {Array|number} + */ + findAllPatternIn(pattern, start = null, length = null) + { + //region Convert "BitStream" values to "ByteStream" + const stringStream = new ByteStream({ + string: this.toString() + }); + const stringPattern = new ByteStream({ + string: pattern.toString() + }); + //endregion + + return stringStream.findAllPatternIn(stringPattern, start, length); + } + //********************************************************************************** + // noinspection JSUnusedGlobalSymbols + /** + * Find first position of data, not included in patterns from input array + * @param {Array.} patterns Array with patterns which should be found + * @param {?number} [start=null] Start position to search from + * @param {?number} [length=null] Length of byte block to search at + * @param {boolean} [backward=false] Flag to search in backward order + * @returns {{left: {id: number, position: *}, right: {id: number, position: number}, value: ByteStream}} + */ + findFirstNotIn(patterns, start = null, length = null, backward = false) + { + //region Convert "BitStream" values to "ByteStream" + const stringStream = new ByteStream({ + string: this.toString() + }); + + const stringPatterns = new Array(patterns.length); + + for(let i = 0; i < patterns.length; i++) + { + stringPatterns[i] = new ByteStream({ + string: patterns[i].toString() + }); + } + //endregion + + return stringStream.findFirstNotIn(stringPatterns, start, length, backward); + } + //********************************************************************************** + // noinspection JSUnusedGlobalSymbols + /** + * Find all positions of data, not included in patterns from input array + * @param {Array.} patterns Array with patterns which should be found + * @param {?number} [start=null] Start position to search from + * @param {?number} [length=null] Length of byte block to search at + * @returns {Array} + */ + findAllNotIn(patterns, start = null, length = null) + { + //region Convert "BitStream" values to "ByteStream" + const stringStream = new ByteStream({ + string: this.toString() + }); + + const stringPatterns = new Array(patterns.length); + + for(let i = 0; i < patterns.length; i++) + { + stringPatterns[i] = new ByteStream({ + string: patterns[i].toString() + }); + } + //endregion + + return stringStream.findAllNotIn(stringPatterns, start, length); + } + //********************************************************************************** + // noinspection JSUnusedGlobalSymbols + /** + * Find position of a sequence of any patterns from input array + * @param {Array.} patterns Array with patterns which should be found + * @param {?number} [start=null] Start position to search from + * @param {?number} [length=null] Length of byte block to search at + * @param {boolean} [backward=false] Flag to search in backward order + * @returns {{position, value}|*} + */ + findFirstSequence(patterns, start = null, length = null, backward = false) + { + //region Convert "BitStream" values to "ByteStream" + const stringStream = new ByteStream({ + string: this.toString() + }); + + const stringPatterns = new Array(patterns.length); + + for(let i = 0; i < patterns.length; i++) + { + stringPatterns[i] = new ByteStream({ + string: patterns[i].toString() + }); + } + //endregion + + return stringStream.findFirstSequence(stringPatterns, start, length, backward); + } + //********************************************************************************** + // noinspection JSUnusedGlobalSymbols + /** + * Find position of a sequence of any patterns from input array + * @param {Array.} patterns Array with patterns which should be found + * @param {?number} [start=null] Start position to search from + * @param {?number} [length=null] Length of byte block to search at + * @returns {Array} + */ + findAllSequences(patterns, start, length) + { + //region Convert "BitStream" values to "ByteStream" + const stringStream = new ByteStream({ + string: this.toString() + }); + + const stringPatterns = new Array(patterns.length); + + for(let i = 0; i < patterns.length; i++) + { + stringPatterns[i] = new ByteStream({ + string: patterns[i].toString() + }); + } + //endregion + + return stringStream.findAllSequences(stringPatterns, start, length); + } + //********************************************************************************** + // noinspection JSUnusedGlobalSymbols + /** + * Find all paired patterns in the stream + * @param {BitStream} leftPattern Left pattern to search for + * @param {BitStream} rightPattern Right pattern to search for + * @param {?number} [start=null] Start position to search from + * @param {?number} [length=null] Length of byte block to search at + * @returns {Array} + */ + findPairedPatterns(leftPattern, rightPattern, start = null, length = null) + { + //region Convert "BitStream" values to "ByteStream" + const stringStream = new ByteStream({ + string: this.toString() + }); + const stringLeftPattern = new ByteStream({ + string: leftPattern.toString() + }); + const stringRightPattern = new ByteStream({ + string: rightPattern.toString() + }); + //endregion + + return stringStream.findPairedPatterns(stringLeftPattern, stringRightPattern, start, length); + } + //********************************************************************************** + // noinspection JSUnusedGlobalSymbols, FunctionWithMultipleLoopsJS + /** + * Find all paired patterns in the stream + * @param {Array.} inputLeftPatterns Array of left patterns to search for + * @param {Array.} inputRightPatterns Array of right patterns to search for + * @param {?number} [start=null] Start position to search from + * @param {?number} [length=null] Length of byte block to search at + * @returns {Array} + */ + findPairedArrays(inputLeftPatterns, inputRightPatterns, start = null, length = null) + { + //region Convert "BitStream" values to "ByteStream" + const stringStream = new ByteStream({ + string: this.toString() + }); + + const stringLeftPatterns = new Array(inputLeftPatterns.length); + + for(let i = 0; i < inputLeftPatterns.length; i++) + { + stringLeftPatterns[i] = new ByteStream({ + string: inputLeftPatterns[i].toString() + }); + } + + const stringRightPatterns = new Array(inputRightPatterns.length); + + for(let i = 0; i < inputRightPatterns.length; i++) + { + stringRightPatterns[i] = new ByteStream({ + string: inputRightPatterns[i].toString() + }); + } + //endregion + + return stringStream.findPairedArrays(stringLeftPatterns, stringRightPatterns, start, length); + } + //********************************************************************************** + // noinspection JSUnusedGlobalSymbols, FunctionWithMultipleReturnPointsJS + /** + * Replace one pattern with other + * @param {BitStream} searchPattern The pattern to search for + * @param {BitStream} replacePattern The pattern to replace initial pattern + * @param {?number} [start=null] Start position to search from + * @param {?number} [length=null] Length of byte block to search at + * @returns {boolean} + */ + replacePattern(searchPattern, replacePattern, start = null, length = null) + { + //region Convert "BitStream" values to "ByteStream" + const stringStream = new ByteStream({ + string: this.toString() + }); + const stringSearchPattern = new ByteStream({ + string: searchPattern.toString() + }); + const stringReplacePattern = new ByteStream({ + string: replacePattern.toString() + }); + //endregion + + //region Re-initialize existing data + if(stringStream.findPairedPatterns(stringSearchPattern, stringReplacePattern, start, length)) + { + // noinspection NestedFunctionCallJS + this.fromString(stringStream.toString()); + return true; + } + //endregion + + return false; + } + //********************************************************************************** + // noinspection JSUnusedGlobalSymbols + /** + * Skip any pattern from input array + * @param {Array.} patterns Array with patterns which should be ommited + * @param {?number} [start=null] Start position to search from + * @param {?number} [length=null] Length of byte block to search at + * @param {boolean} [backward=false] Flag to search in backward order + * @returns {*} + */ + skipPatterns(patterns, start, length, backward) + { + //region Convert "BitStream" values to "ByteStream" + const stringStream = new ByteStream({ + string: this.toString() + }); + + const stringPatterns = new Array(patterns.length); + + for(let i = 0; i < patterns.length; i++) + { + stringPatterns[i] = new ByteStream({ + string: patterns[i].toString() + }); + } + //endregion + + return stringStream.skipPatterns(stringPatterns, start, length, backward); + } + //********************************************************************************** + // noinspection JSUnusedGlobalSymbols + /** + * Skip any pattern not from input array + * @param {Array.} patterns Array with patterns which should be ommited + * @param {?number} [start=null] Start position to search from + * @param {?number} [length=null] Length of byte block to search at + * @param {boolean} [backward=false] Flag to search in backward order + * @returns {number} + */ + skipNotPatterns(patterns, start, length, backward) + { + //region Convert "BitStream" values to "ByteStream" + const stringStream = new ByteStream({ + string: this.toString() + }); + + const stringPatterns = new Array(patterns.length); + + for(let i = 0; i < patterns.length; i++) + { + stringPatterns[i] = new ByteStream({ + string: patterns[i].toString() + }); + } + //endregion + + return stringStream.skipNotPatterns(stringPatterns, start, length, backward); + } + //********************************************************************************** + // noinspection JSUnusedGlobalSymbols + /** + * Append a new "BitStream" content to the current "BitStream" + * @param {BitStream} stream A new "stream" to append to current "stream" + */ + append(stream) + { + //region Initialize current stream with new data + // noinspection NestedFunctionCallJS + this.fromString([ + this.toString(), + stream.toString() + ].join("")); + //endregion + } + //********************************************************************************** +} +//************************************************************************************** +export class SeqBitStream +{ + //********************************************************************************** + constructor(parameters = {}) + { + //region Internal variables + this.stream = new BitStream(); + + this._start = 0; + this._length = this.stream.bitsCount; + + this.backward = false; + + this.appendBlock = 0; + //endregion + + for(const key of Object.keys(parameters)) + { + switch(key) + { + case "stream": + case "start": + case "length": + case "backward": + case "appendBlock": + this[key] = parameters[key]; + break; + default: + } + } + } + //********************************************************************************** + // noinspection FunctionWithMultipleReturnPointsJS + set start(value) + { + // noinspection NonBlockStatementBodyJS + if(value > this.stream.bitsCount) + return; + + // noinspection ConditionalExpressionJS + this._length -= ((this.backward) ? (this._start - value) : (value - this._start)); + this._start = value; + + //region Initialization of "prev" internal variables + // noinspection JSUnusedGlobalSymbols + this.prevStart = this._start; + // noinspection JSUnusedGlobalSymbols + this.prevLength = this._length; + //endregion + } + //********************************************************************************** + get start() + { + return this._start; + } + //********************************************************************************** + // noinspection FunctionWithMultipleReturnPointsJS + set length(value) + { + // noinspection NonBlockStatementBodyJS + if(value > this.stream.bitsCount) + return; + + // noinspection JSUnusedGlobalSymbols + this.prevLength = this._length; + this._length = value; + } + //********************************************************************************** + get length() + { + return this._length; + } + //********************************************************************************** + set stream(value) + { + this._stream = value; + + // noinspection JSUnusedGlobalSymbols + this.prevLength = this._length; + this._length = value.bitsCount; + + // noinspection JSUnusedGlobalSymbols + this.prevStart = this._start; + // noinspection ConditionalExpressionJS + this._start = (this.backward) ? this.length : 0; + } + //********************************************************************************** + get stream() + { + return this._stream; + } + //********************************************************************************** + // noinspection JSUnusedGlobalSymbols + /** + * Get next "length" bits from the stream + * @param {number} length Number of bits to read + * @returns {*} + */ + getBits(length) + { + //region Check input parameters + if((this.start + length) > this.stream.bitsCount) + { + // noinspection AssignmentToFunctionParameterJS + length = (this.stream.bitsCount - this.start); + } + //endregion + + //region Initial variables + let result; + //endregion + + //region Copy necessary length of bits + if(this.backward) + { + result = this.stream.copy(this.start - length, length); + this.start -= result.bitsCount; + } + else + { + result = this.stream.copy(this.start, length); + this.start += result.bitsCount; + } + //endregion + + return result; + } + //********************************************************************************** + // noinspection FunctionTooLongJS + /** + * Get string representation for the next "length" bits from the stream + * @param {number} length Number of bits to read + * @returns {string} + */ + getBitsString(length) + { + //region Check input parameters + if((this.start + length) > this.stream.bitsCount) + { + // noinspection AssignmentToFunctionParameterJS + length = (this.stream.bitsCount - this.start); + } + //endregion + + //region Initial variables + let result = []; + + let start; + + // noinspection NonBlockStatementBodyJS + if(this.backward) + start = this.start - length; + else + start = this.start; + + let end = this.start + length - 1; + + //region Make ability to pass non-value bits + let valueShift = 0; + // noinspection NonBlockStatementBodyJS + if(this.stream.bitsCount % 8) + valueShift = (8 - (this.stream.bitsCount % 8)); + + start += valueShift; + end += valueShift; + //endregion + + const startIndex = start >> 3; + // noinspection MagicNumberJS, NonShortCircuitBooleanExpressionJS + const startOffset = start & 0x07; + + const endIndex = end >> 3; + // noinspection MagicNumberJS, NonShortCircuitBooleanExpressionJS + const endOffset = end & 0x07; + + // noinspection ConstantOnRightSideOfComparisonJS, ConstantOnLeftSideOfComparisonJS, ConditionalExpressionJS, EqualityComparisonWithCoercionJS + const bitsLengthIndex = startIndex + (((endIndex - startIndex) == 0) ? 1 : (endIndex - startIndex + 1)); + //endregion + + //region Get string representation of bits + for(let i = startIndex; i < bitsLengthIndex; i++) + { + let value = bitsToStringArray[this.stream.view[i]]; + + // noinspection EqualityComparisonWithCoercionJS, NonBlockStatementBodyJS + if(i == startIndex) + value = value.slice(startOffset); + + // noinspection EqualityComparisonWithCoercionJS, NonBlockStatementBodyJS + if(i == (bitsLengthIndex - 1)) + value = value.slice(0, endOffset - 7 + value.length); + + result.push(value); + } + + result = result.join(""); + //endregion + + //region Change internal values + // noinspection NonBlockStatementBodyJS + if(this.backward) + this.start -= result.length; + else + this.start += result.length; + //endregion + + return result; + } + //********************************************************************************** + // noinspection JSUnusedGlobalSymbols, FunctionWithMultipleLoopsJS, FunctionWithMultipleReturnPointsJS + /** + * Get number value representation of the next "length" bits from the stream, preliminary reversed + * @param {number} length Number of bits to read + * @returns {*} + */ + getBitsReversedValue(length) + { + //region Initial variables + const initialValue = this.getBitsString(length); + const initialValueLength = initialValue.length; + + let byteIndex; + + const initialOffset = 8 - (initialValueLength % 8); + + const reversedValue = new Array(initialValueLength); + + const value = new Uint32Array(1); + const valueView = new Uint8Array(value.buffer, 0, 4); + + let i; + + // noinspection ConstantOnRightSideOfComparisonJS, ConstantOnLeftSideOfComparisonJS, MagicNumberJS, NonBlockStatementBodyJS + if(initialValueLength > 32) + return (-1); + + // noinspection ConstantOnRightSideOfComparisonJS, ConstantOnLeftSideOfComparisonJS, MagicNumberJS, EqualityComparisonWithCoercionJS, NonBlockStatementBodyJS + if(length == 32) + byteIndex = 3; + else + byteIndex = ((initialValueLength - 1) >> 3); + //endregion + + //region Reverse value + // noinspection NonBlockStatementBodyJS + for(i = 0; i < initialValueLength; i++) + reversedValue[initialValueLength - 1 - i] = initialValue[i]; + //endregion + + //region Convert byte array to "Uint32Array" value + for(i = initialOffset; i < (initialOffset + initialValueLength); i++) + { + // noinspection ConstantOnRightSideOfComparisonJS, ConstantOnLeftSideOfComparisonJS, EqualityComparisonWithCoercionJS + if(reversedValue[i - initialOffset] == "1") + { + // noinspection MagicNumberJS + valueView[byteIndex] |= 0x01 << (7 - (i % 8)); + } + + // noinspection ConstantOnRightSideOfComparisonJS, ConstantOnLeftSideOfComparisonJS, EqualityComparisonWithCoercionJS, NonBlockStatementBodyJS + if(i && (((i + 1) % 8) == 0)) + byteIndex--; + } + //endregion + + return value[0]; + } + //********************************************************************************** + /** + * Represent remaining bits in "BitStream" as a string + * @return {string} + */ + toString() + { + const streamToDisplay = this.stream.copy(this.start, this.length); + return streamToDisplay.toString(); + } + //********************************************************************************** +} +//************************************************************************************** diff --git a/core/third-party/pkijs/common.js b/core/third-party/pkijs/common.js new file mode 100644 index 0000000..1ac6eda --- /dev/null +++ b/core/third-party/pkijs/common.js @@ -0,0 +1,572 @@ +import * as asn1js from "./asn1.js"; +import { utilConcatBuf } from "./pvutils.js"; +import CryptoEngine from "./CryptoEngine.js"; +//************************************************************************************** +//region Crypto engine related function +//************************************************************************************** +let engine = { + name: "none", + crypto: null, + subtle: null +}; +//************************************************************************************** +export function setEngine(name, crypto, subtle) +{ + //region We are in Node + // noinspection JSUnresolvedVariable + if((typeof process !== "undefined") && ("pid" in process) && (typeof global !== "undefined") && (typeof window === "undefined")) + { + // noinspection ES6ModulesDependencies, JSUnresolvedVariable + if(typeof global[process.pid] === "undefined") + { + // noinspection JSUnresolvedVariable + global[process.pid] = {}; + } + else + { + // noinspection JSUnresolvedVariable + if(typeof global[process.pid] !== "object") + { + // noinspection JSUnresolvedVariable + throw new Error(`Name global.${process.pid} already exists and it is not an object`); + } + } + + // noinspection JSUnresolvedVariable + if(typeof global[process.pid].pkijs === "undefined") + { + // noinspection JSUnresolvedVariable + global[process.pid].pkijs = {}; + } + else + { + // noinspection JSUnresolvedVariable + if(typeof global[process.pid].pkijs !== "object") + { + // noinspection JSUnresolvedVariable + throw new Error(`Name global.${process.pid}.pkijs already exists and it is not an object`); + } + } + + // noinspection JSUnresolvedVariable + global[process.pid].pkijs.engine = { + name: name, + crypto: crypto, + subtle: subtle + }; + } + //endregion + //region We are in browser + else + { + engine = { + name: name, + crypto: crypto, + subtle: subtle + }; + } + //endregion +} +//************************************************************************************** +export function getEngine() +{ + //region We are in Node + // noinspection JSUnresolvedVariable + if((typeof process !== "undefined") && ("pid" in process) && (typeof global !== "undefined") && (typeof window === "undefined")) + { + let _engine; + + try + { + // noinspection JSUnresolvedVariable + _engine = global[process.pid].pkijs.engine; + } + catch(ex) + { + throw new Error("Please call \"setEngine\" before call to \"getEngine\""); + } + + return _engine; + } + //endregion + + return engine; +} +//************************************************************************************** +(function initCryptoEngine() +{ + if(typeof self !== "undefined") + { + if("crypto" in self) + { + let engineName = "webcrypto"; + + /** + * Standard crypto object + * @type {Object} + * @property {Object} [webkitSubtle] Subtle object from Apple + */ + const cryptoObject = self.crypto; + let subtleObject; + + // Apple Safari support + if("webkitSubtle" in self.crypto) + { + try + { + subtleObject = self.crypto.webkitSubtle; + } + catch(ex) + { + subtleObject = self.crypto.subtle; + } + + engineName = "safari"; + } + + if("subtle" in self.crypto) + subtleObject = self.crypto.subtle; + + + if(typeof subtleObject === "undefined") + { + engine = { + name: engineName, + crypto: cryptoObject, + subtle: null + }; + } + else + { + engine = { + name: engineName, + crypto: cryptoObject, + subtle: new CryptoEngine({name: engineName, crypto: self.crypto, subtle: subtleObject}) + }; + } + } + } + + setEngine(engine.name, engine.crypto, engine.subtle); +})(); +//************************************************************************************** +//endregion +//************************************************************************************** +//region Declaration of common functions +//************************************************************************************** +/** + * Get crypto subtle from current "crypto engine" or "undefined" + * @returns {({decrypt, deriveKey, digest, encrypt, exportKey, generateKey, importKey, sign, unwrapKey, verify, wrapKey}|null)} + */ +export function getCrypto() +{ + const _engine = getEngine(); + + if(_engine.subtle !== null) + return _engine.subtle; + + return undefined; +} +//************************************************************************************** +/** + * Initialize input Uint8Array by random values (with help from current "crypto engine") + * @param {!Uint8Array} view + * @returns {*} + */ +export function getRandomValues(view) +{ + return getEngine().subtle.getRandomValues(view); +} +//************************************************************************************** +/** + * Get OID for each specific algorithm + * @param {Object} algorithm + * @returns {string} + */ +export function getOIDByAlgorithm(algorithm) +{ + return getEngine().subtle.getOIDByAlgorithm(algorithm); +} +//************************************************************************************** +/** + * Get default algorithm parameters for each kind of operation + * @param {string} algorithmName Algorithm name to get common parameters for + * @param {string} operation Kind of operation: "sign", "encrypt", "generatekey", "importkey", "exportkey", "verify" + * @returns {*} + */ +export function getAlgorithmParameters(algorithmName, operation) +{ + return getEngine().subtle.getAlgorithmParameters(algorithmName, operation); +} +//************************************************************************************** +/** + * Create CMS ECDSA signature from WebCrypto ECDSA signature + * @param {ArrayBuffer} signatureBuffer WebCrypto result of "sign" function + * @returns {ArrayBuffer} + */ +export function createCMSECDSASignature(signatureBuffer) +{ + //region Initial check for correct length + if((signatureBuffer.byteLength % 2) !== 0) + return new ArrayBuffer(0); + //endregion + + //region Initial variables + const length = signatureBuffer.byteLength / 2; // There are two equal parts inside incoming ArrayBuffer + + const rBuffer = new ArrayBuffer(length); + const rView = new Uint8Array(rBuffer); + rView.set(new Uint8Array(signatureBuffer, 0, length)); + + const rInteger = new asn1js.Integer({ valueHex: rBuffer }); + + const sBuffer = new ArrayBuffer(length); + const sView = new Uint8Array(sBuffer); + sView.set(new Uint8Array(signatureBuffer, length, length)); + + const sInteger = new asn1js.Integer({ valueHex: sBuffer }); + //endregion + + return (new asn1js.Sequence({ + value: [ + rInteger.convertToDER(), + sInteger.convertToDER() + ] + })).toBER(false); +} +//************************************************************************************** +/** + * String preparation function. In a future here will be realization of algorithm from RFC4518 + * @param {string} inputString JavaScript string. As soon as for each ASN.1 string type we have a specific transformation function here we will work with pure JavaScript string + * @returns {string} Formated string + */ +export function stringPrep(inputString) +{ + //region Initial variables + let isSpace = false; + let cuttedResult = ""; + //endregion + + const result = inputString.trim(); // Trim input string + + //region Change all sequence of SPACE down to SPACE char + for(let i = 0; i < result.length; i++) + { + if(result.charCodeAt(i) === 32) + { + if(isSpace === false) + isSpace = true; + } + else + { + if(isSpace) + { + cuttedResult += " "; + isSpace = false; + } + + cuttedResult += result[i]; + } + } + //endregion + + return cuttedResult.toLowerCase(); +} +//************************************************************************************** +/** + * Create a single ArrayBuffer from CMS ECDSA signature + * @param {Sequence} cmsSignature ASN.1 SEQUENCE contains CMS ECDSA signature + * @returns {ArrayBuffer} + */ +export function createECDSASignatureFromCMS(cmsSignature) +{ + //region Check input variables + if((cmsSignature instanceof asn1js.Sequence) === false) + return new ArrayBuffer(0); + + if(cmsSignature.valueBlock.value.length !== 2) + return new ArrayBuffer(0); + + if((cmsSignature.valueBlock.value[0] instanceof asn1js.Integer) === false) + return new ArrayBuffer(0); + + if((cmsSignature.valueBlock.value[1] instanceof asn1js.Integer) === false) + return new ArrayBuffer(0); + //endregion + + const rValue = cmsSignature.valueBlock.value[0].convertFromDER(); + const sValue = cmsSignature.valueBlock.value[1].convertFromDER(); + + //region Check the lengths of two parts are equal + switch(true) + { + case (rValue.valueBlock.valueHex.byteLength < sValue.valueBlock.valueHex.byteLength): + { + if((sValue.valueBlock.valueHex.byteLength - rValue.valueBlock.valueHex.byteLength) !== 1) + throw new Error("Incorrect DER integer decoding"); + + const correctedLength = sValue.valueBlock.valueHex.byteLength; + + const rValueView = new Uint8Array(rValue.valueBlock.valueHex); + + const rValueBufferCorrected = new ArrayBuffer(correctedLength); + const rValueViewCorrected = new Uint8Array(rValueBufferCorrected); + + rValueViewCorrected.set(rValueView, 1); + rValueViewCorrected[0] = 0x00; // In order to be sure we do not have any garbage here + + return utilConcatBuf(rValueBufferCorrected, sValue.valueBlock.valueHex); + } + case (rValue.valueBlock.valueHex.byteLength > sValue.valueBlock.valueHex.byteLength): + { + if((rValue.valueBlock.valueHex.byteLength - sValue.valueBlock.valueHex.byteLength) !== 1) + throw new Error("Incorrect DER integer decoding"); + + const correctedLength = rValue.valueBlock.valueHex.byteLength; + + const sValueView = new Uint8Array(sValue.valueBlock.valueHex); + + const sValueBufferCorrected = new ArrayBuffer(correctedLength); + const sValueViewCorrected = new Uint8Array(sValueBufferCorrected); + + sValueViewCorrected.set(sValueView, 1); + sValueViewCorrected[0] = 0x00; // In order to be sure we do not have any garbage here + + return utilConcatBuf(rValue.valueBlock.valueHex, sValueBufferCorrected); + } + default: + { + //region In case we have equal length and the length is not even with 2 + if(rValue.valueBlock.valueHex.byteLength % 2) + { + const correctedLength = (rValue.valueBlock.valueHex.byteLength + 1); + + const rValueView = new Uint8Array(rValue.valueBlock.valueHex); + + const rValueBufferCorrected = new ArrayBuffer(correctedLength); + const rValueViewCorrected = new Uint8Array(rValueBufferCorrected); + + rValueViewCorrected.set(rValueView, 1); + rValueViewCorrected[0] = 0x00; // In order to be sure we do not have any garbage here + + const sValueView = new Uint8Array(sValue.valueBlock.valueHex); + + const sValueBufferCorrected = new ArrayBuffer(correctedLength); + const sValueViewCorrected = new Uint8Array(sValueBufferCorrected); + + sValueViewCorrected.set(sValueView, 1); + sValueViewCorrected[0] = 0x00; // In order to be sure we do not have any garbage here + + return utilConcatBuf(rValueBufferCorrected, sValueBufferCorrected); + } + //endregion + } + } + //endregion + + return utilConcatBuf(rValue.valueBlock.valueHex, sValue.valueBlock.valueHex); +} +//************************************************************************************** +/** + * Get WebCrypto algorithm by wel-known OID + * @param {string} oid well-known OID to search for + * @returns {Object} + */ +export function getAlgorithmByOID(oid) +{ + return getEngine().subtle.getAlgorithmByOID(oid); +} +//************************************************************************************** +/** + * Getting hash algorithm by signature algorithm + * @param {AlgorithmIdentifier} signatureAlgorithm Signature algorithm + * @returns {string} + */ +export function getHashAlgorithm(signatureAlgorithm) +{ + return getEngine().subtle.getHashAlgorithm(signatureAlgorithm); +} +//************************************************************************************** +/** + * ANS X9.63 Key Derivation Function having a "Counter" as a parameter + * @param {string} hashFunction Used hash function + * @param {ArrayBuffer} Zbuffer ArrayBuffer containing ECDH shared secret to derive from + * @param {number} Counter + * @param {ArrayBuffer} SharedInfo Usually DER encoded "ECC_CMS_SharedInfo" structure + */ +export function kdfWithCounter(hashFunction, Zbuffer, Counter, SharedInfo) +{ + //region Check of input parameters + switch(hashFunction.toUpperCase()) + { + case "SHA-1": + case "SHA-256": + case "SHA-384": + case "SHA-512": + break; + default: + return Promise.reject(`Unknown hash function: ${hashFunction}`); + } + + if((Zbuffer instanceof ArrayBuffer) === false) + return Promise.reject("Please set \"Zbuffer\" as \"ArrayBuffer\""); + + if(Zbuffer.byteLength === 0) + return Promise.reject("\"Zbuffer\" has zero length, error"); + + if((SharedInfo instanceof ArrayBuffer) === false) + return Promise.reject("Please set \"SharedInfo\" as \"ArrayBuffer\""); + + if(Counter > 255) + return Promise.reject("Please set \"Counter\" variable to value less or equal to 255"); + //endregion + + //region Initial variables + const counterBuffer = new ArrayBuffer(4); + const counterView = new Uint8Array(counterBuffer); + counterView[0] = 0x00; + counterView[1] = 0x00; + counterView[2] = 0x00; + counterView[3] = Counter; + + let combinedBuffer = new ArrayBuffer(0); + //endregion + + //region Get a "crypto" extension + const crypto = getCrypto(); + if(typeof crypto === "undefined") + return Promise.reject("Unable to create WebCrypto object"); + //endregion + + //region Create a combined ArrayBuffer for digesting + combinedBuffer = utilConcatBuf(combinedBuffer, Zbuffer); + combinedBuffer = utilConcatBuf(combinedBuffer, counterBuffer); + combinedBuffer = utilConcatBuf(combinedBuffer, SharedInfo); + //endregion + + //region Return digest of combined ArrayBuffer and information about current counter + return crypto.digest({ + name: hashFunction + }, + combinedBuffer) + .then(result => + ({ + counter: Counter, + result + })); + //endregion +} +//************************************************************************************** +/** + * ANS X9.63 Key Derivation Function + * @param {string} hashFunction Used hash function + * @param {ArrayBuffer} Zbuffer ArrayBuffer containing ECDH shared secret to derive from + * @param {number} keydatalen Length (!!! in BITS !!!) of used kew derivation function + * @param {ArrayBuffer} SharedInfo Usually DER encoded "ECC_CMS_SharedInfo" structure + */ +export function kdf(hashFunction, Zbuffer, keydatalen, SharedInfo) +{ + //region Initial variables + let hashLength = 0; + let maxCounter = 1; + + const kdfArray = []; + //endregion + + //region Check of input parameters + switch(hashFunction.toUpperCase()) + { + case "SHA-1": + hashLength = 160; // In bits + break; + case "SHA-256": + hashLength = 256; // In bits + break; + case "SHA-384": + hashLength = 384; // In bits + break; + case "SHA-512": + hashLength = 512; // In bits + break; + default: + return Promise.reject(`Unknown hash function: ${hashFunction}`); + } + + if((Zbuffer instanceof ArrayBuffer) === false) + return Promise.reject("Please set \"Zbuffer\" as \"ArrayBuffer\""); + + if(Zbuffer.byteLength === 0) + return Promise.reject("\"Zbuffer\" has zero length, error"); + + if((SharedInfo instanceof ArrayBuffer) === false) + return Promise.reject("Please set \"SharedInfo\" as \"ArrayBuffer\""); + //endregion + + //region Calculated maximum value of "Counter" variable + const quotient = keydatalen / hashLength; + + if(Math.floor(quotient) > 0) + { + maxCounter = Math.floor(quotient); + + if((quotient - maxCounter) > 0) + maxCounter++; + } + //endregion + + //region Create an array of "kdfWithCounter" + for(let i = 1; i <= maxCounter; i++) + kdfArray.push(kdfWithCounter(hashFunction, Zbuffer, i, SharedInfo)); + //endregion + + //region Return combined digest with specified length + return Promise.all(kdfArray).then(incomingResult => + { + //region Initial variables + let combinedBuffer = new ArrayBuffer(0); + let currentCounter = 1; + let found = true; + //endregion + + //region Combine all buffer together + while(found) + { + found = false; + + for(const result of incomingResult) + { + if(result.counter === currentCounter) + { + combinedBuffer = utilConcatBuf(combinedBuffer, result.result); + found = true; + break; + } + } + + currentCounter++; + } + //endregion + + //region Create output buffer with specified length + keydatalen >>= 3; // Divide by 8 since "keydatalen" is in bits + + if(combinedBuffer.byteLength > keydatalen) + { + const newBuffer = new ArrayBuffer(keydatalen); + const newView = new Uint8Array(newBuffer); + const combinedView = new Uint8Array(combinedBuffer); + + for(let i = 0; i < keydatalen; i++) + newView[i] = combinedView[i]; + + return newBuffer; + } + + return combinedBuffer; // Since the situation when "combinedBuffer.byteLength < keydatalen" here we have only "combinedBuffer.byteLength === keydatalen" + //endregion + }); + //endregion +} +//************************************************************************************** +//endregion +//************************************************************************************** diff --git a/core/third-party/pkijs/index.js b/core/third-party/pkijs/index.js new file mode 100644 index 0000000..844a541 --- /dev/null +++ b/core/third-party/pkijs/index.js @@ -0,0 +1,216 @@ +import { setEngine, getEngine, getCrypto, getRandomValues, getOIDByAlgorithm, getAlgorithmParameters, createCMSECDSASignature, stringPrep, createECDSASignatureFromCMS, getAlgorithmByOID, getHashAlgorithm, kdfWithCounter, kdf } from "./common.js"; +export { setEngine, getEngine, getCrypto, getRandomValues, getOIDByAlgorithm, getAlgorithmParameters, createCMSECDSASignature, stringPrep, createECDSASignatureFromCMS, getAlgorithmByOID, getHashAlgorithm, kdfWithCounter, kdf }; +import AccessDescription from "./AccessDescription.js"; +export { AccessDescription }; +import Accuracy from "./Accuracy.js"; +export { Accuracy }; +import AlgorithmIdentifier from "./AlgorithmIdentifier.js"; +export { AlgorithmIdentifier }; +import AltName from "./AltName.js"; +export { AltName }; +import Attribute from "./Attribute.js"; +export { Attribute }; +import AttributeTypeAndValue from "./AttributeTypeAndValue.js"; +export { AttributeTypeAndValue }; +import AuthenticatedSafe from "./AuthenticatedSafe.js"; +export { AuthenticatedSafe }; +import AuthorityKeyIdentifier from "./AuthorityKeyIdentifier.js"; +export { AuthorityKeyIdentifier }; +import BasicConstraints from "./BasicConstraints.js"; +export { BasicConstraints }; +import BasicOCSPResponse from "./BasicOCSPResponse.js"; +export { BasicOCSPResponse }; +import CRLBag from "./CRLBag.js"; +export { CRLBag }; +import CRLDistributionPoints from "./CRLDistributionPoints.js"; +export { CRLDistributionPoints }; +import CertBag from "./CertBag.js"; +export { CertBag }; +import CertID from "./CertID.js"; +export { CertID }; +import Certificate from "./Certificate.js"; +export { Certificate }; +import CertificateChainValidationEngine from "./CertificateChainValidationEngine.js"; +export { CertificateChainValidationEngine }; +import CertificatePolicies from "./CertificatePolicies.js"; +export { CertificatePolicies }; +import CertificateRevocationList from "./CertificateRevocationList.js"; +export { CertificateRevocationList }; +import CertificateSet from "./CertificateSet.js"; +export { CertificateSet }; +import CertificationRequest from "./CertificationRequest.js"; +export { CertificationRequest }; +import ContentInfo from "./ContentInfo.js"; +export { ContentInfo }; +import CryptoEngine from "./CryptoEngine.js"; +export { CryptoEngine }; +import DigestInfo from "./DigestInfo.js"; +export { DigestInfo }; +import DistributionPoint from "./DistributionPoint.js"; +export { DistributionPoint }; +import ECCCMSSharedInfo from "./ECCCMSSharedInfo.js"; +export { ECCCMSSharedInfo }; +import ECPrivateKey from "./ECPrivateKey.js"; +export { ECPrivateKey }; +import ECPublicKey from "./ECPublicKey.js"; +export { ECPublicKey }; +import EncapsulatedContentInfo from "./EncapsulatedContentInfo.js"; +export { EncapsulatedContentInfo }; +import EncryptedContentInfo from "./EncryptedContentInfo.js"; +export { EncryptedContentInfo }; +import EncryptedData from "./EncryptedData.js"; +export { EncryptedData }; +import EnvelopedData from "./EnvelopedData.js"; +export { EnvelopedData }; +import ExtKeyUsage from "./ExtKeyUsage.js"; +export { ExtKeyUsage }; +import Extension from "./Extension.js"; +export { Extension }; +import Extensions from "./Extensions.js"; +export { Extensions }; +import GeneralName from "./GeneralName.js"; +export { GeneralName }; +import GeneralNames from "./GeneralNames.js"; +export { GeneralNames }; +import GeneralSubtree from "./GeneralSubtree.js"; +export { GeneralSubtree }; +import InfoAccess from "./InfoAccess.js"; +export { InfoAccess }; +import IssuerAndSerialNumber from "./IssuerAndSerialNumber.js"; +export { IssuerAndSerialNumber }; +import IssuingDistributionPoint from "./IssuingDistributionPoint.js"; +export { IssuingDistributionPoint }; +import KEKIdentifier from "./KEKIdentifier.js"; +export { KEKIdentifier }; +import KEKRecipientInfo from "./KEKRecipientInfo.js"; +export { KEKRecipientInfo }; +import KeyAgreeRecipientIdentifier from "./KeyAgreeRecipientIdentifier.js"; +export { KeyAgreeRecipientIdentifier }; +import KeyAgreeRecipientInfo from "./KeyAgreeRecipientInfo.js"; +export { KeyAgreeRecipientInfo }; +import KeyBag from "./KeyBag.js"; +export { KeyBag }; +import KeyTransRecipientInfo from "./KeyTransRecipientInfo.js"; +export { KeyTransRecipientInfo }; +import MacData from "./MacData.js"; +export { MacData }; +import MessageImprint from "./MessageImprint.js"; +export { MessageImprint }; +import NameConstraints from "./NameConstraints.js"; +export { NameConstraints }; +import OCSPRequest from "./OCSPRequest.js"; +export { OCSPRequest }; +import OCSPResponse from "./OCSPResponse.js"; +export { OCSPResponse }; +import OriginatorIdentifierOrKey from "./OriginatorIdentifierOrKey.js"; +export { OriginatorIdentifierOrKey }; +import OriginatorInfo from "./OriginatorInfo.js"; +export { OriginatorInfo }; +import OriginatorPublicKey from "./OriginatorPublicKey.js"; +export { OriginatorPublicKey }; +import OtherCertificateFormat from "./OtherCertificateFormat.js"; +export { OtherCertificateFormat }; +import OtherKeyAttribute from "./OtherKeyAttribute.js"; +export { OtherKeyAttribute }; +import OtherPrimeInfo from "./OtherPrimeInfo.js"; +export { OtherPrimeInfo }; +import OtherRecipientInfo from "./OtherRecipientInfo.js"; +export { OtherRecipientInfo }; +import OtherRevocationInfoFormat from "./OtherRevocationInfoFormat.js"; +export { OtherRevocationInfoFormat }; +import PBES2Params from "./PBES2Params.js"; +export { PBES2Params }; +import PBKDF2Params from "./PBKDF2Params.js"; +export { PBKDF2Params }; +import PFX from "./PFX.js"; +export { PFX }; +import PKCS8ShroudedKeyBag from "./PKCS8ShroudedKeyBag.js"; +export { PKCS8ShroudedKeyBag }; +import PKIStatusInfo from "./PKIStatusInfo.js"; +export { PKIStatusInfo }; +import PasswordRecipientinfo from "./PasswordRecipientinfo.js"; +export { PasswordRecipientinfo }; +import PolicyConstraints from "./PolicyConstraints.js"; +export { PolicyConstraints }; +import PolicyInformation from "./PolicyInformation.js"; +export { PolicyInformation }; +import PolicyMapping from "./PolicyMapping.js"; +export { PolicyMapping }; +import PolicyMappings from "./PolicyMappings.js"; +export { PolicyMappings }; +import PolicyQualifierInfo from "./PolicyQualifierInfo.js"; +export { PolicyQualifierInfo }; +import PrivateKeyInfo from "./PrivateKeyInfo.js"; +export { PrivateKeyInfo }; +import PrivateKeyUsagePeriod from "./PrivateKeyUsagePeriod.js"; +export { PrivateKeyUsagePeriod }; +import PublicKeyInfo from "./PublicKeyInfo.js"; +export { PublicKeyInfo }; +import RSAESOAEPParams from "./RSAESOAEPParams.js"; +export { RSAESOAEPParams }; +import RSAPrivateKey from "./RSAPrivateKey.js"; +export { RSAPrivateKey }; +import RSAPublicKey from "./RSAPublicKey.js"; +export { RSAPublicKey }; +import RSASSAPSSParams from "./RSASSAPSSParams.js"; +export { RSASSAPSSParams }; +import RecipientEncryptedKey from "./RecipientEncryptedKey.js"; +export { RecipientEncryptedKey }; +import RecipientEncryptedKeys from "./RecipientEncryptedKeys.js"; +export { RecipientEncryptedKeys }; +import RecipientIdentifier from "./RecipientIdentifier.js"; +export { RecipientIdentifier }; +import RecipientInfo from "./RecipientInfo.js"; +export { RecipientInfo }; +import RecipientKeyIdentifier from "./RecipientKeyIdentifier.js"; +export { RecipientKeyIdentifier }; +import RelativeDistinguishedNames from "./RelativeDistinguishedNames.js"; +export { RelativeDistinguishedNames }; +import Request from "./Request.js"; +export { Request }; +import ResponseBytes from "./ResponseBytes.js"; +export { ResponseBytes }; +import ResponseData from "./ResponseData.js"; +export { ResponseData }; +import RevocationInfoChoices from "./RevocationInfoChoices.js"; +export { RevocationInfoChoices }; +import RevokedCertificate from "./RevokedCertificate.js"; +export { RevokedCertificate }; +import SafeBag from "./SafeBag.js"; +export { SafeBag }; +import SafeContents from "./SafeContents.js"; +export { SafeContents }; +import SecretBag from "./SecretBag.js"; +export { SecretBag }; +import Signature from "./Signature.js"; +export { Signature }; +import SignedAndUnsignedAttributes from "./SignedAndUnsignedAttributes.js"; +export { SignedAndUnsignedAttributes }; +import SignedData from "./SignedData.js"; +export { SignedData }; +import SignerInfo from "./SignerInfo.js"; +export { SignerInfo }; +import SingleResponse from "./SingleResponse.js"; +export { SingleResponse }; +import SubjectDirectoryAttributes from "./SubjectDirectoryAttributes.js"; +export { SubjectDirectoryAttributes }; +import TBSRequest from "./TBSRequest.js"; +export { TBSRequest }; +import TSTInfo from "./TSTInfo.js"; +export { TSTInfo }; +import Time from "./Time.js"; +export { Time }; +import TimeStampReq from "./TimeStampReq.js"; +export { TimeStampReq }; +import TimeStampResp from "./TimeStampResp.js"; +export { TimeStampResp }; +import SignedCertificateTimestampList from "./SignedCertificateTimestampList.js"; +import { SignedCertificateTimestamp, verifySCTsForCertificate } from "./SignedCertificateTimestampList.js"; +export { SignedCertificateTimestampList, SignedCertificateTimestamp, verifySCTsForCertificate }; +import CertificateTemplate from "./CertificateTemplate.js"; +export { CertificateTemplate }; +import CAVersion from "./CAVersion.js"; +export { CAVersion }; +import { QCStatement }from "./QCStatements.js"; +import QCStatements from "./QCStatements.js"; +export { QCStatement, QCStatements }; diff --git a/core/third-party/pkijs/package.json b/core/third-party/pkijs/package.json new file mode 100644 index 0000000..96ae6e5 --- /dev/null +++ b/core/third-party/pkijs/package.json @@ -0,0 +1,3 @@ +{ + "type": "module" +} \ No newline at end of file diff --git a/core/third-party/pkijs/pvutils.js b/core/third-party/pkijs/pvutils.js new file mode 100644 index 0000000..6039d69 --- /dev/null +++ b/core/third-party/pkijs/pvutils.js @@ -0,0 +1,690 @@ +//************************************************************************************** +/** + * Making UTC date from local date + * @param {Date} date Date to convert from + * @returns {Date} + */ +export function getUTCDate(date) +{ + // noinspection NestedFunctionCallJS, MagicNumberJS + return new Date(date.getTime() + (date.getTimezoneOffset() * 60000)); +} +//************************************************************************************** +// noinspection FunctionWithMultipleReturnPointsJS +/** + * Get value for input parameters, or set a default value + * @param {Object} parameters + * @param {string} name + * @param defaultValue + */ +export function getParametersValue(parameters, name, defaultValue) +{ + // noinspection ConstantOnRightSideOfComparisonJS, NonBlockStatementBodyJS + if((parameters instanceof Object) === false) + return defaultValue; + + // noinspection NonBlockStatementBodyJS + if(name in parameters) + return parameters[name]; + + return defaultValue; +} +//************************************************************************************** +/** + * Converts "ArrayBuffer" into a hexdecimal string + * @param {ArrayBuffer} inputBuffer + * @param {number} [inputOffset=0] + * @param {number} [inputLength=inputBuffer.byteLength] + * @param {boolean} [insertSpace=false] + * @returns {string} + */ +export function bufferToHexCodes(inputBuffer, inputOffset = 0, inputLength = (inputBuffer.byteLength - inputOffset), insertSpace = false) +{ + let result = ""; + + for(const item of (new Uint8Array(inputBuffer, inputOffset, inputLength))) + { + // noinspection ChainedFunctionCallJS + const str = item.toString(16).toUpperCase(); + + // noinspection ConstantOnRightSideOfComparisonJS, NonBlockStatementBodyJS + if(str.length === 1) + result += "0"; + + result += str; + + // noinspection NonBlockStatementBodyJS + if(insertSpace) + result += " "; + } + + return result.trim(); +} +//************************************************************************************** +// noinspection JSValidateJSDoc, FunctionWithMultipleReturnPointsJS +/** + * Check input "ArrayBuffer" for common functions + * @param {LocalBaseBlock} baseBlock + * @param {ArrayBuffer} inputBuffer + * @param {number} inputOffset + * @param {number} inputLength + * @returns {boolean} + */ +export function checkBufferParams(baseBlock, inputBuffer, inputOffset, inputLength) +{ + // noinspection ConstantOnRightSideOfComparisonJS + if((inputBuffer instanceof ArrayBuffer) === false) + { + // noinspection JSUndefinedPropertyAssignment + baseBlock.error = "Wrong parameter: inputBuffer must be \"ArrayBuffer\""; + return false; + } + + // noinspection ConstantOnRightSideOfComparisonJS + if(inputBuffer.byteLength === 0) + { + // noinspection JSUndefinedPropertyAssignment + baseBlock.error = "Wrong parameter: inputBuffer has zero length"; + return false; + } + + // noinspection ConstantOnRightSideOfComparisonJS + if(inputOffset < 0) + { + // noinspection JSUndefinedPropertyAssignment + baseBlock.error = "Wrong parameter: inputOffset less than zero"; + return false; + } + + // noinspection ConstantOnRightSideOfComparisonJS + if(inputLength < 0) + { + // noinspection JSUndefinedPropertyAssignment + baseBlock.error = "Wrong parameter: inputLength less than zero"; + return false; + } + + // noinspection ConstantOnRightSideOfComparisonJS + if((inputBuffer.byteLength - inputOffset - inputLength) < 0) + { + // noinspection JSUndefinedPropertyAssignment + baseBlock.error = "End of input reached before message was fully decoded (inconsistent offset and length values)"; + return false; + } + + return true; +} +//************************************************************************************** +// noinspection FunctionWithMultipleReturnPointsJS +/** + * Convert number from 2^base to 2^10 + * @param {Uint8Array} inputBuffer + * @param {number} inputBase + * @returns {number} + */ +export function utilFromBase(inputBuffer, inputBase) +{ + let result = 0; + + // noinspection ConstantOnRightSideOfComparisonJS, NonBlockStatementBodyJS + if(inputBuffer.length === 1) + return inputBuffer[0]; + + // noinspection ConstantOnRightSideOfComparisonJS, NonBlockStatementBodyJS + for(let i = (inputBuffer.length - 1); i >= 0; i--) + result += inputBuffer[(inputBuffer.length - 1) - i] * Math.pow(2, inputBase * i); + + return result; +} +//************************************************************************************** +// noinspection FunctionWithMultipleLoopsJS, FunctionWithMultipleReturnPointsJS +/** + * Convert number from 2^10 to 2^base + * @param {!number} value The number to convert + * @param {!number} base The base for 2^base + * @param {number} [reserved=0] Pre-defined number of bytes in output array (-1 = limited by function itself) + * @returns {ArrayBuffer} + */ +export function utilToBase(value, base, reserved = (-1)) +{ + const internalReserved = reserved; + let internalValue = value; + + let result = 0; + let biggest = Math.pow(2, base); + + // noinspection ConstantOnRightSideOfComparisonJS + for(let i = 1; i < 8; i++) + { + if(value < biggest) + { + let retBuf; + + // noinspection ConstantOnRightSideOfComparisonJS + if(internalReserved < 0) + { + retBuf = new ArrayBuffer(i); + result = i; + } + else + { + // noinspection NonBlockStatementBodyJS + if(internalReserved < i) + return (new ArrayBuffer(0)); + + retBuf = new ArrayBuffer(internalReserved); + + result = internalReserved; + } + + const retView = new Uint8Array(retBuf); + + // noinspection ConstantOnRightSideOfComparisonJS + for(let j = (i - 1); j >= 0; j--) + { + const basis = Math.pow(2, j * base); + + retView[result - j - 1] = Math.floor(internalValue / basis); + internalValue -= (retView[result - j - 1]) * basis; + } + + return retBuf; + } + + biggest *= Math.pow(2, base); + } + + return new ArrayBuffer(0); +} +//************************************************************************************** +// noinspection FunctionWithMultipleLoopsJS +/** + * Concatenate two ArrayBuffers + * @param {...ArrayBuffer} buffers Set of ArrayBuffer + */ +export function utilConcatBuf(...buffers) +{ + //region Initial variables + let outputLength = 0; + let prevLength = 0; + //endregion + + //region Calculate output length + + // noinspection NonBlockStatementBodyJS + for(const buffer of buffers) + outputLength += buffer.byteLength; + //endregion + + const retBuf = new ArrayBuffer(outputLength); + const retView = new Uint8Array(retBuf); + + for(const buffer of buffers) + { + // noinspection NestedFunctionCallJS + retView.set(new Uint8Array(buffer), prevLength); + prevLength += buffer.byteLength; + } + + return retBuf; +} +//************************************************************************************** +// noinspection FunctionWithMultipleLoopsJS +/** + * Concatenate two Uint8Array + * @param {...Uint8Array} views Set of Uint8Array + */ +export function utilConcatView(...views) +{ + //region Initial variables + let outputLength = 0; + let prevLength = 0; + //endregion + + //region Calculate output length + // noinspection NonBlockStatementBodyJS + for(const view of views) + outputLength += view.length; + //endregion + + const retBuf = new ArrayBuffer(outputLength); + const retView = new Uint8Array(retBuf); + + for(const view of views) + { + retView.set(view, prevLength); + prevLength += view.length; + } + + return retView; +} +//************************************************************************************** +// noinspection FunctionWithMultipleLoopsJS +/** + * Decoding of "two complement" values + * The function must be called in scope of instance of "hexBlock" class ("valueHex" and "warnings" properties must be present) + * @returns {number} + */ +export function utilDecodeTC() +{ + const buf = new Uint8Array(this.valueHex); + + // noinspection ConstantOnRightSideOfComparisonJS + if(this.valueHex.byteLength >= 2) + { + //noinspection JSBitwiseOperatorUsage, ConstantOnRightSideOfComparisonJS, LocalVariableNamingConventionJS, MagicNumberJS, NonShortCircuitBooleanExpressionJS + const condition1 = (buf[0] === 0xFF) && (buf[1] & 0x80); + // noinspection ConstantOnRightSideOfComparisonJS, LocalVariableNamingConventionJS, MagicNumberJS, NonShortCircuitBooleanExpressionJS + const condition2 = (buf[0] === 0x00) && ((buf[1] & 0x80) === 0x00); + + // noinspection NonBlockStatementBodyJS + if(condition1 || condition2) + this.warnings.push("Needlessly long format"); + } + + //region Create big part of the integer + const bigIntBuffer = new ArrayBuffer(this.valueHex.byteLength); + const bigIntView = new Uint8Array(bigIntBuffer); + // noinspection NonBlockStatementBodyJS + for(let i = 0; i < this.valueHex.byteLength; i++) + bigIntView[i] = 0; + + // noinspection MagicNumberJS, NonShortCircuitBooleanExpressionJS + bigIntView[0] = (buf[0] & 0x80); // mask only the biggest bit + + const bigInt = utilFromBase(bigIntView, 8); + //endregion + + //region Create small part of the integer + const smallIntBuffer = new ArrayBuffer(this.valueHex.byteLength); + const smallIntView = new Uint8Array(smallIntBuffer); + // noinspection NonBlockStatementBodyJS + for(let j = 0; j < this.valueHex.byteLength; j++) + smallIntView[j] = buf[j]; + + // noinspection MagicNumberJS + smallIntView[0] &= 0x7F; // mask biggest bit + + const smallInt = utilFromBase(smallIntView, 8); + //endregion + + return (smallInt - bigInt); +} +//************************************************************************************** +// noinspection FunctionWithMultipleLoopsJS, FunctionWithMultipleReturnPointsJS +/** + * Encode integer value to "two complement" format + * @param {number} value Value to encode + * @returns {ArrayBuffer} + */ +export function utilEncodeTC(value) +{ + // noinspection ConstantOnRightSideOfComparisonJS, ConditionalExpressionJS + const modValue = (value < 0) ? (value * (-1)) : value; + let bigInt = 128; + + // noinspection ConstantOnRightSideOfComparisonJS + for(let i = 1; i < 8; i++) + { + if(modValue <= bigInt) + { + // noinspection ConstantOnRightSideOfComparisonJS + if(value < 0) + { + const smallInt = bigInt - modValue; + + const retBuf = utilToBase(smallInt, 8, i); + const retView = new Uint8Array(retBuf); + + // noinspection MagicNumberJS + retView[0] |= 0x80; + + return retBuf; + } + + let retBuf = utilToBase(modValue, 8, i); + let retView = new Uint8Array(retBuf); + + //noinspection JSBitwiseOperatorUsage, MagicNumberJS, NonShortCircuitBooleanExpressionJS + if(retView[0] & 0x80) + { + //noinspection JSCheckFunctionSignatures + const tempBuf = retBuf.slice(0); + const tempView = new Uint8Array(tempBuf); + + retBuf = new ArrayBuffer(retBuf.byteLength + 1); + // noinspection ReuseOfLocalVariableJS + retView = new Uint8Array(retBuf); + + // noinspection NonBlockStatementBodyJS + for(let k = 0; k < tempBuf.byteLength; k++) + retView[k + 1] = tempView[k]; + + // noinspection MagicNumberJS + retView[0] = 0x00; + } + + return retBuf; + } + + bigInt *= Math.pow(2, 8); + } + + return (new ArrayBuffer(0)); +} +//************************************************************************************** +// noinspection FunctionWithMultipleReturnPointsJS, ParameterNamingConventionJS +/** + * Compare two array buffers + * @param {!ArrayBuffer} inputBuffer1 + * @param {!ArrayBuffer} inputBuffer2 + * @returns {boolean} + */ +export function isEqualBuffer(inputBuffer1, inputBuffer2) +{ + // noinspection NonBlockStatementBodyJS + if(inputBuffer1.byteLength !== inputBuffer2.byteLength) + return false; + + // noinspection LocalVariableNamingConventionJS + const view1 = new Uint8Array(inputBuffer1); + // noinspection LocalVariableNamingConventionJS + const view2 = new Uint8Array(inputBuffer2); + + for(let i = 0; i < view1.length; i++) + { + // noinspection NonBlockStatementBodyJS + if(view1[i] !== view2[i]) + return false; + } + + return true; +} +//************************************************************************************** +// noinspection FunctionWithMultipleReturnPointsJS +/** + * Pad input number with leade "0" if needed + * @returns {string} + * @param {number} inputNumber + * @param {number} fullLength + */ +export function padNumber(inputNumber, fullLength) +{ + const str = inputNumber.toString(10); + + // noinspection NonBlockStatementBodyJS + if(fullLength < str.length) + return ""; + + const dif = fullLength - str.length; + + const padding = new Array(dif); + // noinspection NonBlockStatementBodyJS + for(let i = 0; i < dif; i++) + padding[i] = "0"; + + const paddingString = padding.join(""); + + return paddingString.concat(str); +} +//************************************************************************************** +const base64Template = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="; +const base64UrlTemplate = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_="; +//************************************************************************************** +// noinspection FunctionWithMultipleLoopsJS, OverlyComplexFunctionJS, FunctionTooLongJS, FunctionNamingConventionJS +/** + * Encode string into BASE64 (or "base64url") + * @param {string} input + * @param {boolean} useUrlTemplate If "true" then output would be encoded using "base64url" + * @param {boolean} skipPadding Skip BASE-64 padding or not + * @param {boolean} skipLeadingZeros Skip leading zeros in input data or not + * @returns {string} + */ +export function toBase64(input, useUrlTemplate = false, skipPadding = false, skipLeadingZeros = false) +{ + let i = 0; + + // noinspection LocalVariableNamingConventionJS + let flag1 = 0; + // noinspection LocalVariableNamingConventionJS + let flag2 = 0; + + let output = ""; + + // noinspection ConditionalExpressionJS + const template = (useUrlTemplate) ? base64UrlTemplate : base64Template; + + if(skipLeadingZeros) + { + let nonZeroPosition = 0; + + for(let i = 0; i < input.length; i++) + { + // noinspection ConstantOnRightSideOfComparisonJS + if(input.charCodeAt(i) !== 0) + { + nonZeroPosition = i; + // noinspection BreakStatementJS + break; + } + } + + // noinspection AssignmentToFunctionParameterJS + input = input.slice(nonZeroPosition); + } + + while(i < input.length) + { + // noinspection LocalVariableNamingConventionJS, IncrementDecrementResultUsedJS + const chr1 = input.charCodeAt(i++); + // noinspection NonBlockStatementBodyJS + if(i >= input.length) + flag1 = 1; + // noinspection LocalVariableNamingConventionJS, IncrementDecrementResultUsedJS + const chr2 = input.charCodeAt(i++); + // noinspection NonBlockStatementBodyJS + if(i >= input.length) + flag2 = 1; + // noinspection LocalVariableNamingConventionJS, IncrementDecrementResultUsedJS + const chr3 = input.charCodeAt(i++); + + // noinspection LocalVariableNamingConventionJS + const enc1 = chr1 >> 2; + // noinspection LocalVariableNamingConventionJS, MagicNumberJS, NonShortCircuitBooleanExpressionJS + const enc2 = ((chr1 & 0x03) << 4) | (chr2 >> 4); + // noinspection LocalVariableNamingConventionJS, MagicNumberJS, NonShortCircuitBooleanExpressionJS + let enc3 = ((chr2 & 0x0F) << 2) | (chr3 >> 6); + // noinspection LocalVariableNamingConventionJS, MagicNumberJS, NonShortCircuitBooleanExpressionJS + let enc4 = chr3 & 0x3F; + + // noinspection ConstantOnRightSideOfComparisonJS + if(flag1 === 1) + { + // noinspection NestedAssignmentJS, AssignmentResultUsedJS, MagicNumberJS + enc3 = enc4 = 64; + } + else + { + // noinspection ConstantOnRightSideOfComparisonJS + if(flag2 === 1) + { + // noinspection MagicNumberJS + enc4 = 64; + } + } + + // noinspection NonBlockStatementBodyJS + if(skipPadding) + { + // noinspection ConstantOnRightSideOfComparisonJS, NonBlockStatementBodyJS, MagicNumberJS + if(enc3 === 64) + output += `${template.charAt(enc1)}${template.charAt(enc2)}`; + else + { + // noinspection ConstantOnRightSideOfComparisonJS, NonBlockStatementBodyJS, MagicNumberJS + if(enc4 === 64) + output += `${template.charAt(enc1)}${template.charAt(enc2)}${template.charAt(enc3)}`; + else + output += `${template.charAt(enc1)}${template.charAt(enc2)}${template.charAt(enc3)}${template.charAt(enc4)}`; + } + } + else + output += `${template.charAt(enc1)}${template.charAt(enc2)}${template.charAt(enc3)}${template.charAt(enc4)}`; + } + + return output; +} +//************************************************************************************** +// noinspection FunctionWithMoreThanThreeNegationsJS, FunctionWithMultipleLoopsJS, OverlyComplexFunctionJS, FunctionNamingConventionJS +/** + * Decode string from BASE64 (or "base64url") + * @param {string} input + * @param {boolean} [useUrlTemplate=false] If "true" then output would be encoded using "base64url" + * @param {boolean} [cutTailZeros=false] If "true" then cut tailing zeroz from function result + * @returns {string} + */ +export function fromBase64(input, useUrlTemplate = false, cutTailZeros = false) +{ + // noinspection ConditionalExpressionJS + const template = (useUrlTemplate) ? base64UrlTemplate : base64Template; + + //region Aux functions + // noinspection FunctionWithMultipleReturnPointsJS, NestedFunctionJS + function indexof(toSearch) + { + // noinspection ConstantOnRightSideOfComparisonJS, MagicNumberJS + for(let i = 0; i < 64; i++) + { + // noinspection NonBlockStatementBodyJS + if(template.charAt(i) === toSearch) + return i; + } + + // noinspection MagicNumberJS + return 64; + } + + // noinspection NestedFunctionJS + function test(incoming) + { + // noinspection ConstantOnRightSideOfComparisonJS, ConditionalExpressionJS, MagicNumberJS + return ((incoming === 64) ? 0x00 : incoming); + } + //endregion + + let i = 0; + + let output = ""; + + while(i < input.length) + { + // noinspection NestedFunctionCallJS, LocalVariableNamingConventionJS, IncrementDecrementResultUsedJS + const enc1 = indexof(input.charAt(i++)); + // noinspection NestedFunctionCallJS, LocalVariableNamingConventionJS, ConditionalExpressionJS, MagicNumberJS, IncrementDecrementResultUsedJS + const enc2 = (i >= input.length) ? 0x00 : indexof(input.charAt(i++)); + // noinspection NestedFunctionCallJS, LocalVariableNamingConventionJS, ConditionalExpressionJS, MagicNumberJS, IncrementDecrementResultUsedJS + const enc3 = (i >= input.length) ? 0x00 : indexof(input.charAt(i++)); + // noinspection NestedFunctionCallJS, LocalVariableNamingConventionJS, ConditionalExpressionJS, MagicNumberJS, IncrementDecrementResultUsedJS + const enc4 = (i >= input.length) ? 0x00 : indexof(input.charAt(i++)); + + // noinspection LocalVariableNamingConventionJS, NonShortCircuitBooleanExpressionJS + const chr1 = (test(enc1) << 2) | (test(enc2) >> 4); + // noinspection LocalVariableNamingConventionJS, MagicNumberJS, NonShortCircuitBooleanExpressionJS + const chr2 = ((test(enc2) & 0x0F) << 4) | (test(enc3) >> 2); + // noinspection LocalVariableNamingConventionJS, MagicNumberJS, NonShortCircuitBooleanExpressionJS + const chr3 = ((test(enc3) & 0x03) << 6) | test(enc4); + + output += String.fromCharCode(chr1); + + // noinspection ConstantOnRightSideOfComparisonJS, NonBlockStatementBodyJS, MagicNumberJS + if(enc3 !== 64) + output += String.fromCharCode(chr2); + + // noinspection ConstantOnRightSideOfComparisonJS, NonBlockStatementBodyJS, MagicNumberJS + if(enc4 !== 64) + output += String.fromCharCode(chr3); + } + + if(cutTailZeros) + { + const outputLength = output.length; + let nonZeroStart = (-1); + + // noinspection ConstantOnRightSideOfComparisonJS + for(let i = (outputLength - 1); i >= 0; i--) + { + // noinspection ConstantOnRightSideOfComparisonJS + if(output.charCodeAt(i) !== 0) + { + nonZeroStart = i; + // noinspection BreakStatementJS + break; + } + } + + // noinspection NonBlockStatementBodyJS, NegatedIfStatementJS + if(nonZeroStart !== (-1)) + output = output.slice(0, nonZeroStart + 1); + else + output = ""; + } + + return output; +} +//************************************************************************************** +export function arrayBufferToString(buffer) +{ + let resultString = ""; + const view = new Uint8Array(buffer); + + // noinspection NonBlockStatementBodyJS + for(const element of view) + resultString += String.fromCharCode(element); + + return resultString; +} +//************************************************************************************** +export function stringToArrayBuffer(str) +{ + const stringLength = str.length; + + const resultBuffer = new ArrayBuffer(stringLength); + const resultView = new Uint8Array(resultBuffer); + + // noinspection NonBlockStatementBodyJS + for(let i = 0; i < stringLength; i++) + resultView[i] = str.charCodeAt(i); + + return resultBuffer; +} +//************************************************************************************** +const log2 = Math.log(2); +//************************************************************************************** +// noinspection FunctionNamingConventionJS +/** + * Get nearest to input length power of 2 + * @param {number} length Current length of existing array + * @returns {number} + */ +export function nearestPowerOf2(length) +{ + const base = (Math.log(length) / log2); + + const floor = Math.floor(base); + const round = Math.round(base); + + // noinspection ConditionalExpressionJS + return ((floor === round) ? floor : round); +} +//************************************************************************************** +/** + * Delete properties by name from specified object + * @param {Object} object Object to delete properties from + * @param {Array.} propsArray Array of properties names + */ +export function clearProps(object, propsArray) +{ + for(const prop of propsArray) + delete object[prop]; +} +//************************************************************************************** diff --git a/core/third-party/simple-js-ec-math.js b/core/third-party/simple-js-ec-math.js new file mode 100644 index 0000000..0b3ced2 --- /dev/null +++ b/core/third-party/simple-js-ec-math.js @@ -0,0 +1,26877 @@ +(function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.ECSimple = f()}})(function(){var define,module,exports;return (function(){function r(e,n,t){function o(i,f){if(!n[i]){if(!e[i]){var c="function"==typeof require&&require;if(!f&&c)return c(i,!0);if(u)return u(i,!0);var a=new Error("Cannot find module '"+i+"'");throw a.code="MODULE_NOT_FOUND",a}var p=n[i]={exports:{}};e[i][0].call(p.exports,function(r){var n=e[i][1][r];return o(n||r)},p,p.exports,r,e,n,t)}return n[i].exports}for(var u="function"==typeof require&&require,i=0;i> 6]; + const primitive = (tag & 0x20) === 0; + + // Multi-octet tag - load + if ((tag & 0x1f) === 0x1f) { + let oct = tag; + tag = 0; + while ((oct & 0x80) === 0x80) { + oct = buf.readUInt8(fail); + if (buf.isError(oct)) + return oct; + + tag <<= 7; + tag |= oct & 0x7f; + } + } else { + tag &= 0x1f; + } + const tagStr = der.tag[tag]; + + return { + cls: cls, + primitive: primitive, + tag: tag, + tagStr: tagStr + }; +} + +function derDecodeLen(buf, primitive, fail) { + let len = buf.readUInt8(fail); + if (buf.isError(len)) + return len; + + // Indefinite form + if (!primitive && len === 0x80) + return null; + + // Definite form + if ((len & 0x80) === 0) { + // Short form + return len; + } + + // Long form + const num = len & 0x7f; + if (num > 4) + return buf.error('length octect is too long'); + + len = 0; + for (let i = 0; i < num; i++) { + len <<= 8; + const j = buf.readUInt8(fail); + if (buf.isError(j)) + return j; + len |= j; + } + + return len; +} + +},{"../base/buffer":3,"../base/node":5,"../constants/der":7,"bn.js":15,"inherits":132}],10:[function(require,module,exports){ +'use strict'; + +const decoders = exports; + +decoders.der = require('./der'); +decoders.pem = require('./pem'); + +},{"./der":9,"./pem":11}],11:[function(require,module,exports){ +'use strict'; + +const inherits = require('inherits'); +const Buffer = require('safer-buffer').Buffer; + +const DERDecoder = require('./der'); + +function PEMDecoder(entity) { + DERDecoder.call(this, entity); + this.enc = 'pem'; +} +inherits(PEMDecoder, DERDecoder); +module.exports = PEMDecoder; + +PEMDecoder.prototype.decode = function decode(data, options) { + const lines = data.toString().split(/[\r\n]+/g); + + const label = options.label.toUpperCase(); + + const re = /^-----(BEGIN|END) ([^-]+)-----$/; + let start = -1; + let end = -1; + for (let i = 0; i < lines.length; i++) { + const match = lines[i].match(re); + if (match === null) + continue; + + if (match[2] !== label) + continue; + + if (start === -1) { + if (match[1] !== 'BEGIN') + break; + start = i; + } else { + if (match[1] !== 'END') + break; + end = i; + break; + } + } + if (start === -1 || end === -1) + throw new Error('PEM section not found for: ' + label); + + const base64 = lines.slice(start + 1, end).join(''); + // Remove excessive symbols + base64.replace(/[^a-z0-9+/=]+/gi, ''); + + const input = Buffer.from(base64, 'base64'); + return DERDecoder.prototype.decode.call(this, input, options); +}; + +},{"./der":9,"inherits":132,"safer-buffer":161}],12:[function(require,module,exports){ +'use strict'; + +const inherits = require('inherits'); +const Buffer = require('safer-buffer').Buffer; +const Node = require('../base/node'); + +// Import DER constants +const der = require('../constants/der'); + +function DEREncoder(entity) { + this.enc = 'der'; + this.name = entity.name; + this.entity = entity; + + // Construct base tree + this.tree = new DERNode(); + this.tree._init(entity.body); +} +module.exports = DEREncoder; + +DEREncoder.prototype.encode = function encode(data, reporter) { + return this.tree._encode(data, reporter).join(); +}; + +// Tree methods + +function DERNode(parent) { + Node.call(this, 'der', parent); +} +inherits(DERNode, Node); + +DERNode.prototype._encodeComposite = function encodeComposite(tag, + primitive, + cls, + content) { + const encodedTag = encodeTag(tag, primitive, cls, this.reporter); + + // Short form + if (content.length < 0x80) { + const header = Buffer.alloc(2); + header[0] = encodedTag; + header[1] = content.length; + return this._createEncoderBuffer([ header, content ]); + } + + // Long form + // Count octets required to store length + let lenOctets = 1; + for (let i = content.length; i >= 0x100; i >>= 8) + lenOctets++; + + const header = Buffer.alloc(1 + 1 + lenOctets); + header[0] = encodedTag; + header[1] = 0x80 | lenOctets; + + for (let i = 1 + lenOctets, j = content.length; j > 0; i--, j >>= 8) + header[i] = j & 0xff; + + return this._createEncoderBuffer([ header, content ]); +}; + +DERNode.prototype._encodeStr = function encodeStr(str, tag) { + if (tag === 'bitstr') { + return this._createEncoderBuffer([ str.unused | 0, str.data ]); + } else if (tag === 'bmpstr') { + const buf = Buffer.alloc(str.length * 2); + for (let i = 0; i < str.length; i++) { + buf.writeUInt16BE(str.charCodeAt(i), i * 2); + } + return this._createEncoderBuffer(buf); + } else if (tag === 'numstr') { + if (!this._isNumstr(str)) { + return this.reporter.error('Encoding of string type: numstr supports ' + + 'only digits and space'); + } + return this._createEncoderBuffer(str); + } else if (tag === 'printstr') { + if (!this._isPrintstr(str)) { + return this.reporter.error('Encoding of string type: printstr supports ' + + 'only latin upper and lower case letters, ' + + 'digits, space, apostrophe, left and rigth ' + + 'parenthesis, plus sign, comma, hyphen, ' + + 'dot, slash, colon, equal sign, ' + + 'question mark'); + } + return this._createEncoderBuffer(str); + } else if (/str$/.test(tag)) { + return this._createEncoderBuffer(str); + } else if (tag === 'objDesc') { + return this._createEncoderBuffer(str); + } else { + return this.reporter.error('Encoding of string type: ' + tag + + ' unsupported'); + } +}; + +DERNode.prototype._encodeObjid = function encodeObjid(id, values, relative) { + if (typeof id === 'string') { + if (!values) + return this.reporter.error('string objid given, but no values map found'); + if (!values.hasOwnProperty(id)) + return this.reporter.error('objid not found in values map'); + id = values[id].split(/[\s.]+/g); + for (let i = 0; i < id.length; i++) + id[i] |= 0; + } else if (Array.isArray(id)) { + id = id.slice(); + for (let i = 0; i < id.length; i++) + id[i] |= 0; + } + + if (!Array.isArray(id)) { + return this.reporter.error('objid() should be either array or string, ' + + 'got: ' + JSON.stringify(id)); + } + + if (!relative) { + if (id[1] >= 40) + return this.reporter.error('Second objid identifier OOB'); + id.splice(0, 2, id[0] * 40 + id[1]); + } + + // Count number of octets + let size = 0; + for (let i = 0; i < id.length; i++) { + let ident = id[i]; + for (size++; ident >= 0x80; ident >>= 7) + size++; + } + + const objid = Buffer.alloc(size); + let offset = objid.length - 1; + for (let i = id.length - 1; i >= 0; i--) { + let ident = id[i]; + objid[offset--] = ident & 0x7f; + while ((ident >>= 7) > 0) + objid[offset--] = 0x80 | (ident & 0x7f); + } + + return this._createEncoderBuffer(objid); +}; + +function two(num) { + if (num < 10) + return '0' + num; + else + return num; +} + +DERNode.prototype._encodeTime = function encodeTime(time, tag) { + let str; + const date = new Date(time); + + if (tag === 'gentime') { + str = [ + two(date.getUTCFullYear()), + two(date.getUTCMonth() + 1), + two(date.getUTCDate()), + two(date.getUTCHours()), + two(date.getUTCMinutes()), + two(date.getUTCSeconds()), + 'Z' + ].join(''); + } else if (tag === 'utctime') { + str = [ + two(date.getUTCFullYear() % 100), + two(date.getUTCMonth() + 1), + two(date.getUTCDate()), + two(date.getUTCHours()), + two(date.getUTCMinutes()), + two(date.getUTCSeconds()), + 'Z' + ].join(''); + } else { + this.reporter.error('Encoding ' + tag + ' time is not supported yet'); + } + + return this._encodeStr(str, 'octstr'); +}; + +DERNode.prototype._encodeNull = function encodeNull() { + return this._createEncoderBuffer(''); +}; + +DERNode.prototype._encodeInt = function encodeInt(num, values) { + if (typeof num === 'string') { + if (!values) + return this.reporter.error('String int or enum given, but no values map'); + if (!values.hasOwnProperty(num)) { + return this.reporter.error('Values map doesn\'t contain: ' + + JSON.stringify(num)); + } + num = values[num]; + } + + // Bignum, assume big endian + if (typeof num !== 'number' && !Buffer.isBuffer(num)) { + const numArray = num.toArray(); + if (!num.sign && numArray[0] & 0x80) { + numArray.unshift(0); + } + num = Buffer.from(numArray); + } + + if (Buffer.isBuffer(num)) { + let size = num.length; + if (num.length === 0) + size++; + + const out = Buffer.alloc(size); + num.copy(out); + if (num.length === 0) + out[0] = 0; + return this._createEncoderBuffer(out); + } + + if (num < 0x80) + return this._createEncoderBuffer(num); + + if (num < 0x100) + return this._createEncoderBuffer([0, num]); + + let size = 1; + for (let i = num; i >= 0x100; i >>= 8) + size++; + + const out = new Array(size); + for (let i = out.length - 1; i >= 0; i--) { + out[i] = num & 0xff; + num >>= 8; + } + if(out[0] & 0x80) { + out.unshift(0); + } + + return this._createEncoderBuffer(Buffer.from(out)); +}; + +DERNode.prototype._encodeBool = function encodeBool(value) { + return this._createEncoderBuffer(value ? 0xff : 0); +}; + +DERNode.prototype._use = function use(entity, obj) { + if (typeof entity === 'function') + entity = entity(obj); + return entity._getEncoder('der').tree; +}; + +DERNode.prototype._skipDefault = function skipDefault(dataBuffer, reporter, parent) { + const state = this._baseState; + let i; + if (state['default'] === null) + return false; + + const data = dataBuffer.join(); + if (state.defaultBuffer === undefined) + state.defaultBuffer = this._encodeValue(state['default'], reporter, parent).join(); + + if (data.length !== state.defaultBuffer.length) + return false; + + for (i=0; i < data.length; i++) + if (data[i] !== state.defaultBuffer[i]) + return false; + + return true; +}; + +// Utility methods + +function encodeTag(tag, primitive, cls, reporter) { + let res; + + if (tag === 'seqof') + tag = 'seq'; + else if (tag === 'setof') + tag = 'set'; + + if (der.tagByName.hasOwnProperty(tag)) + res = der.tagByName[tag]; + else if (typeof tag === 'number' && (tag | 0) === tag) + res = tag; + else + return reporter.error('Unknown tag: ' + tag); + + if (res >= 0x1f) + return reporter.error('Multi-octet tag encoding unsupported'); + + if (!primitive) + res |= 0x20; + + res |= (der.tagClassByName[cls || 'universal'] << 6); + + return res; +} + +},{"../base/node":5,"../constants/der":7,"inherits":132,"safer-buffer":161}],13:[function(require,module,exports){ +'use strict'; + +const encoders = exports; + +encoders.der = require('./der'); +encoders.pem = require('./pem'); + +},{"./der":12,"./pem":14}],14:[function(require,module,exports){ +'use strict'; + +const inherits = require('inherits'); + +const DEREncoder = require('./der'); + +function PEMEncoder(entity) { + DEREncoder.call(this, entity); + this.enc = 'pem'; +} +inherits(PEMEncoder, DEREncoder); +module.exports = PEMEncoder; + +PEMEncoder.prototype.encode = function encode(data, options) { + const buf = DEREncoder.prototype.encode.call(this, data); + + const p = buf.toString('base64'); + const out = [ '-----BEGIN ' + options.label + '-----' ]; + for (let i = 0; i < p.length; i += 64) + out.push(p.slice(i, i + 64)); + out.push('-----END ' + options.label + '-----'); + return out.join('\n'); +}; + +},{"./der":12,"inherits":132}],15:[function(require,module,exports){ +(function (module, exports) { + 'use strict'; + + // Utils + function assert (val, msg) { + if (!val) throw new Error(msg || 'Assertion failed'); + } + + // Could use `inherits` module, but don't want to move from single file + // architecture yet. + function inherits (ctor, superCtor) { + ctor.super_ = superCtor; + var TempCtor = function () {}; + TempCtor.prototype = superCtor.prototype; + ctor.prototype = new TempCtor(); + ctor.prototype.constructor = ctor; + } + + // BN + + function BN (number, base, endian) { + if (BN.isBN(number)) { + return number; + } + + this.negative = 0; + this.words = null; + this.length = 0; + + // Reduction context + this.red = null; + + if (number !== null) { + if (base === 'le' || base === 'be') { + endian = base; + base = 10; + } + + this._init(number || 0, base || 10, endian || 'be'); + } + } + if (typeof module === 'object') { + module.exports = BN; + } else { + exports.BN = BN; + } + + BN.BN = BN; + BN.wordSize = 26; + + var Buffer; + try { + if (typeof window !== 'undefined' && typeof window.Buffer !== 'undefined') { + Buffer = window.Buffer; + } else { + Buffer = require('buffer').Buffer; + } + } catch (e) { + } + + BN.isBN = function isBN (num) { + if (num instanceof BN) { + return true; + } + + return num !== null && typeof num === 'object' && + num.constructor.wordSize === BN.wordSize && Array.isArray(num.words); + }; + + BN.max = function max (left, right) { + if (left.cmp(right) > 0) return left; + return right; + }; + + BN.min = function min (left, right) { + if (left.cmp(right) < 0) return left; + return right; + }; + + BN.prototype._init = function init (number, base, endian) { + if (typeof number === 'number') { + return this._initNumber(number, base, endian); + } + + if (typeof number === 'object') { + return this._initArray(number, base, endian); + } + + if (base === 'hex') { + base = 16; + } + assert(base === (base | 0) && base >= 2 && base <= 36); + + number = number.toString().replace(/\s+/g, ''); + var start = 0; + if (number[0] === '-') { + start++; + this.negative = 1; + } + + if (start < number.length) { + if (base === 16) { + this._parseHex(number, start, endian); + } else { + this._parseBase(number, base, start); + if (endian === 'le') { + this._initArray(this.toArray(), base, endian); + } + } + } + }; + + BN.prototype._initNumber = function _initNumber (number, base, endian) { + if (number < 0) { + this.negative = 1; + number = -number; + } + if (number < 0x4000000) { + this.words = [ number & 0x3ffffff ]; + this.length = 1; + } else if (number < 0x10000000000000) { + this.words = [ + number & 0x3ffffff, + (number / 0x4000000) & 0x3ffffff + ]; + this.length = 2; + } else { + assert(number < 0x20000000000000); // 2 ^ 53 (unsafe) + this.words = [ + number & 0x3ffffff, + (number / 0x4000000) & 0x3ffffff, + 1 + ]; + this.length = 3; + } + + if (endian !== 'le') return; + + // Reverse the bytes + this._initArray(this.toArray(), base, endian); + }; + + BN.prototype._initArray = function _initArray (number, base, endian) { + // Perhaps a Uint8Array + assert(typeof number.length === 'number'); + if (number.length <= 0) { + this.words = [ 0 ]; + this.length = 1; + return this; + } + + this.length = Math.ceil(number.length / 3); + this.words = new Array(this.length); + for (var i = 0; i < this.length; i++) { + this.words[i] = 0; + } + + var j, w; + var off = 0; + if (endian === 'be') { + for (i = number.length - 1, j = 0; i >= 0; i -= 3) { + w = number[i] | (number[i - 1] << 8) | (number[i - 2] << 16); + this.words[j] |= (w << off) & 0x3ffffff; + this.words[j + 1] = (w >>> (26 - off)) & 0x3ffffff; + off += 24; + if (off >= 26) { + off -= 26; + j++; + } + } + } else if (endian === 'le') { + for (i = 0, j = 0; i < number.length; i += 3) { + w = number[i] | (number[i + 1] << 8) | (number[i + 2] << 16); + this.words[j] |= (w << off) & 0x3ffffff; + this.words[j + 1] = (w >>> (26 - off)) & 0x3ffffff; + off += 24; + if (off >= 26) { + off -= 26; + j++; + } + } + } + return this.strip(); + }; + + function parseHex4Bits (string, index) { + var c = string.charCodeAt(index); + // 'A' - 'F' + if (c >= 65 && c <= 70) { + return c - 55; + // 'a' - 'f' + } else if (c >= 97 && c <= 102) { + return c - 87; + // '0' - '9' + } else { + return (c - 48) & 0xf; + } + } + + function parseHexByte (string, lowerBound, index) { + var r = parseHex4Bits(string, index); + if (index - 1 >= lowerBound) { + r |= parseHex4Bits(string, index - 1) << 4; + } + return r; + } + + BN.prototype._parseHex = function _parseHex (number, start, endian) { + // Create possibly bigger array to ensure that it fits the number + this.length = Math.ceil((number.length - start) / 6); + this.words = new Array(this.length); + for (var i = 0; i < this.length; i++) { + this.words[i] = 0; + } + + // 24-bits chunks + var off = 0; + var j = 0; + + var w; + if (endian === 'be') { + for (i = number.length - 1; i >= start; i -= 2) { + w = parseHexByte(number, start, i) << off; + this.words[j] |= w & 0x3ffffff; + if (off >= 18) { + off -= 18; + j += 1; + this.words[j] |= w >>> 26; + } else { + off += 8; + } + } + } else { + var parseLength = number.length - start; + for (i = parseLength % 2 === 0 ? start + 1 : start; i < number.length; i += 2) { + w = parseHexByte(number, start, i) << off; + this.words[j] |= w & 0x3ffffff; + if (off >= 18) { + off -= 18; + j += 1; + this.words[j] |= w >>> 26; + } else { + off += 8; + } + } + } + + this.strip(); + }; + + function parseBase (str, start, end, mul) { + var r = 0; + var len = Math.min(str.length, end); + for (var i = start; i < len; i++) { + var c = str.charCodeAt(i) - 48; + + r *= mul; + + // 'a' + if (c >= 49) { + r += c - 49 + 0xa; + + // 'A' + } else if (c >= 17) { + r += c - 17 + 0xa; + + // '0' - '9' + } else { + r += c; + } + } + return r; + } + + BN.prototype._parseBase = function _parseBase (number, base, start) { + // Initialize as zero + this.words = [ 0 ]; + this.length = 1; + + // Find length of limb in base + for (var limbLen = 0, limbPow = 1; limbPow <= 0x3ffffff; limbPow *= base) { + limbLen++; + } + limbLen--; + limbPow = (limbPow / base) | 0; + + var total = number.length - start; + var mod = total % limbLen; + var end = Math.min(total, total - mod) + start; + + var word = 0; + for (var i = start; i < end; i += limbLen) { + word = parseBase(number, i, i + limbLen, base); + + this.imuln(limbPow); + if (this.words[0] + word < 0x4000000) { + this.words[0] += word; + } else { + this._iaddn(word); + } + } + + if (mod !== 0) { + var pow = 1; + word = parseBase(number, i, number.length, base); + + for (i = 0; i < mod; i++) { + pow *= base; + } + + this.imuln(pow); + if (this.words[0] + word < 0x4000000) { + this.words[0] += word; + } else { + this._iaddn(word); + } + } + + this.strip(); + }; + + BN.prototype.copy = function copy (dest) { + dest.words = new Array(this.length); + for (var i = 0; i < this.length; i++) { + dest.words[i] = this.words[i]; + } + dest.length = this.length; + dest.negative = this.negative; + dest.red = this.red; + }; + + BN.prototype.clone = function clone () { + var r = new BN(null); + this.copy(r); + return r; + }; + + BN.prototype._expand = function _expand (size) { + while (this.length < size) { + this.words[this.length++] = 0; + } + return this; + }; + + // Remove leading `0` from `this` + BN.prototype.strip = function strip () { + while (this.length > 1 && this.words[this.length - 1] === 0) { + this.length--; + } + return this._normSign(); + }; + + BN.prototype._normSign = function _normSign () { + // -0 = 0 + if (this.length === 1 && this.words[0] === 0) { + this.negative = 0; + } + return this; + }; + + BN.prototype.inspect = function inspect () { + return (this.red ? ''; + }; + + /* + + var zeros = []; + var groupSizes = []; + var groupBases = []; + + var s = ''; + var i = -1; + while (++i < BN.wordSize) { + zeros[i] = s; + s += '0'; + } + groupSizes[0] = 0; + groupSizes[1] = 0; + groupBases[0] = 0; + groupBases[1] = 0; + var base = 2 - 1; + while (++base < 36 + 1) { + var groupSize = 0; + var groupBase = 1; + while (groupBase < (1 << BN.wordSize) / base) { + groupBase *= base; + groupSize += 1; + } + groupSizes[base] = groupSize; + groupBases[base] = groupBase; + } + + */ + + var zeros = [ + '', + '0', + '00', + '000', + '0000', + '00000', + '000000', + '0000000', + '00000000', + '000000000', + '0000000000', + '00000000000', + '000000000000', + '0000000000000', + '00000000000000', + '000000000000000', + '0000000000000000', + '00000000000000000', + '000000000000000000', + '0000000000000000000', + '00000000000000000000', + '000000000000000000000', + '0000000000000000000000', + '00000000000000000000000', + '000000000000000000000000', + '0000000000000000000000000' + ]; + + var groupSizes = [ + 0, 0, + 25, 16, 12, 11, 10, 9, 8, + 8, 7, 7, 7, 7, 6, 6, + 6, 6, 6, 6, 6, 5, 5, + 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5 + ]; + + var groupBases = [ + 0, 0, + 33554432, 43046721, 16777216, 48828125, 60466176, 40353607, 16777216, + 43046721, 10000000, 19487171, 35831808, 62748517, 7529536, 11390625, + 16777216, 24137569, 34012224, 47045881, 64000000, 4084101, 5153632, + 6436343, 7962624, 9765625, 11881376, 14348907, 17210368, 20511149, + 24300000, 28629151, 33554432, 39135393, 45435424, 52521875, 60466176 + ]; + + BN.prototype.toString = function toString (base, padding) { + base = base || 10; + padding = padding | 0 || 1; + + var out; + if (base === 16 || base === 'hex') { + out = ''; + var off = 0; + var carry = 0; + for (var i = 0; i < this.length; i++) { + var w = this.words[i]; + var word = (((w << off) | carry) & 0xffffff).toString(16); + carry = (w >>> (24 - off)) & 0xffffff; + if (carry !== 0 || i !== this.length - 1) { + out = zeros[6 - word.length] + word + out; + } else { + out = word + out; + } + off += 2; + if (off >= 26) { + off -= 26; + i--; + } + } + if (carry !== 0) { + out = carry.toString(16) + out; + } + while (out.length % padding !== 0) { + out = '0' + out; + } + if (this.negative !== 0) { + out = '-' + out; + } + return out; + } + + if (base === (base | 0) && base >= 2 && base <= 36) { + // var groupSize = Math.floor(BN.wordSize * Math.LN2 / Math.log(base)); + var groupSize = groupSizes[base]; + // var groupBase = Math.pow(base, groupSize); + var groupBase = groupBases[base]; + out = ''; + var c = this.clone(); + c.negative = 0; + while (!c.isZero()) { + var r = c.modn(groupBase).toString(base); + c = c.idivn(groupBase); + + if (!c.isZero()) { + out = zeros[groupSize - r.length] + r + out; + } else { + out = r + out; + } + } + if (this.isZero()) { + out = '0' + out; + } + while (out.length % padding !== 0) { + out = '0' + out; + } + if (this.negative !== 0) { + out = '-' + out; + } + return out; + } + + assert(false, 'Base should be between 2 and 36'); + }; + + BN.prototype.toNumber = function toNumber () { + var ret = this.words[0]; + if (this.length === 2) { + ret += this.words[1] * 0x4000000; + } else if (this.length === 3 && this.words[2] === 0x01) { + // NOTE: at this stage it is known that the top bit is set + ret += 0x10000000000000 + (this.words[1] * 0x4000000); + } else if (this.length > 2) { + assert(false, 'Number can only safely store up to 53 bits'); + } + return (this.negative !== 0) ? -ret : ret; + }; + + BN.prototype.toJSON = function toJSON () { + return this.toString(16); + }; + + BN.prototype.toBuffer = function toBuffer (endian, length) { + assert(typeof Buffer !== 'undefined'); + return this.toArrayLike(Buffer, endian, length); + }; + + BN.prototype.toArray = function toArray (endian, length) { + return this.toArrayLike(Array, endian, length); + }; + + BN.prototype.toArrayLike = function toArrayLike (ArrayType, endian, length) { + var byteLength = this.byteLength(); + var reqLength = length || Math.max(1, byteLength); + assert(byteLength <= reqLength, 'byte array longer than desired length'); + assert(reqLength > 0, 'Requested array length <= 0'); + + this.strip(); + var littleEndian = endian === 'le'; + var res = new ArrayType(reqLength); + + var b, i; + var q = this.clone(); + if (!littleEndian) { + // Assume big-endian + for (i = 0; i < reqLength - byteLength; i++) { + res[i] = 0; + } + + for (i = 0; !q.isZero(); i++) { + b = q.andln(0xff); + q.iushrn(8); + + res[reqLength - i - 1] = b; + } + } else { + for (i = 0; !q.isZero(); i++) { + b = q.andln(0xff); + q.iushrn(8); + + res[i] = b; + } + + for (; i < reqLength; i++) { + res[i] = 0; + } + } + + return res; + }; + + if (Math.clz32) { + BN.prototype._countBits = function _countBits (w) { + return 32 - Math.clz32(w); + }; + } else { + BN.prototype._countBits = function _countBits (w) { + var t = w; + var r = 0; + if (t >= 0x1000) { + r += 13; + t >>>= 13; + } + if (t >= 0x40) { + r += 7; + t >>>= 7; + } + if (t >= 0x8) { + r += 4; + t >>>= 4; + } + if (t >= 0x02) { + r += 2; + t >>>= 2; + } + return r + t; + }; + } + + BN.prototype._zeroBits = function _zeroBits (w) { + // Short-cut + if (w === 0) return 26; + + var t = w; + var r = 0; + if ((t & 0x1fff) === 0) { + r += 13; + t >>>= 13; + } + if ((t & 0x7f) === 0) { + r += 7; + t >>>= 7; + } + if ((t & 0xf) === 0) { + r += 4; + t >>>= 4; + } + if ((t & 0x3) === 0) { + r += 2; + t >>>= 2; + } + if ((t & 0x1) === 0) { + r++; + } + return r; + }; + + // Return number of used bits in a BN + BN.prototype.bitLength = function bitLength () { + var w = this.words[this.length - 1]; + var hi = this._countBits(w); + return (this.length - 1) * 26 + hi; + }; + + function toBitArray (num) { + var w = new Array(num.bitLength()); + + for (var bit = 0; bit < w.length; bit++) { + var off = (bit / 26) | 0; + var wbit = bit % 26; + + w[bit] = (num.words[off] & (1 << wbit)) >>> wbit; + } + + return w; + } + + // Number of trailing zero bits + BN.prototype.zeroBits = function zeroBits () { + if (this.isZero()) return 0; + + var r = 0; + for (var i = 0; i < this.length; i++) { + var b = this._zeroBits(this.words[i]); + r += b; + if (b !== 26) break; + } + return r; + }; + + BN.prototype.byteLength = function byteLength () { + return Math.ceil(this.bitLength() / 8); + }; + + BN.prototype.toTwos = function toTwos (width) { + if (this.negative !== 0) { + return this.abs().inotn(width).iaddn(1); + } + return this.clone(); + }; + + BN.prototype.fromTwos = function fromTwos (width) { + if (this.testn(width - 1)) { + return this.notn(width).iaddn(1).ineg(); + } + return this.clone(); + }; + + BN.prototype.isNeg = function isNeg () { + return this.negative !== 0; + }; + + // Return negative clone of `this` + BN.prototype.neg = function neg () { + return this.clone().ineg(); + }; + + BN.prototype.ineg = function ineg () { + if (!this.isZero()) { + this.negative ^= 1; + } + + return this; + }; + + // Or `num` with `this` in-place + BN.prototype.iuor = function iuor (num) { + while (this.length < num.length) { + this.words[this.length++] = 0; + } + + for (var i = 0; i < num.length; i++) { + this.words[i] = this.words[i] | num.words[i]; + } + + return this.strip(); + }; + + BN.prototype.ior = function ior (num) { + assert((this.negative | num.negative) === 0); + return this.iuor(num); + }; + + // Or `num` with `this` + BN.prototype.or = function or (num) { + if (this.length > num.length) return this.clone().ior(num); + return num.clone().ior(this); + }; + + BN.prototype.uor = function uor (num) { + if (this.length > num.length) return this.clone().iuor(num); + return num.clone().iuor(this); + }; + + // And `num` with `this` in-place + BN.prototype.iuand = function iuand (num) { + // b = min-length(num, this) + var b; + if (this.length > num.length) { + b = num; + } else { + b = this; + } + + for (var i = 0; i < b.length; i++) { + this.words[i] = this.words[i] & num.words[i]; + } + + this.length = b.length; + + return this.strip(); + }; + + BN.prototype.iand = function iand (num) { + assert((this.negative | num.negative) === 0); + return this.iuand(num); + }; + + // And `num` with `this` + BN.prototype.and = function and (num) { + if (this.length > num.length) return this.clone().iand(num); + return num.clone().iand(this); + }; + + BN.prototype.uand = function uand (num) { + if (this.length > num.length) return this.clone().iuand(num); + return num.clone().iuand(this); + }; + + // Xor `num` with `this` in-place + BN.prototype.iuxor = function iuxor (num) { + // a.length > b.length + var a; + var b; + if (this.length > num.length) { + a = this; + b = num; + } else { + a = num; + b = this; + } + + for (var i = 0; i < b.length; i++) { + this.words[i] = a.words[i] ^ b.words[i]; + } + + if (this !== a) { + for (; i < a.length; i++) { + this.words[i] = a.words[i]; + } + } + + this.length = a.length; + + return this.strip(); + }; + + BN.prototype.ixor = function ixor (num) { + assert((this.negative | num.negative) === 0); + return this.iuxor(num); + }; + + // Xor `num` with `this` + BN.prototype.xor = function xor (num) { + if (this.length > num.length) return this.clone().ixor(num); + return num.clone().ixor(this); + }; + + BN.prototype.uxor = function uxor (num) { + if (this.length > num.length) return this.clone().iuxor(num); + return num.clone().iuxor(this); + }; + + // Not ``this`` with ``width`` bitwidth + BN.prototype.inotn = function inotn (width) { + assert(typeof width === 'number' && width >= 0); + + var bytesNeeded = Math.ceil(width / 26) | 0; + var bitsLeft = width % 26; + + // Extend the buffer with leading zeroes + this._expand(bytesNeeded); + + if (bitsLeft > 0) { + bytesNeeded--; + } + + // Handle complete words + for (var i = 0; i < bytesNeeded; i++) { + this.words[i] = ~this.words[i] & 0x3ffffff; + } + + // Handle the residue + if (bitsLeft > 0) { + this.words[i] = ~this.words[i] & (0x3ffffff >> (26 - bitsLeft)); + } + + // And remove leading zeroes + return this.strip(); + }; + + BN.prototype.notn = function notn (width) { + return this.clone().inotn(width); + }; + + // Set `bit` of `this` + BN.prototype.setn = function setn (bit, val) { + assert(typeof bit === 'number' && bit >= 0); + + var off = (bit / 26) | 0; + var wbit = bit % 26; + + this._expand(off + 1); + + if (val) { + this.words[off] = this.words[off] | (1 << wbit); + } else { + this.words[off] = this.words[off] & ~(1 << wbit); + } + + return this.strip(); + }; + + // Add `num` to `this` in-place + BN.prototype.iadd = function iadd (num) { + var r; + + // negative + positive + if (this.negative !== 0 && num.negative === 0) { + this.negative = 0; + r = this.isub(num); + this.negative ^= 1; + return this._normSign(); + + // positive + negative + } else if (this.negative === 0 && num.negative !== 0) { + num.negative = 0; + r = this.isub(num); + num.negative = 1; + return r._normSign(); + } + + // a.length > b.length + var a, b; + if (this.length > num.length) { + a = this; + b = num; + } else { + a = num; + b = this; + } + + var carry = 0; + for (var i = 0; i < b.length; i++) { + r = (a.words[i] | 0) + (b.words[i] | 0) + carry; + this.words[i] = r & 0x3ffffff; + carry = r >>> 26; + } + for (; carry !== 0 && i < a.length; i++) { + r = (a.words[i] | 0) + carry; + this.words[i] = r & 0x3ffffff; + carry = r >>> 26; + } + + this.length = a.length; + if (carry !== 0) { + this.words[this.length] = carry; + this.length++; + // Copy the rest of the words + } else if (a !== this) { + for (; i < a.length; i++) { + this.words[i] = a.words[i]; + } + } + + return this; + }; + + // Add `num` to `this` + BN.prototype.add = function add (num) { + var res; + if (num.negative !== 0 && this.negative === 0) { + num.negative = 0; + res = this.sub(num); + num.negative ^= 1; + return res; + } else if (num.negative === 0 && this.negative !== 0) { + this.negative = 0; + res = num.sub(this); + this.negative = 1; + return res; + } + + if (this.length > num.length) return this.clone().iadd(num); + + return num.clone().iadd(this); + }; + + // Subtract `num` from `this` in-place + BN.prototype.isub = function isub (num) { + // this - (-num) = this + num + if (num.negative !== 0) { + num.negative = 0; + var r = this.iadd(num); + num.negative = 1; + return r._normSign(); + + // -this - num = -(this + num) + } else if (this.negative !== 0) { + this.negative = 0; + this.iadd(num); + this.negative = 1; + return this._normSign(); + } + + // At this point both numbers are positive + var cmp = this.cmp(num); + + // Optimization - zeroify + if (cmp === 0) { + this.negative = 0; + this.length = 1; + this.words[0] = 0; + return this; + } + + // a > b + var a, b; + if (cmp > 0) { + a = this; + b = num; + } else { + a = num; + b = this; + } + + var carry = 0; + for (var i = 0; i < b.length; i++) { + r = (a.words[i] | 0) - (b.words[i] | 0) + carry; + carry = r >> 26; + this.words[i] = r & 0x3ffffff; + } + for (; carry !== 0 && i < a.length; i++) { + r = (a.words[i] | 0) + carry; + carry = r >> 26; + this.words[i] = r & 0x3ffffff; + } + + // Copy rest of the words + if (carry === 0 && i < a.length && a !== this) { + for (; i < a.length; i++) { + this.words[i] = a.words[i]; + } + } + + this.length = Math.max(this.length, i); + + if (a !== this) { + this.negative = 1; + } + + return this.strip(); + }; + + // Subtract `num` from `this` + BN.prototype.sub = function sub (num) { + return this.clone().isub(num); + }; + + function smallMulTo (self, num, out) { + out.negative = num.negative ^ self.negative; + var len = (self.length + num.length) | 0; + out.length = len; + len = (len - 1) | 0; + + // Peel one iteration (compiler can't do it, because of code complexity) + var a = self.words[0] | 0; + var b = num.words[0] | 0; + var r = a * b; + + var lo = r & 0x3ffffff; + var carry = (r / 0x4000000) | 0; + out.words[0] = lo; + + for (var k = 1; k < len; k++) { + // Sum all words with the same `i + j = k` and accumulate `ncarry`, + // note that ncarry could be >= 0x3ffffff + var ncarry = carry >>> 26; + var rword = carry & 0x3ffffff; + var maxJ = Math.min(k, num.length - 1); + for (var j = Math.max(0, k - self.length + 1); j <= maxJ; j++) { + var i = (k - j) | 0; + a = self.words[i] | 0; + b = num.words[j] | 0; + r = a * b + rword; + ncarry += (r / 0x4000000) | 0; + rword = r & 0x3ffffff; + } + out.words[k] = rword | 0; + carry = ncarry | 0; + } + if (carry !== 0) { + out.words[k] = carry | 0; + } else { + out.length--; + } + + return out.strip(); + } + + // TODO(indutny): it may be reasonable to omit it for users who don't need + // to work with 256-bit numbers, otherwise it gives 20% improvement for 256-bit + // multiplication (like elliptic secp256k1). + var comb10MulTo = function comb10MulTo (self, num, out) { + var a = self.words; + var b = num.words; + var o = out.words; + var c = 0; + var lo; + var mid; + var hi; + var a0 = a[0] | 0; + var al0 = a0 & 0x1fff; + var ah0 = a0 >>> 13; + var a1 = a[1] | 0; + var al1 = a1 & 0x1fff; + var ah1 = a1 >>> 13; + var a2 = a[2] | 0; + var al2 = a2 & 0x1fff; + var ah2 = a2 >>> 13; + var a3 = a[3] | 0; + var al3 = a3 & 0x1fff; + var ah3 = a3 >>> 13; + var a4 = a[4] | 0; + var al4 = a4 & 0x1fff; + var ah4 = a4 >>> 13; + var a5 = a[5] | 0; + var al5 = a5 & 0x1fff; + var ah5 = a5 >>> 13; + var a6 = a[6] | 0; + var al6 = a6 & 0x1fff; + var ah6 = a6 >>> 13; + var a7 = a[7] | 0; + var al7 = a7 & 0x1fff; + var ah7 = a7 >>> 13; + var a8 = a[8] | 0; + var al8 = a8 & 0x1fff; + var ah8 = a8 >>> 13; + var a9 = a[9] | 0; + var al9 = a9 & 0x1fff; + var ah9 = a9 >>> 13; + var b0 = b[0] | 0; + var bl0 = b0 & 0x1fff; + var bh0 = b0 >>> 13; + var b1 = b[1] | 0; + var bl1 = b1 & 0x1fff; + var bh1 = b1 >>> 13; + var b2 = b[2] | 0; + var bl2 = b2 & 0x1fff; + var bh2 = b2 >>> 13; + var b3 = b[3] | 0; + var bl3 = b3 & 0x1fff; + var bh3 = b3 >>> 13; + var b4 = b[4] | 0; + var bl4 = b4 & 0x1fff; + var bh4 = b4 >>> 13; + var b5 = b[5] | 0; + var bl5 = b5 & 0x1fff; + var bh5 = b5 >>> 13; + var b6 = b[6] | 0; + var bl6 = b6 & 0x1fff; + var bh6 = b6 >>> 13; + var b7 = b[7] | 0; + var bl7 = b7 & 0x1fff; + var bh7 = b7 >>> 13; + var b8 = b[8] | 0; + var bl8 = b8 & 0x1fff; + var bh8 = b8 >>> 13; + var b9 = b[9] | 0; + var bl9 = b9 & 0x1fff; + var bh9 = b9 >>> 13; + + out.negative = self.negative ^ num.negative; + out.length = 19; + /* k = 0 */ + lo = Math.imul(al0, bl0); + mid = Math.imul(al0, bh0); + mid = (mid + Math.imul(ah0, bl0)) | 0; + hi = Math.imul(ah0, bh0); + var w0 = (((c + lo) | 0) + ((mid & 0x1fff) << 13)) | 0; + c = (((hi + (mid >>> 13)) | 0) + (w0 >>> 26)) | 0; + w0 &= 0x3ffffff; + /* k = 1 */ + lo = Math.imul(al1, bl0); + mid = Math.imul(al1, bh0); + mid = (mid + Math.imul(ah1, bl0)) | 0; + hi = Math.imul(ah1, bh0); + lo = (lo + Math.imul(al0, bl1)) | 0; + mid = (mid + Math.imul(al0, bh1)) | 0; + mid = (mid + Math.imul(ah0, bl1)) | 0; + hi = (hi + Math.imul(ah0, bh1)) | 0; + var w1 = (((c + lo) | 0) + ((mid & 0x1fff) << 13)) | 0; + c = (((hi + (mid >>> 13)) | 0) + (w1 >>> 26)) | 0; + w1 &= 0x3ffffff; + /* k = 2 */ + lo = Math.imul(al2, bl0); + mid = Math.imul(al2, bh0); + mid = (mid + Math.imul(ah2, bl0)) | 0; + hi = Math.imul(ah2, bh0); + lo = (lo + Math.imul(al1, bl1)) | 0; + mid = (mid + Math.imul(al1, bh1)) | 0; + mid = (mid + Math.imul(ah1, bl1)) | 0; + hi = (hi + Math.imul(ah1, bh1)) | 0; + lo = (lo + Math.imul(al0, bl2)) | 0; + mid = (mid + Math.imul(al0, bh2)) | 0; + mid = (mid + Math.imul(ah0, bl2)) | 0; + hi = (hi + Math.imul(ah0, bh2)) | 0; + var w2 = (((c + lo) | 0) + ((mid & 0x1fff) << 13)) | 0; + c = (((hi + (mid >>> 13)) | 0) + (w2 >>> 26)) | 0; + w2 &= 0x3ffffff; + /* k = 3 */ + lo = Math.imul(al3, bl0); + mid = Math.imul(al3, bh0); + mid = (mid + Math.imul(ah3, bl0)) | 0; + hi = Math.imul(ah3, bh0); + lo = (lo + Math.imul(al2, bl1)) | 0; + mid = (mid + Math.imul(al2, bh1)) | 0; + mid = (mid + Math.imul(ah2, bl1)) | 0; + hi = (hi + Math.imul(ah2, bh1)) | 0; + lo = (lo + Math.imul(al1, bl2)) | 0; + mid = (mid + Math.imul(al1, bh2)) | 0; + mid = (mid + Math.imul(ah1, bl2)) | 0; + hi = (hi + Math.imul(ah1, bh2)) | 0; + lo = (lo + Math.imul(al0, bl3)) | 0; + mid = (mid + Math.imul(al0, bh3)) | 0; + mid = (mid + Math.imul(ah0, bl3)) | 0; + hi = (hi + Math.imul(ah0, bh3)) | 0; + var w3 = (((c + lo) | 0) + ((mid & 0x1fff) << 13)) | 0; + c = (((hi + (mid >>> 13)) | 0) + (w3 >>> 26)) | 0; + w3 &= 0x3ffffff; + /* k = 4 */ + lo = Math.imul(al4, bl0); + mid = Math.imul(al4, bh0); + mid = (mid + Math.imul(ah4, bl0)) | 0; + hi = Math.imul(ah4, bh0); + lo = (lo + Math.imul(al3, bl1)) | 0; + mid = (mid + Math.imul(al3, bh1)) | 0; + mid = (mid + Math.imul(ah3, bl1)) | 0; + hi = (hi + Math.imul(ah3, bh1)) | 0; + lo = (lo + Math.imul(al2, bl2)) | 0; + mid = (mid + Math.imul(al2, bh2)) | 0; + mid = (mid + Math.imul(ah2, bl2)) | 0; + hi = (hi + Math.imul(ah2, bh2)) | 0; + lo = (lo + Math.imul(al1, bl3)) | 0; + mid = (mid + Math.imul(al1, bh3)) | 0; + mid = (mid + Math.imul(ah1, bl3)) | 0; + hi = (hi + Math.imul(ah1, bh3)) | 0; + lo = (lo + Math.imul(al0, bl4)) | 0; + mid = (mid + Math.imul(al0, bh4)) | 0; + mid = (mid + Math.imul(ah0, bl4)) | 0; + hi = (hi + Math.imul(ah0, bh4)) | 0; + var w4 = (((c + lo) | 0) + ((mid & 0x1fff) << 13)) | 0; + c = (((hi + (mid >>> 13)) | 0) + (w4 >>> 26)) | 0; + w4 &= 0x3ffffff; + /* k = 5 */ + lo = Math.imul(al5, bl0); + mid = Math.imul(al5, bh0); + mid = (mid + Math.imul(ah5, bl0)) | 0; + hi = Math.imul(ah5, bh0); + lo = (lo + Math.imul(al4, bl1)) | 0; + mid = (mid + Math.imul(al4, bh1)) | 0; + mid = (mid + Math.imul(ah4, bl1)) | 0; + hi = (hi + Math.imul(ah4, bh1)) | 0; + lo = (lo + Math.imul(al3, bl2)) | 0; + mid = (mid + Math.imul(al3, bh2)) | 0; + mid = (mid + Math.imul(ah3, bl2)) | 0; + hi = (hi + Math.imul(ah3, bh2)) | 0; + lo = (lo + Math.imul(al2, bl3)) | 0; + mid = (mid + Math.imul(al2, bh3)) | 0; + mid = (mid + Math.imul(ah2, bl3)) | 0; + hi = (hi + Math.imul(ah2, bh3)) | 0; + lo = (lo + Math.imul(al1, bl4)) | 0; + mid = (mid + Math.imul(al1, bh4)) | 0; + mid = (mid + Math.imul(ah1, bl4)) | 0; + hi = (hi + Math.imul(ah1, bh4)) | 0; + lo = (lo + Math.imul(al0, bl5)) | 0; + mid = (mid + Math.imul(al0, bh5)) | 0; + mid = (mid + Math.imul(ah0, bl5)) | 0; + hi = (hi + Math.imul(ah0, bh5)) | 0; + var w5 = (((c + lo) | 0) + ((mid & 0x1fff) << 13)) | 0; + c = (((hi + (mid >>> 13)) | 0) + (w5 >>> 26)) | 0; + w5 &= 0x3ffffff; + /* k = 6 */ + lo = Math.imul(al6, bl0); + mid = Math.imul(al6, bh0); + mid = (mid + Math.imul(ah6, bl0)) | 0; + hi = Math.imul(ah6, bh0); + lo = (lo + Math.imul(al5, bl1)) | 0; + mid = (mid + Math.imul(al5, bh1)) | 0; + mid = (mid + Math.imul(ah5, bl1)) | 0; + hi = (hi + Math.imul(ah5, bh1)) | 0; + lo = (lo + Math.imul(al4, bl2)) | 0; + mid = (mid + Math.imul(al4, bh2)) | 0; + mid = (mid + Math.imul(ah4, bl2)) | 0; + hi = (hi + Math.imul(ah4, bh2)) | 0; + lo = (lo + Math.imul(al3, bl3)) | 0; + mid = (mid + Math.imul(al3, bh3)) | 0; + mid = (mid + Math.imul(ah3, bl3)) | 0; + hi = (hi + Math.imul(ah3, bh3)) | 0; + lo = (lo + Math.imul(al2, bl4)) | 0; + mid = (mid + Math.imul(al2, bh4)) | 0; + mid = (mid + Math.imul(ah2, bl4)) | 0; + hi = (hi + Math.imul(ah2, bh4)) | 0; + lo = (lo + Math.imul(al1, bl5)) | 0; + mid = (mid + Math.imul(al1, bh5)) | 0; + mid = (mid + Math.imul(ah1, bl5)) | 0; + hi = (hi + Math.imul(ah1, bh5)) | 0; + lo = (lo + Math.imul(al0, bl6)) | 0; + mid = (mid + Math.imul(al0, bh6)) | 0; + mid = (mid + Math.imul(ah0, bl6)) | 0; + hi = (hi + Math.imul(ah0, bh6)) | 0; + var w6 = (((c + lo) | 0) + ((mid & 0x1fff) << 13)) | 0; + c = (((hi + (mid >>> 13)) | 0) + (w6 >>> 26)) | 0; + w6 &= 0x3ffffff; + /* k = 7 */ + lo = Math.imul(al7, bl0); + mid = Math.imul(al7, bh0); + mid = (mid + Math.imul(ah7, bl0)) | 0; + hi = Math.imul(ah7, bh0); + lo = (lo + Math.imul(al6, bl1)) | 0; + mid = (mid + Math.imul(al6, bh1)) | 0; + mid = (mid + Math.imul(ah6, bl1)) | 0; + hi = (hi + Math.imul(ah6, bh1)) | 0; + lo = (lo + Math.imul(al5, bl2)) | 0; + mid = (mid + Math.imul(al5, bh2)) | 0; + mid = (mid + Math.imul(ah5, bl2)) | 0; + hi = (hi + Math.imul(ah5, bh2)) | 0; + lo = (lo + Math.imul(al4, bl3)) | 0; + mid = (mid + Math.imul(al4, bh3)) | 0; + mid = (mid + Math.imul(ah4, bl3)) | 0; + hi = (hi + Math.imul(ah4, bh3)) | 0; + lo = (lo + Math.imul(al3, bl4)) | 0; + mid = (mid + Math.imul(al3, bh4)) | 0; + mid = (mid + Math.imul(ah3, bl4)) | 0; + hi = (hi + Math.imul(ah3, bh4)) | 0; + lo = (lo + Math.imul(al2, bl5)) | 0; + mid = (mid + Math.imul(al2, bh5)) | 0; + mid = (mid + Math.imul(ah2, bl5)) | 0; + hi = (hi + Math.imul(ah2, bh5)) | 0; + lo = (lo + Math.imul(al1, bl6)) | 0; + mid = (mid + Math.imul(al1, bh6)) | 0; + mid = (mid + Math.imul(ah1, bl6)) | 0; + hi = (hi + Math.imul(ah1, bh6)) | 0; + lo = (lo + Math.imul(al0, bl7)) | 0; + mid = (mid + Math.imul(al0, bh7)) | 0; + mid = (mid + Math.imul(ah0, bl7)) | 0; + hi = (hi + Math.imul(ah0, bh7)) | 0; + var w7 = (((c + lo) | 0) + ((mid & 0x1fff) << 13)) | 0; + c = (((hi + (mid >>> 13)) | 0) + (w7 >>> 26)) | 0; + w7 &= 0x3ffffff; + /* k = 8 */ + lo = Math.imul(al8, bl0); + mid = Math.imul(al8, bh0); + mid = (mid + Math.imul(ah8, bl0)) | 0; + hi = Math.imul(ah8, bh0); + lo = (lo + Math.imul(al7, bl1)) | 0; + mid = (mid + Math.imul(al7, bh1)) | 0; + mid = (mid + Math.imul(ah7, bl1)) | 0; + hi = (hi + Math.imul(ah7, bh1)) | 0; + lo = (lo + Math.imul(al6, bl2)) | 0; + mid = (mid + Math.imul(al6, bh2)) | 0; + mid = (mid + Math.imul(ah6, bl2)) | 0; + hi = (hi + Math.imul(ah6, bh2)) | 0; + lo = (lo + Math.imul(al5, bl3)) | 0; + mid = (mid + Math.imul(al5, bh3)) | 0; + mid = (mid + Math.imul(ah5, bl3)) | 0; + hi = (hi + Math.imul(ah5, bh3)) | 0; + lo = (lo + Math.imul(al4, bl4)) | 0; + mid = (mid + Math.imul(al4, bh4)) | 0; + mid = (mid + Math.imul(ah4, bl4)) | 0; + hi = (hi + Math.imul(ah4, bh4)) | 0; + lo = (lo + Math.imul(al3, bl5)) | 0; + mid = (mid + Math.imul(al3, bh5)) | 0; + mid = (mid + Math.imul(ah3, bl5)) | 0; + hi = (hi + Math.imul(ah3, bh5)) | 0; + lo = (lo + Math.imul(al2, bl6)) | 0; + mid = (mid + Math.imul(al2, bh6)) | 0; + mid = (mid + Math.imul(ah2, bl6)) | 0; + hi = (hi + Math.imul(ah2, bh6)) | 0; + lo = (lo + Math.imul(al1, bl7)) | 0; + mid = (mid + Math.imul(al1, bh7)) | 0; + mid = (mid + Math.imul(ah1, bl7)) | 0; + hi = (hi + Math.imul(ah1, bh7)) | 0; + lo = (lo + Math.imul(al0, bl8)) | 0; + mid = (mid + Math.imul(al0, bh8)) | 0; + mid = (mid + Math.imul(ah0, bl8)) | 0; + hi = (hi + Math.imul(ah0, bh8)) | 0; + var w8 = (((c + lo) | 0) + ((mid & 0x1fff) << 13)) | 0; + c = (((hi + (mid >>> 13)) | 0) + (w8 >>> 26)) | 0; + w8 &= 0x3ffffff; + /* k = 9 */ + lo = Math.imul(al9, bl0); + mid = Math.imul(al9, bh0); + mid = (mid + Math.imul(ah9, bl0)) | 0; + hi = Math.imul(ah9, bh0); + lo = (lo + Math.imul(al8, bl1)) | 0; + mid = (mid + Math.imul(al8, bh1)) | 0; + mid = (mid + Math.imul(ah8, bl1)) | 0; + hi = (hi + Math.imul(ah8, bh1)) | 0; + lo = (lo + Math.imul(al7, bl2)) | 0; + mid = (mid + Math.imul(al7, bh2)) | 0; + mid = (mid + Math.imul(ah7, bl2)) | 0; + hi = (hi + Math.imul(ah7, bh2)) | 0; + lo = (lo + Math.imul(al6, bl3)) | 0; + mid = (mid + Math.imul(al6, bh3)) | 0; + mid = (mid + Math.imul(ah6, bl3)) | 0; + hi = (hi + Math.imul(ah6, bh3)) | 0; + lo = (lo + Math.imul(al5, bl4)) | 0; + mid = (mid + Math.imul(al5, bh4)) | 0; + mid = (mid + Math.imul(ah5, bl4)) | 0; + hi = (hi + Math.imul(ah5, bh4)) | 0; + lo = (lo + Math.imul(al4, bl5)) | 0; + mid = (mid + Math.imul(al4, bh5)) | 0; + mid = (mid + Math.imul(ah4, bl5)) | 0; + hi = (hi + Math.imul(ah4, bh5)) | 0; + lo = (lo + Math.imul(al3, bl6)) | 0; + mid = (mid + Math.imul(al3, bh6)) | 0; + mid = (mid + Math.imul(ah3, bl6)) | 0; + hi = (hi + Math.imul(ah3, bh6)) | 0; + lo = (lo + Math.imul(al2, bl7)) | 0; + mid = (mid + Math.imul(al2, bh7)) | 0; + mid = (mid + Math.imul(ah2, bl7)) | 0; + hi = (hi + Math.imul(ah2, bh7)) | 0; + lo = (lo + Math.imul(al1, bl8)) | 0; + mid = (mid + Math.imul(al1, bh8)) | 0; + mid = (mid + Math.imul(ah1, bl8)) | 0; + hi = (hi + Math.imul(ah1, bh8)) | 0; + lo = (lo + Math.imul(al0, bl9)) | 0; + mid = (mid + Math.imul(al0, bh9)) | 0; + mid = (mid + Math.imul(ah0, bl9)) | 0; + hi = (hi + Math.imul(ah0, bh9)) | 0; + var w9 = (((c + lo) | 0) + ((mid & 0x1fff) << 13)) | 0; + c = (((hi + (mid >>> 13)) | 0) + (w9 >>> 26)) | 0; + w9 &= 0x3ffffff; + /* k = 10 */ + lo = Math.imul(al9, bl1); + mid = Math.imul(al9, bh1); + mid = (mid + Math.imul(ah9, bl1)) | 0; + hi = Math.imul(ah9, bh1); + lo = (lo + Math.imul(al8, bl2)) | 0; + mid = (mid + Math.imul(al8, bh2)) | 0; + mid = (mid + Math.imul(ah8, bl2)) | 0; + hi = (hi + Math.imul(ah8, bh2)) | 0; + lo = (lo + Math.imul(al7, bl3)) | 0; + mid = (mid + Math.imul(al7, bh3)) | 0; + mid = (mid + Math.imul(ah7, bl3)) | 0; + hi = (hi + Math.imul(ah7, bh3)) | 0; + lo = (lo + Math.imul(al6, bl4)) | 0; + mid = (mid + Math.imul(al6, bh4)) | 0; + mid = (mid + Math.imul(ah6, bl4)) | 0; + hi = (hi + Math.imul(ah6, bh4)) | 0; + lo = (lo + Math.imul(al5, bl5)) | 0; + mid = (mid + Math.imul(al5, bh5)) | 0; + mid = (mid + Math.imul(ah5, bl5)) | 0; + hi = (hi + Math.imul(ah5, bh5)) | 0; + lo = (lo + Math.imul(al4, bl6)) | 0; + mid = (mid + Math.imul(al4, bh6)) | 0; + mid = (mid + Math.imul(ah4, bl6)) | 0; + hi = (hi + Math.imul(ah4, bh6)) | 0; + lo = (lo + Math.imul(al3, bl7)) | 0; + mid = (mid + Math.imul(al3, bh7)) | 0; + mid = (mid + Math.imul(ah3, bl7)) | 0; + hi = (hi + Math.imul(ah3, bh7)) | 0; + lo = (lo + Math.imul(al2, bl8)) | 0; + mid = (mid + Math.imul(al2, bh8)) | 0; + mid = (mid + Math.imul(ah2, bl8)) | 0; + hi = (hi + Math.imul(ah2, bh8)) | 0; + lo = (lo + Math.imul(al1, bl9)) | 0; + mid = (mid + Math.imul(al1, bh9)) | 0; + mid = (mid + Math.imul(ah1, bl9)) | 0; + hi = (hi + Math.imul(ah1, bh9)) | 0; + var w10 = (((c + lo) | 0) + ((mid & 0x1fff) << 13)) | 0; + c = (((hi + (mid >>> 13)) | 0) + (w10 >>> 26)) | 0; + w10 &= 0x3ffffff; + /* k = 11 */ + lo = Math.imul(al9, bl2); + mid = Math.imul(al9, bh2); + mid = (mid + Math.imul(ah9, bl2)) | 0; + hi = Math.imul(ah9, bh2); + lo = (lo + Math.imul(al8, bl3)) | 0; + mid = (mid + Math.imul(al8, bh3)) | 0; + mid = (mid + Math.imul(ah8, bl3)) | 0; + hi = (hi + Math.imul(ah8, bh3)) | 0; + lo = (lo + Math.imul(al7, bl4)) | 0; + mid = (mid + Math.imul(al7, bh4)) | 0; + mid = (mid + Math.imul(ah7, bl4)) | 0; + hi = (hi + Math.imul(ah7, bh4)) | 0; + lo = (lo + Math.imul(al6, bl5)) | 0; + mid = (mid + Math.imul(al6, bh5)) | 0; + mid = (mid + Math.imul(ah6, bl5)) | 0; + hi = (hi + Math.imul(ah6, bh5)) | 0; + lo = (lo + Math.imul(al5, bl6)) | 0; + mid = (mid + Math.imul(al5, bh6)) | 0; + mid = (mid + Math.imul(ah5, bl6)) | 0; + hi = (hi + Math.imul(ah5, bh6)) | 0; + lo = (lo + Math.imul(al4, bl7)) | 0; + mid = (mid + Math.imul(al4, bh7)) | 0; + mid = (mid + Math.imul(ah4, bl7)) | 0; + hi = (hi + Math.imul(ah4, bh7)) | 0; + lo = (lo + Math.imul(al3, bl8)) | 0; + mid = (mid + Math.imul(al3, bh8)) | 0; + mid = (mid + Math.imul(ah3, bl8)) | 0; + hi = (hi + Math.imul(ah3, bh8)) | 0; + lo = (lo + Math.imul(al2, bl9)) | 0; + mid = (mid + Math.imul(al2, bh9)) | 0; + mid = (mid + Math.imul(ah2, bl9)) | 0; + hi = (hi + Math.imul(ah2, bh9)) | 0; + var w11 = (((c + lo) | 0) + ((mid & 0x1fff) << 13)) | 0; + c = (((hi + (mid >>> 13)) | 0) + (w11 >>> 26)) | 0; + w11 &= 0x3ffffff; + /* k = 12 */ + lo = Math.imul(al9, bl3); + mid = Math.imul(al9, bh3); + mid = (mid + Math.imul(ah9, bl3)) | 0; + hi = Math.imul(ah9, bh3); + lo = (lo + Math.imul(al8, bl4)) | 0; + mid = (mid + Math.imul(al8, bh4)) | 0; + mid = (mid + Math.imul(ah8, bl4)) | 0; + hi = (hi + Math.imul(ah8, bh4)) | 0; + lo = (lo + Math.imul(al7, bl5)) | 0; + mid = (mid + Math.imul(al7, bh5)) | 0; + mid = (mid + Math.imul(ah7, bl5)) | 0; + hi = (hi + Math.imul(ah7, bh5)) | 0; + lo = (lo + Math.imul(al6, bl6)) | 0; + mid = (mid + Math.imul(al6, bh6)) | 0; + mid = (mid + Math.imul(ah6, bl6)) | 0; + hi = (hi + Math.imul(ah6, bh6)) | 0; + lo = (lo + Math.imul(al5, bl7)) | 0; + mid = (mid + Math.imul(al5, bh7)) | 0; + mid = (mid + Math.imul(ah5, bl7)) | 0; + hi = (hi + Math.imul(ah5, bh7)) | 0; + lo = (lo + Math.imul(al4, bl8)) | 0; + mid = (mid + Math.imul(al4, bh8)) | 0; + mid = (mid + Math.imul(ah4, bl8)) | 0; + hi = (hi + Math.imul(ah4, bh8)) | 0; + lo = (lo + Math.imul(al3, bl9)) | 0; + mid = (mid + Math.imul(al3, bh9)) | 0; + mid = (mid + Math.imul(ah3, bl9)) | 0; + hi = (hi + Math.imul(ah3, bh9)) | 0; + var w12 = (((c + lo) | 0) + ((mid & 0x1fff) << 13)) | 0; + c = (((hi + (mid >>> 13)) | 0) + (w12 >>> 26)) | 0; + w12 &= 0x3ffffff; + /* k = 13 */ + lo = Math.imul(al9, bl4); + mid = Math.imul(al9, bh4); + mid = (mid + Math.imul(ah9, bl4)) | 0; + hi = Math.imul(ah9, bh4); + lo = (lo + Math.imul(al8, bl5)) | 0; + mid = (mid + Math.imul(al8, bh5)) | 0; + mid = (mid + Math.imul(ah8, bl5)) | 0; + hi = (hi + Math.imul(ah8, bh5)) | 0; + lo = (lo + Math.imul(al7, bl6)) | 0; + mid = (mid + Math.imul(al7, bh6)) | 0; + mid = (mid + Math.imul(ah7, bl6)) | 0; + hi = (hi + Math.imul(ah7, bh6)) | 0; + lo = (lo + Math.imul(al6, bl7)) | 0; + mid = (mid + Math.imul(al6, bh7)) | 0; + mid = (mid + Math.imul(ah6, bl7)) | 0; + hi = (hi + Math.imul(ah6, bh7)) | 0; + lo = (lo + Math.imul(al5, bl8)) | 0; + mid = (mid + Math.imul(al5, bh8)) | 0; + mid = (mid + Math.imul(ah5, bl8)) | 0; + hi = (hi + Math.imul(ah5, bh8)) | 0; + lo = (lo + Math.imul(al4, bl9)) | 0; + mid = (mid + Math.imul(al4, bh9)) | 0; + mid = (mid + Math.imul(ah4, bl9)) | 0; + hi = (hi + Math.imul(ah4, bh9)) | 0; + var w13 = (((c + lo) | 0) + ((mid & 0x1fff) << 13)) | 0; + c = (((hi + (mid >>> 13)) | 0) + (w13 >>> 26)) | 0; + w13 &= 0x3ffffff; + /* k = 14 */ + lo = Math.imul(al9, bl5); + mid = Math.imul(al9, bh5); + mid = (mid + Math.imul(ah9, bl5)) | 0; + hi = Math.imul(ah9, bh5); + lo = (lo + Math.imul(al8, bl6)) | 0; + mid = (mid + Math.imul(al8, bh6)) | 0; + mid = (mid + Math.imul(ah8, bl6)) | 0; + hi = (hi + Math.imul(ah8, bh6)) | 0; + lo = (lo + Math.imul(al7, bl7)) | 0; + mid = (mid + Math.imul(al7, bh7)) | 0; + mid = (mid + Math.imul(ah7, bl7)) | 0; + hi = (hi + Math.imul(ah7, bh7)) | 0; + lo = (lo + Math.imul(al6, bl8)) | 0; + mid = (mid + Math.imul(al6, bh8)) | 0; + mid = (mid + Math.imul(ah6, bl8)) | 0; + hi = (hi + Math.imul(ah6, bh8)) | 0; + lo = (lo + Math.imul(al5, bl9)) | 0; + mid = (mid + Math.imul(al5, bh9)) | 0; + mid = (mid + Math.imul(ah5, bl9)) | 0; + hi = (hi + Math.imul(ah5, bh9)) | 0; + var w14 = (((c + lo) | 0) + ((mid & 0x1fff) << 13)) | 0; + c = (((hi + (mid >>> 13)) | 0) + (w14 >>> 26)) | 0; + w14 &= 0x3ffffff; + /* k = 15 */ + lo = Math.imul(al9, bl6); + mid = Math.imul(al9, bh6); + mid = (mid + Math.imul(ah9, bl6)) | 0; + hi = Math.imul(ah9, bh6); + lo = (lo + Math.imul(al8, bl7)) | 0; + mid = (mid + Math.imul(al8, bh7)) | 0; + mid = (mid + Math.imul(ah8, bl7)) | 0; + hi = (hi + Math.imul(ah8, bh7)) | 0; + lo = (lo + Math.imul(al7, bl8)) | 0; + mid = (mid + Math.imul(al7, bh8)) | 0; + mid = (mid + Math.imul(ah7, bl8)) | 0; + hi = (hi + Math.imul(ah7, bh8)) | 0; + lo = (lo + Math.imul(al6, bl9)) | 0; + mid = (mid + Math.imul(al6, bh9)) | 0; + mid = (mid + Math.imul(ah6, bl9)) | 0; + hi = (hi + Math.imul(ah6, bh9)) | 0; + var w15 = (((c + lo) | 0) + ((mid & 0x1fff) << 13)) | 0; + c = (((hi + (mid >>> 13)) | 0) + (w15 >>> 26)) | 0; + w15 &= 0x3ffffff; + /* k = 16 */ + lo = Math.imul(al9, bl7); + mid = Math.imul(al9, bh7); + mid = (mid + Math.imul(ah9, bl7)) | 0; + hi = Math.imul(ah9, bh7); + lo = (lo + Math.imul(al8, bl8)) | 0; + mid = (mid + Math.imul(al8, bh8)) | 0; + mid = (mid + Math.imul(ah8, bl8)) | 0; + hi = (hi + Math.imul(ah8, bh8)) | 0; + lo = (lo + Math.imul(al7, bl9)) | 0; + mid = (mid + Math.imul(al7, bh9)) | 0; + mid = (mid + Math.imul(ah7, bl9)) | 0; + hi = (hi + Math.imul(ah7, bh9)) | 0; + var w16 = (((c + lo) | 0) + ((mid & 0x1fff) << 13)) | 0; + c = (((hi + (mid >>> 13)) | 0) + (w16 >>> 26)) | 0; + w16 &= 0x3ffffff; + /* k = 17 */ + lo = Math.imul(al9, bl8); + mid = Math.imul(al9, bh8); + mid = (mid + Math.imul(ah9, bl8)) | 0; + hi = Math.imul(ah9, bh8); + lo = (lo + Math.imul(al8, bl9)) | 0; + mid = (mid + Math.imul(al8, bh9)) | 0; + mid = (mid + Math.imul(ah8, bl9)) | 0; + hi = (hi + Math.imul(ah8, bh9)) | 0; + var w17 = (((c + lo) | 0) + ((mid & 0x1fff) << 13)) | 0; + c = (((hi + (mid >>> 13)) | 0) + (w17 >>> 26)) | 0; + w17 &= 0x3ffffff; + /* k = 18 */ + lo = Math.imul(al9, bl9); + mid = Math.imul(al9, bh9); + mid = (mid + Math.imul(ah9, bl9)) | 0; + hi = Math.imul(ah9, bh9); + var w18 = (((c + lo) | 0) + ((mid & 0x1fff) << 13)) | 0; + c = (((hi + (mid >>> 13)) | 0) + (w18 >>> 26)) | 0; + w18 &= 0x3ffffff; + o[0] = w0; + o[1] = w1; + o[2] = w2; + o[3] = w3; + o[4] = w4; + o[5] = w5; + o[6] = w6; + o[7] = w7; + o[8] = w8; + o[9] = w9; + o[10] = w10; + o[11] = w11; + o[12] = w12; + o[13] = w13; + o[14] = w14; + o[15] = w15; + o[16] = w16; + o[17] = w17; + o[18] = w18; + if (c !== 0) { + o[19] = c; + out.length++; + } + return out; + }; + + // Polyfill comb + if (!Math.imul) { + comb10MulTo = smallMulTo; + } + + function bigMulTo (self, num, out) { + out.negative = num.negative ^ self.negative; + out.length = self.length + num.length; + + var carry = 0; + var hncarry = 0; + for (var k = 0; k < out.length - 1; k++) { + // Sum all words with the same `i + j = k` and accumulate `ncarry`, + // note that ncarry could be >= 0x3ffffff + var ncarry = hncarry; + hncarry = 0; + var rword = carry & 0x3ffffff; + var maxJ = Math.min(k, num.length - 1); + for (var j = Math.max(0, k - self.length + 1); j <= maxJ; j++) { + var i = k - j; + var a = self.words[i] | 0; + var b = num.words[j] | 0; + var r = a * b; + + var lo = r & 0x3ffffff; + ncarry = (ncarry + ((r / 0x4000000) | 0)) | 0; + lo = (lo + rword) | 0; + rword = lo & 0x3ffffff; + ncarry = (ncarry + (lo >>> 26)) | 0; + + hncarry += ncarry >>> 26; + ncarry &= 0x3ffffff; + } + out.words[k] = rword; + carry = ncarry; + ncarry = hncarry; + } + if (carry !== 0) { + out.words[k] = carry; + } else { + out.length--; + } + + return out.strip(); + } + + function jumboMulTo (self, num, out) { + var fftm = new FFTM(); + return fftm.mulp(self, num, out); + } + + BN.prototype.mulTo = function mulTo (num, out) { + var res; + var len = this.length + num.length; + if (this.length === 10 && num.length === 10) { + res = comb10MulTo(this, num, out); + } else if (len < 63) { + res = smallMulTo(this, num, out); + } else if (len < 1024) { + res = bigMulTo(this, num, out); + } else { + res = jumboMulTo(this, num, out); + } + + return res; + }; + + // Cooley-Tukey algorithm for FFT + // slightly revisited to rely on looping instead of recursion + + function FFTM (x, y) { + this.x = x; + this.y = y; + } + + FFTM.prototype.makeRBT = function makeRBT (N) { + var t = new Array(N); + var l = BN.prototype._countBits(N) - 1; + for (var i = 0; i < N; i++) { + t[i] = this.revBin(i, l, N); + } + + return t; + }; + + // Returns binary-reversed representation of `x` + FFTM.prototype.revBin = function revBin (x, l, N) { + if (x === 0 || x === N - 1) return x; + + var rb = 0; + for (var i = 0; i < l; i++) { + rb |= (x & 1) << (l - i - 1); + x >>= 1; + } + + return rb; + }; + + // Performs "tweedling" phase, therefore 'emulating' + // behaviour of the recursive algorithm + FFTM.prototype.permute = function permute (rbt, rws, iws, rtws, itws, N) { + for (var i = 0; i < N; i++) { + rtws[i] = rws[rbt[i]]; + itws[i] = iws[rbt[i]]; + } + }; + + FFTM.prototype.transform = function transform (rws, iws, rtws, itws, N, rbt) { + this.permute(rbt, rws, iws, rtws, itws, N); + + for (var s = 1; s < N; s <<= 1) { + var l = s << 1; + + var rtwdf = Math.cos(2 * Math.PI / l); + var itwdf = Math.sin(2 * Math.PI / l); + + for (var p = 0; p < N; p += l) { + var rtwdf_ = rtwdf; + var itwdf_ = itwdf; + + for (var j = 0; j < s; j++) { + var re = rtws[p + j]; + var ie = itws[p + j]; + + var ro = rtws[p + j + s]; + var io = itws[p + j + s]; + + var rx = rtwdf_ * ro - itwdf_ * io; + + io = rtwdf_ * io + itwdf_ * ro; + ro = rx; + + rtws[p + j] = re + ro; + itws[p + j] = ie + io; + + rtws[p + j + s] = re - ro; + itws[p + j + s] = ie - io; + + /* jshint maxdepth : false */ + if (j !== l) { + rx = rtwdf * rtwdf_ - itwdf * itwdf_; + + itwdf_ = rtwdf * itwdf_ + itwdf * rtwdf_; + rtwdf_ = rx; + } + } + } + } + }; + + FFTM.prototype.guessLen13b = function guessLen13b (n, m) { + var N = Math.max(m, n) | 1; + var odd = N & 1; + var i = 0; + for (N = N / 2 | 0; N; N = N >>> 1) { + i++; + } + + return 1 << i + 1 + odd; + }; + + FFTM.prototype.conjugate = function conjugate (rws, iws, N) { + if (N <= 1) return; + + for (var i = 0; i < N / 2; i++) { + var t = rws[i]; + + rws[i] = rws[N - i - 1]; + rws[N - i - 1] = t; + + t = iws[i]; + + iws[i] = -iws[N - i - 1]; + iws[N - i - 1] = -t; + } + }; + + FFTM.prototype.normalize13b = function normalize13b (ws, N) { + var carry = 0; + for (var i = 0; i < N / 2; i++) { + var w = Math.round(ws[2 * i + 1] / N) * 0x2000 + + Math.round(ws[2 * i] / N) + + carry; + + ws[i] = w & 0x3ffffff; + + if (w < 0x4000000) { + carry = 0; + } else { + carry = w / 0x4000000 | 0; + } + } + + return ws; + }; + + FFTM.prototype.convert13b = function convert13b (ws, len, rws, N) { + var carry = 0; + for (var i = 0; i < len; i++) { + carry = carry + (ws[i] | 0); + + rws[2 * i] = carry & 0x1fff; carry = carry >>> 13; + rws[2 * i + 1] = carry & 0x1fff; carry = carry >>> 13; + } + + // Pad with zeroes + for (i = 2 * len; i < N; ++i) { + rws[i] = 0; + } + + assert(carry === 0); + assert((carry & ~0x1fff) === 0); + }; + + FFTM.prototype.stub = function stub (N) { + var ph = new Array(N); + for (var i = 0; i < N; i++) { + ph[i] = 0; + } + + return ph; + }; + + FFTM.prototype.mulp = function mulp (x, y, out) { + var N = 2 * this.guessLen13b(x.length, y.length); + + var rbt = this.makeRBT(N); + + var _ = this.stub(N); + + var rws = new Array(N); + var rwst = new Array(N); + var iwst = new Array(N); + + var nrws = new Array(N); + var nrwst = new Array(N); + var niwst = new Array(N); + + var rmws = out.words; + rmws.length = N; + + this.convert13b(x.words, x.length, rws, N); + this.convert13b(y.words, y.length, nrws, N); + + this.transform(rws, _, rwst, iwst, N, rbt); + this.transform(nrws, _, nrwst, niwst, N, rbt); + + for (var i = 0; i < N; i++) { + var rx = rwst[i] * nrwst[i] - iwst[i] * niwst[i]; + iwst[i] = rwst[i] * niwst[i] + iwst[i] * nrwst[i]; + rwst[i] = rx; + } + + this.conjugate(rwst, iwst, N); + this.transform(rwst, iwst, rmws, _, N, rbt); + this.conjugate(rmws, _, N); + this.normalize13b(rmws, N); + + out.negative = x.negative ^ y.negative; + out.length = x.length + y.length; + return out.strip(); + }; + + // Multiply `this` by `num` + BN.prototype.mul = function mul (num) { + var out = new BN(null); + out.words = new Array(this.length + num.length); + return this.mulTo(num, out); + }; + + // Multiply employing FFT + BN.prototype.mulf = function mulf (num) { + var out = new BN(null); + out.words = new Array(this.length + num.length); + return jumboMulTo(this, num, out); + }; + + // In-place Multiplication + BN.prototype.imul = function imul (num) { + return this.clone().mulTo(num, this); + }; + + BN.prototype.imuln = function imuln (num) { + assert(typeof num === 'number'); + assert(num < 0x4000000); + + // Carry + var carry = 0; + for (var i = 0; i < this.length; i++) { + var w = (this.words[i] | 0) * num; + var lo = (w & 0x3ffffff) + (carry & 0x3ffffff); + carry >>= 26; + carry += (w / 0x4000000) | 0; + // NOTE: lo is 27bit maximum + carry += lo >>> 26; + this.words[i] = lo & 0x3ffffff; + } + + if (carry !== 0) { + this.words[i] = carry; + this.length++; + } + + return this; + }; + + BN.prototype.muln = function muln (num) { + return this.clone().imuln(num); + }; + + // `this` * `this` + BN.prototype.sqr = function sqr () { + return this.mul(this); + }; + + // `this` * `this` in-place + BN.prototype.isqr = function isqr () { + return this.imul(this.clone()); + }; + + // Math.pow(`this`, `num`) + BN.prototype.pow = function pow (num) { + var w = toBitArray(num); + if (w.length === 0) return new BN(1); + + // Skip leading zeroes + var res = this; + for (var i = 0; i < w.length; i++, res = res.sqr()) { + if (w[i] !== 0) break; + } + + if (++i < w.length) { + for (var q = res.sqr(); i < w.length; i++, q = q.sqr()) { + if (w[i] === 0) continue; + + res = res.mul(q); + } + } + + return res; + }; + + // Shift-left in-place + BN.prototype.iushln = function iushln (bits) { + assert(typeof bits === 'number' && bits >= 0); + var r = bits % 26; + var s = (bits - r) / 26; + var carryMask = (0x3ffffff >>> (26 - r)) << (26 - r); + var i; + + if (r !== 0) { + var carry = 0; + + for (i = 0; i < this.length; i++) { + var newCarry = this.words[i] & carryMask; + var c = ((this.words[i] | 0) - newCarry) << r; + this.words[i] = c | carry; + carry = newCarry >>> (26 - r); + } + + if (carry) { + this.words[i] = carry; + this.length++; + } + } + + if (s !== 0) { + for (i = this.length - 1; i >= 0; i--) { + this.words[i + s] = this.words[i]; + } + + for (i = 0; i < s; i++) { + this.words[i] = 0; + } + + this.length += s; + } + + return this.strip(); + }; + + BN.prototype.ishln = function ishln (bits) { + // TODO(indutny): implement me + assert(this.negative === 0); + return this.iushln(bits); + }; + + // Shift-right in-place + // NOTE: `hint` is a lowest bit before trailing zeroes + // NOTE: if `extended` is present - it will be filled with destroyed bits + BN.prototype.iushrn = function iushrn (bits, hint, extended) { + assert(typeof bits === 'number' && bits >= 0); + var h; + if (hint) { + h = (hint - (hint % 26)) / 26; + } else { + h = 0; + } + + var r = bits % 26; + var s = Math.min((bits - r) / 26, this.length); + var mask = 0x3ffffff ^ ((0x3ffffff >>> r) << r); + var maskedWords = extended; + + h -= s; + h = Math.max(0, h); + + // Extended mode, copy masked part + if (maskedWords) { + for (var i = 0; i < s; i++) { + maskedWords.words[i] = this.words[i]; + } + maskedWords.length = s; + } + + if (s === 0) { + // No-op, we should not move anything at all + } else if (this.length > s) { + this.length -= s; + for (i = 0; i < this.length; i++) { + this.words[i] = this.words[i + s]; + } + } else { + this.words[0] = 0; + this.length = 1; + } + + var carry = 0; + for (i = this.length - 1; i >= 0 && (carry !== 0 || i >= h); i--) { + var word = this.words[i] | 0; + this.words[i] = (carry << (26 - r)) | (word >>> r); + carry = word & mask; + } + + // Push carried bits as a mask + if (maskedWords && carry !== 0) { + maskedWords.words[maskedWords.length++] = carry; + } + + if (this.length === 0) { + this.words[0] = 0; + this.length = 1; + } + + return this.strip(); + }; + + BN.prototype.ishrn = function ishrn (bits, hint, extended) { + // TODO(indutny): implement me + assert(this.negative === 0); + return this.iushrn(bits, hint, extended); + }; + + // Shift-left + BN.prototype.shln = function shln (bits) { + return this.clone().ishln(bits); + }; + + BN.prototype.ushln = function ushln (bits) { + return this.clone().iushln(bits); + }; + + // Shift-right + BN.prototype.shrn = function shrn (bits) { + return this.clone().ishrn(bits); + }; + + BN.prototype.ushrn = function ushrn (bits) { + return this.clone().iushrn(bits); + }; + + // Test if n bit is set + BN.prototype.testn = function testn (bit) { + assert(typeof bit === 'number' && bit >= 0); + var r = bit % 26; + var s = (bit - r) / 26; + var q = 1 << r; + + // Fast case: bit is much higher than all existing words + if (this.length <= s) return false; + + // Check bit and return + var w = this.words[s]; + + return !!(w & q); + }; + + // Return only lowers bits of number (in-place) + BN.prototype.imaskn = function imaskn (bits) { + assert(typeof bits === 'number' && bits >= 0); + var r = bits % 26; + var s = (bits - r) / 26; + + assert(this.negative === 0, 'imaskn works only with positive numbers'); + + if (this.length <= s) { + return this; + } + + if (r !== 0) { + s++; + } + this.length = Math.min(s, this.length); + + if (r !== 0) { + var mask = 0x3ffffff ^ ((0x3ffffff >>> r) << r); + this.words[this.length - 1] &= mask; + } + + return this.strip(); + }; + + // Return only lowers bits of number + BN.prototype.maskn = function maskn (bits) { + return this.clone().imaskn(bits); + }; + + // Add plain number `num` to `this` + BN.prototype.iaddn = function iaddn (num) { + assert(typeof num === 'number'); + assert(num < 0x4000000); + if (num < 0) return this.isubn(-num); + + // Possible sign change + if (this.negative !== 0) { + if (this.length === 1 && (this.words[0] | 0) < num) { + this.words[0] = num - (this.words[0] | 0); + this.negative = 0; + return this; + } + + this.negative = 0; + this.isubn(num); + this.negative = 1; + return this; + } + + // Add without checks + return this._iaddn(num); + }; + + BN.prototype._iaddn = function _iaddn (num) { + this.words[0] += num; + + // Carry + for (var i = 0; i < this.length && this.words[i] >= 0x4000000; i++) { + this.words[i] -= 0x4000000; + if (i === this.length - 1) { + this.words[i + 1] = 1; + } else { + this.words[i + 1]++; + } + } + this.length = Math.max(this.length, i + 1); + + return this; + }; + + // Subtract plain number `num` from `this` + BN.prototype.isubn = function isubn (num) { + assert(typeof num === 'number'); + assert(num < 0x4000000); + if (num < 0) return this.iaddn(-num); + + if (this.negative !== 0) { + this.negative = 0; + this.iaddn(num); + this.negative = 1; + return this; + } + + this.words[0] -= num; + + if (this.length === 1 && this.words[0] < 0) { + this.words[0] = -this.words[0]; + this.negative = 1; + } else { + // Carry + for (var i = 0; i < this.length && this.words[i] < 0; i++) { + this.words[i] += 0x4000000; + this.words[i + 1] -= 1; + } + } + + return this.strip(); + }; + + BN.prototype.addn = function addn (num) { + return this.clone().iaddn(num); + }; + + BN.prototype.subn = function subn (num) { + return this.clone().isubn(num); + }; + + BN.prototype.iabs = function iabs () { + this.negative = 0; + + return this; + }; + + BN.prototype.abs = function abs () { + return this.clone().iabs(); + }; + + BN.prototype._ishlnsubmul = function _ishlnsubmul (num, mul, shift) { + var len = num.length + shift; + var i; + + this._expand(len); + + var w; + var carry = 0; + for (i = 0; i < num.length; i++) { + w = (this.words[i + shift] | 0) + carry; + var right = (num.words[i] | 0) * mul; + w -= right & 0x3ffffff; + carry = (w >> 26) - ((right / 0x4000000) | 0); + this.words[i + shift] = w & 0x3ffffff; + } + for (; i < this.length - shift; i++) { + w = (this.words[i + shift] | 0) + carry; + carry = w >> 26; + this.words[i + shift] = w & 0x3ffffff; + } + + if (carry === 0) return this.strip(); + + // Subtraction overflow + assert(carry === -1); + carry = 0; + for (i = 0; i < this.length; i++) { + w = -(this.words[i] | 0) + carry; + carry = w >> 26; + this.words[i] = w & 0x3ffffff; + } + this.negative = 1; + + return this.strip(); + }; + + BN.prototype._wordDiv = function _wordDiv (num, mode) { + var shift = this.length - num.length; + + var a = this.clone(); + var b = num; + + // Normalize + var bhi = b.words[b.length - 1] | 0; + var bhiBits = this._countBits(bhi); + shift = 26 - bhiBits; + if (shift !== 0) { + b = b.ushln(shift); + a.iushln(shift); + bhi = b.words[b.length - 1] | 0; + } + + // Initialize quotient + var m = a.length - b.length; + var q; + + if (mode !== 'mod') { + q = new BN(null); + q.length = m + 1; + q.words = new Array(q.length); + for (var i = 0; i < q.length; i++) { + q.words[i] = 0; + } + } + + var diff = a.clone()._ishlnsubmul(b, 1, m); + if (diff.negative === 0) { + a = diff; + if (q) { + q.words[m] = 1; + } + } + + for (var j = m - 1; j >= 0; j--) { + var qj = (a.words[b.length + j] | 0) * 0x4000000 + + (a.words[b.length + j - 1] | 0); + + // NOTE: (qj / bhi) is (0x3ffffff * 0x4000000 + 0x3ffffff) / 0x2000000 max + // (0x7ffffff) + qj = Math.min((qj / bhi) | 0, 0x3ffffff); + + a._ishlnsubmul(b, qj, j); + while (a.negative !== 0) { + qj--; + a.negative = 0; + a._ishlnsubmul(b, 1, j); + if (!a.isZero()) { + a.negative ^= 1; + } + } + if (q) { + q.words[j] = qj; + } + } + if (q) { + q.strip(); + } + a.strip(); + + // Denormalize + if (mode !== 'div' && shift !== 0) { + a.iushrn(shift); + } + + return { + div: q || null, + mod: a + }; + }; + + // NOTE: 1) `mode` can be set to `mod` to request mod only, + // to `div` to request div only, or be absent to + // request both div & mod + // 2) `positive` is true if unsigned mod is requested + BN.prototype.divmod = function divmod (num, mode, positive) { + assert(!num.isZero()); + + if (this.isZero()) { + return { + div: new BN(0), + mod: new BN(0) + }; + } + + var div, mod, res; + if (this.negative !== 0 && num.negative === 0) { + res = this.neg().divmod(num, mode); + + if (mode !== 'mod') { + div = res.div.neg(); + } + + if (mode !== 'div') { + mod = res.mod.neg(); + if (positive && mod.negative !== 0) { + mod.iadd(num); + } + } + + return { + div: div, + mod: mod + }; + } + + if (this.negative === 0 && num.negative !== 0) { + res = this.divmod(num.neg(), mode); + + if (mode !== 'mod') { + div = res.div.neg(); + } + + return { + div: div, + mod: res.mod + }; + } + + if ((this.negative & num.negative) !== 0) { + res = this.neg().divmod(num.neg(), mode); + + if (mode !== 'div') { + mod = res.mod.neg(); + if (positive && mod.negative !== 0) { + mod.isub(num); + } + } + + return { + div: res.div, + mod: mod + }; + } + + // Both numbers are positive at this point + + // Strip both numbers to approximate shift value + if (num.length > this.length || this.cmp(num) < 0) { + return { + div: new BN(0), + mod: this + }; + } + + // Very short reduction + if (num.length === 1) { + if (mode === 'div') { + return { + div: this.divn(num.words[0]), + mod: null + }; + } + + if (mode === 'mod') { + return { + div: null, + mod: new BN(this.modn(num.words[0])) + }; + } + + return { + div: this.divn(num.words[0]), + mod: new BN(this.modn(num.words[0])) + }; + } + + return this._wordDiv(num, mode); + }; + + // Find `this` / `num` + BN.prototype.div = function div (num) { + return this.divmod(num, 'div', false).div; + }; + + // Find `this` % `num` + BN.prototype.mod = function mod (num) { + return this.divmod(num, 'mod', false).mod; + }; + + BN.prototype.umod = function umod (num) { + return this.divmod(num, 'mod', true).mod; + }; + + // Find Round(`this` / `num`) + BN.prototype.divRound = function divRound (num) { + var dm = this.divmod(num); + + // Fast case - exact division + if (dm.mod.isZero()) return dm.div; + + var mod = dm.div.negative !== 0 ? dm.mod.isub(num) : dm.mod; + + var half = num.ushrn(1); + var r2 = num.andln(1); + var cmp = mod.cmp(half); + + // Round down + if (cmp < 0 || r2 === 1 && cmp === 0) return dm.div; + + // Round up + return dm.div.negative !== 0 ? dm.div.isubn(1) : dm.div.iaddn(1); + }; + + BN.prototype.modn = function modn (num) { + assert(num <= 0x3ffffff); + var p = (1 << 26) % num; + + var acc = 0; + for (var i = this.length - 1; i >= 0; i--) { + acc = (p * acc + (this.words[i] | 0)) % num; + } + + return acc; + }; + + // In-place division by number + BN.prototype.idivn = function idivn (num) { + assert(num <= 0x3ffffff); + + var carry = 0; + for (var i = this.length - 1; i >= 0; i--) { + var w = (this.words[i] | 0) + carry * 0x4000000; + this.words[i] = (w / num) | 0; + carry = w % num; + } + + return this.strip(); + }; + + BN.prototype.divn = function divn (num) { + return this.clone().idivn(num); + }; + + BN.prototype.egcd = function egcd (p) { + assert(p.negative === 0); + assert(!p.isZero()); + + var x = this; + var y = p.clone(); + + if (x.negative !== 0) { + x = x.umod(p); + } else { + x = x.clone(); + } + + // A * x + B * y = x + var A = new BN(1); + var B = new BN(0); + + // C * x + D * y = y + var C = new BN(0); + var D = new BN(1); + + var g = 0; + + while (x.isEven() && y.isEven()) { + x.iushrn(1); + y.iushrn(1); + ++g; + } + + var yp = y.clone(); + var xp = x.clone(); + + while (!x.isZero()) { + for (var i = 0, im = 1; (x.words[0] & im) === 0 && i < 26; ++i, im <<= 1); + if (i > 0) { + x.iushrn(i); + while (i-- > 0) { + if (A.isOdd() || B.isOdd()) { + A.iadd(yp); + B.isub(xp); + } + + A.iushrn(1); + B.iushrn(1); + } + } + + for (var j = 0, jm = 1; (y.words[0] & jm) === 0 && j < 26; ++j, jm <<= 1); + if (j > 0) { + y.iushrn(j); + while (j-- > 0) { + if (C.isOdd() || D.isOdd()) { + C.iadd(yp); + D.isub(xp); + } + + C.iushrn(1); + D.iushrn(1); + } + } + + if (x.cmp(y) >= 0) { + x.isub(y); + A.isub(C); + B.isub(D); + } else { + y.isub(x); + C.isub(A); + D.isub(B); + } + } + + return { + a: C, + b: D, + gcd: y.iushln(g) + }; + }; + + // This is reduced incarnation of the binary EEA + // above, designated to invert members of the + // _prime_ fields F(p) at a maximal speed + BN.prototype._invmp = function _invmp (p) { + assert(p.negative === 0); + assert(!p.isZero()); + + var a = this; + var b = p.clone(); + + if (a.negative !== 0) { + a = a.umod(p); + } else { + a = a.clone(); + } + + var x1 = new BN(1); + var x2 = new BN(0); + + var delta = b.clone(); + + while (a.cmpn(1) > 0 && b.cmpn(1) > 0) { + for (var i = 0, im = 1; (a.words[0] & im) === 0 && i < 26; ++i, im <<= 1); + if (i > 0) { + a.iushrn(i); + while (i-- > 0) { + if (x1.isOdd()) { + x1.iadd(delta); + } + + x1.iushrn(1); + } + } + + for (var j = 0, jm = 1; (b.words[0] & jm) === 0 && j < 26; ++j, jm <<= 1); + if (j > 0) { + b.iushrn(j); + while (j-- > 0) { + if (x2.isOdd()) { + x2.iadd(delta); + } + + x2.iushrn(1); + } + } + + if (a.cmp(b) >= 0) { + a.isub(b); + x1.isub(x2); + } else { + b.isub(a); + x2.isub(x1); + } + } + + var res; + if (a.cmpn(1) === 0) { + res = x1; + } else { + res = x2; + } + + if (res.cmpn(0) < 0) { + res.iadd(p); + } + + return res; + }; + + BN.prototype.gcd = function gcd (num) { + if (this.isZero()) return num.abs(); + if (num.isZero()) return this.abs(); + + var a = this.clone(); + var b = num.clone(); + a.negative = 0; + b.negative = 0; + + // Remove common factor of two + for (var shift = 0; a.isEven() && b.isEven(); shift++) { + a.iushrn(1); + b.iushrn(1); + } + + do { + while (a.isEven()) { + a.iushrn(1); + } + while (b.isEven()) { + b.iushrn(1); + } + + var r = a.cmp(b); + if (r < 0) { + // Swap `a` and `b` to make `a` always bigger than `b` + var t = a; + a = b; + b = t; + } else if (r === 0 || b.cmpn(1) === 0) { + break; + } + + a.isub(b); + } while (true); + + return b.iushln(shift); + }; + + // Invert number in the field F(num) + BN.prototype.invm = function invm (num) { + return this.egcd(num).a.umod(num); + }; + + BN.prototype.isEven = function isEven () { + return (this.words[0] & 1) === 0; + }; + + BN.prototype.isOdd = function isOdd () { + return (this.words[0] & 1) === 1; + }; + + // And first word and num + BN.prototype.andln = function andln (num) { + return this.words[0] & num; + }; + + // Increment at the bit position in-line + BN.prototype.bincn = function bincn (bit) { + assert(typeof bit === 'number'); + var r = bit % 26; + var s = (bit - r) / 26; + var q = 1 << r; + + // Fast case: bit is much higher than all existing words + if (this.length <= s) { + this._expand(s + 1); + this.words[s] |= q; + return this; + } + + // Add bit and propagate, if needed + var carry = q; + for (var i = s; carry !== 0 && i < this.length; i++) { + var w = this.words[i] | 0; + w += carry; + carry = w >>> 26; + w &= 0x3ffffff; + this.words[i] = w; + } + if (carry !== 0) { + this.words[i] = carry; + this.length++; + } + return this; + }; + + BN.prototype.isZero = function isZero () { + return this.length === 1 && this.words[0] === 0; + }; + + BN.prototype.cmpn = function cmpn (num) { + var negative = num < 0; + + if (this.negative !== 0 && !negative) return -1; + if (this.negative === 0 && negative) return 1; + + this.strip(); + + var res; + if (this.length > 1) { + res = 1; + } else { + if (negative) { + num = -num; + } + + assert(num <= 0x3ffffff, 'Number is too big'); + + var w = this.words[0] | 0; + res = w === num ? 0 : w < num ? -1 : 1; + } + if (this.negative !== 0) return -res | 0; + return res; + }; + + // Compare two numbers and return: + // 1 - if `this` > `num` + // 0 - if `this` == `num` + // -1 - if `this` < `num` + BN.prototype.cmp = function cmp (num) { + if (this.negative !== 0 && num.negative === 0) return -1; + if (this.negative === 0 && num.negative !== 0) return 1; + + var res = this.ucmp(num); + if (this.negative !== 0) return -res | 0; + return res; + }; + + // Unsigned comparison + BN.prototype.ucmp = function ucmp (num) { + // At this point both numbers have the same sign + if (this.length > num.length) return 1; + if (this.length < num.length) return -1; + + var res = 0; + for (var i = this.length - 1; i >= 0; i--) { + var a = this.words[i] | 0; + var b = num.words[i] | 0; + + if (a === b) continue; + if (a < b) { + res = -1; + } else if (a > b) { + res = 1; + } + break; + } + return res; + }; + + BN.prototype.gtn = function gtn (num) { + return this.cmpn(num) === 1; + }; + + BN.prototype.gt = function gt (num) { + return this.cmp(num) === 1; + }; + + BN.prototype.gten = function gten (num) { + return this.cmpn(num) >= 0; + }; + + BN.prototype.gte = function gte (num) { + return this.cmp(num) >= 0; + }; + + BN.prototype.ltn = function ltn (num) { + return this.cmpn(num) === -1; + }; + + BN.prototype.lt = function lt (num) { + return this.cmp(num) === -1; + }; + + BN.prototype.lten = function lten (num) { + return this.cmpn(num) <= 0; + }; + + BN.prototype.lte = function lte (num) { + return this.cmp(num) <= 0; + }; + + BN.prototype.eqn = function eqn (num) { + return this.cmpn(num) === 0; + }; + + BN.prototype.eq = function eq (num) { + return this.cmp(num) === 0; + }; + + // + // A reduce context, could be using montgomery or something better, depending + // on the `m` itself. + // + BN.red = function red (num) { + return new Red(num); + }; + + BN.prototype.toRed = function toRed (ctx) { + assert(!this.red, 'Already a number in reduction context'); + assert(this.negative === 0, 'red works only with positives'); + return ctx.convertTo(this)._forceRed(ctx); + }; + + BN.prototype.fromRed = function fromRed () { + assert(this.red, 'fromRed works only with numbers in reduction context'); + return this.red.convertFrom(this); + }; + + BN.prototype._forceRed = function _forceRed (ctx) { + this.red = ctx; + return this; + }; + + BN.prototype.forceRed = function forceRed (ctx) { + assert(!this.red, 'Already a number in reduction context'); + return this._forceRed(ctx); + }; + + BN.prototype.redAdd = function redAdd (num) { + assert(this.red, 'redAdd works only with red numbers'); + return this.red.add(this, num); + }; + + BN.prototype.redIAdd = function redIAdd (num) { + assert(this.red, 'redIAdd works only with red numbers'); + return this.red.iadd(this, num); + }; + + BN.prototype.redSub = function redSub (num) { + assert(this.red, 'redSub works only with red numbers'); + return this.red.sub(this, num); + }; + + BN.prototype.redISub = function redISub (num) { + assert(this.red, 'redISub works only with red numbers'); + return this.red.isub(this, num); + }; + + BN.prototype.redShl = function redShl (num) { + assert(this.red, 'redShl works only with red numbers'); + return this.red.shl(this, num); + }; + + BN.prototype.redMul = function redMul (num) { + assert(this.red, 'redMul works only with red numbers'); + this.red._verify2(this, num); + return this.red.mul(this, num); + }; + + BN.prototype.redIMul = function redIMul (num) { + assert(this.red, 'redMul works only with red numbers'); + this.red._verify2(this, num); + return this.red.imul(this, num); + }; + + BN.prototype.redSqr = function redSqr () { + assert(this.red, 'redSqr works only with red numbers'); + this.red._verify1(this); + return this.red.sqr(this); + }; + + BN.prototype.redISqr = function redISqr () { + assert(this.red, 'redISqr works only with red numbers'); + this.red._verify1(this); + return this.red.isqr(this); + }; + + // Square root over p + BN.prototype.redSqrt = function redSqrt () { + assert(this.red, 'redSqrt works only with red numbers'); + this.red._verify1(this); + return this.red.sqrt(this); + }; + + BN.prototype.redInvm = function redInvm () { + assert(this.red, 'redInvm works only with red numbers'); + this.red._verify1(this); + return this.red.invm(this); + }; + + // Return negative clone of `this` % `red modulo` + BN.prototype.redNeg = function redNeg () { + assert(this.red, 'redNeg works only with red numbers'); + this.red._verify1(this); + return this.red.neg(this); + }; + + BN.prototype.redPow = function redPow (num) { + assert(this.red && !num.red, 'redPow(normalNum)'); + this.red._verify1(this); + return this.red.pow(this, num); + }; + + // Prime numbers with efficient reduction + var primes = { + k256: null, + p224: null, + p192: null, + p25519: null + }; + + // Pseudo-Mersenne prime + function MPrime (name, p) { + // P = 2 ^ N - K + this.name = name; + this.p = new BN(p, 16); + this.n = this.p.bitLength(); + this.k = new BN(1).iushln(this.n).isub(this.p); + + this.tmp = this._tmp(); + } + + MPrime.prototype._tmp = function _tmp () { + var tmp = new BN(null); + tmp.words = new Array(Math.ceil(this.n / 13)); + return tmp; + }; + + MPrime.prototype.ireduce = function ireduce (num) { + // Assumes that `num` is less than `P^2` + // num = HI * (2 ^ N - K) + HI * K + LO = HI * K + LO (mod P) + var r = num; + var rlen; + + do { + this.split(r, this.tmp); + r = this.imulK(r); + r = r.iadd(this.tmp); + rlen = r.bitLength(); + } while (rlen > this.n); + + var cmp = rlen < this.n ? -1 : r.ucmp(this.p); + if (cmp === 0) { + r.words[0] = 0; + r.length = 1; + } else if (cmp > 0) { + r.isub(this.p); + } else { + if (r.strip !== undefined) { + // r is BN v4 instance + r.strip(); + } else { + // r is BN v5 instance + r._strip(); + } + } + + return r; + }; + + MPrime.prototype.split = function split (input, out) { + input.iushrn(this.n, 0, out); + }; + + MPrime.prototype.imulK = function imulK (num) { + return num.imul(this.k); + }; + + function K256 () { + MPrime.call( + this, + 'k256', + 'ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff fffffffe fffffc2f'); + } + inherits(K256, MPrime); + + K256.prototype.split = function split (input, output) { + // 256 = 9 * 26 + 22 + var mask = 0x3fffff; + + var outLen = Math.min(input.length, 9); + for (var i = 0; i < outLen; i++) { + output.words[i] = input.words[i]; + } + output.length = outLen; + + if (input.length <= 9) { + input.words[0] = 0; + input.length = 1; + return; + } + + // Shift by 9 limbs + var prev = input.words[9]; + output.words[output.length++] = prev & mask; + + for (i = 10; i < input.length; i++) { + var next = input.words[i] | 0; + input.words[i - 10] = ((next & mask) << 4) | (prev >>> 22); + prev = next; + } + prev >>>= 22; + input.words[i - 10] = prev; + if (prev === 0 && input.length > 10) { + input.length -= 10; + } else { + input.length -= 9; + } + }; + + K256.prototype.imulK = function imulK (num) { + // K = 0x1000003d1 = [ 0x40, 0x3d1 ] + num.words[num.length] = 0; + num.words[num.length + 1] = 0; + num.length += 2; + + // bounded at: 0x40 * 0x3ffffff + 0x3d0 = 0x100000390 + var lo = 0; + for (var i = 0; i < num.length; i++) { + var w = num.words[i] | 0; + lo += w * 0x3d1; + num.words[i] = lo & 0x3ffffff; + lo = w * 0x40 + ((lo / 0x4000000) | 0); + } + + // Fast length reduction + if (num.words[num.length - 1] === 0) { + num.length--; + if (num.words[num.length - 1] === 0) { + num.length--; + } + } + return num; + }; + + function P224 () { + MPrime.call( + this, + 'p224', + 'ffffffff ffffffff ffffffff ffffffff 00000000 00000000 00000001'); + } + inherits(P224, MPrime); + + function P192 () { + MPrime.call( + this, + 'p192', + 'ffffffff ffffffff ffffffff fffffffe ffffffff ffffffff'); + } + inherits(P192, MPrime); + + function P25519 () { + // 2 ^ 255 - 19 + MPrime.call( + this, + '25519', + '7fffffffffffffff ffffffffffffffff ffffffffffffffff ffffffffffffffed'); + } + inherits(P25519, MPrime); + + P25519.prototype.imulK = function imulK (num) { + // K = 0x13 + var carry = 0; + for (var i = 0; i < num.length; i++) { + var hi = (num.words[i] | 0) * 0x13 + carry; + var lo = hi & 0x3ffffff; + hi >>>= 26; + + num.words[i] = lo; + carry = hi; + } + if (carry !== 0) { + num.words[num.length++] = carry; + } + return num; + }; + + // Exported mostly for testing purposes, use plain name instead + BN._prime = function prime (name) { + // Cached version of prime + if (primes[name]) return primes[name]; + + var prime; + if (name === 'k256') { + prime = new K256(); + } else if (name === 'p224') { + prime = new P224(); + } else if (name === 'p192') { + prime = new P192(); + } else if (name === 'p25519') { + prime = new P25519(); + } else { + throw new Error('Unknown prime ' + name); + } + primes[name] = prime; + + return prime; + }; + + // + // Base reduction engine + // + function Red (m) { + if (typeof m === 'string') { + var prime = BN._prime(m); + this.m = prime.p; + this.prime = prime; + } else { + assert(m.gtn(1), 'modulus must be greater than 1'); + this.m = m; + this.prime = null; + } + } + + Red.prototype._verify1 = function _verify1 (a) { + assert(a.negative === 0, 'red works only with positives'); + assert(a.red, 'red works only with red numbers'); + }; + + Red.prototype._verify2 = function _verify2 (a, b) { + assert((a.negative | b.negative) === 0, 'red works only with positives'); + assert(a.red && a.red === b.red, + 'red works only with red numbers'); + }; + + Red.prototype.imod = function imod (a) { + if (this.prime) return this.prime.ireduce(a)._forceRed(this); + return a.umod(this.m)._forceRed(this); + }; + + Red.prototype.neg = function neg (a) { + if (a.isZero()) { + return a.clone(); + } + + return this.m.sub(a)._forceRed(this); + }; + + Red.prototype.add = function add (a, b) { + this._verify2(a, b); + + var res = a.add(b); + if (res.cmp(this.m) >= 0) { + res.isub(this.m); + } + return res._forceRed(this); + }; + + Red.prototype.iadd = function iadd (a, b) { + this._verify2(a, b); + + var res = a.iadd(b); + if (res.cmp(this.m) >= 0) { + res.isub(this.m); + } + return res; + }; + + Red.prototype.sub = function sub (a, b) { + this._verify2(a, b); + + var res = a.sub(b); + if (res.cmpn(0) < 0) { + res.iadd(this.m); + } + return res._forceRed(this); + }; + + Red.prototype.isub = function isub (a, b) { + this._verify2(a, b); + + var res = a.isub(b); + if (res.cmpn(0) < 0) { + res.iadd(this.m); + } + return res; + }; + + Red.prototype.shl = function shl (a, num) { + this._verify1(a); + return this.imod(a.ushln(num)); + }; + + Red.prototype.imul = function imul (a, b) { + this._verify2(a, b); + return this.imod(a.imul(b)); + }; + + Red.prototype.mul = function mul (a, b) { + this._verify2(a, b); + return this.imod(a.mul(b)); + }; + + Red.prototype.isqr = function isqr (a) { + return this.imul(a, a.clone()); + }; + + Red.prototype.sqr = function sqr (a) { + return this.mul(a, a); + }; + + Red.prototype.sqrt = function sqrt (a) { + if (a.isZero()) return a.clone(); + + var mod3 = this.m.andln(3); + assert(mod3 % 2 === 1); + + // Fast case + if (mod3 === 3) { + var pow = this.m.add(new BN(1)).iushrn(2); + return this.pow(a, pow); + } + + // Tonelli-Shanks algorithm (Totally unoptimized and slow) + // + // Find Q and S, that Q * 2 ^ S = (P - 1) + var q = this.m.subn(1); + var s = 0; + while (!q.isZero() && q.andln(1) === 0) { + s++; + q.iushrn(1); + } + assert(!q.isZero()); + + var one = new BN(1).toRed(this); + var nOne = one.redNeg(); + + // Find quadratic non-residue + // NOTE: Max is such because of generalized Riemann hypothesis. + var lpow = this.m.subn(1).iushrn(1); + var z = this.m.bitLength(); + z = new BN(2 * z * z).toRed(this); + + while (this.pow(z, lpow).cmp(nOne) !== 0) { + z.redIAdd(nOne); + } + + var c = this.pow(z, q); + var r = this.pow(a, q.addn(1).iushrn(1)); + var t = this.pow(a, q); + var m = s; + while (t.cmp(one) !== 0) { + var tmp = t; + for (var i = 0; tmp.cmp(one) !== 0; i++) { + tmp = tmp.redSqr(); + } + assert(i < m); + var b = this.pow(c, new BN(1).iushln(m - i - 1)); + + r = r.redMul(b); + c = b.redSqr(); + t = t.redMul(c); + m = i; + } + + return r; + }; + + Red.prototype.invm = function invm (a) { + var inv = a._invmp(this.m); + if (inv.negative !== 0) { + inv.negative = 0; + return this.imod(inv).redNeg(); + } else { + return this.imod(inv); + } + }; + + Red.prototype.pow = function pow (a, num) { + if (num.isZero()) return new BN(1).toRed(this); + if (num.cmpn(1) === 0) return a.clone(); + + var windowSize = 4; + var wnd = new Array(1 << windowSize); + wnd[0] = new BN(1).toRed(this); + wnd[1] = a; + for (var i = 2; i < wnd.length; i++) { + wnd[i] = this.mul(wnd[i - 1], a); + } + + var res = wnd[0]; + var current = 0; + var currentLen = 0; + var start = num.bitLength() % 26; + if (start === 0) { + start = 26; + } + + for (i = num.length - 1; i >= 0; i--) { + var word = num.words[i]; + for (var j = start - 1; j >= 0; j--) { + var bit = (word >> j) & 1; + if (res !== wnd[0]) { + res = this.sqr(res); + } + + if (bit === 0 && current === 0) { + currentLen = 0; + continue; + } + + current <<= 1; + current |= bit; + currentLen++; + if (currentLen !== windowSize && (i !== 0 || j !== 0)) continue; + + res = this.mul(res, wnd[current]); + currentLen = 0; + current = 0; + } + start = 26; + } + + return res; + }; + + Red.prototype.convertTo = function convertTo (num) { + var r = num.umod(this.m); + + return r === num ? r.clone() : r; + }; + + Red.prototype.convertFrom = function convertFrom (num) { + var res = num.clone(); + res.red = null; + return res; + }; + + // + // Montgomery method engine + // + + BN.mont = function mont (num) { + return new Mont(num); + }; + + function Mont (m) { + Red.call(this, m); + + this.shift = this.m.bitLength(); + if (this.shift % 26 !== 0) { + this.shift += 26 - (this.shift % 26); + } + + this.r = new BN(1).iushln(this.shift); + this.r2 = this.imod(this.r.sqr()); + this.rinv = this.r._invmp(this.m); + + this.minv = this.rinv.mul(this.r).isubn(1).div(this.m); + this.minv = this.minv.umod(this.r); + this.minv = this.r.sub(this.minv); + } + inherits(Mont, Red); + + Mont.prototype.convertTo = function convertTo (num) { + return this.imod(num.ushln(this.shift)); + }; + + Mont.prototype.convertFrom = function convertFrom (num) { + var r = this.imod(num.mul(this.rinv)); + r.red = null; + return r; + }; + + Mont.prototype.imul = function imul (a, b) { + if (a.isZero() || b.isZero()) { + a.words[0] = 0; + a.length = 1; + return a; + } + + var t = a.imul(b); + var c = t.maskn(this.shift).mul(this.minv).imaskn(this.shift).mul(this.m); + var u = t.isub(c).iushrn(this.shift); + var res = u; + + if (u.cmp(this.m) >= 0) { + res = u.isub(this.m); + } else if (u.cmpn(0) < 0) { + res = u.iadd(this.m); + } + + return res._forceRed(this); + }; + + Mont.prototype.mul = function mul (a, b) { + if (a.isZero() || b.isZero()) return new BN(0)._forceRed(this); + + var t = a.mul(b); + var c = t.maskn(this.shift).mul(this.minv).imaskn(this.shift).mul(this.m); + var u = t.isub(c).iushrn(this.shift); + var res = u; + if (u.cmp(this.m) >= 0) { + res = u.isub(this.m); + } else if (u.cmpn(0) < 0) { + res = u.iadd(this.m); + } + + return res._forceRed(this); + }; + + Mont.prototype.invm = function invm (a) { + // (AR)^-1 * R^2 = (A^-1 * R^-1) * R^2 = A^-1 * R + var res = this.imod(a._invmp(this.m).mul(this.r2)); + return res._forceRed(this); + }; +})(typeof module === 'undefined' || module, this); + +},{"buffer":19}],16:[function(require,module,exports){ +'use strict' + +exports.byteLength = byteLength +exports.toByteArray = toByteArray +exports.fromByteArray = fromByteArray + +var lookup = [] +var revLookup = [] +var Arr = typeof Uint8Array !== 'undefined' ? Uint8Array : Array + +var code = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/' +for (var i = 0, len = code.length; i < len; ++i) { + lookup[i] = code[i] + revLookup[code.charCodeAt(i)] = i +} + +// Support decoding URL-safe base64 strings, as Node.js does. +// See: https://en.wikipedia.org/wiki/Base64#URL_applications +revLookup['-'.charCodeAt(0)] = 62 +revLookup['_'.charCodeAt(0)] = 63 + +function getLens (b64) { + var len = b64.length + + if (len % 4 > 0) { + throw new Error('Invalid string. Length must be a multiple of 4') + } + + // Trim off extra bytes after placeholder bytes are found + // See: https://github.com/beatgammit/base64-js/issues/42 + var validLen = b64.indexOf('=') + if (validLen === -1) validLen = len + + var placeHoldersLen = validLen === len + ? 0 + : 4 - (validLen % 4) + + return [validLen, placeHoldersLen] +} + +// base64 is 4/3 + up to two characters of the original data +function byteLength (b64) { + var lens = getLens(b64) + var validLen = lens[0] + var placeHoldersLen = lens[1] + return ((validLen + placeHoldersLen) * 3 / 4) - placeHoldersLen +} + +function _byteLength (b64, validLen, placeHoldersLen) { + return ((validLen + placeHoldersLen) * 3 / 4) - placeHoldersLen +} + +function toByteArray (b64) { + var tmp + var lens = getLens(b64) + var validLen = lens[0] + var placeHoldersLen = lens[1] + + var arr = new Arr(_byteLength(b64, validLen, placeHoldersLen)) + + var curByte = 0 + + // if there are placeholders, only get up to the last complete 4 chars + var len = placeHoldersLen > 0 + ? validLen - 4 + : validLen + + var i + for (i = 0; i < len; i += 4) { + tmp = + (revLookup[b64.charCodeAt(i)] << 18) | + (revLookup[b64.charCodeAt(i + 1)] << 12) | + (revLookup[b64.charCodeAt(i + 2)] << 6) | + revLookup[b64.charCodeAt(i + 3)] + arr[curByte++] = (tmp >> 16) & 0xFF + arr[curByte++] = (tmp >> 8) & 0xFF + arr[curByte++] = tmp & 0xFF + } + + if (placeHoldersLen === 2) { + tmp = + (revLookup[b64.charCodeAt(i)] << 2) | + (revLookup[b64.charCodeAt(i + 1)] >> 4) + arr[curByte++] = tmp & 0xFF + } + + if (placeHoldersLen === 1) { + tmp = + (revLookup[b64.charCodeAt(i)] << 10) | + (revLookup[b64.charCodeAt(i + 1)] << 4) | + (revLookup[b64.charCodeAt(i + 2)] >> 2) + arr[curByte++] = (tmp >> 8) & 0xFF + arr[curByte++] = tmp & 0xFF + } + + return arr +} + +function tripletToBase64 (num) { + return lookup[num >> 18 & 0x3F] + + lookup[num >> 12 & 0x3F] + + lookup[num >> 6 & 0x3F] + + lookup[num & 0x3F] +} + +function encodeChunk (uint8, start, end) { + var tmp + var output = [] + for (var i = start; i < end; i += 3) { + tmp = + ((uint8[i] << 16) & 0xFF0000) + + ((uint8[i + 1] << 8) & 0xFF00) + + (uint8[i + 2] & 0xFF) + output.push(tripletToBase64(tmp)) + } + return output.join('') +} + +function fromByteArray (uint8) { + var tmp + var len = uint8.length + var extraBytes = len % 3 // if we have 1 byte left, pad 2 bytes + var parts = [] + var maxChunkLength = 16383 // must be multiple of 3 + + // go through the array every three bytes, we'll deal with trailing stuff later + for (var i = 0, len2 = len - extraBytes; i < len2; i += maxChunkLength) { + parts.push(encodeChunk(uint8, i, (i + maxChunkLength) > len2 ? len2 : (i + maxChunkLength))) + } + + // pad the end with zeros, but make sure to not forget the extra bytes + if (extraBytes === 1) { + tmp = uint8[len - 1] + parts.push( + lookup[tmp >> 2] + + lookup[(tmp << 4) & 0x3F] + + '==' + ) + } else if (extraBytes === 2) { + tmp = (uint8[len - 2] << 8) + uint8[len - 1] + parts.push( + lookup[tmp >> 10] + + lookup[(tmp >> 4) & 0x3F] + + lookup[(tmp << 2) & 0x3F] + + '=' + ) + } + + return parts.join('') +} + +},{}],17:[function(require,module,exports){ +(function (module, exports) { + 'use strict'; + + // Utils + function assert (val, msg) { + if (!val) throw new Error(msg || 'Assertion failed'); + } + + // Could use `inherits` module, but don't want to move from single file + // architecture yet. + function inherits (ctor, superCtor) { + ctor.super_ = superCtor; + var TempCtor = function () {}; + TempCtor.prototype = superCtor.prototype; + ctor.prototype = new TempCtor(); + ctor.prototype.constructor = ctor; + } + + // BN + + function BN (number, base, endian) { + if (BN.isBN(number)) { + return number; + } + + this.negative = 0; + this.words = null; + this.length = 0; + + // Reduction context + this.red = null; + + if (number !== null) { + if (base === 'le' || base === 'be') { + endian = base; + base = 10; + } + + this._init(number || 0, base || 10, endian || 'be'); + } + } + if (typeof module === 'object') { + module.exports = BN; + } else { + exports.BN = BN; + } + + BN.BN = BN; + BN.wordSize = 26; + + var Buffer; + try { + if (typeof window !== 'undefined' && typeof window.Buffer !== 'undefined') { + Buffer = window.Buffer; + } else { + Buffer = require('buffer').Buffer; + } + } catch (e) { + } + + BN.isBN = function isBN (num) { + if (num instanceof BN) { + return true; + } + + return num !== null && typeof num === 'object' && + num.constructor.wordSize === BN.wordSize && Array.isArray(num.words); + }; + + BN.max = function max (left, right) { + if (left.cmp(right) > 0) return left; + return right; + }; + + BN.min = function min (left, right) { + if (left.cmp(right) < 0) return left; + return right; + }; + + BN.prototype._init = function init (number, base, endian) { + if (typeof number === 'number') { + return this._initNumber(number, base, endian); + } + + if (typeof number === 'object') { + return this._initArray(number, base, endian); + } + + if (base === 'hex') { + base = 16; + } + assert(base === (base | 0) && base >= 2 && base <= 36); + + number = number.toString().replace(/\s+/g, ''); + var start = 0; + if (number[0] === '-') { + start++; + this.negative = 1; + } + + if (start < number.length) { + if (base === 16) { + this._parseHex(number, start, endian); + } else { + this._parseBase(number, base, start); + if (endian === 'le') { + this._initArray(this.toArray(), base, endian); + } + } + } + }; + + BN.prototype._initNumber = function _initNumber (number, base, endian) { + if (number < 0) { + this.negative = 1; + number = -number; + } + if (number < 0x4000000) { + this.words = [number & 0x3ffffff]; + this.length = 1; + } else if (number < 0x10000000000000) { + this.words = [ + number & 0x3ffffff, + (number / 0x4000000) & 0x3ffffff + ]; + this.length = 2; + } else { + assert(number < 0x20000000000000); // 2 ^ 53 (unsafe) + this.words = [ + number & 0x3ffffff, + (number / 0x4000000) & 0x3ffffff, + 1 + ]; + this.length = 3; + } + + if (endian !== 'le') return; + + // Reverse the bytes + this._initArray(this.toArray(), base, endian); + }; + + BN.prototype._initArray = function _initArray (number, base, endian) { + // Perhaps a Uint8Array + assert(typeof number.length === 'number'); + if (number.length <= 0) { + this.words = [0]; + this.length = 1; + return this; + } + + this.length = Math.ceil(number.length / 3); + this.words = new Array(this.length); + for (var i = 0; i < this.length; i++) { + this.words[i] = 0; + } + + var j, w; + var off = 0; + if (endian === 'be') { + for (i = number.length - 1, j = 0; i >= 0; i -= 3) { + w = number[i] | (number[i - 1] << 8) | (number[i - 2] << 16); + this.words[j] |= (w << off) & 0x3ffffff; + this.words[j + 1] = (w >>> (26 - off)) & 0x3ffffff; + off += 24; + if (off >= 26) { + off -= 26; + j++; + } + } + } else if (endian === 'le') { + for (i = 0, j = 0; i < number.length; i += 3) { + w = number[i] | (number[i + 1] << 8) | (number[i + 2] << 16); + this.words[j] |= (w << off) & 0x3ffffff; + this.words[j + 1] = (w >>> (26 - off)) & 0x3ffffff; + off += 24; + if (off >= 26) { + off -= 26; + j++; + } + } + } + return this._strip(); + }; + + function parseHex4Bits (string, index) { + var c = string.charCodeAt(index); + // '0' - '9' + if (c >= 48 && c <= 57) { + return c - 48; + // 'A' - 'F' + } else if (c >= 65 && c <= 70) { + return c - 55; + // 'a' - 'f' + } else if (c >= 97 && c <= 102) { + return c - 87; + } else { + assert(false, 'Invalid character in ' + string); + } + } + + function parseHexByte (string, lowerBound, index) { + var r = parseHex4Bits(string, index); + if (index - 1 >= lowerBound) { + r |= parseHex4Bits(string, index - 1) << 4; + } + return r; + } + + BN.prototype._parseHex = function _parseHex (number, start, endian) { + // Create possibly bigger array to ensure that it fits the number + this.length = Math.ceil((number.length - start) / 6); + this.words = new Array(this.length); + for (var i = 0; i < this.length; i++) { + this.words[i] = 0; + } + + // 24-bits chunks + var off = 0; + var j = 0; + + var w; + if (endian === 'be') { + for (i = number.length - 1; i >= start; i -= 2) { + w = parseHexByte(number, start, i) << off; + this.words[j] |= w & 0x3ffffff; + if (off >= 18) { + off -= 18; + j += 1; + this.words[j] |= w >>> 26; + } else { + off += 8; + } + } + } else { + var parseLength = number.length - start; + for (i = parseLength % 2 === 0 ? start + 1 : start; i < number.length; i += 2) { + w = parseHexByte(number, start, i) << off; + this.words[j] |= w & 0x3ffffff; + if (off >= 18) { + off -= 18; + j += 1; + this.words[j] |= w >>> 26; + } else { + off += 8; + } + } + } + + this._strip(); + }; + + function parseBase (str, start, end, mul) { + var r = 0; + var b = 0; + var len = Math.min(str.length, end); + for (var i = start; i < len; i++) { + var c = str.charCodeAt(i) - 48; + + r *= mul; + + // 'a' + if (c >= 49) { + b = c - 49 + 0xa; + + // 'A' + } else if (c >= 17) { + b = c - 17 + 0xa; + + // '0' - '9' + } else { + b = c; + } + assert(c >= 0 && b < mul, 'Invalid character'); + r += b; + } + return r; + } + + BN.prototype._parseBase = function _parseBase (number, base, start) { + // Initialize as zero + this.words = [0]; + this.length = 1; + + // Find length of limb in base + for (var limbLen = 0, limbPow = 1; limbPow <= 0x3ffffff; limbPow *= base) { + limbLen++; + } + limbLen--; + limbPow = (limbPow / base) | 0; + + var total = number.length - start; + var mod = total % limbLen; + var end = Math.min(total, total - mod) + start; + + var word = 0; + for (var i = start; i < end; i += limbLen) { + word = parseBase(number, i, i + limbLen, base); + + this.imuln(limbPow); + if (this.words[0] + word < 0x4000000) { + this.words[0] += word; + } else { + this._iaddn(word); + } + } + + if (mod !== 0) { + var pow = 1; + word = parseBase(number, i, number.length, base); + + for (i = 0; i < mod; i++) { + pow *= base; + } + + this.imuln(pow); + if (this.words[0] + word < 0x4000000) { + this.words[0] += word; + } else { + this._iaddn(word); + } + } + + this._strip(); + }; + + BN.prototype.copy = function copy (dest) { + dest.words = new Array(this.length); + for (var i = 0; i < this.length; i++) { + dest.words[i] = this.words[i]; + } + dest.length = this.length; + dest.negative = this.negative; + dest.red = this.red; + }; + + function move (dest, src) { + dest.words = src.words; + dest.length = src.length; + dest.negative = src.negative; + dest.red = src.red; + } + + BN.prototype._move = function _move (dest) { + move(dest, this); + }; + + BN.prototype.clone = function clone () { + var r = new BN(null); + this.copy(r); + return r; + }; + + BN.prototype._expand = function _expand (size) { + while (this.length < size) { + this.words[this.length++] = 0; + } + return this; + }; + + // Remove leading `0` from `this` + BN.prototype._strip = function strip () { + while (this.length > 1 && this.words[this.length - 1] === 0) { + this.length--; + } + return this._normSign(); + }; + + BN.prototype._normSign = function _normSign () { + // -0 = 0 + if (this.length === 1 && this.words[0] === 0) { + this.negative = 0; + } + return this; + }; + + // Check Symbol.for because not everywhere where Symbol defined + // See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Symbol#Browser_compatibility + if (typeof Symbol !== 'undefined' && typeof Symbol.for === 'function') { + try { + BN.prototype[Symbol.for('nodejs.util.inspect.custom')] = inspect; + } catch (e) { + BN.prototype.inspect = inspect; + } + } else { + BN.prototype.inspect = inspect; + } + + function inspect () { + return (this.red ? ''; + } + + /* + + var zeros = []; + var groupSizes = []; + var groupBases = []; + + var s = ''; + var i = -1; + while (++i < BN.wordSize) { + zeros[i] = s; + s += '0'; + } + groupSizes[0] = 0; + groupSizes[1] = 0; + groupBases[0] = 0; + groupBases[1] = 0; + var base = 2 - 1; + while (++base < 36 + 1) { + var groupSize = 0; + var groupBase = 1; + while (groupBase < (1 << BN.wordSize) / base) { + groupBase *= base; + groupSize += 1; + } + groupSizes[base] = groupSize; + groupBases[base] = groupBase; + } + + */ + + var zeros = [ + '', + '0', + '00', + '000', + '0000', + '00000', + '000000', + '0000000', + '00000000', + '000000000', + '0000000000', + '00000000000', + '000000000000', + '0000000000000', + '00000000000000', + '000000000000000', + '0000000000000000', + '00000000000000000', + '000000000000000000', + '0000000000000000000', + '00000000000000000000', + '000000000000000000000', + '0000000000000000000000', + '00000000000000000000000', + '000000000000000000000000', + '0000000000000000000000000' + ]; + + var groupSizes = [ + 0, 0, + 25, 16, 12, 11, 10, 9, 8, + 8, 7, 7, 7, 7, 6, 6, + 6, 6, 6, 6, 6, 5, 5, + 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5 + ]; + + var groupBases = [ + 0, 0, + 33554432, 43046721, 16777216, 48828125, 60466176, 40353607, 16777216, + 43046721, 10000000, 19487171, 35831808, 62748517, 7529536, 11390625, + 16777216, 24137569, 34012224, 47045881, 64000000, 4084101, 5153632, + 6436343, 7962624, 9765625, 11881376, 14348907, 17210368, 20511149, + 24300000, 28629151, 33554432, 39135393, 45435424, 52521875, 60466176 + ]; + + BN.prototype.toString = function toString (base, padding) { + base = base || 10; + padding = padding | 0 || 1; + + var out; + if (base === 16 || base === 'hex') { + out = ''; + var off = 0; + var carry = 0; + for (var i = 0; i < this.length; i++) { + var w = this.words[i]; + var word = (((w << off) | carry) & 0xffffff).toString(16); + carry = (w >>> (24 - off)) & 0xffffff; + if (carry !== 0 || i !== this.length - 1) { + out = zeros[6 - word.length] + word + out; + } else { + out = word + out; + } + off += 2; + if (off >= 26) { + off -= 26; + i--; + } + } + if (carry !== 0) { + out = carry.toString(16) + out; + } + while (out.length % padding !== 0) { + out = '0' + out; + } + if (this.negative !== 0) { + out = '-' + out; + } + return out; + } + + if (base === (base | 0) && base >= 2 && base <= 36) { + // var groupSize = Math.floor(BN.wordSize * Math.LN2 / Math.log(base)); + var groupSize = groupSizes[base]; + // var groupBase = Math.pow(base, groupSize); + var groupBase = groupBases[base]; + out = ''; + var c = this.clone(); + c.negative = 0; + while (!c.isZero()) { + var r = c.modrn(groupBase).toString(base); + c = c.idivn(groupBase); + + if (!c.isZero()) { + out = zeros[groupSize - r.length] + r + out; + } else { + out = r + out; + } + } + if (this.isZero()) { + out = '0' + out; + } + while (out.length % padding !== 0) { + out = '0' + out; + } + if (this.negative !== 0) { + out = '-' + out; + } + return out; + } + + assert(false, 'Base should be between 2 and 36'); + }; + + BN.prototype.toNumber = function toNumber () { + var ret = this.words[0]; + if (this.length === 2) { + ret += this.words[1] * 0x4000000; + } else if (this.length === 3 && this.words[2] === 0x01) { + // NOTE: at this stage it is known that the top bit is set + ret += 0x10000000000000 + (this.words[1] * 0x4000000); + } else if (this.length > 2) { + assert(false, 'Number can only safely store up to 53 bits'); + } + return (this.negative !== 0) ? -ret : ret; + }; + + BN.prototype.toJSON = function toJSON () { + return this.toString(16, 2); + }; + + if (Buffer) { + BN.prototype.toBuffer = function toBuffer (endian, length) { + return this.toArrayLike(Buffer, endian, length); + }; + } + + BN.prototype.toArray = function toArray (endian, length) { + return this.toArrayLike(Array, endian, length); + }; + + var allocate = function allocate (ArrayType, size) { + if (ArrayType.allocUnsafe) { + return ArrayType.allocUnsafe(size); + } + return new ArrayType(size); + }; + + BN.prototype.toArrayLike = function toArrayLike (ArrayType, endian, length) { + this._strip(); + + var byteLength = this.byteLength(); + var reqLength = length || Math.max(1, byteLength); + assert(byteLength <= reqLength, 'byte array longer than desired length'); + assert(reqLength > 0, 'Requested array length <= 0'); + + var res = allocate(ArrayType, reqLength); + var postfix = endian === 'le' ? 'LE' : 'BE'; + this['_toArrayLike' + postfix](res, byteLength); + return res; + }; + + BN.prototype._toArrayLikeLE = function _toArrayLikeLE (res, byteLength) { + var position = 0; + var carry = 0; + + for (var i = 0, shift = 0; i < this.length; i++) { + var word = (this.words[i] << shift) | carry; + + res[position++] = word & 0xff; + if (position < res.length) { + res[position++] = (word >> 8) & 0xff; + } + if (position < res.length) { + res[position++] = (word >> 16) & 0xff; + } + + if (shift === 6) { + if (position < res.length) { + res[position++] = (word >> 24) & 0xff; + } + carry = 0; + shift = 0; + } else { + carry = word >>> 24; + shift += 2; + } + } + + if (position < res.length) { + res[position++] = carry; + + while (position < res.length) { + res[position++] = 0; + } + } + }; + + BN.prototype._toArrayLikeBE = function _toArrayLikeBE (res, byteLength) { + var position = res.length - 1; + var carry = 0; + + for (var i = 0, shift = 0; i < this.length; i++) { + var word = (this.words[i] << shift) | carry; + + res[position--] = word & 0xff; + if (position >= 0) { + res[position--] = (word >> 8) & 0xff; + } + if (position >= 0) { + res[position--] = (word >> 16) & 0xff; + } + + if (shift === 6) { + if (position >= 0) { + res[position--] = (word >> 24) & 0xff; + } + carry = 0; + shift = 0; + } else { + carry = word >>> 24; + shift += 2; + } + } + + if (position >= 0) { + res[position--] = carry; + + while (position >= 0) { + res[position--] = 0; + } + } + }; + + if (Math.clz32) { + BN.prototype._countBits = function _countBits (w) { + return 32 - Math.clz32(w); + }; + } else { + BN.prototype._countBits = function _countBits (w) { + var t = w; + var r = 0; + if (t >= 0x1000) { + r += 13; + t >>>= 13; + } + if (t >= 0x40) { + r += 7; + t >>>= 7; + } + if (t >= 0x8) { + r += 4; + t >>>= 4; + } + if (t >= 0x02) { + r += 2; + t >>>= 2; + } + return r + t; + }; + } + + BN.prototype._zeroBits = function _zeroBits (w) { + // Short-cut + if (w === 0) return 26; + + var t = w; + var r = 0; + if ((t & 0x1fff) === 0) { + r += 13; + t >>>= 13; + } + if ((t & 0x7f) === 0) { + r += 7; + t >>>= 7; + } + if ((t & 0xf) === 0) { + r += 4; + t >>>= 4; + } + if ((t & 0x3) === 0) { + r += 2; + t >>>= 2; + } + if ((t & 0x1) === 0) { + r++; + } + return r; + }; + + // Return number of used bits in a BN + BN.prototype.bitLength = function bitLength () { + var w = this.words[this.length - 1]; + var hi = this._countBits(w); + return (this.length - 1) * 26 + hi; + }; + + function toBitArray (num) { + var w = new Array(num.bitLength()); + + for (var bit = 0; bit < w.length; bit++) { + var off = (bit / 26) | 0; + var wbit = bit % 26; + + w[bit] = (num.words[off] >>> wbit) & 0x01; + } + + return w; + } + + // Number of trailing zero bits + BN.prototype.zeroBits = function zeroBits () { + if (this.isZero()) return 0; + + var r = 0; + for (var i = 0; i < this.length; i++) { + var b = this._zeroBits(this.words[i]); + r += b; + if (b !== 26) break; + } + return r; + }; + + BN.prototype.byteLength = function byteLength () { + return Math.ceil(this.bitLength() / 8); + }; + + BN.prototype.toTwos = function toTwos (width) { + if (this.negative !== 0) { + return this.abs().inotn(width).iaddn(1); + } + return this.clone(); + }; + + BN.prototype.fromTwos = function fromTwos (width) { + if (this.testn(width - 1)) { + return this.notn(width).iaddn(1).ineg(); + } + return this.clone(); + }; + + BN.prototype.isNeg = function isNeg () { + return this.negative !== 0; + }; + + // Return negative clone of `this` + BN.prototype.neg = function neg () { + return this.clone().ineg(); + }; + + BN.prototype.ineg = function ineg () { + if (!this.isZero()) { + this.negative ^= 1; + } + + return this; + }; + + // Or `num` with `this` in-place + BN.prototype.iuor = function iuor (num) { + while (this.length < num.length) { + this.words[this.length++] = 0; + } + + for (var i = 0; i < num.length; i++) { + this.words[i] = this.words[i] | num.words[i]; + } + + return this._strip(); + }; + + BN.prototype.ior = function ior (num) { + assert((this.negative | num.negative) === 0); + return this.iuor(num); + }; + + // Or `num` with `this` + BN.prototype.or = function or (num) { + if (this.length > num.length) return this.clone().ior(num); + return num.clone().ior(this); + }; + + BN.prototype.uor = function uor (num) { + if (this.length > num.length) return this.clone().iuor(num); + return num.clone().iuor(this); + }; + + // And `num` with `this` in-place + BN.prototype.iuand = function iuand (num) { + // b = min-length(num, this) + var b; + if (this.length > num.length) { + b = num; + } else { + b = this; + } + + for (var i = 0; i < b.length; i++) { + this.words[i] = this.words[i] & num.words[i]; + } + + this.length = b.length; + + return this._strip(); + }; + + BN.prototype.iand = function iand (num) { + assert((this.negative | num.negative) === 0); + return this.iuand(num); + }; + + // And `num` with `this` + BN.prototype.and = function and (num) { + if (this.length > num.length) return this.clone().iand(num); + return num.clone().iand(this); + }; + + BN.prototype.uand = function uand (num) { + if (this.length > num.length) return this.clone().iuand(num); + return num.clone().iuand(this); + }; + + // Xor `num` with `this` in-place + BN.prototype.iuxor = function iuxor (num) { + // a.length > b.length + var a; + var b; + if (this.length > num.length) { + a = this; + b = num; + } else { + a = num; + b = this; + } + + for (var i = 0; i < b.length; i++) { + this.words[i] = a.words[i] ^ b.words[i]; + } + + if (this !== a) { + for (; i < a.length; i++) { + this.words[i] = a.words[i]; + } + } + + this.length = a.length; + + return this._strip(); + }; + + BN.prototype.ixor = function ixor (num) { + assert((this.negative | num.negative) === 0); + return this.iuxor(num); + }; + + // Xor `num` with `this` + BN.prototype.xor = function xor (num) { + if (this.length > num.length) return this.clone().ixor(num); + return num.clone().ixor(this); + }; + + BN.prototype.uxor = function uxor (num) { + if (this.length > num.length) return this.clone().iuxor(num); + return num.clone().iuxor(this); + }; + + // Not ``this`` with ``width`` bitwidth + BN.prototype.inotn = function inotn (width) { + assert(typeof width === 'number' && width >= 0); + + var bytesNeeded = Math.ceil(width / 26) | 0; + var bitsLeft = width % 26; + + // Extend the buffer with leading zeroes + this._expand(bytesNeeded); + + if (bitsLeft > 0) { + bytesNeeded--; + } + + // Handle complete words + for (var i = 0; i < bytesNeeded; i++) { + this.words[i] = ~this.words[i] & 0x3ffffff; + } + + // Handle the residue + if (bitsLeft > 0) { + this.words[i] = ~this.words[i] & (0x3ffffff >> (26 - bitsLeft)); + } + + // And remove leading zeroes + return this._strip(); + }; + + BN.prototype.notn = function notn (width) { + return this.clone().inotn(width); + }; + + // Set `bit` of `this` + BN.prototype.setn = function setn (bit, val) { + assert(typeof bit === 'number' && bit >= 0); + + var off = (bit / 26) | 0; + var wbit = bit % 26; + + this._expand(off + 1); + + if (val) { + this.words[off] = this.words[off] | (1 << wbit); + } else { + this.words[off] = this.words[off] & ~(1 << wbit); + } + + return this._strip(); + }; + + // Add `num` to `this` in-place + BN.prototype.iadd = function iadd (num) { + var r; + + // negative + positive + if (this.negative !== 0 && num.negative === 0) { + this.negative = 0; + r = this.isub(num); + this.negative ^= 1; + return this._normSign(); + + // positive + negative + } else if (this.negative === 0 && num.negative !== 0) { + num.negative = 0; + r = this.isub(num); + num.negative = 1; + return r._normSign(); + } + + // a.length > b.length + var a, b; + if (this.length > num.length) { + a = this; + b = num; + } else { + a = num; + b = this; + } + + var carry = 0; + for (var i = 0; i < b.length; i++) { + r = (a.words[i] | 0) + (b.words[i] | 0) + carry; + this.words[i] = r & 0x3ffffff; + carry = r >>> 26; + } + for (; carry !== 0 && i < a.length; i++) { + r = (a.words[i] | 0) + carry; + this.words[i] = r & 0x3ffffff; + carry = r >>> 26; + } + + this.length = a.length; + if (carry !== 0) { + this.words[this.length] = carry; + this.length++; + // Copy the rest of the words + } else if (a !== this) { + for (; i < a.length; i++) { + this.words[i] = a.words[i]; + } + } + + return this; + }; + + // Add `num` to `this` + BN.prototype.add = function add (num) { + var res; + if (num.negative !== 0 && this.negative === 0) { + num.negative = 0; + res = this.sub(num); + num.negative ^= 1; + return res; + } else if (num.negative === 0 && this.negative !== 0) { + this.negative = 0; + res = num.sub(this); + this.negative = 1; + return res; + } + + if (this.length > num.length) return this.clone().iadd(num); + + return num.clone().iadd(this); + }; + + // Subtract `num` from `this` in-place + BN.prototype.isub = function isub (num) { + // this - (-num) = this + num + if (num.negative !== 0) { + num.negative = 0; + var r = this.iadd(num); + num.negative = 1; + return r._normSign(); + + // -this - num = -(this + num) + } else if (this.negative !== 0) { + this.negative = 0; + this.iadd(num); + this.negative = 1; + return this._normSign(); + } + + // At this point both numbers are positive + var cmp = this.cmp(num); + + // Optimization - zeroify + if (cmp === 0) { + this.negative = 0; + this.length = 1; + this.words[0] = 0; + return this; + } + + // a > b + var a, b; + if (cmp > 0) { + a = this; + b = num; + } else { + a = num; + b = this; + } + + var carry = 0; + for (var i = 0; i < b.length; i++) { + r = (a.words[i] | 0) - (b.words[i] | 0) + carry; + carry = r >> 26; + this.words[i] = r & 0x3ffffff; + } + for (; carry !== 0 && i < a.length; i++) { + r = (a.words[i] | 0) + carry; + carry = r >> 26; + this.words[i] = r & 0x3ffffff; + } + + // Copy rest of the words + if (carry === 0 && i < a.length && a !== this) { + for (; i < a.length; i++) { + this.words[i] = a.words[i]; + } + } + + this.length = Math.max(this.length, i); + + if (a !== this) { + this.negative = 1; + } + + return this._strip(); + }; + + // Subtract `num` from `this` + BN.prototype.sub = function sub (num) { + return this.clone().isub(num); + }; + + function smallMulTo (self, num, out) { + out.negative = num.negative ^ self.negative; + var len = (self.length + num.length) | 0; + out.length = len; + len = (len - 1) | 0; + + // Peel one iteration (compiler can't do it, because of code complexity) + var a = self.words[0] | 0; + var b = num.words[0] | 0; + var r = a * b; + + var lo = r & 0x3ffffff; + var carry = (r / 0x4000000) | 0; + out.words[0] = lo; + + for (var k = 1; k < len; k++) { + // Sum all words with the same `i + j = k` and accumulate `ncarry`, + // note that ncarry could be >= 0x3ffffff + var ncarry = carry >>> 26; + var rword = carry & 0x3ffffff; + var maxJ = Math.min(k, num.length - 1); + for (var j = Math.max(0, k - self.length + 1); j <= maxJ; j++) { + var i = (k - j) | 0; + a = self.words[i] | 0; + b = num.words[j] | 0; + r = a * b + rword; + ncarry += (r / 0x4000000) | 0; + rword = r & 0x3ffffff; + } + out.words[k] = rword | 0; + carry = ncarry | 0; + } + if (carry !== 0) { + out.words[k] = carry | 0; + } else { + out.length--; + } + + return out._strip(); + } + + // TODO(indutny): it may be reasonable to omit it for users who don't need + // to work with 256-bit numbers, otherwise it gives 20% improvement for 256-bit + // multiplication (like elliptic secp256k1). + var comb10MulTo = function comb10MulTo (self, num, out) { + var a = self.words; + var b = num.words; + var o = out.words; + var c = 0; + var lo; + var mid; + var hi; + var a0 = a[0] | 0; + var al0 = a0 & 0x1fff; + var ah0 = a0 >>> 13; + var a1 = a[1] | 0; + var al1 = a1 & 0x1fff; + var ah1 = a1 >>> 13; + var a2 = a[2] | 0; + var al2 = a2 & 0x1fff; + var ah2 = a2 >>> 13; + var a3 = a[3] | 0; + var al3 = a3 & 0x1fff; + var ah3 = a3 >>> 13; + var a4 = a[4] | 0; + var al4 = a4 & 0x1fff; + var ah4 = a4 >>> 13; + var a5 = a[5] | 0; + var al5 = a5 & 0x1fff; + var ah5 = a5 >>> 13; + var a6 = a[6] | 0; + var al6 = a6 & 0x1fff; + var ah6 = a6 >>> 13; + var a7 = a[7] | 0; + var al7 = a7 & 0x1fff; + var ah7 = a7 >>> 13; + var a8 = a[8] | 0; + var al8 = a8 & 0x1fff; + var ah8 = a8 >>> 13; + var a9 = a[9] | 0; + var al9 = a9 & 0x1fff; + var ah9 = a9 >>> 13; + var b0 = b[0] | 0; + var bl0 = b0 & 0x1fff; + var bh0 = b0 >>> 13; + var b1 = b[1] | 0; + var bl1 = b1 & 0x1fff; + var bh1 = b1 >>> 13; + var b2 = b[2] | 0; + var bl2 = b2 & 0x1fff; + var bh2 = b2 >>> 13; + var b3 = b[3] | 0; + var bl3 = b3 & 0x1fff; + var bh3 = b3 >>> 13; + var b4 = b[4] | 0; + var bl4 = b4 & 0x1fff; + var bh4 = b4 >>> 13; + var b5 = b[5] | 0; + var bl5 = b5 & 0x1fff; + var bh5 = b5 >>> 13; + var b6 = b[6] | 0; + var bl6 = b6 & 0x1fff; + var bh6 = b6 >>> 13; + var b7 = b[7] | 0; + var bl7 = b7 & 0x1fff; + var bh7 = b7 >>> 13; + var b8 = b[8] | 0; + var bl8 = b8 & 0x1fff; + var bh8 = b8 >>> 13; + var b9 = b[9] | 0; + var bl9 = b9 & 0x1fff; + var bh9 = b9 >>> 13; + + out.negative = self.negative ^ num.negative; + out.length = 19; + /* k = 0 */ + lo = Math.imul(al0, bl0); + mid = Math.imul(al0, bh0); + mid = (mid + Math.imul(ah0, bl0)) | 0; + hi = Math.imul(ah0, bh0); + var w0 = (((c + lo) | 0) + ((mid & 0x1fff) << 13)) | 0; + c = (((hi + (mid >>> 13)) | 0) + (w0 >>> 26)) | 0; + w0 &= 0x3ffffff; + /* k = 1 */ + lo = Math.imul(al1, bl0); + mid = Math.imul(al1, bh0); + mid = (mid + Math.imul(ah1, bl0)) | 0; + hi = Math.imul(ah1, bh0); + lo = (lo + Math.imul(al0, bl1)) | 0; + mid = (mid + Math.imul(al0, bh1)) | 0; + mid = (mid + Math.imul(ah0, bl1)) | 0; + hi = (hi + Math.imul(ah0, bh1)) | 0; + var w1 = (((c + lo) | 0) + ((mid & 0x1fff) << 13)) | 0; + c = (((hi + (mid >>> 13)) | 0) + (w1 >>> 26)) | 0; + w1 &= 0x3ffffff; + /* k = 2 */ + lo = Math.imul(al2, bl0); + mid = Math.imul(al2, bh0); + mid = (mid + Math.imul(ah2, bl0)) | 0; + hi = Math.imul(ah2, bh0); + lo = (lo + Math.imul(al1, bl1)) | 0; + mid = (mid + Math.imul(al1, bh1)) | 0; + mid = (mid + Math.imul(ah1, bl1)) | 0; + hi = (hi + Math.imul(ah1, bh1)) | 0; + lo = (lo + Math.imul(al0, bl2)) | 0; + mid = (mid + Math.imul(al0, bh2)) | 0; + mid = (mid + Math.imul(ah0, bl2)) | 0; + hi = (hi + Math.imul(ah0, bh2)) | 0; + var w2 = (((c + lo) | 0) + ((mid & 0x1fff) << 13)) | 0; + c = (((hi + (mid >>> 13)) | 0) + (w2 >>> 26)) | 0; + w2 &= 0x3ffffff; + /* k = 3 */ + lo = Math.imul(al3, bl0); + mid = Math.imul(al3, bh0); + mid = (mid + Math.imul(ah3, bl0)) | 0; + hi = Math.imul(ah3, bh0); + lo = (lo + Math.imul(al2, bl1)) | 0; + mid = (mid + Math.imul(al2, bh1)) | 0; + mid = (mid + Math.imul(ah2, bl1)) | 0; + hi = (hi + Math.imul(ah2, bh1)) | 0; + lo = (lo + Math.imul(al1, bl2)) | 0; + mid = (mid + Math.imul(al1, bh2)) | 0; + mid = (mid + Math.imul(ah1, bl2)) | 0; + hi = (hi + Math.imul(ah1, bh2)) | 0; + lo = (lo + Math.imul(al0, bl3)) | 0; + mid = (mid + Math.imul(al0, bh3)) | 0; + mid = (mid + Math.imul(ah0, bl3)) | 0; + hi = (hi + Math.imul(ah0, bh3)) | 0; + var w3 = (((c + lo) | 0) + ((mid & 0x1fff) << 13)) | 0; + c = (((hi + (mid >>> 13)) | 0) + (w3 >>> 26)) | 0; + w3 &= 0x3ffffff; + /* k = 4 */ + lo = Math.imul(al4, bl0); + mid = Math.imul(al4, bh0); + mid = (mid + Math.imul(ah4, bl0)) | 0; + hi = Math.imul(ah4, bh0); + lo = (lo + Math.imul(al3, bl1)) | 0; + mid = (mid + Math.imul(al3, bh1)) | 0; + mid = (mid + Math.imul(ah3, bl1)) | 0; + hi = (hi + Math.imul(ah3, bh1)) | 0; + lo = (lo + Math.imul(al2, bl2)) | 0; + mid = (mid + Math.imul(al2, bh2)) | 0; + mid = (mid + Math.imul(ah2, bl2)) | 0; + hi = (hi + Math.imul(ah2, bh2)) | 0; + lo = (lo + Math.imul(al1, bl3)) | 0; + mid = (mid + Math.imul(al1, bh3)) | 0; + mid = (mid + Math.imul(ah1, bl3)) | 0; + hi = (hi + Math.imul(ah1, bh3)) | 0; + lo = (lo + Math.imul(al0, bl4)) | 0; + mid = (mid + Math.imul(al0, bh4)) | 0; + mid = (mid + Math.imul(ah0, bl4)) | 0; + hi = (hi + Math.imul(ah0, bh4)) | 0; + var w4 = (((c + lo) | 0) + ((mid & 0x1fff) << 13)) | 0; + c = (((hi + (mid >>> 13)) | 0) + (w4 >>> 26)) | 0; + w4 &= 0x3ffffff; + /* k = 5 */ + lo = Math.imul(al5, bl0); + mid = Math.imul(al5, bh0); + mid = (mid + Math.imul(ah5, bl0)) | 0; + hi = Math.imul(ah5, bh0); + lo = (lo + Math.imul(al4, bl1)) | 0; + mid = (mid + Math.imul(al4, bh1)) | 0; + mid = (mid + Math.imul(ah4, bl1)) | 0; + hi = (hi + Math.imul(ah4, bh1)) | 0; + lo = (lo + Math.imul(al3, bl2)) | 0; + mid = (mid + Math.imul(al3, bh2)) | 0; + mid = (mid + Math.imul(ah3, bl2)) | 0; + hi = (hi + Math.imul(ah3, bh2)) | 0; + lo = (lo + Math.imul(al2, bl3)) | 0; + mid = (mid + Math.imul(al2, bh3)) | 0; + mid = (mid + Math.imul(ah2, bl3)) | 0; + hi = (hi + Math.imul(ah2, bh3)) | 0; + lo = (lo + Math.imul(al1, bl4)) | 0; + mid = (mid + Math.imul(al1, bh4)) | 0; + mid = (mid + Math.imul(ah1, bl4)) | 0; + hi = (hi + Math.imul(ah1, bh4)) | 0; + lo = (lo + Math.imul(al0, bl5)) | 0; + mid = (mid + Math.imul(al0, bh5)) | 0; + mid = (mid + Math.imul(ah0, bl5)) | 0; + hi = (hi + Math.imul(ah0, bh5)) | 0; + var w5 = (((c + lo) | 0) + ((mid & 0x1fff) << 13)) | 0; + c = (((hi + (mid >>> 13)) | 0) + (w5 >>> 26)) | 0; + w5 &= 0x3ffffff; + /* k = 6 */ + lo = Math.imul(al6, bl0); + mid = Math.imul(al6, bh0); + mid = (mid + Math.imul(ah6, bl0)) | 0; + hi = Math.imul(ah6, bh0); + lo = (lo + Math.imul(al5, bl1)) | 0; + mid = (mid + Math.imul(al5, bh1)) | 0; + mid = (mid + Math.imul(ah5, bl1)) | 0; + hi = (hi + Math.imul(ah5, bh1)) | 0; + lo = (lo + Math.imul(al4, bl2)) | 0; + mid = (mid + Math.imul(al4, bh2)) | 0; + mid = (mid + Math.imul(ah4, bl2)) | 0; + hi = (hi + Math.imul(ah4, bh2)) | 0; + lo = (lo + Math.imul(al3, bl3)) | 0; + mid = (mid + Math.imul(al3, bh3)) | 0; + mid = (mid + Math.imul(ah3, bl3)) | 0; + hi = (hi + Math.imul(ah3, bh3)) | 0; + lo = (lo + Math.imul(al2, bl4)) | 0; + mid = (mid + Math.imul(al2, bh4)) | 0; + mid = (mid + Math.imul(ah2, bl4)) | 0; + hi = (hi + Math.imul(ah2, bh4)) | 0; + lo = (lo + Math.imul(al1, bl5)) | 0; + mid = (mid + Math.imul(al1, bh5)) | 0; + mid = (mid + Math.imul(ah1, bl5)) | 0; + hi = (hi + Math.imul(ah1, bh5)) | 0; + lo = (lo + Math.imul(al0, bl6)) | 0; + mid = (mid + Math.imul(al0, bh6)) | 0; + mid = (mid + Math.imul(ah0, bl6)) | 0; + hi = (hi + Math.imul(ah0, bh6)) | 0; + var w6 = (((c + lo) | 0) + ((mid & 0x1fff) << 13)) | 0; + c = (((hi + (mid >>> 13)) | 0) + (w6 >>> 26)) | 0; + w6 &= 0x3ffffff; + /* k = 7 */ + lo = Math.imul(al7, bl0); + mid = Math.imul(al7, bh0); + mid = (mid + Math.imul(ah7, bl0)) | 0; + hi = Math.imul(ah7, bh0); + lo = (lo + Math.imul(al6, bl1)) | 0; + mid = (mid + Math.imul(al6, bh1)) | 0; + mid = (mid + Math.imul(ah6, bl1)) | 0; + hi = (hi + Math.imul(ah6, bh1)) | 0; + lo = (lo + Math.imul(al5, bl2)) | 0; + mid = (mid + Math.imul(al5, bh2)) | 0; + mid = (mid + Math.imul(ah5, bl2)) | 0; + hi = (hi + Math.imul(ah5, bh2)) | 0; + lo = (lo + Math.imul(al4, bl3)) | 0; + mid = (mid + Math.imul(al4, bh3)) | 0; + mid = (mid + Math.imul(ah4, bl3)) | 0; + hi = (hi + Math.imul(ah4, bh3)) | 0; + lo = (lo + Math.imul(al3, bl4)) | 0; + mid = (mid + Math.imul(al3, bh4)) | 0; + mid = (mid + Math.imul(ah3, bl4)) | 0; + hi = (hi + Math.imul(ah3, bh4)) | 0; + lo = (lo + Math.imul(al2, bl5)) | 0; + mid = (mid + Math.imul(al2, bh5)) | 0; + mid = (mid + Math.imul(ah2, bl5)) | 0; + hi = (hi + Math.imul(ah2, bh5)) | 0; + lo = (lo + Math.imul(al1, bl6)) | 0; + mid = (mid + Math.imul(al1, bh6)) | 0; + mid = (mid + Math.imul(ah1, bl6)) | 0; + hi = (hi + Math.imul(ah1, bh6)) | 0; + lo = (lo + Math.imul(al0, bl7)) | 0; + mid = (mid + Math.imul(al0, bh7)) | 0; + mid = (mid + Math.imul(ah0, bl7)) | 0; + hi = (hi + Math.imul(ah0, bh7)) | 0; + var w7 = (((c + lo) | 0) + ((mid & 0x1fff) << 13)) | 0; + c = (((hi + (mid >>> 13)) | 0) + (w7 >>> 26)) | 0; + w7 &= 0x3ffffff; + /* k = 8 */ + lo = Math.imul(al8, bl0); + mid = Math.imul(al8, bh0); + mid = (mid + Math.imul(ah8, bl0)) | 0; + hi = Math.imul(ah8, bh0); + lo = (lo + Math.imul(al7, bl1)) | 0; + mid = (mid + Math.imul(al7, bh1)) | 0; + mid = (mid + Math.imul(ah7, bl1)) | 0; + hi = (hi + Math.imul(ah7, bh1)) | 0; + lo = (lo + Math.imul(al6, bl2)) | 0; + mid = (mid + Math.imul(al6, bh2)) | 0; + mid = (mid + Math.imul(ah6, bl2)) | 0; + hi = (hi + Math.imul(ah6, bh2)) | 0; + lo = (lo + Math.imul(al5, bl3)) | 0; + mid = (mid + Math.imul(al5, bh3)) | 0; + mid = (mid + Math.imul(ah5, bl3)) | 0; + hi = (hi + Math.imul(ah5, bh3)) | 0; + lo = (lo + Math.imul(al4, bl4)) | 0; + mid = (mid + Math.imul(al4, bh4)) | 0; + mid = (mid + Math.imul(ah4, bl4)) | 0; + hi = (hi + Math.imul(ah4, bh4)) | 0; + lo = (lo + Math.imul(al3, bl5)) | 0; + mid = (mid + Math.imul(al3, bh5)) | 0; + mid = (mid + Math.imul(ah3, bl5)) | 0; + hi = (hi + Math.imul(ah3, bh5)) | 0; + lo = (lo + Math.imul(al2, bl6)) | 0; + mid = (mid + Math.imul(al2, bh6)) | 0; + mid = (mid + Math.imul(ah2, bl6)) | 0; + hi = (hi + Math.imul(ah2, bh6)) | 0; + lo = (lo + Math.imul(al1, bl7)) | 0; + mid = (mid + Math.imul(al1, bh7)) | 0; + mid = (mid + Math.imul(ah1, bl7)) | 0; + hi = (hi + Math.imul(ah1, bh7)) | 0; + lo = (lo + Math.imul(al0, bl8)) | 0; + mid = (mid + Math.imul(al0, bh8)) | 0; + mid = (mid + Math.imul(ah0, bl8)) | 0; + hi = (hi + Math.imul(ah0, bh8)) | 0; + var w8 = (((c + lo) | 0) + ((mid & 0x1fff) << 13)) | 0; + c = (((hi + (mid >>> 13)) | 0) + (w8 >>> 26)) | 0; + w8 &= 0x3ffffff; + /* k = 9 */ + lo = Math.imul(al9, bl0); + mid = Math.imul(al9, bh0); + mid = (mid + Math.imul(ah9, bl0)) | 0; + hi = Math.imul(ah9, bh0); + lo = (lo + Math.imul(al8, bl1)) | 0; + mid = (mid + Math.imul(al8, bh1)) | 0; + mid = (mid + Math.imul(ah8, bl1)) | 0; + hi = (hi + Math.imul(ah8, bh1)) | 0; + lo = (lo + Math.imul(al7, bl2)) | 0; + mid = (mid + Math.imul(al7, bh2)) | 0; + mid = (mid + Math.imul(ah7, bl2)) | 0; + hi = (hi + Math.imul(ah7, bh2)) | 0; + lo = (lo + Math.imul(al6, bl3)) | 0; + mid = (mid + Math.imul(al6, bh3)) | 0; + mid = (mid + Math.imul(ah6, bl3)) | 0; + hi = (hi + Math.imul(ah6, bh3)) | 0; + lo = (lo + Math.imul(al5, bl4)) | 0; + mid = (mid + Math.imul(al5, bh4)) | 0; + mid = (mid + Math.imul(ah5, bl4)) | 0; + hi = (hi + Math.imul(ah5, bh4)) | 0; + lo = (lo + Math.imul(al4, bl5)) | 0; + mid = (mid + Math.imul(al4, bh5)) | 0; + mid = (mid + Math.imul(ah4, bl5)) | 0; + hi = (hi + Math.imul(ah4, bh5)) | 0; + lo = (lo + Math.imul(al3, bl6)) | 0; + mid = (mid + Math.imul(al3, bh6)) | 0; + mid = (mid + Math.imul(ah3, bl6)) | 0; + hi = (hi + Math.imul(ah3, bh6)) | 0; + lo = (lo + Math.imul(al2, bl7)) | 0; + mid = (mid + Math.imul(al2, bh7)) | 0; + mid = (mid + Math.imul(ah2, bl7)) | 0; + hi = (hi + Math.imul(ah2, bh7)) | 0; + lo = (lo + Math.imul(al1, bl8)) | 0; + mid = (mid + Math.imul(al1, bh8)) | 0; + mid = (mid + Math.imul(ah1, bl8)) | 0; + hi = (hi + Math.imul(ah1, bh8)) | 0; + lo = (lo + Math.imul(al0, bl9)) | 0; + mid = (mid + Math.imul(al0, bh9)) | 0; + mid = (mid + Math.imul(ah0, bl9)) | 0; + hi = (hi + Math.imul(ah0, bh9)) | 0; + var w9 = (((c + lo) | 0) + ((mid & 0x1fff) << 13)) | 0; + c = (((hi + (mid >>> 13)) | 0) + (w9 >>> 26)) | 0; + w9 &= 0x3ffffff; + /* k = 10 */ + lo = Math.imul(al9, bl1); + mid = Math.imul(al9, bh1); + mid = (mid + Math.imul(ah9, bl1)) | 0; + hi = Math.imul(ah9, bh1); + lo = (lo + Math.imul(al8, bl2)) | 0; + mid = (mid + Math.imul(al8, bh2)) | 0; + mid = (mid + Math.imul(ah8, bl2)) | 0; + hi = (hi + Math.imul(ah8, bh2)) | 0; + lo = (lo + Math.imul(al7, bl3)) | 0; + mid = (mid + Math.imul(al7, bh3)) | 0; + mid = (mid + Math.imul(ah7, bl3)) | 0; + hi = (hi + Math.imul(ah7, bh3)) | 0; + lo = (lo + Math.imul(al6, bl4)) | 0; + mid = (mid + Math.imul(al6, bh4)) | 0; + mid = (mid + Math.imul(ah6, bl4)) | 0; + hi = (hi + Math.imul(ah6, bh4)) | 0; + lo = (lo + Math.imul(al5, bl5)) | 0; + mid = (mid + Math.imul(al5, bh5)) | 0; + mid = (mid + Math.imul(ah5, bl5)) | 0; + hi = (hi + Math.imul(ah5, bh5)) | 0; + lo = (lo + Math.imul(al4, bl6)) | 0; + mid = (mid + Math.imul(al4, bh6)) | 0; + mid = (mid + Math.imul(ah4, bl6)) | 0; + hi = (hi + Math.imul(ah4, bh6)) | 0; + lo = (lo + Math.imul(al3, bl7)) | 0; + mid = (mid + Math.imul(al3, bh7)) | 0; + mid = (mid + Math.imul(ah3, bl7)) | 0; + hi = (hi + Math.imul(ah3, bh7)) | 0; + lo = (lo + Math.imul(al2, bl8)) | 0; + mid = (mid + Math.imul(al2, bh8)) | 0; + mid = (mid + Math.imul(ah2, bl8)) | 0; + hi = (hi + Math.imul(ah2, bh8)) | 0; + lo = (lo + Math.imul(al1, bl9)) | 0; + mid = (mid + Math.imul(al1, bh9)) | 0; + mid = (mid + Math.imul(ah1, bl9)) | 0; + hi = (hi + Math.imul(ah1, bh9)) | 0; + var w10 = (((c + lo) | 0) + ((mid & 0x1fff) << 13)) | 0; + c = (((hi + (mid >>> 13)) | 0) + (w10 >>> 26)) | 0; + w10 &= 0x3ffffff; + /* k = 11 */ + lo = Math.imul(al9, bl2); + mid = Math.imul(al9, bh2); + mid = (mid + Math.imul(ah9, bl2)) | 0; + hi = Math.imul(ah9, bh2); + lo = (lo + Math.imul(al8, bl3)) | 0; + mid = (mid + Math.imul(al8, bh3)) | 0; + mid = (mid + Math.imul(ah8, bl3)) | 0; + hi = (hi + Math.imul(ah8, bh3)) | 0; + lo = (lo + Math.imul(al7, bl4)) | 0; + mid = (mid + Math.imul(al7, bh4)) | 0; + mid = (mid + Math.imul(ah7, bl4)) | 0; + hi = (hi + Math.imul(ah7, bh4)) | 0; + lo = (lo + Math.imul(al6, bl5)) | 0; + mid = (mid + Math.imul(al6, bh5)) | 0; + mid = (mid + Math.imul(ah6, bl5)) | 0; + hi = (hi + Math.imul(ah6, bh5)) | 0; + lo = (lo + Math.imul(al5, bl6)) | 0; + mid = (mid + Math.imul(al5, bh6)) | 0; + mid = (mid + Math.imul(ah5, bl6)) | 0; + hi = (hi + Math.imul(ah5, bh6)) | 0; + lo = (lo + Math.imul(al4, bl7)) | 0; + mid = (mid + Math.imul(al4, bh7)) | 0; + mid = (mid + Math.imul(ah4, bl7)) | 0; + hi = (hi + Math.imul(ah4, bh7)) | 0; + lo = (lo + Math.imul(al3, bl8)) | 0; + mid = (mid + Math.imul(al3, bh8)) | 0; + mid = (mid + Math.imul(ah3, bl8)) | 0; + hi = (hi + Math.imul(ah3, bh8)) | 0; + lo = (lo + Math.imul(al2, bl9)) | 0; + mid = (mid + Math.imul(al2, bh9)) | 0; + mid = (mid + Math.imul(ah2, bl9)) | 0; + hi = (hi + Math.imul(ah2, bh9)) | 0; + var w11 = (((c + lo) | 0) + ((mid & 0x1fff) << 13)) | 0; + c = (((hi + (mid >>> 13)) | 0) + (w11 >>> 26)) | 0; + w11 &= 0x3ffffff; + /* k = 12 */ + lo = Math.imul(al9, bl3); + mid = Math.imul(al9, bh3); + mid = (mid + Math.imul(ah9, bl3)) | 0; + hi = Math.imul(ah9, bh3); + lo = (lo + Math.imul(al8, bl4)) | 0; + mid = (mid + Math.imul(al8, bh4)) | 0; + mid = (mid + Math.imul(ah8, bl4)) | 0; + hi = (hi + Math.imul(ah8, bh4)) | 0; + lo = (lo + Math.imul(al7, bl5)) | 0; + mid = (mid + Math.imul(al7, bh5)) | 0; + mid = (mid + Math.imul(ah7, bl5)) | 0; + hi = (hi + Math.imul(ah7, bh5)) | 0; + lo = (lo + Math.imul(al6, bl6)) | 0; + mid = (mid + Math.imul(al6, bh6)) | 0; + mid = (mid + Math.imul(ah6, bl6)) | 0; + hi = (hi + Math.imul(ah6, bh6)) | 0; + lo = (lo + Math.imul(al5, bl7)) | 0; + mid = (mid + Math.imul(al5, bh7)) | 0; + mid = (mid + Math.imul(ah5, bl7)) | 0; + hi = (hi + Math.imul(ah5, bh7)) | 0; + lo = (lo + Math.imul(al4, bl8)) | 0; + mid = (mid + Math.imul(al4, bh8)) | 0; + mid = (mid + Math.imul(ah4, bl8)) | 0; + hi = (hi + Math.imul(ah4, bh8)) | 0; + lo = (lo + Math.imul(al3, bl9)) | 0; + mid = (mid + Math.imul(al3, bh9)) | 0; + mid = (mid + Math.imul(ah3, bl9)) | 0; + hi = (hi + Math.imul(ah3, bh9)) | 0; + var w12 = (((c + lo) | 0) + ((mid & 0x1fff) << 13)) | 0; + c = (((hi + (mid >>> 13)) | 0) + (w12 >>> 26)) | 0; + w12 &= 0x3ffffff; + /* k = 13 */ + lo = Math.imul(al9, bl4); + mid = Math.imul(al9, bh4); + mid = (mid + Math.imul(ah9, bl4)) | 0; + hi = Math.imul(ah9, bh4); + lo = (lo + Math.imul(al8, bl5)) | 0; + mid = (mid + Math.imul(al8, bh5)) | 0; + mid = (mid + Math.imul(ah8, bl5)) | 0; + hi = (hi + Math.imul(ah8, bh5)) | 0; + lo = (lo + Math.imul(al7, bl6)) | 0; + mid = (mid + Math.imul(al7, bh6)) | 0; + mid = (mid + Math.imul(ah7, bl6)) | 0; + hi = (hi + Math.imul(ah7, bh6)) | 0; + lo = (lo + Math.imul(al6, bl7)) | 0; + mid = (mid + Math.imul(al6, bh7)) | 0; + mid = (mid + Math.imul(ah6, bl7)) | 0; + hi = (hi + Math.imul(ah6, bh7)) | 0; + lo = (lo + Math.imul(al5, bl8)) | 0; + mid = (mid + Math.imul(al5, bh8)) | 0; + mid = (mid + Math.imul(ah5, bl8)) | 0; + hi = (hi + Math.imul(ah5, bh8)) | 0; + lo = (lo + Math.imul(al4, bl9)) | 0; + mid = (mid + Math.imul(al4, bh9)) | 0; + mid = (mid + Math.imul(ah4, bl9)) | 0; + hi = (hi + Math.imul(ah4, bh9)) | 0; + var w13 = (((c + lo) | 0) + ((mid & 0x1fff) << 13)) | 0; + c = (((hi + (mid >>> 13)) | 0) + (w13 >>> 26)) | 0; + w13 &= 0x3ffffff; + /* k = 14 */ + lo = Math.imul(al9, bl5); + mid = Math.imul(al9, bh5); + mid = (mid + Math.imul(ah9, bl5)) | 0; + hi = Math.imul(ah9, bh5); + lo = (lo + Math.imul(al8, bl6)) | 0; + mid = (mid + Math.imul(al8, bh6)) | 0; + mid = (mid + Math.imul(ah8, bl6)) | 0; + hi = (hi + Math.imul(ah8, bh6)) | 0; + lo = (lo + Math.imul(al7, bl7)) | 0; + mid = (mid + Math.imul(al7, bh7)) | 0; + mid = (mid + Math.imul(ah7, bl7)) | 0; + hi = (hi + Math.imul(ah7, bh7)) | 0; + lo = (lo + Math.imul(al6, bl8)) | 0; + mid = (mid + Math.imul(al6, bh8)) | 0; + mid = (mid + Math.imul(ah6, bl8)) | 0; + hi = (hi + Math.imul(ah6, bh8)) | 0; + lo = (lo + Math.imul(al5, bl9)) | 0; + mid = (mid + Math.imul(al5, bh9)) | 0; + mid = (mid + Math.imul(ah5, bl9)) | 0; + hi = (hi + Math.imul(ah5, bh9)) | 0; + var w14 = (((c + lo) | 0) + ((mid & 0x1fff) << 13)) | 0; + c = (((hi + (mid >>> 13)) | 0) + (w14 >>> 26)) | 0; + w14 &= 0x3ffffff; + /* k = 15 */ + lo = Math.imul(al9, bl6); + mid = Math.imul(al9, bh6); + mid = (mid + Math.imul(ah9, bl6)) | 0; + hi = Math.imul(ah9, bh6); + lo = (lo + Math.imul(al8, bl7)) | 0; + mid = (mid + Math.imul(al8, bh7)) | 0; + mid = (mid + Math.imul(ah8, bl7)) | 0; + hi = (hi + Math.imul(ah8, bh7)) | 0; + lo = (lo + Math.imul(al7, bl8)) | 0; + mid = (mid + Math.imul(al7, bh8)) | 0; + mid = (mid + Math.imul(ah7, bl8)) | 0; + hi = (hi + Math.imul(ah7, bh8)) | 0; + lo = (lo + Math.imul(al6, bl9)) | 0; + mid = (mid + Math.imul(al6, bh9)) | 0; + mid = (mid + Math.imul(ah6, bl9)) | 0; + hi = (hi + Math.imul(ah6, bh9)) | 0; + var w15 = (((c + lo) | 0) + ((mid & 0x1fff) << 13)) | 0; + c = (((hi + (mid >>> 13)) | 0) + (w15 >>> 26)) | 0; + w15 &= 0x3ffffff; + /* k = 16 */ + lo = Math.imul(al9, bl7); + mid = Math.imul(al9, bh7); + mid = (mid + Math.imul(ah9, bl7)) | 0; + hi = Math.imul(ah9, bh7); + lo = (lo + Math.imul(al8, bl8)) | 0; + mid = (mid + Math.imul(al8, bh8)) | 0; + mid = (mid + Math.imul(ah8, bl8)) | 0; + hi = (hi + Math.imul(ah8, bh8)) | 0; + lo = (lo + Math.imul(al7, bl9)) | 0; + mid = (mid + Math.imul(al7, bh9)) | 0; + mid = (mid + Math.imul(ah7, bl9)) | 0; + hi = (hi + Math.imul(ah7, bh9)) | 0; + var w16 = (((c + lo) | 0) + ((mid & 0x1fff) << 13)) | 0; + c = (((hi + (mid >>> 13)) | 0) + (w16 >>> 26)) | 0; + w16 &= 0x3ffffff; + /* k = 17 */ + lo = Math.imul(al9, bl8); + mid = Math.imul(al9, bh8); + mid = (mid + Math.imul(ah9, bl8)) | 0; + hi = Math.imul(ah9, bh8); + lo = (lo + Math.imul(al8, bl9)) | 0; + mid = (mid + Math.imul(al8, bh9)) | 0; + mid = (mid + Math.imul(ah8, bl9)) | 0; + hi = (hi + Math.imul(ah8, bh9)) | 0; + var w17 = (((c + lo) | 0) + ((mid & 0x1fff) << 13)) | 0; + c = (((hi + (mid >>> 13)) | 0) + (w17 >>> 26)) | 0; + w17 &= 0x3ffffff; + /* k = 18 */ + lo = Math.imul(al9, bl9); + mid = Math.imul(al9, bh9); + mid = (mid + Math.imul(ah9, bl9)) | 0; + hi = Math.imul(ah9, bh9); + var w18 = (((c + lo) | 0) + ((mid & 0x1fff) << 13)) | 0; + c = (((hi + (mid >>> 13)) | 0) + (w18 >>> 26)) | 0; + w18 &= 0x3ffffff; + o[0] = w0; + o[1] = w1; + o[2] = w2; + o[3] = w3; + o[4] = w4; + o[5] = w5; + o[6] = w6; + o[7] = w7; + o[8] = w8; + o[9] = w9; + o[10] = w10; + o[11] = w11; + o[12] = w12; + o[13] = w13; + o[14] = w14; + o[15] = w15; + o[16] = w16; + o[17] = w17; + o[18] = w18; + if (c !== 0) { + o[19] = c; + out.length++; + } + return out; + }; + + // Polyfill comb + if (!Math.imul) { + comb10MulTo = smallMulTo; + } + + function bigMulTo (self, num, out) { + out.negative = num.negative ^ self.negative; + out.length = self.length + num.length; + + var carry = 0; + var hncarry = 0; + for (var k = 0; k < out.length - 1; k++) { + // Sum all words with the same `i + j = k` and accumulate `ncarry`, + // note that ncarry could be >= 0x3ffffff + var ncarry = hncarry; + hncarry = 0; + var rword = carry & 0x3ffffff; + var maxJ = Math.min(k, num.length - 1); + for (var j = Math.max(0, k - self.length + 1); j <= maxJ; j++) { + var i = k - j; + var a = self.words[i] | 0; + var b = num.words[j] | 0; + var r = a * b; + + var lo = r & 0x3ffffff; + ncarry = (ncarry + ((r / 0x4000000) | 0)) | 0; + lo = (lo + rword) | 0; + rword = lo & 0x3ffffff; + ncarry = (ncarry + (lo >>> 26)) | 0; + + hncarry += ncarry >>> 26; + ncarry &= 0x3ffffff; + } + out.words[k] = rword; + carry = ncarry; + ncarry = hncarry; + } + if (carry !== 0) { + out.words[k] = carry; + } else { + out.length--; + } + + return out._strip(); + } + + function jumboMulTo (self, num, out) { + // Temporary disable, see https://github.com/indutny/bn.js/issues/211 + // var fftm = new FFTM(); + // return fftm.mulp(self, num, out); + return bigMulTo(self, num, out); + } + + BN.prototype.mulTo = function mulTo (num, out) { + var res; + var len = this.length + num.length; + if (this.length === 10 && num.length === 10) { + res = comb10MulTo(this, num, out); + } else if (len < 63) { + res = smallMulTo(this, num, out); + } else if (len < 1024) { + res = bigMulTo(this, num, out); + } else { + res = jumboMulTo(this, num, out); + } + + return res; + }; + + // Cooley-Tukey algorithm for FFT + // slightly revisited to rely on looping instead of recursion + + function FFTM (x, y) { + this.x = x; + this.y = y; + } + + FFTM.prototype.makeRBT = function makeRBT (N) { + var t = new Array(N); + var l = BN.prototype._countBits(N) - 1; + for (var i = 0; i < N; i++) { + t[i] = this.revBin(i, l, N); + } + + return t; + }; + + // Returns binary-reversed representation of `x` + FFTM.prototype.revBin = function revBin (x, l, N) { + if (x === 0 || x === N - 1) return x; + + var rb = 0; + for (var i = 0; i < l; i++) { + rb |= (x & 1) << (l - i - 1); + x >>= 1; + } + + return rb; + }; + + // Performs "tweedling" phase, therefore 'emulating' + // behaviour of the recursive algorithm + FFTM.prototype.permute = function permute (rbt, rws, iws, rtws, itws, N) { + for (var i = 0; i < N; i++) { + rtws[i] = rws[rbt[i]]; + itws[i] = iws[rbt[i]]; + } + }; + + FFTM.prototype.transform = function transform (rws, iws, rtws, itws, N, rbt) { + this.permute(rbt, rws, iws, rtws, itws, N); + + for (var s = 1; s < N; s <<= 1) { + var l = s << 1; + + var rtwdf = Math.cos(2 * Math.PI / l); + var itwdf = Math.sin(2 * Math.PI / l); + + for (var p = 0; p < N; p += l) { + var rtwdf_ = rtwdf; + var itwdf_ = itwdf; + + for (var j = 0; j < s; j++) { + var re = rtws[p + j]; + var ie = itws[p + j]; + + var ro = rtws[p + j + s]; + var io = itws[p + j + s]; + + var rx = rtwdf_ * ro - itwdf_ * io; + + io = rtwdf_ * io + itwdf_ * ro; + ro = rx; + + rtws[p + j] = re + ro; + itws[p + j] = ie + io; + + rtws[p + j + s] = re - ro; + itws[p + j + s] = ie - io; + + /* jshint maxdepth : false */ + if (j !== l) { + rx = rtwdf * rtwdf_ - itwdf * itwdf_; + + itwdf_ = rtwdf * itwdf_ + itwdf * rtwdf_; + rtwdf_ = rx; + } + } + } + } + }; + + FFTM.prototype.guessLen13b = function guessLen13b (n, m) { + var N = Math.max(m, n) | 1; + var odd = N & 1; + var i = 0; + for (N = N / 2 | 0; N; N = N >>> 1) { + i++; + } + + return 1 << i + 1 + odd; + }; + + FFTM.prototype.conjugate = function conjugate (rws, iws, N) { + if (N <= 1) return; + + for (var i = 0; i < N / 2; i++) { + var t = rws[i]; + + rws[i] = rws[N - i - 1]; + rws[N - i - 1] = t; + + t = iws[i]; + + iws[i] = -iws[N - i - 1]; + iws[N - i - 1] = -t; + } + }; + + FFTM.prototype.normalize13b = function normalize13b (ws, N) { + var carry = 0; + for (var i = 0; i < N / 2; i++) { + var w = Math.round(ws[2 * i + 1] / N) * 0x2000 + + Math.round(ws[2 * i] / N) + + carry; + + ws[i] = w & 0x3ffffff; + + if (w < 0x4000000) { + carry = 0; + } else { + carry = w / 0x4000000 | 0; + } + } + + return ws; + }; + + FFTM.prototype.convert13b = function convert13b (ws, len, rws, N) { + var carry = 0; + for (var i = 0; i < len; i++) { + carry = carry + (ws[i] | 0); + + rws[2 * i] = carry & 0x1fff; carry = carry >>> 13; + rws[2 * i + 1] = carry & 0x1fff; carry = carry >>> 13; + } + + // Pad with zeroes + for (i = 2 * len; i < N; ++i) { + rws[i] = 0; + } + + assert(carry === 0); + assert((carry & ~0x1fff) === 0); + }; + + FFTM.prototype.stub = function stub (N) { + var ph = new Array(N); + for (var i = 0; i < N; i++) { + ph[i] = 0; + } + + return ph; + }; + + FFTM.prototype.mulp = function mulp (x, y, out) { + var N = 2 * this.guessLen13b(x.length, y.length); + + var rbt = this.makeRBT(N); + + var _ = this.stub(N); + + var rws = new Array(N); + var rwst = new Array(N); + var iwst = new Array(N); + + var nrws = new Array(N); + var nrwst = new Array(N); + var niwst = new Array(N); + + var rmws = out.words; + rmws.length = N; + + this.convert13b(x.words, x.length, rws, N); + this.convert13b(y.words, y.length, nrws, N); + + this.transform(rws, _, rwst, iwst, N, rbt); + this.transform(nrws, _, nrwst, niwst, N, rbt); + + for (var i = 0; i < N; i++) { + var rx = rwst[i] * nrwst[i] - iwst[i] * niwst[i]; + iwst[i] = rwst[i] * niwst[i] + iwst[i] * nrwst[i]; + rwst[i] = rx; + } + + this.conjugate(rwst, iwst, N); + this.transform(rwst, iwst, rmws, _, N, rbt); + this.conjugate(rmws, _, N); + this.normalize13b(rmws, N); + + out.negative = x.negative ^ y.negative; + out.length = x.length + y.length; + return out._strip(); + }; + + // Multiply `this` by `num` + BN.prototype.mul = function mul (num) { + var out = new BN(null); + out.words = new Array(this.length + num.length); + return this.mulTo(num, out); + }; + + // Multiply employing FFT + BN.prototype.mulf = function mulf (num) { + var out = new BN(null); + out.words = new Array(this.length + num.length); + return jumboMulTo(this, num, out); + }; + + // In-place Multiplication + BN.prototype.imul = function imul (num) { + return this.clone().mulTo(num, this); + }; + + BN.prototype.imuln = function imuln (num) { + var isNegNum = num < 0; + if (isNegNum) num = -num; + + assert(typeof num === 'number'); + assert(num < 0x4000000); + + // Carry + var carry = 0; + for (var i = 0; i < this.length; i++) { + var w = (this.words[i] | 0) * num; + var lo = (w & 0x3ffffff) + (carry & 0x3ffffff); + carry >>= 26; + carry += (w / 0x4000000) | 0; + // NOTE: lo is 27bit maximum + carry += lo >>> 26; + this.words[i] = lo & 0x3ffffff; + } + + if (carry !== 0) { + this.words[i] = carry; + this.length++; + } + + return isNegNum ? this.ineg() : this; + }; + + BN.prototype.muln = function muln (num) { + return this.clone().imuln(num); + }; + + // `this` * `this` + BN.prototype.sqr = function sqr () { + return this.mul(this); + }; + + // `this` * `this` in-place + BN.prototype.isqr = function isqr () { + return this.imul(this.clone()); + }; + + // Math.pow(`this`, `num`) + BN.prototype.pow = function pow (num) { + var w = toBitArray(num); + if (w.length === 0) return new BN(1); + + // Skip leading zeroes + var res = this; + for (var i = 0; i < w.length; i++, res = res.sqr()) { + if (w[i] !== 0) break; + } + + if (++i < w.length) { + for (var q = res.sqr(); i < w.length; i++, q = q.sqr()) { + if (w[i] === 0) continue; + + res = res.mul(q); + } + } + + return res; + }; + + // Shift-left in-place + BN.prototype.iushln = function iushln (bits) { + assert(typeof bits === 'number' && bits >= 0); + var r = bits % 26; + var s = (bits - r) / 26; + var carryMask = (0x3ffffff >>> (26 - r)) << (26 - r); + var i; + + if (r !== 0) { + var carry = 0; + + for (i = 0; i < this.length; i++) { + var newCarry = this.words[i] & carryMask; + var c = ((this.words[i] | 0) - newCarry) << r; + this.words[i] = c | carry; + carry = newCarry >>> (26 - r); + } + + if (carry) { + this.words[i] = carry; + this.length++; + } + } + + if (s !== 0) { + for (i = this.length - 1; i >= 0; i--) { + this.words[i + s] = this.words[i]; + } + + for (i = 0; i < s; i++) { + this.words[i] = 0; + } + + this.length += s; + } + + return this._strip(); + }; + + BN.prototype.ishln = function ishln (bits) { + // TODO(indutny): implement me + assert(this.negative === 0); + return this.iushln(bits); + }; + + // Shift-right in-place + // NOTE: `hint` is a lowest bit before trailing zeroes + // NOTE: if `extended` is present - it will be filled with destroyed bits + BN.prototype.iushrn = function iushrn (bits, hint, extended) { + assert(typeof bits === 'number' && bits >= 0); + var h; + if (hint) { + h = (hint - (hint % 26)) / 26; + } else { + h = 0; + } + + var r = bits % 26; + var s = Math.min((bits - r) / 26, this.length); + var mask = 0x3ffffff ^ ((0x3ffffff >>> r) << r); + var maskedWords = extended; + + h -= s; + h = Math.max(0, h); + + // Extended mode, copy masked part + if (maskedWords) { + for (var i = 0; i < s; i++) { + maskedWords.words[i] = this.words[i]; + } + maskedWords.length = s; + } + + if (s === 0) { + // No-op, we should not move anything at all + } else if (this.length > s) { + this.length -= s; + for (i = 0; i < this.length; i++) { + this.words[i] = this.words[i + s]; + } + } else { + this.words[0] = 0; + this.length = 1; + } + + var carry = 0; + for (i = this.length - 1; i >= 0 && (carry !== 0 || i >= h); i--) { + var word = this.words[i] | 0; + this.words[i] = (carry << (26 - r)) | (word >>> r); + carry = word & mask; + } + + // Push carried bits as a mask + if (maskedWords && carry !== 0) { + maskedWords.words[maskedWords.length++] = carry; + } + + if (this.length === 0) { + this.words[0] = 0; + this.length = 1; + } + + return this._strip(); + }; + + BN.prototype.ishrn = function ishrn (bits, hint, extended) { + // TODO(indutny): implement me + assert(this.negative === 0); + return this.iushrn(bits, hint, extended); + }; + + // Shift-left + BN.prototype.shln = function shln (bits) { + return this.clone().ishln(bits); + }; + + BN.prototype.ushln = function ushln (bits) { + return this.clone().iushln(bits); + }; + + // Shift-right + BN.prototype.shrn = function shrn (bits) { + return this.clone().ishrn(bits); + }; + + BN.prototype.ushrn = function ushrn (bits) { + return this.clone().iushrn(bits); + }; + + // Test if n bit is set + BN.prototype.testn = function testn (bit) { + assert(typeof bit === 'number' && bit >= 0); + var r = bit % 26; + var s = (bit - r) / 26; + var q = 1 << r; + + // Fast case: bit is much higher than all existing words + if (this.length <= s) return false; + + // Check bit and return + var w = this.words[s]; + + return !!(w & q); + }; + + // Return only lowers bits of number (in-place) + BN.prototype.imaskn = function imaskn (bits) { + assert(typeof bits === 'number' && bits >= 0); + var r = bits % 26; + var s = (bits - r) / 26; + + assert(this.negative === 0, 'imaskn works only with positive numbers'); + + if (this.length <= s) { + return this; + } + + if (r !== 0) { + s++; + } + this.length = Math.min(s, this.length); + + if (r !== 0) { + var mask = 0x3ffffff ^ ((0x3ffffff >>> r) << r); + this.words[this.length - 1] &= mask; + } + + return this._strip(); + }; + + // Return only lowers bits of number + BN.prototype.maskn = function maskn (bits) { + return this.clone().imaskn(bits); + }; + + // Add plain number `num` to `this` + BN.prototype.iaddn = function iaddn (num) { + assert(typeof num === 'number'); + assert(num < 0x4000000); + if (num < 0) return this.isubn(-num); + + // Possible sign change + if (this.negative !== 0) { + if (this.length === 1 && (this.words[0] | 0) <= num) { + this.words[0] = num - (this.words[0] | 0); + this.negative = 0; + return this; + } + + this.negative = 0; + this.isubn(num); + this.negative = 1; + return this; + } + + // Add without checks + return this._iaddn(num); + }; + + BN.prototype._iaddn = function _iaddn (num) { + this.words[0] += num; + + // Carry + for (var i = 0; i < this.length && this.words[i] >= 0x4000000; i++) { + this.words[i] -= 0x4000000; + if (i === this.length - 1) { + this.words[i + 1] = 1; + } else { + this.words[i + 1]++; + } + } + this.length = Math.max(this.length, i + 1); + + return this; + }; + + // Subtract plain number `num` from `this` + BN.prototype.isubn = function isubn (num) { + assert(typeof num === 'number'); + assert(num < 0x4000000); + if (num < 0) return this.iaddn(-num); + + if (this.negative !== 0) { + this.negative = 0; + this.iaddn(num); + this.negative = 1; + return this; + } + + this.words[0] -= num; + + if (this.length === 1 && this.words[0] < 0) { + this.words[0] = -this.words[0]; + this.negative = 1; + } else { + // Carry + for (var i = 0; i < this.length && this.words[i] < 0; i++) { + this.words[i] += 0x4000000; + this.words[i + 1] -= 1; + } + } + + return this._strip(); + }; + + BN.prototype.addn = function addn (num) { + return this.clone().iaddn(num); + }; + + BN.prototype.subn = function subn (num) { + return this.clone().isubn(num); + }; + + BN.prototype.iabs = function iabs () { + this.negative = 0; + + return this; + }; + + BN.prototype.abs = function abs () { + return this.clone().iabs(); + }; + + BN.prototype._ishlnsubmul = function _ishlnsubmul (num, mul, shift) { + var len = num.length + shift; + var i; + + this._expand(len); + + var w; + var carry = 0; + for (i = 0; i < num.length; i++) { + w = (this.words[i + shift] | 0) + carry; + var right = (num.words[i] | 0) * mul; + w -= right & 0x3ffffff; + carry = (w >> 26) - ((right / 0x4000000) | 0); + this.words[i + shift] = w & 0x3ffffff; + } + for (; i < this.length - shift; i++) { + w = (this.words[i + shift] | 0) + carry; + carry = w >> 26; + this.words[i + shift] = w & 0x3ffffff; + } + + if (carry === 0) return this._strip(); + + // Subtraction overflow + assert(carry === -1); + carry = 0; + for (i = 0; i < this.length; i++) { + w = -(this.words[i] | 0) + carry; + carry = w >> 26; + this.words[i] = w & 0x3ffffff; + } + this.negative = 1; + + return this._strip(); + }; + + BN.prototype._wordDiv = function _wordDiv (num, mode) { + var shift = this.length - num.length; + + var a = this.clone(); + var b = num; + + // Normalize + var bhi = b.words[b.length - 1] | 0; + var bhiBits = this._countBits(bhi); + shift = 26 - bhiBits; + if (shift !== 0) { + b = b.ushln(shift); + a.iushln(shift); + bhi = b.words[b.length - 1] | 0; + } + + // Initialize quotient + var m = a.length - b.length; + var q; + + if (mode !== 'mod') { + q = new BN(null); + q.length = m + 1; + q.words = new Array(q.length); + for (var i = 0; i < q.length; i++) { + q.words[i] = 0; + } + } + + var diff = a.clone()._ishlnsubmul(b, 1, m); + if (diff.negative === 0) { + a = diff; + if (q) { + q.words[m] = 1; + } + } + + for (var j = m - 1; j >= 0; j--) { + var qj = (a.words[b.length + j] | 0) * 0x4000000 + + (a.words[b.length + j - 1] | 0); + + // NOTE: (qj / bhi) is (0x3ffffff * 0x4000000 + 0x3ffffff) / 0x2000000 max + // (0x7ffffff) + qj = Math.min((qj / bhi) | 0, 0x3ffffff); + + a._ishlnsubmul(b, qj, j); + while (a.negative !== 0) { + qj--; + a.negative = 0; + a._ishlnsubmul(b, 1, j); + if (!a.isZero()) { + a.negative ^= 1; + } + } + if (q) { + q.words[j] = qj; + } + } + if (q) { + q._strip(); + } + a._strip(); + + // Denormalize + if (mode !== 'div' && shift !== 0) { + a.iushrn(shift); + } + + return { + div: q || null, + mod: a + }; + }; + + // NOTE: 1) `mode` can be set to `mod` to request mod only, + // to `div` to request div only, or be absent to + // request both div & mod + // 2) `positive` is true if unsigned mod is requested + BN.prototype.divmod = function divmod (num, mode, positive) { + assert(!num.isZero()); + + if (this.isZero()) { + return { + div: new BN(0), + mod: new BN(0) + }; + } + + var div, mod, res; + if (this.negative !== 0 && num.negative === 0) { + res = this.neg().divmod(num, mode); + + if (mode !== 'mod') { + div = res.div.neg(); + } + + if (mode !== 'div') { + mod = res.mod.neg(); + if (positive && mod.negative !== 0) { + mod.iadd(num); + } + } + + return { + div: div, + mod: mod + }; + } + + if (this.negative === 0 && num.negative !== 0) { + res = this.divmod(num.neg(), mode); + + if (mode !== 'mod') { + div = res.div.neg(); + } + + return { + div: div, + mod: res.mod + }; + } + + if ((this.negative & num.negative) !== 0) { + res = this.neg().divmod(num.neg(), mode); + + if (mode !== 'div') { + mod = res.mod.neg(); + if (positive && mod.negative !== 0) { + mod.isub(num); + } + } + + return { + div: res.div, + mod: mod + }; + } + + // Both numbers are positive at this point + + // Strip both numbers to approximate shift value + if (num.length > this.length || this.cmp(num) < 0) { + return { + div: new BN(0), + mod: this + }; + } + + // Very short reduction + if (num.length === 1) { + if (mode === 'div') { + return { + div: this.divn(num.words[0]), + mod: null + }; + } + + if (mode === 'mod') { + return { + div: null, + mod: new BN(this.modrn(num.words[0])) + }; + } + + return { + div: this.divn(num.words[0]), + mod: new BN(this.modrn(num.words[0])) + }; + } + + return this._wordDiv(num, mode); + }; + + // Find `this` / `num` + BN.prototype.div = function div (num) { + return this.divmod(num, 'div', false).div; + }; + + // Find `this` % `num` + BN.prototype.mod = function mod (num) { + return this.divmod(num, 'mod', false).mod; + }; + + BN.prototype.umod = function umod (num) { + return this.divmod(num, 'mod', true).mod; + }; + + // Find Round(`this` / `num`) + BN.prototype.divRound = function divRound (num) { + var dm = this.divmod(num); + + // Fast case - exact division + if (dm.mod.isZero()) return dm.div; + + var mod = dm.div.negative !== 0 ? dm.mod.isub(num) : dm.mod; + + var half = num.ushrn(1); + var r2 = num.andln(1); + var cmp = mod.cmp(half); + + // Round down + if (cmp < 0 || (r2 === 1 && cmp === 0)) return dm.div; + + // Round up + return dm.div.negative !== 0 ? dm.div.isubn(1) : dm.div.iaddn(1); + }; + + BN.prototype.modrn = function modrn (num) { + var isNegNum = num < 0; + if (isNegNum) num = -num; + + assert(num <= 0x3ffffff); + var p = (1 << 26) % num; + + var acc = 0; + for (var i = this.length - 1; i >= 0; i--) { + acc = (p * acc + (this.words[i] | 0)) % num; + } + + return isNegNum ? -acc : acc; + }; + + // WARNING: DEPRECATED + BN.prototype.modn = function modn (num) { + return this.modrn(num); + }; + + // In-place division by number + BN.prototype.idivn = function idivn (num) { + var isNegNum = num < 0; + if (isNegNum) num = -num; + + assert(num <= 0x3ffffff); + + var carry = 0; + for (var i = this.length - 1; i >= 0; i--) { + var w = (this.words[i] | 0) + carry * 0x4000000; + this.words[i] = (w / num) | 0; + carry = w % num; + } + + this._strip(); + return isNegNum ? this.ineg() : this; + }; + + BN.prototype.divn = function divn (num) { + return this.clone().idivn(num); + }; + + BN.prototype.egcd = function egcd (p) { + assert(p.negative === 0); + assert(!p.isZero()); + + var x = this; + var y = p.clone(); + + if (x.negative !== 0) { + x = x.umod(p); + } else { + x = x.clone(); + } + + // A * x + B * y = x + var A = new BN(1); + var B = new BN(0); + + // C * x + D * y = y + var C = new BN(0); + var D = new BN(1); + + var g = 0; + + while (x.isEven() && y.isEven()) { + x.iushrn(1); + y.iushrn(1); + ++g; + } + + var yp = y.clone(); + var xp = x.clone(); + + while (!x.isZero()) { + for (var i = 0, im = 1; (x.words[0] & im) === 0 && i < 26; ++i, im <<= 1); + if (i > 0) { + x.iushrn(i); + while (i-- > 0) { + if (A.isOdd() || B.isOdd()) { + A.iadd(yp); + B.isub(xp); + } + + A.iushrn(1); + B.iushrn(1); + } + } + + for (var j = 0, jm = 1; (y.words[0] & jm) === 0 && j < 26; ++j, jm <<= 1); + if (j > 0) { + y.iushrn(j); + while (j-- > 0) { + if (C.isOdd() || D.isOdd()) { + C.iadd(yp); + D.isub(xp); + } + + C.iushrn(1); + D.iushrn(1); + } + } + + if (x.cmp(y) >= 0) { + x.isub(y); + A.isub(C); + B.isub(D); + } else { + y.isub(x); + C.isub(A); + D.isub(B); + } + } + + return { + a: C, + b: D, + gcd: y.iushln(g) + }; + }; + + // This is reduced incarnation of the binary EEA + // above, designated to invert members of the + // _prime_ fields F(p) at a maximal speed + BN.prototype._invmp = function _invmp (p) { + assert(p.negative === 0); + assert(!p.isZero()); + + var a = this; + var b = p.clone(); + + if (a.negative !== 0) { + a = a.umod(p); + } else { + a = a.clone(); + } + + var x1 = new BN(1); + var x2 = new BN(0); + + var delta = b.clone(); + + while (a.cmpn(1) > 0 && b.cmpn(1) > 0) { + for (var i = 0, im = 1; (a.words[0] & im) === 0 && i < 26; ++i, im <<= 1); + if (i > 0) { + a.iushrn(i); + while (i-- > 0) { + if (x1.isOdd()) { + x1.iadd(delta); + } + + x1.iushrn(1); + } + } + + for (var j = 0, jm = 1; (b.words[0] & jm) === 0 && j < 26; ++j, jm <<= 1); + if (j > 0) { + b.iushrn(j); + while (j-- > 0) { + if (x2.isOdd()) { + x2.iadd(delta); + } + + x2.iushrn(1); + } + } + + if (a.cmp(b) >= 0) { + a.isub(b); + x1.isub(x2); + } else { + b.isub(a); + x2.isub(x1); + } + } + + var res; + if (a.cmpn(1) === 0) { + res = x1; + } else { + res = x2; + } + + if (res.cmpn(0) < 0) { + res.iadd(p); + } + + return res; + }; + + BN.prototype.gcd = function gcd (num) { + if (this.isZero()) return num.abs(); + if (num.isZero()) return this.abs(); + + var a = this.clone(); + var b = num.clone(); + a.negative = 0; + b.negative = 0; + + // Remove common factor of two + for (var shift = 0; a.isEven() && b.isEven(); shift++) { + a.iushrn(1); + b.iushrn(1); + } + + do { + while (a.isEven()) { + a.iushrn(1); + } + while (b.isEven()) { + b.iushrn(1); + } + + var r = a.cmp(b); + if (r < 0) { + // Swap `a` and `b` to make `a` always bigger than `b` + var t = a; + a = b; + b = t; + } else if (r === 0 || b.cmpn(1) === 0) { + break; + } + + a.isub(b); + } while (true); + + return b.iushln(shift); + }; + + // Invert number in the field F(num) + BN.prototype.invm = function invm (num) { + return this.egcd(num).a.umod(num); + }; + + BN.prototype.isEven = function isEven () { + return (this.words[0] & 1) === 0; + }; + + BN.prototype.isOdd = function isOdd () { + return (this.words[0] & 1) === 1; + }; + + // And first word and num + BN.prototype.andln = function andln (num) { + return this.words[0] & num; + }; + + // Increment at the bit position in-line + BN.prototype.bincn = function bincn (bit) { + assert(typeof bit === 'number'); + var r = bit % 26; + var s = (bit - r) / 26; + var q = 1 << r; + + // Fast case: bit is much higher than all existing words + if (this.length <= s) { + this._expand(s + 1); + this.words[s] |= q; + return this; + } + + // Add bit and propagate, if needed + var carry = q; + for (var i = s; carry !== 0 && i < this.length; i++) { + var w = this.words[i] | 0; + w += carry; + carry = w >>> 26; + w &= 0x3ffffff; + this.words[i] = w; + } + if (carry !== 0) { + this.words[i] = carry; + this.length++; + } + return this; + }; + + BN.prototype.isZero = function isZero () { + return this.length === 1 && this.words[0] === 0; + }; + + BN.prototype.cmpn = function cmpn (num) { + var negative = num < 0; + + if (this.negative !== 0 && !negative) return -1; + if (this.negative === 0 && negative) return 1; + + this._strip(); + + var res; + if (this.length > 1) { + res = 1; + } else { + if (negative) { + num = -num; + } + + assert(num <= 0x3ffffff, 'Number is too big'); + + var w = this.words[0] | 0; + res = w === num ? 0 : w < num ? -1 : 1; + } + if (this.negative !== 0) return -res | 0; + return res; + }; + + // Compare two numbers and return: + // 1 - if `this` > `num` + // 0 - if `this` == `num` + // -1 - if `this` < `num` + BN.prototype.cmp = function cmp (num) { + if (this.negative !== 0 && num.negative === 0) return -1; + if (this.negative === 0 && num.negative !== 0) return 1; + + var res = this.ucmp(num); + if (this.negative !== 0) return -res | 0; + return res; + }; + + // Unsigned comparison + BN.prototype.ucmp = function ucmp (num) { + // At this point both numbers have the same sign + if (this.length > num.length) return 1; + if (this.length < num.length) return -1; + + var res = 0; + for (var i = this.length - 1; i >= 0; i--) { + var a = this.words[i] | 0; + var b = num.words[i] | 0; + + if (a === b) continue; + if (a < b) { + res = -1; + } else if (a > b) { + res = 1; + } + break; + } + return res; + }; + + BN.prototype.gtn = function gtn (num) { + return this.cmpn(num) === 1; + }; + + BN.prototype.gt = function gt (num) { + return this.cmp(num) === 1; + }; + + BN.prototype.gten = function gten (num) { + return this.cmpn(num) >= 0; + }; + + BN.prototype.gte = function gte (num) { + return this.cmp(num) >= 0; + }; + + BN.prototype.ltn = function ltn (num) { + return this.cmpn(num) === -1; + }; + + BN.prototype.lt = function lt (num) { + return this.cmp(num) === -1; + }; + + BN.prototype.lten = function lten (num) { + return this.cmpn(num) <= 0; + }; + + BN.prototype.lte = function lte (num) { + return this.cmp(num) <= 0; + }; + + BN.prototype.eqn = function eqn (num) { + return this.cmpn(num) === 0; + }; + + BN.prototype.eq = function eq (num) { + return this.cmp(num) === 0; + }; + + // + // A reduce context, could be using montgomery or something better, depending + // on the `m` itself. + // + BN.red = function red (num) { + return new Red(num); + }; + + BN.prototype.toRed = function toRed (ctx) { + assert(!this.red, 'Already a number in reduction context'); + assert(this.negative === 0, 'red works only with positives'); + return ctx.convertTo(this)._forceRed(ctx); + }; + + BN.prototype.fromRed = function fromRed () { + assert(this.red, 'fromRed works only with numbers in reduction context'); + return this.red.convertFrom(this); + }; + + BN.prototype._forceRed = function _forceRed (ctx) { + this.red = ctx; + return this; + }; + + BN.prototype.forceRed = function forceRed (ctx) { + assert(!this.red, 'Already a number in reduction context'); + return this._forceRed(ctx); + }; + + BN.prototype.redAdd = function redAdd (num) { + assert(this.red, 'redAdd works only with red numbers'); + return this.red.add(this, num); + }; + + BN.prototype.redIAdd = function redIAdd (num) { + assert(this.red, 'redIAdd works only with red numbers'); + return this.red.iadd(this, num); + }; + + BN.prototype.redSub = function redSub (num) { + assert(this.red, 'redSub works only with red numbers'); + return this.red.sub(this, num); + }; + + BN.prototype.redISub = function redISub (num) { + assert(this.red, 'redISub works only with red numbers'); + return this.red.isub(this, num); + }; + + BN.prototype.redShl = function redShl (num) { + assert(this.red, 'redShl works only with red numbers'); + return this.red.shl(this, num); + }; + + BN.prototype.redMul = function redMul (num) { + assert(this.red, 'redMul works only with red numbers'); + this.red._verify2(this, num); + return this.red.mul(this, num); + }; + + BN.prototype.redIMul = function redIMul (num) { + assert(this.red, 'redMul works only with red numbers'); + this.red._verify2(this, num); + return this.red.imul(this, num); + }; + + BN.prototype.redSqr = function redSqr () { + assert(this.red, 'redSqr works only with red numbers'); + this.red._verify1(this); + return this.red.sqr(this); + }; + + BN.prototype.redISqr = function redISqr () { + assert(this.red, 'redISqr works only with red numbers'); + this.red._verify1(this); + return this.red.isqr(this); + }; + + // Square root over p + BN.prototype.redSqrt = function redSqrt () { + assert(this.red, 'redSqrt works only with red numbers'); + this.red._verify1(this); + return this.red.sqrt(this); + }; + + BN.prototype.redInvm = function redInvm () { + assert(this.red, 'redInvm works only with red numbers'); + this.red._verify1(this); + return this.red.invm(this); + }; + + // Return negative clone of `this` % `red modulo` + BN.prototype.redNeg = function redNeg () { + assert(this.red, 'redNeg works only with red numbers'); + this.red._verify1(this); + return this.red.neg(this); + }; + + BN.prototype.redPow = function redPow (num) { + assert(this.red && !num.red, 'redPow(normalNum)'); + this.red._verify1(this); + return this.red.pow(this, num); + }; + + // Prime numbers with efficient reduction + var primes = { + k256: null, + p224: null, + p192: null, + p25519: null + }; + + // Pseudo-Mersenne prime + function MPrime (name, p) { + // P = 2 ^ N - K + this.name = name; + this.p = new BN(p, 16); + this.n = this.p.bitLength(); + this.k = new BN(1).iushln(this.n).isub(this.p); + + this.tmp = this._tmp(); + } + + MPrime.prototype._tmp = function _tmp () { + var tmp = new BN(null); + tmp.words = new Array(Math.ceil(this.n / 13)); + return tmp; + }; + + MPrime.prototype.ireduce = function ireduce (num) { + // Assumes that `num` is less than `P^2` + // num = HI * (2 ^ N - K) + HI * K + LO = HI * K + LO (mod P) + var r = num; + var rlen; + + do { + this.split(r, this.tmp); + r = this.imulK(r); + r = r.iadd(this.tmp); + rlen = r.bitLength(); + } while (rlen > this.n); + + var cmp = rlen < this.n ? -1 : r.ucmp(this.p); + if (cmp === 0) { + r.words[0] = 0; + r.length = 1; + } else if (cmp > 0) { + r.isub(this.p); + } else { + if (r.strip !== undefined) { + // r is a BN v4 instance + r.strip(); + } else { + // r is a BN v5 instance + r._strip(); + } + } + + return r; + }; + + MPrime.prototype.split = function split (input, out) { + input.iushrn(this.n, 0, out); + }; + + MPrime.prototype.imulK = function imulK (num) { + return num.imul(this.k); + }; + + function K256 () { + MPrime.call( + this, + 'k256', + 'ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff fffffffe fffffc2f'); + } + inherits(K256, MPrime); + + K256.prototype.split = function split (input, output) { + // 256 = 9 * 26 + 22 + var mask = 0x3fffff; + + var outLen = Math.min(input.length, 9); + for (var i = 0; i < outLen; i++) { + output.words[i] = input.words[i]; + } + output.length = outLen; + + if (input.length <= 9) { + input.words[0] = 0; + input.length = 1; + return; + } + + // Shift by 9 limbs + var prev = input.words[9]; + output.words[output.length++] = prev & mask; + + for (i = 10; i < input.length; i++) { + var next = input.words[i] | 0; + input.words[i - 10] = ((next & mask) << 4) | (prev >>> 22); + prev = next; + } + prev >>>= 22; + input.words[i - 10] = prev; + if (prev === 0 && input.length > 10) { + input.length -= 10; + } else { + input.length -= 9; + } + }; + + K256.prototype.imulK = function imulK (num) { + // K = 0x1000003d1 = [ 0x40, 0x3d1 ] + num.words[num.length] = 0; + num.words[num.length + 1] = 0; + num.length += 2; + + // bounded at: 0x40 * 0x3ffffff + 0x3d0 = 0x100000390 + var lo = 0; + for (var i = 0; i < num.length; i++) { + var w = num.words[i] | 0; + lo += w * 0x3d1; + num.words[i] = lo & 0x3ffffff; + lo = w * 0x40 + ((lo / 0x4000000) | 0); + } + + // Fast length reduction + if (num.words[num.length - 1] === 0) { + num.length--; + if (num.words[num.length - 1] === 0) { + num.length--; + } + } + return num; + }; + + function P224 () { + MPrime.call( + this, + 'p224', + 'ffffffff ffffffff ffffffff ffffffff 00000000 00000000 00000001'); + } + inherits(P224, MPrime); + + function P192 () { + MPrime.call( + this, + 'p192', + 'ffffffff ffffffff ffffffff fffffffe ffffffff ffffffff'); + } + inherits(P192, MPrime); + + function P25519 () { + // 2 ^ 255 - 19 + MPrime.call( + this, + '25519', + '7fffffffffffffff ffffffffffffffff ffffffffffffffff ffffffffffffffed'); + } + inherits(P25519, MPrime); + + P25519.prototype.imulK = function imulK (num) { + // K = 0x13 + var carry = 0; + for (var i = 0; i < num.length; i++) { + var hi = (num.words[i] | 0) * 0x13 + carry; + var lo = hi & 0x3ffffff; + hi >>>= 26; + + num.words[i] = lo; + carry = hi; + } + if (carry !== 0) { + num.words[num.length++] = carry; + } + return num; + }; + + // Exported mostly for testing purposes, use plain name instead + BN._prime = function prime (name) { + // Cached version of prime + if (primes[name]) return primes[name]; + + var prime; + if (name === 'k256') { + prime = new K256(); + } else if (name === 'p224') { + prime = new P224(); + } else if (name === 'p192') { + prime = new P192(); + } else if (name === 'p25519') { + prime = new P25519(); + } else { + throw new Error('Unknown prime ' + name); + } + primes[name] = prime; + + return prime; + }; + + // + // Base reduction engine + // + function Red (m) { + if (typeof m === 'string') { + var prime = BN._prime(m); + this.m = prime.p; + this.prime = prime; + } else { + assert(m.gtn(1), 'modulus must be greater than 1'); + this.m = m; + this.prime = null; + } + } + + Red.prototype._verify1 = function _verify1 (a) { + assert(a.negative === 0, 'red works only with positives'); + assert(a.red, 'red works only with red numbers'); + }; + + Red.prototype._verify2 = function _verify2 (a, b) { + assert((a.negative | b.negative) === 0, 'red works only with positives'); + assert(a.red && a.red === b.red, + 'red works only with red numbers'); + }; + + Red.prototype.imod = function imod (a) { + if (this.prime) return this.prime.ireduce(a)._forceRed(this); + + move(a, a.umod(this.m)._forceRed(this)); + return a; + }; + + Red.prototype.neg = function neg (a) { + if (a.isZero()) { + return a.clone(); + } + + return this.m.sub(a)._forceRed(this); + }; + + Red.prototype.add = function add (a, b) { + this._verify2(a, b); + + var res = a.add(b); + if (res.cmp(this.m) >= 0) { + res.isub(this.m); + } + return res._forceRed(this); + }; + + Red.prototype.iadd = function iadd (a, b) { + this._verify2(a, b); + + var res = a.iadd(b); + if (res.cmp(this.m) >= 0) { + res.isub(this.m); + } + return res; + }; + + Red.prototype.sub = function sub (a, b) { + this._verify2(a, b); + + var res = a.sub(b); + if (res.cmpn(0) < 0) { + res.iadd(this.m); + } + return res._forceRed(this); + }; + + Red.prototype.isub = function isub (a, b) { + this._verify2(a, b); + + var res = a.isub(b); + if (res.cmpn(0) < 0) { + res.iadd(this.m); + } + return res; + }; + + Red.prototype.shl = function shl (a, num) { + this._verify1(a); + return this.imod(a.ushln(num)); + }; + + Red.prototype.imul = function imul (a, b) { + this._verify2(a, b); + return this.imod(a.imul(b)); + }; + + Red.prototype.mul = function mul (a, b) { + this._verify2(a, b); + return this.imod(a.mul(b)); + }; + + Red.prototype.isqr = function isqr (a) { + return this.imul(a, a.clone()); + }; + + Red.prototype.sqr = function sqr (a) { + return this.mul(a, a); + }; + + Red.prototype.sqrt = function sqrt (a) { + if (a.isZero()) return a.clone(); + + var mod3 = this.m.andln(3); + assert(mod3 % 2 === 1); + + // Fast case + if (mod3 === 3) { + var pow = this.m.add(new BN(1)).iushrn(2); + return this.pow(a, pow); + } + + // Tonelli-Shanks algorithm (Totally unoptimized and slow) + // + // Find Q and S, that Q * 2 ^ S = (P - 1) + var q = this.m.subn(1); + var s = 0; + while (!q.isZero() && q.andln(1) === 0) { + s++; + q.iushrn(1); + } + assert(!q.isZero()); + + var one = new BN(1).toRed(this); + var nOne = one.redNeg(); + + // Find quadratic non-residue + // NOTE: Max is such because of generalized Riemann hypothesis. + var lpow = this.m.subn(1).iushrn(1); + var z = this.m.bitLength(); + z = new BN(2 * z * z).toRed(this); + + while (this.pow(z, lpow).cmp(nOne) !== 0) { + z.redIAdd(nOne); + } + + var c = this.pow(z, q); + var r = this.pow(a, q.addn(1).iushrn(1)); + var t = this.pow(a, q); + var m = s; + while (t.cmp(one) !== 0) { + var tmp = t; + for (var i = 0; tmp.cmp(one) !== 0; i++) { + tmp = tmp.redSqr(); + } + assert(i < m); + var b = this.pow(c, new BN(1).iushln(m - i - 1)); + + r = r.redMul(b); + c = b.redSqr(); + t = t.redMul(c); + m = i; + } + + return r; + }; + + Red.prototype.invm = function invm (a) { + var inv = a._invmp(this.m); + if (inv.negative !== 0) { + inv.negative = 0; + return this.imod(inv).redNeg(); + } else { + return this.imod(inv); + } + }; + + Red.prototype.pow = function pow (a, num) { + if (num.isZero()) return new BN(1).toRed(this); + if (num.cmpn(1) === 0) return a.clone(); + + var windowSize = 4; + var wnd = new Array(1 << windowSize); + wnd[0] = new BN(1).toRed(this); + wnd[1] = a; + for (var i = 2; i < wnd.length; i++) { + wnd[i] = this.mul(wnd[i - 1], a); + } + + var res = wnd[0]; + var current = 0; + var currentLen = 0; + var start = num.bitLength() % 26; + if (start === 0) { + start = 26; + } + + for (i = num.length - 1; i >= 0; i--) { + var word = num.words[i]; + for (var j = start - 1; j >= 0; j--) { + var bit = (word >> j) & 1; + if (res !== wnd[0]) { + res = this.sqr(res); + } + + if (bit === 0 && current === 0) { + currentLen = 0; + continue; + } + + current <<= 1; + current |= bit; + currentLen++; + if (currentLen !== windowSize && (i !== 0 || j !== 0)) continue; + + res = this.mul(res, wnd[current]); + currentLen = 0; + current = 0; + } + start = 26; + } + + return res; + }; + + Red.prototype.convertTo = function convertTo (num) { + var r = num.umod(this.m); + + return r === num ? r.clone() : r; + }; + + Red.prototype.convertFrom = function convertFrom (num) { + var res = num.clone(); + res.red = null; + return res; + }; + + // + // Montgomery method engine + // + + BN.mont = function mont (num) { + return new Mont(num); + }; + + function Mont (m) { + Red.call(this, m); + + this.shift = this.m.bitLength(); + if (this.shift % 26 !== 0) { + this.shift += 26 - (this.shift % 26); + } + + this.r = new BN(1).iushln(this.shift); + this.r2 = this.imod(this.r.sqr()); + this.rinv = this.r._invmp(this.m); + + this.minv = this.rinv.mul(this.r).isubn(1).div(this.m); + this.minv = this.minv.umod(this.r); + this.minv = this.r.sub(this.minv); + } + inherits(Mont, Red); + + Mont.prototype.convertTo = function convertTo (num) { + return this.imod(num.ushln(this.shift)); + }; + + Mont.prototype.convertFrom = function convertFrom (num) { + var r = this.imod(num.mul(this.rinv)); + r.red = null; + return r; + }; + + Mont.prototype.imul = function imul (a, b) { + if (a.isZero() || b.isZero()) { + a.words[0] = 0; + a.length = 1; + return a; + } + + var t = a.imul(b); + var c = t.maskn(this.shift).mul(this.minv).imaskn(this.shift).mul(this.m); + var u = t.isub(c).iushrn(this.shift); + var res = u; + + if (u.cmp(this.m) >= 0) { + res = u.isub(this.m); + } else if (u.cmpn(0) < 0) { + res = u.iadd(this.m); + } + + return res._forceRed(this); + }; + + Mont.prototype.mul = function mul (a, b) { + if (a.isZero() || b.isZero()) return new BN(0)._forceRed(this); + + var t = a.mul(b); + var c = t.maskn(this.shift).mul(this.minv).imaskn(this.shift).mul(this.m); + var u = t.isub(c).iushrn(this.shift); + var res = u; + if (u.cmp(this.m) >= 0) { + res = u.isub(this.m); + } else if (u.cmpn(0) < 0) { + res = u.iadd(this.m); + } + + return res._forceRed(this); + }; + + Mont.prototype.invm = function invm (a) { + // (AR)^-1 * R^2 = (A^-1 * R^-1) * R^2 = A^-1 * R + var res = this.imod(a._invmp(this.m).mul(this.r2)); + return res._forceRed(this); + }; +})(typeof module === 'undefined' || module, this); + +},{"buffer":19}],18:[function(require,module,exports){ +var r; + +module.exports = function rand(len) { + if (!r) + r = new Rand(null); + + return r.generate(len); +}; + +function Rand(rand) { + this.rand = rand; +} +module.exports.Rand = Rand; + +Rand.prototype.generate = function generate(len) { + return this._rand(len); +}; + +// Emulate crypto API using randy +Rand.prototype._rand = function _rand(n) { + if (this.rand.getBytes) + return this.rand.getBytes(n); + + var res = new Uint8Array(n); + for (var i = 0; i < res.length; i++) + res[i] = this.rand.getByte(); + return res; +}; + +if (typeof self === 'object') { + if (self.crypto && self.crypto.getRandomValues) { + // Modern browsers + Rand.prototype._rand = function _rand(n) { + var arr = new Uint8Array(n); + self.crypto.getRandomValues(arr); + return arr; + }; + } else if (self.msCrypto && self.msCrypto.getRandomValues) { + // IE + Rand.prototype._rand = function _rand(n) { + var arr = new Uint8Array(n); + self.msCrypto.getRandomValues(arr); + return arr; + }; + + // Safari's WebWorkers do not have `crypto` + } else if (typeof window === 'object') { + // Old junk + Rand.prototype._rand = function() { + throw new Error('Not implemented yet'); + }; + } +} else { + // Node.js or Web worker with no crypto support + try { + var crypto = require('crypto'); + if (typeof crypto.randomBytes !== 'function') + throw new Error('Not supported'); + + Rand.prototype._rand = function _rand(n) { + return crypto.randomBytes(n); + }; + } catch (e) { + } +} + +},{"crypto":19}],19:[function(require,module,exports){ + +},{}],20:[function(require,module,exports){ +// based on the aes implimentation in triple sec +// https://github.com/keybase/triplesec +// which is in turn based on the one from crypto-js +// https://code.google.com/p/crypto-js/ + +var Buffer = require('safe-buffer').Buffer + +function asUInt32Array (buf) { + if (!Buffer.isBuffer(buf)) buf = Buffer.from(buf) + + var len = (buf.length / 4) | 0 + var out = new Array(len) + + for (var i = 0; i < len; i++) { + out[i] = buf.readUInt32BE(i * 4) + } + + return out +} + +function scrubVec (v) { + for (var i = 0; i < v.length; v++) { + v[i] = 0 + } +} + +function cryptBlock (M, keySchedule, SUB_MIX, SBOX, nRounds) { + var SUB_MIX0 = SUB_MIX[0] + var SUB_MIX1 = SUB_MIX[1] + var SUB_MIX2 = SUB_MIX[2] + var SUB_MIX3 = SUB_MIX[3] + + var s0 = M[0] ^ keySchedule[0] + var s1 = M[1] ^ keySchedule[1] + var s2 = M[2] ^ keySchedule[2] + var s3 = M[3] ^ keySchedule[3] + var t0, t1, t2, t3 + var ksRow = 4 + + for (var round = 1; round < nRounds; round++) { + t0 = SUB_MIX0[s0 >>> 24] ^ SUB_MIX1[(s1 >>> 16) & 0xff] ^ SUB_MIX2[(s2 >>> 8) & 0xff] ^ SUB_MIX3[s3 & 0xff] ^ keySchedule[ksRow++] + t1 = SUB_MIX0[s1 >>> 24] ^ SUB_MIX1[(s2 >>> 16) & 0xff] ^ SUB_MIX2[(s3 >>> 8) & 0xff] ^ SUB_MIX3[s0 & 0xff] ^ keySchedule[ksRow++] + t2 = SUB_MIX0[s2 >>> 24] ^ SUB_MIX1[(s3 >>> 16) & 0xff] ^ SUB_MIX2[(s0 >>> 8) & 0xff] ^ SUB_MIX3[s1 & 0xff] ^ keySchedule[ksRow++] + t3 = SUB_MIX0[s3 >>> 24] ^ SUB_MIX1[(s0 >>> 16) & 0xff] ^ SUB_MIX2[(s1 >>> 8) & 0xff] ^ SUB_MIX3[s2 & 0xff] ^ keySchedule[ksRow++] + s0 = t0 + s1 = t1 + s2 = t2 + s3 = t3 + } + + t0 = ((SBOX[s0 >>> 24] << 24) | (SBOX[(s1 >>> 16) & 0xff] << 16) | (SBOX[(s2 >>> 8) & 0xff] << 8) | SBOX[s3 & 0xff]) ^ keySchedule[ksRow++] + t1 = ((SBOX[s1 >>> 24] << 24) | (SBOX[(s2 >>> 16) & 0xff] << 16) | (SBOX[(s3 >>> 8) & 0xff] << 8) | SBOX[s0 & 0xff]) ^ keySchedule[ksRow++] + t2 = ((SBOX[s2 >>> 24] << 24) | (SBOX[(s3 >>> 16) & 0xff] << 16) | (SBOX[(s0 >>> 8) & 0xff] << 8) | SBOX[s1 & 0xff]) ^ keySchedule[ksRow++] + t3 = ((SBOX[s3 >>> 24] << 24) | (SBOX[(s0 >>> 16) & 0xff] << 16) | (SBOX[(s1 >>> 8) & 0xff] << 8) | SBOX[s2 & 0xff]) ^ keySchedule[ksRow++] + t0 = t0 >>> 0 + t1 = t1 >>> 0 + t2 = t2 >>> 0 + t3 = t3 >>> 0 + + return [t0, t1, t2, t3] +} + +// AES constants +var RCON = [0x00, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36] +var G = (function () { + // Compute double table + var d = new Array(256) + for (var j = 0; j < 256; j++) { + if (j < 128) { + d[j] = j << 1 + } else { + d[j] = (j << 1) ^ 0x11b + } + } + + var SBOX = [] + var INV_SBOX = [] + var SUB_MIX = [[], [], [], []] + var INV_SUB_MIX = [[], [], [], []] + + // Walk GF(2^8) + var x = 0 + var xi = 0 + for (var i = 0; i < 256; ++i) { + // Compute sbox + var sx = xi ^ (xi << 1) ^ (xi << 2) ^ (xi << 3) ^ (xi << 4) + sx = (sx >>> 8) ^ (sx & 0xff) ^ 0x63 + SBOX[x] = sx + INV_SBOX[sx] = x + + // Compute multiplication + var x2 = d[x] + var x4 = d[x2] + var x8 = d[x4] + + // Compute sub bytes, mix columns tables + var t = (d[sx] * 0x101) ^ (sx * 0x1010100) + SUB_MIX[0][x] = (t << 24) | (t >>> 8) + SUB_MIX[1][x] = (t << 16) | (t >>> 16) + SUB_MIX[2][x] = (t << 8) | (t >>> 24) + SUB_MIX[3][x] = t + + // Compute inv sub bytes, inv mix columns tables + t = (x8 * 0x1010101) ^ (x4 * 0x10001) ^ (x2 * 0x101) ^ (x * 0x1010100) + INV_SUB_MIX[0][sx] = (t << 24) | (t >>> 8) + INV_SUB_MIX[1][sx] = (t << 16) | (t >>> 16) + INV_SUB_MIX[2][sx] = (t << 8) | (t >>> 24) + INV_SUB_MIX[3][sx] = t + + if (x === 0) { + x = xi = 1 + } else { + x = x2 ^ d[d[d[x8 ^ x2]]] + xi ^= d[d[xi]] + } + } + + return { + SBOX: SBOX, + INV_SBOX: INV_SBOX, + SUB_MIX: SUB_MIX, + INV_SUB_MIX: INV_SUB_MIX + } +})() + +function AES (key) { + this._key = asUInt32Array(key) + this._reset() +} + +AES.blockSize = 4 * 4 +AES.keySize = 256 / 8 +AES.prototype.blockSize = AES.blockSize +AES.prototype.keySize = AES.keySize +AES.prototype._reset = function () { + var keyWords = this._key + var keySize = keyWords.length + var nRounds = keySize + 6 + var ksRows = (nRounds + 1) * 4 + + var keySchedule = [] + for (var k = 0; k < keySize; k++) { + keySchedule[k] = keyWords[k] + } + + for (k = keySize; k < ksRows; k++) { + var t = keySchedule[k - 1] + + if (k % keySize === 0) { + t = (t << 8) | (t >>> 24) + t = + (G.SBOX[t >>> 24] << 24) | + (G.SBOX[(t >>> 16) & 0xff] << 16) | + (G.SBOX[(t >>> 8) & 0xff] << 8) | + (G.SBOX[t & 0xff]) + + t ^= RCON[(k / keySize) | 0] << 24 + } else if (keySize > 6 && k % keySize === 4) { + t = + (G.SBOX[t >>> 24] << 24) | + (G.SBOX[(t >>> 16) & 0xff] << 16) | + (G.SBOX[(t >>> 8) & 0xff] << 8) | + (G.SBOX[t & 0xff]) + } + + keySchedule[k] = keySchedule[k - keySize] ^ t + } + + var invKeySchedule = [] + for (var ik = 0; ik < ksRows; ik++) { + var ksR = ksRows - ik + var tt = keySchedule[ksR - (ik % 4 ? 0 : 4)] + + if (ik < 4 || ksR <= 4) { + invKeySchedule[ik] = tt + } else { + invKeySchedule[ik] = + G.INV_SUB_MIX[0][G.SBOX[tt >>> 24]] ^ + G.INV_SUB_MIX[1][G.SBOX[(tt >>> 16) & 0xff]] ^ + G.INV_SUB_MIX[2][G.SBOX[(tt >>> 8) & 0xff]] ^ + G.INV_SUB_MIX[3][G.SBOX[tt & 0xff]] + } + } + + this._nRounds = nRounds + this._keySchedule = keySchedule + this._invKeySchedule = invKeySchedule +} + +AES.prototype.encryptBlockRaw = function (M) { + M = asUInt32Array(M) + return cryptBlock(M, this._keySchedule, G.SUB_MIX, G.SBOX, this._nRounds) +} + +AES.prototype.encryptBlock = function (M) { + var out = this.encryptBlockRaw(M) + var buf = Buffer.allocUnsafe(16) + buf.writeUInt32BE(out[0], 0) + buf.writeUInt32BE(out[1], 4) + buf.writeUInt32BE(out[2], 8) + buf.writeUInt32BE(out[3], 12) + return buf +} + +AES.prototype.decryptBlock = function (M) { + M = asUInt32Array(M) + + // swap + var m1 = M[1] + M[1] = M[3] + M[3] = m1 + + var out = cryptBlock(M, this._invKeySchedule, G.INV_SUB_MIX, G.INV_SBOX, this._nRounds) + var buf = Buffer.allocUnsafe(16) + buf.writeUInt32BE(out[0], 0) + buf.writeUInt32BE(out[3], 4) + buf.writeUInt32BE(out[2], 8) + buf.writeUInt32BE(out[1], 12) + return buf +} + +AES.prototype.scrub = function () { + scrubVec(this._keySchedule) + scrubVec(this._invKeySchedule) + scrubVec(this._key) +} + +module.exports.AES = AES + +},{"safe-buffer":160}],21:[function(require,module,exports){ +var aes = require('./aes') +var Buffer = require('safe-buffer').Buffer +var Transform = require('cipher-base') +var inherits = require('inherits') +var GHASH = require('./ghash') +var xor = require('buffer-xor') +var incr32 = require('./incr32') + +function xorTest (a, b) { + var out = 0 + if (a.length !== b.length) out++ + + var len = Math.min(a.length, b.length) + for (var i = 0; i < len; ++i) { + out += (a[i] ^ b[i]) + } + + return out +} + +function calcIv (self, iv, ck) { + if (iv.length === 12) { + self._finID = Buffer.concat([iv, Buffer.from([0, 0, 0, 1])]) + return Buffer.concat([iv, Buffer.from([0, 0, 0, 2])]) + } + var ghash = new GHASH(ck) + var len = iv.length + var toPad = len % 16 + ghash.update(iv) + if (toPad) { + toPad = 16 - toPad + ghash.update(Buffer.alloc(toPad, 0)) + } + ghash.update(Buffer.alloc(8, 0)) + var ivBits = len * 8 + var tail = Buffer.alloc(8) + tail.writeUIntBE(ivBits, 0, 8) + ghash.update(tail) + self._finID = ghash.state + var out = Buffer.from(self._finID) + incr32(out) + return out +} +function StreamCipher (mode, key, iv, decrypt) { + Transform.call(this) + + var h = Buffer.alloc(4, 0) + + this._cipher = new aes.AES(key) + var ck = this._cipher.encryptBlock(h) + this._ghash = new GHASH(ck) + iv = calcIv(this, iv, ck) + + this._prev = Buffer.from(iv) + this._cache = Buffer.allocUnsafe(0) + this._secCache = Buffer.allocUnsafe(0) + this._decrypt = decrypt + this._alen = 0 + this._len = 0 + this._mode = mode + + this._authTag = null + this._called = false +} + +inherits(StreamCipher, Transform) + +StreamCipher.prototype._update = function (chunk) { + if (!this._called && this._alen) { + var rump = 16 - (this._alen % 16) + if (rump < 16) { + rump = Buffer.alloc(rump, 0) + this._ghash.update(rump) + } + } + + this._called = true + var out = this._mode.encrypt(this, chunk) + if (this._decrypt) { + this._ghash.update(chunk) + } else { + this._ghash.update(out) + } + this._len += chunk.length + return out +} + +StreamCipher.prototype._final = function () { + if (this._decrypt && !this._authTag) throw new Error('Unsupported state or unable to authenticate data') + + var tag = xor(this._ghash.final(this._alen * 8, this._len * 8), this._cipher.encryptBlock(this._finID)) + if (this._decrypt && xorTest(tag, this._authTag)) throw new Error('Unsupported state or unable to authenticate data') + + this._authTag = tag + this._cipher.scrub() +} + +StreamCipher.prototype.getAuthTag = function getAuthTag () { + if (this._decrypt || !Buffer.isBuffer(this._authTag)) throw new Error('Attempting to get auth tag in unsupported state') + + return this._authTag +} + +StreamCipher.prototype.setAuthTag = function setAuthTag (tag) { + if (!this._decrypt) throw new Error('Attempting to set auth tag in unsupported state') + + this._authTag = tag +} + +StreamCipher.prototype.setAAD = function setAAD (buf) { + if (this._called) throw new Error('Attempting to set AAD in unsupported state') + + this._ghash.update(buf) + this._alen += buf.length +} + +module.exports = StreamCipher + +},{"./aes":20,"./ghash":25,"./incr32":26,"buffer-xor":62,"cipher-base":64,"inherits":132,"safe-buffer":160}],22:[function(require,module,exports){ +var ciphers = require('./encrypter') +var deciphers = require('./decrypter') +var modes = require('./modes/list.json') + +function getCiphers () { + return Object.keys(modes) +} + +exports.createCipher = exports.Cipher = ciphers.createCipher +exports.createCipheriv = exports.Cipheriv = ciphers.createCipheriv +exports.createDecipher = exports.Decipher = deciphers.createDecipher +exports.createDecipheriv = exports.Decipheriv = deciphers.createDecipheriv +exports.listCiphers = exports.getCiphers = getCiphers + +},{"./decrypter":23,"./encrypter":24,"./modes/list.json":34}],23:[function(require,module,exports){ +var AuthCipher = require('./authCipher') +var Buffer = require('safe-buffer').Buffer +var MODES = require('./modes') +var StreamCipher = require('./streamCipher') +var Transform = require('cipher-base') +var aes = require('./aes') +var ebtk = require('evp_bytestokey') +var inherits = require('inherits') + +function Decipher (mode, key, iv) { + Transform.call(this) + + this._cache = new Splitter() + this._last = void 0 + this._cipher = new aes.AES(key) + this._prev = Buffer.from(iv) + this._mode = mode + this._autopadding = true +} + +inherits(Decipher, Transform) + +Decipher.prototype._update = function (data) { + this._cache.add(data) + var chunk + var thing + var out = [] + while ((chunk = this._cache.get(this._autopadding))) { + thing = this._mode.decrypt(this, chunk) + out.push(thing) + } + return Buffer.concat(out) +} + +Decipher.prototype._final = function () { + var chunk = this._cache.flush() + if (this._autopadding) { + return unpad(this._mode.decrypt(this, chunk)) + } else if (chunk) { + throw new Error('data not multiple of block length') + } +} + +Decipher.prototype.setAutoPadding = function (setTo) { + this._autopadding = !!setTo + return this +} + +function Splitter () { + this.cache = Buffer.allocUnsafe(0) +} + +Splitter.prototype.add = function (data) { + this.cache = Buffer.concat([this.cache, data]) +} + +Splitter.prototype.get = function (autoPadding) { + var out + if (autoPadding) { + if (this.cache.length > 16) { + out = this.cache.slice(0, 16) + this.cache = this.cache.slice(16) + return out + } + } else { + if (this.cache.length >= 16) { + out = this.cache.slice(0, 16) + this.cache = this.cache.slice(16) + return out + } + } + + return null +} + +Splitter.prototype.flush = function () { + if (this.cache.length) return this.cache +} + +function unpad (last) { + var padded = last[15] + if (padded < 1 || padded > 16) { + throw new Error('unable to decrypt data') + } + var i = -1 + while (++i < padded) { + if (last[(i + (16 - padded))] !== padded) { + throw new Error('unable to decrypt data') + } + } + if (padded === 16) return + + return last.slice(0, 16 - padded) +} + +function createDecipheriv (suite, password, iv) { + var config = MODES[suite.toLowerCase()] + if (!config) throw new TypeError('invalid suite type') + + if (typeof iv === 'string') iv = Buffer.from(iv) + if (config.mode !== 'GCM' && iv.length !== config.iv) throw new TypeError('invalid iv length ' + iv.length) + + if (typeof password === 'string') password = Buffer.from(password) + if (password.length !== config.key / 8) throw new TypeError('invalid key length ' + password.length) + + if (config.type === 'stream') { + return new StreamCipher(config.module, password, iv, true) + } else if (config.type === 'auth') { + return new AuthCipher(config.module, password, iv, true) + } + + return new Decipher(config.module, password, iv) +} + +function createDecipher (suite, password) { + var config = MODES[suite.toLowerCase()] + if (!config) throw new TypeError('invalid suite type') + + var keys = ebtk(password, false, config.key, config.iv) + return createDecipheriv(suite, keys.key, keys.iv) +} + +exports.createDecipher = createDecipher +exports.createDecipheriv = createDecipheriv + +},{"./aes":20,"./authCipher":21,"./modes":33,"./streamCipher":36,"cipher-base":64,"evp_bytestokey":101,"inherits":132,"safe-buffer":160}],24:[function(require,module,exports){ +var MODES = require('./modes') +var AuthCipher = require('./authCipher') +var Buffer = require('safe-buffer').Buffer +var StreamCipher = require('./streamCipher') +var Transform = require('cipher-base') +var aes = require('./aes') +var ebtk = require('evp_bytestokey') +var inherits = require('inherits') + +function Cipher (mode, key, iv) { + Transform.call(this) + + this._cache = new Splitter() + this._cipher = new aes.AES(key) + this._prev = Buffer.from(iv) + this._mode = mode + this._autopadding = true +} + +inherits(Cipher, Transform) + +Cipher.prototype._update = function (data) { + this._cache.add(data) + var chunk + var thing + var out = [] + + while ((chunk = this._cache.get())) { + thing = this._mode.encrypt(this, chunk) + out.push(thing) + } + + return Buffer.concat(out) +} + +var PADDING = Buffer.alloc(16, 0x10) + +Cipher.prototype._final = function () { + var chunk = this._cache.flush() + if (this._autopadding) { + chunk = this._mode.encrypt(this, chunk) + this._cipher.scrub() + return chunk + } + + if (!chunk.equals(PADDING)) { + this._cipher.scrub() + throw new Error('data not multiple of block length') + } +} + +Cipher.prototype.setAutoPadding = function (setTo) { + this._autopadding = !!setTo + return this +} + +function Splitter () { + this.cache = Buffer.allocUnsafe(0) +} + +Splitter.prototype.add = function (data) { + this.cache = Buffer.concat([this.cache, data]) +} + +Splitter.prototype.get = function () { + if (this.cache.length > 15) { + var out = this.cache.slice(0, 16) + this.cache = this.cache.slice(16) + return out + } + return null +} + +Splitter.prototype.flush = function () { + var len = 16 - this.cache.length + var padBuff = Buffer.allocUnsafe(len) + + var i = -1 + while (++i < len) { + padBuff.writeUInt8(len, i) + } + + return Buffer.concat([this.cache, padBuff]) +} + +function createCipheriv (suite, password, iv) { + var config = MODES[suite.toLowerCase()] + if (!config) throw new TypeError('invalid suite type') + + if (typeof password === 'string') password = Buffer.from(password) + if (password.length !== config.key / 8) throw new TypeError('invalid key length ' + password.length) + + if (typeof iv === 'string') iv = Buffer.from(iv) + if (config.mode !== 'GCM' && iv.length !== config.iv) throw new TypeError('invalid iv length ' + iv.length) + + if (config.type === 'stream') { + return new StreamCipher(config.module, password, iv) + } else if (config.type === 'auth') { + return new AuthCipher(config.module, password, iv) + } + + return new Cipher(config.module, password, iv) +} + +function createCipher (suite, password) { + var config = MODES[suite.toLowerCase()] + if (!config) throw new TypeError('invalid suite type') + + var keys = ebtk(password, false, config.key, config.iv) + return createCipheriv(suite, keys.key, keys.iv) +} + +exports.createCipheriv = createCipheriv +exports.createCipher = createCipher + +},{"./aes":20,"./authCipher":21,"./modes":33,"./streamCipher":36,"cipher-base":64,"evp_bytestokey":101,"inherits":132,"safe-buffer":160}],25:[function(require,module,exports){ +var Buffer = require('safe-buffer').Buffer +var ZEROES = Buffer.alloc(16, 0) + +function toArray (buf) { + return [ + buf.readUInt32BE(0), + buf.readUInt32BE(4), + buf.readUInt32BE(8), + buf.readUInt32BE(12) + ] +} + +function fromArray (out) { + var buf = Buffer.allocUnsafe(16) + buf.writeUInt32BE(out[0] >>> 0, 0) + buf.writeUInt32BE(out[1] >>> 0, 4) + buf.writeUInt32BE(out[2] >>> 0, 8) + buf.writeUInt32BE(out[3] >>> 0, 12) + return buf +} + +function GHASH (key) { + this.h = key + this.state = Buffer.alloc(16, 0) + this.cache = Buffer.allocUnsafe(0) +} + +// from http://bitwiseshiftleft.github.io/sjcl/doc/symbols/src/core_gcm.js.html +// by Juho Vähä-Herttua +GHASH.prototype.ghash = function (block) { + var i = -1 + while (++i < block.length) { + this.state[i] ^= block[i] + } + this._multiply() +} + +GHASH.prototype._multiply = function () { + var Vi = toArray(this.h) + var Zi = [0, 0, 0, 0] + var j, xi, lsbVi + var i = -1 + while (++i < 128) { + xi = (this.state[~~(i / 8)] & (1 << (7 - (i % 8)))) !== 0 + if (xi) { + // Z_i+1 = Z_i ^ V_i + Zi[0] ^= Vi[0] + Zi[1] ^= Vi[1] + Zi[2] ^= Vi[2] + Zi[3] ^= Vi[3] + } + + // Store the value of LSB(V_i) + lsbVi = (Vi[3] & 1) !== 0 + + // V_i+1 = V_i >> 1 + for (j = 3; j > 0; j--) { + Vi[j] = (Vi[j] >>> 1) | ((Vi[j - 1] & 1) << 31) + } + Vi[0] = Vi[0] >>> 1 + + // If LSB(V_i) is 1, V_i+1 = (V_i >> 1) ^ R + if (lsbVi) { + Vi[0] = Vi[0] ^ (0xe1 << 24) + } + } + this.state = fromArray(Zi) +} + +GHASH.prototype.update = function (buf) { + this.cache = Buffer.concat([this.cache, buf]) + var chunk + while (this.cache.length >= 16) { + chunk = this.cache.slice(0, 16) + this.cache = this.cache.slice(16) + this.ghash(chunk) + } +} + +GHASH.prototype.final = function (abl, bl) { + if (this.cache.length) { + this.ghash(Buffer.concat([this.cache, ZEROES], 16)) + } + + this.ghash(fromArray([0, abl, 0, bl])) + return this.state +} + +module.exports = GHASH + +},{"safe-buffer":160}],26:[function(require,module,exports){ +function incr32 (iv) { + var len = iv.length + var item + while (len--) { + item = iv.readUInt8(len) + if (item === 255) { + iv.writeUInt8(0, len) + } else { + item++ + iv.writeUInt8(item, len) + break + } + } +} +module.exports = incr32 + +},{}],27:[function(require,module,exports){ +var xor = require('buffer-xor') + +exports.encrypt = function (self, block) { + var data = xor(block, self._prev) + + self._prev = self._cipher.encryptBlock(data) + return self._prev +} + +exports.decrypt = function (self, block) { + var pad = self._prev + + self._prev = block + var out = self._cipher.decryptBlock(block) + + return xor(out, pad) +} + +},{"buffer-xor":62}],28:[function(require,module,exports){ +var Buffer = require('safe-buffer').Buffer +var xor = require('buffer-xor') + +function encryptStart (self, data, decrypt) { + var len = data.length + var out = xor(data, self._cache) + self._cache = self._cache.slice(len) + self._prev = Buffer.concat([self._prev, decrypt ? data : out]) + return out +} + +exports.encrypt = function (self, data, decrypt) { + var out = Buffer.allocUnsafe(0) + var len + + while (data.length) { + if (self._cache.length === 0) { + self._cache = self._cipher.encryptBlock(self._prev) + self._prev = Buffer.allocUnsafe(0) + } + + if (self._cache.length <= data.length) { + len = self._cache.length + out = Buffer.concat([out, encryptStart(self, data.slice(0, len), decrypt)]) + data = data.slice(len) + } else { + out = Buffer.concat([out, encryptStart(self, data, decrypt)]) + break + } + } + + return out +} + +},{"buffer-xor":62,"safe-buffer":160}],29:[function(require,module,exports){ +var Buffer = require('safe-buffer').Buffer + +function encryptByte (self, byteParam, decrypt) { + var pad + var i = -1 + var len = 8 + var out = 0 + var bit, value + while (++i < len) { + pad = self._cipher.encryptBlock(self._prev) + bit = (byteParam & (1 << (7 - i))) ? 0x80 : 0 + value = pad[0] ^ bit + out += ((value & 0x80) >> (i % 8)) + self._prev = shiftIn(self._prev, decrypt ? bit : value) + } + return out +} + +function shiftIn (buffer, value) { + var len = buffer.length + var i = -1 + var out = Buffer.allocUnsafe(buffer.length) + buffer = Buffer.concat([buffer, Buffer.from([value])]) + + while (++i < len) { + out[i] = buffer[i] << 1 | buffer[i + 1] >> (7) + } + + return out +} + +exports.encrypt = function (self, chunk, decrypt) { + var len = chunk.length + var out = Buffer.allocUnsafe(len) + var i = -1 + + while (++i < len) { + out[i] = encryptByte(self, chunk[i], decrypt) + } + + return out +} + +},{"safe-buffer":160}],30:[function(require,module,exports){ +var Buffer = require('safe-buffer').Buffer + +function encryptByte (self, byteParam, decrypt) { + var pad = self._cipher.encryptBlock(self._prev) + var out = pad[0] ^ byteParam + + self._prev = Buffer.concat([ + self._prev.slice(1), + Buffer.from([decrypt ? byteParam : out]) + ]) + + return out +} + +exports.encrypt = function (self, chunk, decrypt) { + var len = chunk.length + var out = Buffer.allocUnsafe(len) + var i = -1 + + while (++i < len) { + out[i] = encryptByte(self, chunk[i], decrypt) + } + + return out +} + +},{"safe-buffer":160}],31:[function(require,module,exports){ +var xor = require('buffer-xor') +var Buffer = require('safe-buffer').Buffer +var incr32 = require('../incr32') + +function getBlock (self) { + var out = self._cipher.encryptBlockRaw(self._prev) + incr32(self._prev) + return out +} + +var blockSize = 16 +exports.encrypt = function (self, chunk) { + var chunkNum = Math.ceil(chunk.length / blockSize) + var start = self._cache.length + self._cache = Buffer.concat([ + self._cache, + Buffer.allocUnsafe(chunkNum * blockSize) + ]) + for (var i = 0; i < chunkNum; i++) { + var out = getBlock(self) + var offset = start + i * blockSize + self._cache.writeUInt32BE(out[0], offset + 0) + self._cache.writeUInt32BE(out[1], offset + 4) + self._cache.writeUInt32BE(out[2], offset + 8) + self._cache.writeUInt32BE(out[3], offset + 12) + } + var pad = self._cache.slice(0, chunk.length) + self._cache = self._cache.slice(chunk.length) + return xor(chunk, pad) +} + +},{"../incr32":26,"buffer-xor":62,"safe-buffer":160}],32:[function(require,module,exports){ +exports.encrypt = function (self, block) { + return self._cipher.encryptBlock(block) +} + +exports.decrypt = function (self, block) { + return self._cipher.decryptBlock(block) +} + +},{}],33:[function(require,module,exports){ +var modeModules = { + ECB: require('./ecb'), + CBC: require('./cbc'), + CFB: require('./cfb'), + CFB8: require('./cfb8'), + CFB1: require('./cfb1'), + OFB: require('./ofb'), + CTR: require('./ctr'), + GCM: require('./ctr') +} + +var modes = require('./list.json') + +for (var key in modes) { + modes[key].module = modeModules[modes[key].mode] +} + +module.exports = modes + +},{"./cbc":27,"./cfb":28,"./cfb1":29,"./cfb8":30,"./ctr":31,"./ecb":32,"./list.json":34,"./ofb":35}],34:[function(require,module,exports){ +module.exports={ + "aes-128-ecb": { + "cipher": "AES", + "key": 128, + "iv": 0, + "mode": "ECB", + "type": "block" + }, + "aes-192-ecb": { + "cipher": "AES", + "key": 192, + "iv": 0, + "mode": "ECB", + "type": "block" + }, + "aes-256-ecb": { + "cipher": "AES", + "key": 256, + "iv": 0, + "mode": "ECB", + "type": "block" + }, + "aes-128-cbc": { + "cipher": "AES", + "key": 128, + "iv": 16, + "mode": "CBC", + "type": "block" + }, + "aes-192-cbc": { + "cipher": "AES", + "key": 192, + "iv": 16, + "mode": "CBC", + "type": "block" + }, + "aes-256-cbc": { + "cipher": "AES", + "key": 256, + "iv": 16, + "mode": "CBC", + "type": "block" + }, + "aes128": { + "cipher": "AES", + "key": 128, + "iv": 16, + "mode": "CBC", + "type": "block" + }, + "aes192": { + "cipher": "AES", + "key": 192, + "iv": 16, + "mode": "CBC", + "type": "block" + }, + "aes256": { + "cipher": "AES", + "key": 256, + "iv": 16, + "mode": "CBC", + "type": "block" + }, + "aes-128-cfb": { + "cipher": "AES", + "key": 128, + "iv": 16, + "mode": "CFB", + "type": "stream" + }, + "aes-192-cfb": { + "cipher": "AES", + "key": 192, + "iv": 16, + "mode": "CFB", + "type": "stream" + }, + "aes-256-cfb": { + "cipher": "AES", + "key": 256, + "iv": 16, + "mode": "CFB", + "type": "stream" + }, + "aes-128-cfb8": { + "cipher": "AES", + "key": 128, + "iv": 16, + "mode": "CFB8", + "type": "stream" + }, + "aes-192-cfb8": { + "cipher": "AES", + "key": 192, + "iv": 16, + "mode": "CFB8", + "type": "stream" + }, + "aes-256-cfb8": { + "cipher": "AES", + "key": 256, + "iv": 16, + "mode": "CFB8", + "type": "stream" + }, + "aes-128-cfb1": { + "cipher": "AES", + "key": 128, + "iv": 16, + "mode": "CFB1", + "type": "stream" + }, + "aes-192-cfb1": { + "cipher": "AES", + "key": 192, + "iv": 16, + "mode": "CFB1", + "type": "stream" + }, + "aes-256-cfb1": { + "cipher": "AES", + "key": 256, + "iv": 16, + "mode": "CFB1", + "type": "stream" + }, + "aes-128-ofb": { + "cipher": "AES", + "key": 128, + "iv": 16, + "mode": "OFB", + "type": "stream" + }, + "aes-192-ofb": { + "cipher": "AES", + "key": 192, + "iv": 16, + "mode": "OFB", + "type": "stream" + }, + "aes-256-ofb": { + "cipher": "AES", + "key": 256, + "iv": 16, + "mode": "OFB", + "type": "stream" + }, + "aes-128-ctr": { + "cipher": "AES", + "key": 128, + "iv": 16, + "mode": "CTR", + "type": "stream" + }, + "aes-192-ctr": { + "cipher": "AES", + "key": 192, + "iv": 16, + "mode": "CTR", + "type": "stream" + }, + "aes-256-ctr": { + "cipher": "AES", + "key": 256, + "iv": 16, + "mode": "CTR", + "type": "stream" + }, + "aes-128-gcm": { + "cipher": "AES", + "key": 128, + "iv": 12, + "mode": "GCM", + "type": "auth" + }, + "aes-192-gcm": { + "cipher": "AES", + "key": 192, + "iv": 12, + "mode": "GCM", + "type": "auth" + }, + "aes-256-gcm": { + "cipher": "AES", + "key": 256, + "iv": 12, + "mode": "GCM", + "type": "auth" + } +} + +},{}],35:[function(require,module,exports){ +(function (Buffer){(function (){ +var xor = require('buffer-xor') + +function getBlock (self) { + self._prev = self._cipher.encryptBlock(self._prev) + return self._prev +} + +exports.encrypt = function (self, chunk) { + while (self._cache.length < chunk.length) { + self._cache = Buffer.concat([self._cache, getBlock(self)]) + } + + var pad = self._cache.slice(0, chunk.length) + self._cache = self._cache.slice(chunk.length) + return xor(chunk, pad) +} + +}).call(this)}).call(this,require("buffer").Buffer) +},{"buffer":63,"buffer-xor":62}],36:[function(require,module,exports){ +var aes = require('./aes') +var Buffer = require('safe-buffer').Buffer +var Transform = require('cipher-base') +var inherits = require('inherits') + +function StreamCipher (mode, key, iv, decrypt) { + Transform.call(this) + + this._cipher = new aes.AES(key) + this._prev = Buffer.from(iv) + this._cache = Buffer.allocUnsafe(0) + this._secCache = Buffer.allocUnsafe(0) + this._decrypt = decrypt + this._mode = mode +} + +inherits(StreamCipher, Transform) + +StreamCipher.prototype._update = function (chunk) { + return this._mode.encrypt(this, chunk, this._decrypt) +} + +StreamCipher.prototype._final = function () { + this._cipher.scrub() +} + +module.exports = StreamCipher + +},{"./aes":20,"cipher-base":64,"inherits":132,"safe-buffer":160}],37:[function(require,module,exports){ +var DES = require('browserify-des') +var aes = require('browserify-aes/browser') +var aesModes = require('browserify-aes/modes') +var desModes = require('browserify-des/modes') +var ebtk = require('evp_bytestokey') + +function createCipher (suite, password) { + suite = suite.toLowerCase() + + var keyLen, ivLen + if (aesModes[suite]) { + keyLen = aesModes[suite].key + ivLen = aesModes[suite].iv + } else if (desModes[suite]) { + keyLen = desModes[suite].key * 8 + ivLen = desModes[suite].iv + } else { + throw new TypeError('invalid suite type') + } + + var keys = ebtk(password, false, keyLen, ivLen) + return createCipheriv(suite, keys.key, keys.iv) +} + +function createDecipher (suite, password) { + suite = suite.toLowerCase() + + var keyLen, ivLen + if (aesModes[suite]) { + keyLen = aesModes[suite].key + ivLen = aesModes[suite].iv + } else if (desModes[suite]) { + keyLen = desModes[suite].key * 8 + ivLen = desModes[suite].iv + } else { + throw new TypeError('invalid suite type') + } + + var keys = ebtk(password, false, keyLen, ivLen) + return createDecipheriv(suite, keys.key, keys.iv) +} + +function createCipheriv (suite, key, iv) { + suite = suite.toLowerCase() + if (aesModes[suite]) return aes.createCipheriv(suite, key, iv) + if (desModes[suite]) return new DES({ key: key, iv: iv, mode: suite }) + + throw new TypeError('invalid suite type') +} + +function createDecipheriv (suite, key, iv) { + suite = suite.toLowerCase() + if (aesModes[suite]) return aes.createDecipheriv(suite, key, iv) + if (desModes[suite]) return new DES({ key: key, iv: iv, mode: suite, decrypt: true }) + + throw new TypeError('invalid suite type') +} + +function getCiphers () { + return Object.keys(desModes).concat(aes.getCiphers()) +} + +exports.createCipher = exports.Cipher = createCipher +exports.createCipheriv = exports.Cipheriv = createCipheriv +exports.createDecipher = exports.Decipher = createDecipher +exports.createDecipheriv = exports.Decipheriv = createDecipheriv +exports.listCiphers = exports.getCiphers = getCiphers + +},{"browserify-aes/browser":22,"browserify-aes/modes":33,"browserify-des":38,"browserify-des/modes":39,"evp_bytestokey":101}],38:[function(require,module,exports){ +var CipherBase = require('cipher-base') +var des = require('des.js') +var inherits = require('inherits') +var Buffer = require('safe-buffer').Buffer + +var modes = { + 'des-ede3-cbc': des.CBC.instantiate(des.EDE), + 'des-ede3': des.EDE, + 'des-ede-cbc': des.CBC.instantiate(des.EDE), + 'des-ede': des.EDE, + 'des-cbc': des.CBC.instantiate(des.DES), + 'des-ecb': des.DES +} +modes.des = modes['des-cbc'] +modes.des3 = modes['des-ede3-cbc'] +module.exports = DES +inherits(DES, CipherBase) +function DES (opts) { + CipherBase.call(this) + var modeName = opts.mode.toLowerCase() + var mode = modes[modeName] + var type + if (opts.decrypt) { + type = 'decrypt' + } else { + type = 'encrypt' + } + var key = opts.key + if (!Buffer.isBuffer(key)) { + key = Buffer.from(key) + } + if (modeName === 'des-ede' || modeName === 'des-ede-cbc') { + key = Buffer.concat([key, key.slice(0, 8)]) + } + var iv = opts.iv + if (!Buffer.isBuffer(iv)) { + iv = Buffer.from(iv) + } + this._des = mode.create({ + key: key, + iv: iv, + type: type + }) +} +DES.prototype._update = function (data) { + return Buffer.from(this._des.update(data)) +} +DES.prototype._final = function () { + return Buffer.from(this._des.final()) +} + +},{"cipher-base":64,"des.js":72,"inherits":132,"safe-buffer":160}],39:[function(require,module,exports){ +exports['des-ecb'] = { + key: 8, + iv: 0 +} +exports['des-cbc'] = exports.des = { + key: 8, + iv: 8 +} +exports['des-ede3-cbc'] = exports.des3 = { + key: 24, + iv: 8 +} +exports['des-ede3'] = { + key: 24, + iv: 0 +} +exports['des-ede-cbc'] = { + key: 16, + iv: 8 +} +exports['des-ede'] = { + key: 16, + iv: 0 +} + +},{}],40:[function(require,module,exports){ +(function (Buffer){(function (){ +var BN = require('bn.js') +var randomBytes = require('randombytes') + +function blind (priv) { + var r = getr(priv) + var blinder = r.toRed(BN.mont(priv.modulus)).redPow(new BN(priv.publicExponent)).fromRed() + return { blinder: blinder, unblinder: r.invm(priv.modulus) } +} + +function getr (priv) { + var len = priv.modulus.byteLength() + var r + do { + r = new BN(randomBytes(len)) + } while (r.cmp(priv.modulus) >= 0 || !r.umod(priv.prime1) || !r.umod(priv.prime2)) + return r +} + +function crt (msg, priv) { + var blinds = blind(priv) + var len = priv.modulus.byteLength() + var blinded = new BN(msg).mul(blinds.blinder).umod(priv.modulus) + var c1 = blinded.toRed(BN.mont(priv.prime1)) + var c2 = blinded.toRed(BN.mont(priv.prime2)) + var qinv = priv.coefficient + var p = priv.prime1 + var q = priv.prime2 + var m1 = c1.redPow(priv.exponent1).fromRed() + var m2 = c2.redPow(priv.exponent2).fromRed() + var h = m1.isub(m2).imul(qinv).umod(p).imul(q) + return m2.iadd(h).imul(blinds.unblinder).umod(priv.modulus).toArrayLike(Buffer, 'be', len) +} +crt.getr = getr + +module.exports = crt + +}).call(this)}).call(this,require("buffer").Buffer) +},{"bn.js":17,"buffer":63,"randombytes":157}],41:[function(require,module,exports){ +module.exports = require('./browser/algorithms.json') + +},{"./browser/algorithms.json":42}],42:[function(require,module,exports){ +module.exports={ + "sha224WithRSAEncryption": { + "sign": "rsa", + "hash": "sha224", + "id": "302d300d06096086480165030402040500041c" + }, + "RSA-SHA224": { + "sign": "ecdsa/rsa", + "hash": "sha224", + "id": "302d300d06096086480165030402040500041c" + }, + "sha256WithRSAEncryption": { + "sign": "rsa", + "hash": "sha256", + "id": "3031300d060960864801650304020105000420" + }, + "RSA-SHA256": { + "sign": "ecdsa/rsa", + "hash": "sha256", + "id": "3031300d060960864801650304020105000420" + }, + "sha384WithRSAEncryption": { + "sign": "rsa", + "hash": "sha384", + "id": "3041300d060960864801650304020205000430" + }, + "RSA-SHA384": { + "sign": "ecdsa/rsa", + "hash": "sha384", + "id": "3041300d060960864801650304020205000430" + }, + "sha512WithRSAEncryption": { + "sign": "rsa", + "hash": "sha512", + "id": "3051300d060960864801650304020305000440" + }, + "RSA-SHA512": { + "sign": "ecdsa/rsa", + "hash": "sha512", + "id": "3051300d060960864801650304020305000440" + }, + "RSA-SHA1": { + "sign": "rsa", + "hash": "sha1", + "id": "3021300906052b0e03021a05000414" + }, + "ecdsa-with-SHA1": { + "sign": "ecdsa", + "hash": "sha1", + "id": "" + }, + "sha256": { + "sign": "ecdsa", + "hash": "sha256", + "id": "" + }, + "sha224": { + "sign": "ecdsa", + "hash": "sha224", + "id": "" + }, + "sha384": { + "sign": "ecdsa", + "hash": "sha384", + "id": "" + }, + "sha512": { + "sign": "ecdsa", + "hash": "sha512", + "id": "" + }, + "DSA-SHA": { + "sign": "dsa", + "hash": "sha1", + "id": "" + }, + "DSA-SHA1": { + "sign": "dsa", + "hash": "sha1", + "id": "" + }, + "DSA": { + "sign": "dsa", + "hash": "sha1", + "id": "" + }, + "DSA-WITH-SHA224": { + "sign": "dsa", + "hash": "sha224", + "id": "" + }, + "DSA-SHA224": { + "sign": "dsa", + "hash": "sha224", + "id": "" + }, + "DSA-WITH-SHA256": { + "sign": "dsa", + "hash": "sha256", + "id": "" + }, + "DSA-SHA256": { + "sign": "dsa", + "hash": "sha256", + "id": "" + }, + "DSA-WITH-SHA384": { + "sign": "dsa", + "hash": "sha384", + "id": "" + }, + "DSA-SHA384": { + "sign": "dsa", + "hash": "sha384", + "id": "" + }, + "DSA-WITH-SHA512": { + "sign": "dsa", + "hash": "sha512", + "id": "" + }, + "DSA-SHA512": { + "sign": "dsa", + "hash": "sha512", + "id": "" + }, + "DSA-RIPEMD160": { + "sign": "dsa", + "hash": "rmd160", + "id": "" + }, + "ripemd160WithRSA": { + "sign": "rsa", + "hash": "rmd160", + "id": "3021300906052b2403020105000414" + }, + "RSA-RIPEMD160": { + "sign": "rsa", + "hash": "rmd160", + "id": "3021300906052b2403020105000414" + }, + "md5WithRSAEncryption": { + "sign": "rsa", + "hash": "md5", + "id": "3020300c06082a864886f70d020505000410" + }, + "RSA-MD5": { + "sign": "rsa", + "hash": "md5", + "id": "3020300c06082a864886f70d020505000410" + } +} + +},{}],43:[function(require,module,exports){ +module.exports={ + "1.3.132.0.10": "secp256k1", + "1.3.132.0.33": "p224", + "1.2.840.10045.3.1.1": "p192", + "1.2.840.10045.3.1.7": "p256", + "1.3.132.0.34": "p384", + "1.3.132.0.35": "p521" +} + +},{}],44:[function(require,module,exports){ +var Buffer = require('safe-buffer').Buffer +var createHash = require('create-hash') +var stream = require('readable-stream') +var inherits = require('inherits') +var sign = require('./sign') +var verify = require('./verify') + +var algorithms = require('./algorithms.json') +Object.keys(algorithms).forEach(function (key) { + algorithms[key].id = Buffer.from(algorithms[key].id, 'hex') + algorithms[key.toLowerCase()] = algorithms[key] +}) + +function Sign (algorithm) { + stream.Writable.call(this) + + var data = algorithms[algorithm] + if (!data) throw new Error('Unknown message digest') + + this._hashType = data.hash + this._hash = createHash(data.hash) + this._tag = data.id + this._signType = data.sign +} +inherits(Sign, stream.Writable) + +Sign.prototype._write = function _write (data, _, done) { + this._hash.update(data) + done() +} + +Sign.prototype.update = function update (data, enc) { + if (typeof data === 'string') data = Buffer.from(data, enc) + + this._hash.update(data) + return this +} + +Sign.prototype.sign = function signMethod (key, enc) { + this.end() + var hash = this._hash.digest() + var sig = sign(hash, key, this._hashType, this._signType, this._tag) + + return enc ? sig.toString(enc) : sig +} + +function Verify (algorithm) { + stream.Writable.call(this) + + var data = algorithms[algorithm] + if (!data) throw new Error('Unknown message digest') + + this._hash = createHash(data.hash) + this._tag = data.id + this._signType = data.sign +} +inherits(Verify, stream.Writable) + +Verify.prototype._write = function _write (data, _, done) { + this._hash.update(data) + done() +} + +Verify.prototype.update = function update (data, enc) { + if (typeof data === 'string') data = Buffer.from(data, enc) + + this._hash.update(data) + return this +} + +Verify.prototype.verify = function verifyMethod (key, sig, enc) { + if (typeof sig === 'string') sig = Buffer.from(sig, enc) + + this.end() + var hash = this._hash.digest() + return verify(sig, hash, key, this._signType, this._tag) +} + +function createSign (algorithm) { + return new Sign(algorithm) +} + +function createVerify (algorithm) { + return new Verify(algorithm) +} + +module.exports = { + Sign: createSign, + Verify: createVerify, + createSign: createSign, + createVerify: createVerify +} + +},{"./algorithms.json":42,"./sign":45,"./verify":46,"create-hash":67,"inherits":132,"readable-stream":61,"safe-buffer":160}],45:[function(require,module,exports){ +// much of this based on https://github.com/indutny/self-signed/blob/gh-pages/lib/rsa.js +var Buffer = require('safe-buffer').Buffer +var createHmac = require('create-hmac') +var crt = require('browserify-rsa') +var EC = require('elliptic').ec +var BN = require('bn.js') +var parseKeys = require('parse-asn1') +var curves = require('./curves.json') + +function sign (hash, key, hashType, signType, tag) { + var priv = parseKeys(key) + if (priv.curve) { + // rsa keys can be interpreted as ecdsa ones in openssl + if (signType !== 'ecdsa' && signType !== 'ecdsa/rsa') throw new Error('wrong private key type') + return ecSign(hash, priv) + } else if (priv.type === 'dsa') { + if (signType !== 'dsa') throw new Error('wrong private key type') + return dsaSign(hash, priv, hashType) + } else { + if (signType !== 'rsa' && signType !== 'ecdsa/rsa') throw new Error('wrong private key type') + } + hash = Buffer.concat([tag, hash]) + var len = priv.modulus.byteLength() + var pad = [0, 1] + while (hash.length + pad.length + 1 < len) pad.push(0xff) + pad.push(0x00) + var i = -1 + while (++i < hash.length) pad.push(hash[i]) + + var out = crt(pad, priv) + return out +} + +function ecSign (hash, priv) { + var curveId = curves[priv.curve.join('.')] + if (!curveId) throw new Error('unknown curve ' + priv.curve.join('.')) + + var curve = new EC(curveId) + var key = curve.keyFromPrivate(priv.privateKey) + var out = key.sign(hash) + + return Buffer.from(out.toDER()) +} + +function dsaSign (hash, priv, algo) { + var x = priv.params.priv_key + var p = priv.params.p + var q = priv.params.q + var g = priv.params.g + var r = new BN(0) + var k + var H = bits2int(hash, q).mod(q) + var s = false + var kv = getKey(x, q, hash, algo) + while (s === false) { + k = makeKey(q, kv, algo) + r = makeR(g, k, p, q) + s = k.invm(q).imul(H.add(x.mul(r))).mod(q) + if (s.cmpn(0) === 0) { + s = false + r = new BN(0) + } + } + return toDER(r, s) +} + +function toDER (r, s) { + r = r.toArray() + s = s.toArray() + + // Pad values + if (r[0] & 0x80) r = [0].concat(r) + if (s[0] & 0x80) s = [0].concat(s) + + var total = r.length + s.length + 4 + var res = [0x30, total, 0x02, r.length] + res = res.concat(r, [0x02, s.length], s) + return Buffer.from(res) +} + +function getKey (x, q, hash, algo) { + x = Buffer.from(x.toArray()) + if (x.length < q.byteLength()) { + var zeros = Buffer.alloc(q.byteLength() - x.length) + x = Buffer.concat([zeros, x]) + } + var hlen = hash.length + var hbits = bits2octets(hash, q) + var v = Buffer.alloc(hlen) + v.fill(1) + var k = Buffer.alloc(hlen) + k = createHmac(algo, k).update(v).update(Buffer.from([0])).update(x).update(hbits).digest() + v = createHmac(algo, k).update(v).digest() + k = createHmac(algo, k).update(v).update(Buffer.from([1])).update(x).update(hbits).digest() + v = createHmac(algo, k).update(v).digest() + return { k: k, v: v } +} + +function bits2int (obits, q) { + var bits = new BN(obits) + var shift = (obits.length << 3) - q.bitLength() + if (shift > 0) bits.ishrn(shift) + return bits +} + +function bits2octets (bits, q) { + bits = bits2int(bits, q) + bits = bits.mod(q) + var out = Buffer.from(bits.toArray()) + if (out.length < q.byteLength()) { + var zeros = Buffer.alloc(q.byteLength() - out.length) + out = Buffer.concat([zeros, out]) + } + return out +} + +function makeKey (q, kv, algo) { + var t + var k + + do { + t = Buffer.alloc(0) + + while (t.length * 8 < q.bitLength()) { + kv.v = createHmac(algo, kv.k).update(kv.v).digest() + t = Buffer.concat([t, kv.v]) + } + + k = bits2int(t, q) + kv.k = createHmac(algo, kv.k).update(kv.v).update(Buffer.from([0])).digest() + kv.v = createHmac(algo, kv.k).update(kv.v).digest() + } while (k.cmp(q) !== -1) + + return k +} + +function makeR (g, k, p, q) { + return g.toRed(BN.mont(p)).redPow(k).fromRed().mod(q) +} + +module.exports = sign +module.exports.getKey = getKey +module.exports.makeKey = makeKey + +},{"./curves.json":43,"bn.js":17,"browserify-rsa":40,"create-hmac":69,"elliptic":83,"parse-asn1":142,"safe-buffer":160}],46:[function(require,module,exports){ +// much of this based on https://github.com/indutny/self-signed/blob/gh-pages/lib/rsa.js +var Buffer = require('safe-buffer').Buffer +var BN = require('bn.js') +var EC = require('elliptic').ec +var parseKeys = require('parse-asn1') +var curves = require('./curves.json') + +function verify (sig, hash, key, signType, tag) { + var pub = parseKeys(key) + if (pub.type === 'ec') { + // rsa keys can be interpreted as ecdsa ones in openssl + if (signType !== 'ecdsa' && signType !== 'ecdsa/rsa') throw new Error('wrong public key type') + return ecVerify(sig, hash, pub) + } else if (pub.type === 'dsa') { + if (signType !== 'dsa') throw new Error('wrong public key type') + return dsaVerify(sig, hash, pub) + } else { + if (signType !== 'rsa' && signType !== 'ecdsa/rsa') throw new Error('wrong public key type') + } + hash = Buffer.concat([tag, hash]) + var len = pub.modulus.byteLength() + var pad = [1] + var padNum = 0 + while (hash.length + pad.length + 2 < len) { + pad.push(0xff) + padNum++ + } + pad.push(0x00) + var i = -1 + while (++i < hash.length) { + pad.push(hash[i]) + } + pad = Buffer.from(pad) + var red = BN.mont(pub.modulus) + sig = new BN(sig).toRed(red) + + sig = sig.redPow(new BN(pub.publicExponent)) + sig = Buffer.from(sig.fromRed().toArray()) + var out = padNum < 8 ? 1 : 0 + len = Math.min(sig.length, pad.length) + if (sig.length !== pad.length) out = 1 + + i = -1 + while (++i < len) out |= sig[i] ^ pad[i] + return out === 0 +} + +function ecVerify (sig, hash, pub) { + var curveId = curves[pub.data.algorithm.curve.join('.')] + if (!curveId) throw new Error('unknown curve ' + pub.data.algorithm.curve.join('.')) + + var curve = new EC(curveId) + var pubkey = pub.data.subjectPrivateKey.data + + return curve.verify(hash, sig, pubkey) +} + +function dsaVerify (sig, hash, pub) { + var p = pub.data.p + var q = pub.data.q + var g = pub.data.g + var y = pub.data.pub_key + var unpacked = parseKeys.signature.decode(sig, 'der') + var s = unpacked.s + var r = unpacked.r + checkValue(s, q) + checkValue(r, q) + var montp = BN.mont(p) + var w = s.invm(q) + var v = g.toRed(montp) + .redPow(new BN(hash).mul(w).mod(q)) + .fromRed() + .mul(y.toRed(montp).redPow(r.mul(w).mod(q)).fromRed()) + .mod(p) + .mod(q) + return v.cmp(r) === 0 +} + +function checkValue (b, q) { + if (b.cmpn(0) <= 0) throw new Error('invalid sig') + if (b.cmp(q) >= q) throw new Error('invalid sig') +} + +module.exports = verify + +},{"./curves.json":43,"bn.js":17,"elliptic":83,"parse-asn1":142,"safe-buffer":160}],47:[function(require,module,exports){ +'use strict'; + +function _inheritsLoose(subClass, superClass) { subClass.prototype = Object.create(superClass.prototype); subClass.prototype.constructor = subClass; subClass.__proto__ = superClass; } + +var codes = {}; + +function createErrorType(code, message, Base) { + if (!Base) { + Base = Error; + } + + function getMessage(arg1, arg2, arg3) { + if (typeof message === 'string') { + return message; + } else { + return message(arg1, arg2, arg3); + } + } + + var NodeError = + /*#__PURE__*/ + function (_Base) { + _inheritsLoose(NodeError, _Base); + + function NodeError(arg1, arg2, arg3) { + return _Base.call(this, getMessage(arg1, arg2, arg3)) || this; + } + + return NodeError; + }(Base); + + NodeError.prototype.name = Base.name; + NodeError.prototype.code = code; + codes[code] = NodeError; +} // https://github.com/nodejs/node/blob/v10.8.0/lib/internal/errors.js + + +function oneOf(expected, thing) { + if (Array.isArray(expected)) { + var len = expected.length; + expected = expected.map(function (i) { + return String(i); + }); + + if (len > 2) { + return "one of ".concat(thing, " ").concat(expected.slice(0, len - 1).join(', '), ", or ") + expected[len - 1]; + } else if (len === 2) { + return "one of ".concat(thing, " ").concat(expected[0], " or ").concat(expected[1]); + } else { + return "of ".concat(thing, " ").concat(expected[0]); + } + } else { + return "of ".concat(thing, " ").concat(String(expected)); + } +} // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/startsWith + + +function startsWith(str, search, pos) { + return str.substr(!pos || pos < 0 ? 0 : +pos, search.length) === search; +} // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/endsWith + + +function endsWith(str, search, this_len) { + if (this_len === undefined || this_len > str.length) { + this_len = str.length; + } + + return str.substring(this_len - search.length, this_len) === search; +} // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/includes + + +function includes(str, search, start) { + if (typeof start !== 'number') { + start = 0; + } + + if (start + search.length > str.length) { + return false; + } else { + return str.indexOf(search, start) !== -1; + } +} + +createErrorType('ERR_INVALID_OPT_VALUE', function (name, value) { + return 'The value "' + value + '" is invalid for option "' + name + '"'; +}, TypeError); +createErrorType('ERR_INVALID_ARG_TYPE', function (name, expected, actual) { + // determiner: 'must be' or 'must not be' + var determiner; + + if (typeof expected === 'string' && startsWith(expected, 'not ')) { + determiner = 'must not be'; + expected = expected.replace(/^not /, ''); + } else { + determiner = 'must be'; + } + + var msg; + + if (endsWith(name, ' argument')) { + // For cases like 'first argument' + msg = "The ".concat(name, " ").concat(determiner, " ").concat(oneOf(expected, 'type')); + } else { + var type = includes(name, '.') ? 'property' : 'argument'; + msg = "The \"".concat(name, "\" ").concat(type, " ").concat(determiner, " ").concat(oneOf(expected, 'type')); + } + + msg += ". Received type ".concat(typeof actual); + return msg; +}, TypeError); +createErrorType('ERR_STREAM_PUSH_AFTER_EOF', 'stream.push() after EOF'); +createErrorType('ERR_METHOD_NOT_IMPLEMENTED', function (name) { + return 'The ' + name + ' method is not implemented'; +}); +createErrorType('ERR_STREAM_PREMATURE_CLOSE', 'Premature close'); +createErrorType('ERR_STREAM_DESTROYED', function (name) { + return 'Cannot call ' + name + ' after a stream was destroyed'; +}); +createErrorType('ERR_MULTIPLE_CALLBACK', 'Callback called multiple times'); +createErrorType('ERR_STREAM_CANNOT_PIPE', 'Cannot pipe, not readable'); +createErrorType('ERR_STREAM_WRITE_AFTER_END', 'write after end'); +createErrorType('ERR_STREAM_NULL_VALUES', 'May not write null values to stream', TypeError); +createErrorType('ERR_UNKNOWN_ENCODING', function (arg) { + return 'Unknown encoding: ' + arg; +}, TypeError); +createErrorType('ERR_STREAM_UNSHIFT_AFTER_END_EVENT', 'stream.unshift() after end event'); +module.exports.codes = codes; + +},{}],48:[function(require,module,exports){ +(function (process){(function (){ +// Copyright Joyent, Inc. and other Node contributors. +// +// 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. +// a duplex stream is just a stream that is both readable and writable. +// Since JS doesn't have multiple prototypal inheritance, this class +// prototypally inherits from Readable, and then parasitically from +// Writable. +'use strict'; +/**/ + +var objectKeys = Object.keys || function (obj) { + var keys = []; + + for (var key in obj) { + keys.push(key); + } + + return keys; +}; +/**/ + + +module.exports = Duplex; + +var Readable = require('./_stream_readable'); + +var Writable = require('./_stream_writable'); + +require('inherits')(Duplex, Readable); + +{ + // Allow the keys array to be GC'ed. + var keys = objectKeys(Writable.prototype); + + for (var v = 0; v < keys.length; v++) { + var method = keys[v]; + if (!Duplex.prototype[method]) Duplex.prototype[method] = Writable.prototype[method]; + } +} + +function Duplex(options) { + if (!(this instanceof Duplex)) return new Duplex(options); + Readable.call(this, options); + Writable.call(this, options); + this.allowHalfOpen = true; + + if (options) { + if (options.readable === false) this.readable = false; + if (options.writable === false) this.writable = false; + + if (options.allowHalfOpen === false) { + this.allowHalfOpen = false; + this.once('end', onend); + } + } +} + +Object.defineProperty(Duplex.prototype, 'writableHighWaterMark', { + // making it explicit this property is not enumerable + // because otherwise some prototype manipulation in + // userland will fail + enumerable: false, + get: function get() { + return this._writableState.highWaterMark; + } +}); +Object.defineProperty(Duplex.prototype, 'writableBuffer', { + // making it explicit this property is not enumerable + // because otherwise some prototype manipulation in + // userland will fail + enumerable: false, + get: function get() { + return this._writableState && this._writableState.getBuffer(); + } +}); +Object.defineProperty(Duplex.prototype, 'writableLength', { + // making it explicit this property is not enumerable + // because otherwise some prototype manipulation in + // userland will fail + enumerable: false, + get: function get() { + return this._writableState.length; + } +}); // the no-half-open enforcer + +function onend() { + // If the writable side ended, then we're ok. + if (this._writableState.ended) return; // no more data can be written. + // But allow more writes to happen in this tick. + + process.nextTick(onEndNT, this); +} + +function onEndNT(self) { + self.end(); +} + +Object.defineProperty(Duplex.prototype, 'destroyed', { + // making it explicit this property is not enumerable + // because otherwise some prototype manipulation in + // userland will fail + enumerable: false, + get: function get() { + if (this._readableState === undefined || this._writableState === undefined) { + return false; + } + + return this._readableState.destroyed && this._writableState.destroyed; + }, + set: function set(value) { + // we ignore the value if the stream + // has not been initialized yet + if (this._readableState === undefined || this._writableState === undefined) { + return; + } // backward compatibility, the user is explicitly + // managing destroyed + + + this._readableState.destroyed = value; + this._writableState.destroyed = value; + } +}); +}).call(this)}).call(this,require('_process')) +},{"./_stream_readable":50,"./_stream_writable":52,"_process":149,"inherits":132}],49:[function(require,module,exports){ +// Copyright Joyent, Inc. and other Node contributors. +// +// 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. +// a passthrough stream. +// basically just the most minimal sort of Transform stream. +// Every written chunk gets output as-is. +'use strict'; + +module.exports = PassThrough; + +var Transform = require('./_stream_transform'); + +require('inherits')(PassThrough, Transform); + +function PassThrough(options) { + if (!(this instanceof PassThrough)) return new PassThrough(options); + Transform.call(this, options); +} + +PassThrough.prototype._transform = function (chunk, encoding, cb) { + cb(null, chunk); +}; +},{"./_stream_transform":51,"inherits":132}],50:[function(require,module,exports){ +(function (process,global){(function (){ +// Copyright Joyent, Inc. and other Node contributors. +// +// 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. +'use strict'; + +module.exports = Readable; +/**/ + +var Duplex; +/**/ + +Readable.ReadableState = ReadableState; +/**/ + +var EE = require('events').EventEmitter; + +var EElistenerCount = function EElistenerCount(emitter, type) { + return emitter.listeners(type).length; +}; +/**/ + +/**/ + + +var Stream = require('./internal/streams/stream'); +/**/ + + +var Buffer = require('buffer').Buffer; + +var OurUint8Array = global.Uint8Array || function () {}; + +function _uint8ArrayToBuffer(chunk) { + return Buffer.from(chunk); +} + +function _isUint8Array(obj) { + return Buffer.isBuffer(obj) || obj instanceof OurUint8Array; +} +/**/ + + +var debugUtil = require('util'); + +var debug; + +if (debugUtil && debugUtil.debuglog) { + debug = debugUtil.debuglog('stream'); +} else { + debug = function debug() {}; +} +/**/ + + +var BufferList = require('./internal/streams/buffer_list'); + +var destroyImpl = require('./internal/streams/destroy'); + +var _require = require('./internal/streams/state'), + getHighWaterMark = _require.getHighWaterMark; + +var _require$codes = require('../errors').codes, + ERR_INVALID_ARG_TYPE = _require$codes.ERR_INVALID_ARG_TYPE, + ERR_STREAM_PUSH_AFTER_EOF = _require$codes.ERR_STREAM_PUSH_AFTER_EOF, + ERR_METHOD_NOT_IMPLEMENTED = _require$codes.ERR_METHOD_NOT_IMPLEMENTED, + ERR_STREAM_UNSHIFT_AFTER_END_EVENT = _require$codes.ERR_STREAM_UNSHIFT_AFTER_END_EVENT; // Lazy loaded to improve the startup performance. + + +var StringDecoder; +var createReadableStreamAsyncIterator; +var from; + +require('inherits')(Readable, Stream); + +var errorOrDestroy = destroyImpl.errorOrDestroy; +var kProxyEvents = ['error', 'close', 'destroy', 'pause', 'resume']; + +function prependListener(emitter, event, fn) { + // Sadly this is not cacheable as some libraries bundle their own + // event emitter implementation with them. + if (typeof emitter.prependListener === 'function') return emitter.prependListener(event, fn); // This is a hack to make sure that our error handler is attached before any + // userland ones. NEVER DO THIS. This is here only because this code needs + // to continue to work with older versions of Node.js that do not include + // the prependListener() method. The goal is to eventually remove this hack. + + if (!emitter._events || !emitter._events[event]) emitter.on(event, fn);else if (Array.isArray(emitter._events[event])) emitter._events[event].unshift(fn);else emitter._events[event] = [fn, emitter._events[event]]; +} + +function ReadableState(options, stream, isDuplex) { + Duplex = Duplex || require('./_stream_duplex'); + options = options || {}; // Duplex streams are both readable and writable, but share + // the same options object. + // However, some cases require setting options to different + // values for the readable and the writable sides of the duplex stream. + // These options can be provided separately as readableXXX and writableXXX. + + if (typeof isDuplex !== 'boolean') isDuplex = stream instanceof Duplex; // object stream flag. Used to make read(n) ignore n and to + // make all the buffer merging and length checks go away + + this.objectMode = !!options.objectMode; + if (isDuplex) this.objectMode = this.objectMode || !!options.readableObjectMode; // the point at which it stops calling _read() to fill the buffer + // Note: 0 is a valid value, means "don't call _read preemptively ever" + + this.highWaterMark = getHighWaterMark(this, options, 'readableHighWaterMark', isDuplex); // A linked list is used to store data chunks instead of an array because the + // linked list can remove elements from the beginning faster than + // array.shift() + + this.buffer = new BufferList(); + this.length = 0; + this.pipes = null; + this.pipesCount = 0; + this.flowing = null; + this.ended = false; + this.endEmitted = false; + this.reading = false; // a flag to be able to tell if the event 'readable'/'data' is emitted + // immediately, or on a later tick. We set this to true at first, because + // any actions that shouldn't happen until "later" should generally also + // not happen before the first read call. + + this.sync = true; // whenever we return null, then we set a flag to say + // that we're awaiting a 'readable' event emission. + + this.needReadable = false; + this.emittedReadable = false; + this.readableListening = false; + this.resumeScheduled = false; + this.paused = true; // Should close be emitted on destroy. Defaults to true. + + this.emitClose = options.emitClose !== false; // Should .destroy() be called after 'end' (and potentially 'finish') + + this.autoDestroy = !!options.autoDestroy; // has it been destroyed + + this.destroyed = false; // Crypto is kind of old and crusty. Historically, its default string + // encoding is 'binary' so we have to make this configurable. + // Everything else in the universe uses 'utf8', though. + + this.defaultEncoding = options.defaultEncoding || 'utf8'; // the number of writers that are awaiting a drain event in .pipe()s + + this.awaitDrain = 0; // if true, a maybeReadMore has been scheduled + + this.readingMore = false; + this.decoder = null; + this.encoding = null; + + if (options.encoding) { + if (!StringDecoder) StringDecoder = require('string_decoder/').StringDecoder; + this.decoder = new StringDecoder(options.encoding); + this.encoding = options.encoding; + } +} + +function Readable(options) { + Duplex = Duplex || require('./_stream_duplex'); + if (!(this instanceof Readable)) return new Readable(options); // Checking for a Stream.Duplex instance is faster here instead of inside + // the ReadableState constructor, at least with V8 6.5 + + var isDuplex = this instanceof Duplex; + this._readableState = new ReadableState(options, this, isDuplex); // legacy + + this.readable = true; + + if (options) { + if (typeof options.read === 'function') this._read = options.read; + if (typeof options.destroy === 'function') this._destroy = options.destroy; + } + + Stream.call(this); +} + +Object.defineProperty(Readable.prototype, 'destroyed', { + // making it explicit this property is not enumerable + // because otherwise some prototype manipulation in + // userland will fail + enumerable: false, + get: function get() { + if (this._readableState === undefined) { + return false; + } + + return this._readableState.destroyed; + }, + set: function set(value) { + // we ignore the value if the stream + // has not been initialized yet + if (!this._readableState) { + return; + } // backward compatibility, the user is explicitly + // managing destroyed + + + this._readableState.destroyed = value; + } +}); +Readable.prototype.destroy = destroyImpl.destroy; +Readable.prototype._undestroy = destroyImpl.undestroy; + +Readable.prototype._destroy = function (err, cb) { + cb(err); +}; // Manually shove something into the read() buffer. +// This returns true if the highWaterMark has not been hit yet, +// similar to how Writable.write() returns true if you should +// write() some more. + + +Readable.prototype.push = function (chunk, encoding) { + var state = this._readableState; + var skipChunkCheck; + + if (!state.objectMode) { + if (typeof chunk === 'string') { + encoding = encoding || state.defaultEncoding; + + if (encoding !== state.encoding) { + chunk = Buffer.from(chunk, encoding); + encoding = ''; + } + + skipChunkCheck = true; + } + } else { + skipChunkCheck = true; + } + + return readableAddChunk(this, chunk, encoding, false, skipChunkCheck); +}; // Unshift should *always* be something directly out of read() + + +Readable.prototype.unshift = function (chunk) { + return readableAddChunk(this, chunk, null, true, false); +}; + +function readableAddChunk(stream, chunk, encoding, addToFront, skipChunkCheck) { + debug('readableAddChunk', chunk); + var state = stream._readableState; + + if (chunk === null) { + state.reading = false; + onEofChunk(stream, state); + } else { + var er; + if (!skipChunkCheck) er = chunkInvalid(state, chunk); + + if (er) { + errorOrDestroy(stream, er); + } else if (state.objectMode || chunk && chunk.length > 0) { + if (typeof chunk !== 'string' && !state.objectMode && Object.getPrototypeOf(chunk) !== Buffer.prototype) { + chunk = _uint8ArrayToBuffer(chunk); + } + + if (addToFront) { + if (state.endEmitted) errorOrDestroy(stream, new ERR_STREAM_UNSHIFT_AFTER_END_EVENT());else addChunk(stream, state, chunk, true); + } else if (state.ended) { + errorOrDestroy(stream, new ERR_STREAM_PUSH_AFTER_EOF()); + } else if (state.destroyed) { + return false; + } else { + state.reading = false; + + if (state.decoder && !encoding) { + chunk = state.decoder.write(chunk); + if (state.objectMode || chunk.length !== 0) addChunk(stream, state, chunk, false);else maybeReadMore(stream, state); + } else { + addChunk(stream, state, chunk, false); + } + } + } else if (!addToFront) { + state.reading = false; + maybeReadMore(stream, state); + } + } // We can push more data if we are below the highWaterMark. + // Also, if we have no data yet, we can stand some more bytes. + // This is to work around cases where hwm=0, such as the repl. + + + return !state.ended && (state.length < state.highWaterMark || state.length === 0); +} + +function addChunk(stream, state, chunk, addToFront) { + if (state.flowing && state.length === 0 && !state.sync) { + state.awaitDrain = 0; + stream.emit('data', chunk); + } else { + // update the buffer info. + state.length += state.objectMode ? 1 : chunk.length; + if (addToFront) state.buffer.unshift(chunk);else state.buffer.push(chunk); + if (state.needReadable) emitReadable(stream); + } + + maybeReadMore(stream, state); +} + +function chunkInvalid(state, chunk) { + var er; + + if (!_isUint8Array(chunk) && typeof chunk !== 'string' && chunk !== undefined && !state.objectMode) { + er = new ERR_INVALID_ARG_TYPE('chunk', ['string', 'Buffer', 'Uint8Array'], chunk); + } + + return er; +} + +Readable.prototype.isPaused = function () { + return this._readableState.flowing === false; +}; // backwards compatibility. + + +Readable.prototype.setEncoding = function (enc) { + if (!StringDecoder) StringDecoder = require('string_decoder/').StringDecoder; + var decoder = new StringDecoder(enc); + this._readableState.decoder = decoder; // If setEncoding(null), decoder.encoding equals utf8 + + this._readableState.encoding = this._readableState.decoder.encoding; // Iterate over current buffer to convert already stored Buffers: + + var p = this._readableState.buffer.head; + var content = ''; + + while (p !== null) { + content += decoder.write(p.data); + p = p.next; + } + + this._readableState.buffer.clear(); + + if (content !== '') this._readableState.buffer.push(content); + this._readableState.length = content.length; + return this; +}; // Don't raise the hwm > 1GB + + +var MAX_HWM = 0x40000000; + +function computeNewHighWaterMark(n) { + if (n >= MAX_HWM) { + // TODO(ronag): Throw ERR_VALUE_OUT_OF_RANGE. + n = MAX_HWM; + } else { + // Get the next highest power of 2 to prevent increasing hwm excessively in + // tiny amounts + n--; + n |= n >>> 1; + n |= n >>> 2; + n |= n >>> 4; + n |= n >>> 8; + n |= n >>> 16; + n++; + } + + return n; +} // This function is designed to be inlinable, so please take care when making +// changes to the function body. + + +function howMuchToRead(n, state) { + if (n <= 0 || state.length === 0 && state.ended) return 0; + if (state.objectMode) return 1; + + if (n !== n) { + // Only flow one buffer at a time + if (state.flowing && state.length) return state.buffer.head.data.length;else return state.length; + } // If we're asking for more than the current hwm, then raise the hwm. + + + if (n > state.highWaterMark) state.highWaterMark = computeNewHighWaterMark(n); + if (n <= state.length) return n; // Don't have enough + + if (!state.ended) { + state.needReadable = true; + return 0; + } + + return state.length; +} // you can override either this method, or the async _read(n) below. + + +Readable.prototype.read = function (n) { + debug('read', n); + n = parseInt(n, 10); + var state = this._readableState; + var nOrig = n; + if (n !== 0) state.emittedReadable = false; // if we're doing read(0) to trigger a readable event, but we + // already have a bunch of data in the buffer, then just trigger + // the 'readable' event and move on. + + if (n === 0 && state.needReadable && ((state.highWaterMark !== 0 ? state.length >= state.highWaterMark : state.length > 0) || state.ended)) { + debug('read: emitReadable', state.length, state.ended); + if (state.length === 0 && state.ended) endReadable(this);else emitReadable(this); + return null; + } + + n = howMuchToRead(n, state); // if we've ended, and we're now clear, then finish it up. + + if (n === 0 && state.ended) { + if (state.length === 0) endReadable(this); + return null; + } // All the actual chunk generation logic needs to be + // *below* the call to _read. The reason is that in certain + // synthetic stream cases, such as passthrough streams, _read + // may be a completely synchronous operation which may change + // the state of the read buffer, providing enough data when + // before there was *not* enough. + // + // So, the steps are: + // 1. Figure out what the state of things will be after we do + // a read from the buffer. + // + // 2. If that resulting state will trigger a _read, then call _read. + // Note that this may be asynchronous, or synchronous. Yes, it is + // deeply ugly to write APIs this way, but that still doesn't mean + // that the Readable class should behave improperly, as streams are + // designed to be sync/async agnostic. + // Take note if the _read call is sync or async (ie, if the read call + // has returned yet), so that we know whether or not it's safe to emit + // 'readable' etc. + // + // 3. Actually pull the requested chunks out of the buffer and return. + // if we need a readable event, then we need to do some reading. + + + var doRead = state.needReadable; + debug('need readable', doRead); // if we currently have less than the highWaterMark, then also read some + + if (state.length === 0 || state.length - n < state.highWaterMark) { + doRead = true; + debug('length less than watermark', doRead); + } // however, if we've ended, then there's no point, and if we're already + // reading, then it's unnecessary. + + + if (state.ended || state.reading) { + doRead = false; + debug('reading or ended', doRead); + } else if (doRead) { + debug('do read'); + state.reading = true; + state.sync = true; // if the length is currently zero, then we *need* a readable event. + + if (state.length === 0) state.needReadable = true; // call internal read method + + this._read(state.highWaterMark); + + state.sync = false; // If _read pushed data synchronously, then `reading` will be false, + // and we need to re-evaluate how much data we can return to the user. + + if (!state.reading) n = howMuchToRead(nOrig, state); + } + + var ret; + if (n > 0) ret = fromList(n, state);else ret = null; + + if (ret === null) { + state.needReadable = state.length <= state.highWaterMark; + n = 0; + } else { + state.length -= n; + state.awaitDrain = 0; + } + + if (state.length === 0) { + // If we have nothing in the buffer, then we want to know + // as soon as we *do* get something into the buffer. + if (!state.ended) state.needReadable = true; // If we tried to read() past the EOF, then emit end on the next tick. + + if (nOrig !== n && state.ended) endReadable(this); + } + + if (ret !== null) this.emit('data', ret); + return ret; +}; + +function onEofChunk(stream, state) { + debug('onEofChunk'); + if (state.ended) return; + + if (state.decoder) { + var chunk = state.decoder.end(); + + if (chunk && chunk.length) { + state.buffer.push(chunk); + state.length += state.objectMode ? 1 : chunk.length; + } + } + + state.ended = true; + + if (state.sync) { + // if we are sync, wait until next tick to emit the data. + // Otherwise we risk emitting data in the flow() + // the readable code triggers during a read() call + emitReadable(stream); + } else { + // emit 'readable' now to make sure it gets picked up. + state.needReadable = false; + + if (!state.emittedReadable) { + state.emittedReadable = true; + emitReadable_(stream); + } + } +} // Don't emit readable right away in sync mode, because this can trigger +// another read() call => stack overflow. This way, it might trigger +// a nextTick recursion warning, but that's not so bad. + + +function emitReadable(stream) { + var state = stream._readableState; + debug('emitReadable', state.needReadable, state.emittedReadable); + state.needReadable = false; + + if (!state.emittedReadable) { + debug('emitReadable', state.flowing); + state.emittedReadable = true; + process.nextTick(emitReadable_, stream); + } +} + +function emitReadable_(stream) { + var state = stream._readableState; + debug('emitReadable_', state.destroyed, state.length, state.ended); + + if (!state.destroyed && (state.length || state.ended)) { + stream.emit('readable'); + state.emittedReadable = false; + } // The stream needs another readable event if + // 1. It is not flowing, as the flow mechanism will take + // care of it. + // 2. It is not ended. + // 3. It is below the highWaterMark, so we can schedule + // another readable later. + + + state.needReadable = !state.flowing && !state.ended && state.length <= state.highWaterMark; + flow(stream); +} // at this point, the user has presumably seen the 'readable' event, +// and called read() to consume some data. that may have triggered +// in turn another _read(n) call, in which case reading = true if +// it's in progress. +// However, if we're not ended, or reading, and the length < hwm, +// then go ahead and try to read some more preemptively. + + +function maybeReadMore(stream, state) { + if (!state.readingMore) { + state.readingMore = true; + process.nextTick(maybeReadMore_, stream, state); + } +} + +function maybeReadMore_(stream, state) { + // Attempt to read more data if we should. + // + // The conditions for reading more data are (one of): + // - Not enough data buffered (state.length < state.highWaterMark). The loop + // is responsible for filling the buffer with enough data if such data + // is available. If highWaterMark is 0 and we are not in the flowing mode + // we should _not_ attempt to buffer any extra data. We'll get more data + // when the stream consumer calls read() instead. + // - No data in the buffer, and the stream is in flowing mode. In this mode + // the loop below is responsible for ensuring read() is called. Failing to + // call read here would abort the flow and there's no other mechanism for + // continuing the flow if the stream consumer has just subscribed to the + // 'data' event. + // + // In addition to the above conditions to keep reading data, the following + // conditions prevent the data from being read: + // - The stream has ended (state.ended). + // - There is already a pending 'read' operation (state.reading). This is a + // case where the the stream has called the implementation defined _read() + // method, but they are processing the call asynchronously and have _not_ + // called push() with new data. In this case we skip performing more + // read()s. The execution ends in this method again after the _read() ends + // up calling push() with more data. + while (!state.reading && !state.ended && (state.length < state.highWaterMark || state.flowing && state.length === 0)) { + var len = state.length; + debug('maybeReadMore read 0'); + stream.read(0); + if (len === state.length) // didn't get any data, stop spinning. + break; + } + + state.readingMore = false; +} // abstract method. to be overridden in specific implementation classes. +// call cb(er, data) where data is <= n in length. +// for virtual (non-string, non-buffer) streams, "length" is somewhat +// arbitrary, and perhaps not very meaningful. + + +Readable.prototype._read = function (n) { + errorOrDestroy(this, new ERR_METHOD_NOT_IMPLEMENTED('_read()')); +}; + +Readable.prototype.pipe = function (dest, pipeOpts) { + var src = this; + var state = this._readableState; + + switch (state.pipesCount) { + case 0: + state.pipes = dest; + break; + + case 1: + state.pipes = [state.pipes, dest]; + break; + + default: + state.pipes.push(dest); + break; + } + + state.pipesCount += 1; + debug('pipe count=%d opts=%j', state.pipesCount, pipeOpts); + var doEnd = (!pipeOpts || pipeOpts.end !== false) && dest !== process.stdout && dest !== process.stderr; + var endFn = doEnd ? onend : unpipe; + if (state.endEmitted) process.nextTick(endFn);else src.once('end', endFn); + dest.on('unpipe', onunpipe); + + function onunpipe(readable, unpipeInfo) { + debug('onunpipe'); + + if (readable === src) { + if (unpipeInfo && unpipeInfo.hasUnpiped === false) { + unpipeInfo.hasUnpiped = true; + cleanup(); + } + } + } + + function onend() { + debug('onend'); + dest.end(); + } // when the dest drains, it reduces the awaitDrain counter + // on the source. This would be more elegant with a .once() + // handler in flow(), but adding and removing repeatedly is + // too slow. + + + var ondrain = pipeOnDrain(src); + dest.on('drain', ondrain); + var cleanedUp = false; + + function cleanup() { + debug('cleanup'); // cleanup event handlers once the pipe is broken + + dest.removeListener('close', onclose); + dest.removeListener('finish', onfinish); + dest.removeListener('drain', ondrain); + dest.removeListener('error', onerror); + dest.removeListener('unpipe', onunpipe); + src.removeListener('end', onend); + src.removeListener('end', unpipe); + src.removeListener('data', ondata); + cleanedUp = true; // if the reader is waiting for a drain event from this + // specific writer, then it would cause it to never start + // flowing again. + // So, if this is awaiting a drain, then we just call it now. + // If we don't know, then assume that we are waiting for one. + + if (state.awaitDrain && (!dest._writableState || dest._writableState.needDrain)) ondrain(); + } + + src.on('data', ondata); + + function ondata(chunk) { + debug('ondata'); + var ret = dest.write(chunk); + debug('dest.write', ret); + + if (ret === false) { + // If the user unpiped during `dest.write()`, it is possible + // to get stuck in a permanently paused state if that write + // also returned false. + // => Check whether `dest` is still a piping destination. + if ((state.pipesCount === 1 && state.pipes === dest || state.pipesCount > 1 && indexOf(state.pipes, dest) !== -1) && !cleanedUp) { + debug('false write response, pause', state.awaitDrain); + state.awaitDrain++; + } + + src.pause(); + } + } // if the dest has an error, then stop piping into it. + // however, don't suppress the throwing behavior for this. + + + function onerror(er) { + debug('onerror', er); + unpipe(); + dest.removeListener('error', onerror); + if (EElistenerCount(dest, 'error') === 0) errorOrDestroy(dest, er); + } // Make sure our error handler is attached before userland ones. + + + prependListener(dest, 'error', onerror); // Both close and finish should trigger unpipe, but only once. + + function onclose() { + dest.removeListener('finish', onfinish); + unpipe(); + } + + dest.once('close', onclose); + + function onfinish() { + debug('onfinish'); + dest.removeListener('close', onclose); + unpipe(); + } + + dest.once('finish', onfinish); + + function unpipe() { + debug('unpipe'); + src.unpipe(dest); + } // tell the dest that it's being piped to + + + dest.emit('pipe', src); // start the flow if it hasn't been started already. + + if (!state.flowing) { + debug('pipe resume'); + src.resume(); + } + + return dest; +}; + +function pipeOnDrain(src) { + return function pipeOnDrainFunctionResult() { + var state = src._readableState; + debug('pipeOnDrain', state.awaitDrain); + if (state.awaitDrain) state.awaitDrain--; + + if (state.awaitDrain === 0 && EElistenerCount(src, 'data')) { + state.flowing = true; + flow(src); + } + }; +} + +Readable.prototype.unpipe = function (dest) { + var state = this._readableState; + var unpipeInfo = { + hasUnpiped: false + }; // if we're not piping anywhere, then do nothing. + + if (state.pipesCount === 0) return this; // just one destination. most common case. + + if (state.pipesCount === 1) { + // passed in one, but it's not the right one. + if (dest && dest !== state.pipes) return this; + if (!dest) dest = state.pipes; // got a match. + + state.pipes = null; + state.pipesCount = 0; + state.flowing = false; + if (dest) dest.emit('unpipe', this, unpipeInfo); + return this; + } // slow case. multiple pipe destinations. + + + if (!dest) { + // remove all. + var dests = state.pipes; + var len = state.pipesCount; + state.pipes = null; + state.pipesCount = 0; + state.flowing = false; + + for (var i = 0; i < len; i++) { + dests[i].emit('unpipe', this, { + hasUnpiped: false + }); + } + + return this; + } // try to find the right one. + + + var index = indexOf(state.pipes, dest); + if (index === -1) return this; + state.pipes.splice(index, 1); + state.pipesCount -= 1; + if (state.pipesCount === 1) state.pipes = state.pipes[0]; + dest.emit('unpipe', this, unpipeInfo); + return this; +}; // set up data events if they are asked for +// Ensure readable listeners eventually get something + + +Readable.prototype.on = function (ev, fn) { + var res = Stream.prototype.on.call(this, ev, fn); + var state = this._readableState; + + if (ev === 'data') { + // update readableListening so that resume() may be a no-op + // a few lines down. This is needed to support once('readable'). + state.readableListening = this.listenerCount('readable') > 0; // Try start flowing on next tick if stream isn't explicitly paused + + if (state.flowing !== false) this.resume(); + } else if (ev === 'readable') { + if (!state.endEmitted && !state.readableListening) { + state.readableListening = state.needReadable = true; + state.flowing = false; + state.emittedReadable = false; + debug('on readable', state.length, state.reading); + + if (state.length) { + emitReadable(this); + } else if (!state.reading) { + process.nextTick(nReadingNextTick, this); + } + } + } + + return res; +}; + +Readable.prototype.addListener = Readable.prototype.on; + +Readable.prototype.removeListener = function (ev, fn) { + var res = Stream.prototype.removeListener.call(this, ev, fn); + + if (ev === 'readable') { + // We need to check if there is someone still listening to + // readable and reset the state. However this needs to happen + // after readable has been emitted but before I/O (nextTick) to + // support once('readable', fn) cycles. This means that calling + // resume within the same tick will have no + // effect. + process.nextTick(updateReadableListening, this); + } + + return res; +}; + +Readable.prototype.removeAllListeners = function (ev) { + var res = Stream.prototype.removeAllListeners.apply(this, arguments); + + if (ev === 'readable' || ev === undefined) { + // We need to check if there is someone still listening to + // readable and reset the state. However this needs to happen + // after readable has been emitted but before I/O (nextTick) to + // support once('readable', fn) cycles. This means that calling + // resume within the same tick will have no + // effect. + process.nextTick(updateReadableListening, this); + } + + return res; +}; + +function updateReadableListening(self) { + var state = self._readableState; + state.readableListening = self.listenerCount('readable') > 0; + + if (state.resumeScheduled && !state.paused) { + // flowing needs to be set to true now, otherwise + // the upcoming resume will not flow. + state.flowing = true; // crude way to check if we should resume + } else if (self.listenerCount('data') > 0) { + self.resume(); + } +} + +function nReadingNextTick(self) { + debug('readable nexttick read 0'); + self.read(0); +} // pause() and resume() are remnants of the legacy readable stream API +// If the user uses them, then switch into old mode. + + +Readable.prototype.resume = function () { + var state = this._readableState; + + if (!state.flowing) { + debug('resume'); // we flow only if there is no one listening + // for readable, but we still have to call + // resume() + + state.flowing = !state.readableListening; + resume(this, state); + } + + state.paused = false; + return this; +}; + +function resume(stream, state) { + if (!state.resumeScheduled) { + state.resumeScheduled = true; + process.nextTick(resume_, stream, state); + } +} + +function resume_(stream, state) { + debug('resume', state.reading); + + if (!state.reading) { + stream.read(0); + } + + state.resumeScheduled = false; + stream.emit('resume'); + flow(stream); + if (state.flowing && !state.reading) stream.read(0); +} + +Readable.prototype.pause = function () { + debug('call pause flowing=%j', this._readableState.flowing); + + if (this._readableState.flowing !== false) { + debug('pause'); + this._readableState.flowing = false; + this.emit('pause'); + } + + this._readableState.paused = true; + return this; +}; + +function flow(stream) { + var state = stream._readableState; + debug('flow', state.flowing); + + while (state.flowing && stream.read() !== null) { + ; + } +} // wrap an old-style stream as the async data source. +// This is *not* part of the readable stream interface. +// It is an ugly unfortunate mess of history. + + +Readable.prototype.wrap = function (stream) { + var _this = this; + + var state = this._readableState; + var paused = false; + stream.on('end', function () { + debug('wrapped end'); + + if (state.decoder && !state.ended) { + var chunk = state.decoder.end(); + if (chunk && chunk.length) _this.push(chunk); + } + + _this.push(null); + }); + stream.on('data', function (chunk) { + debug('wrapped data'); + if (state.decoder) chunk = state.decoder.write(chunk); // don't skip over falsy values in objectMode + + if (state.objectMode && (chunk === null || chunk === undefined)) return;else if (!state.objectMode && (!chunk || !chunk.length)) return; + + var ret = _this.push(chunk); + + if (!ret) { + paused = true; + stream.pause(); + } + }); // proxy all the other methods. + // important when wrapping filters and duplexes. + + for (var i in stream) { + if (this[i] === undefined && typeof stream[i] === 'function') { + this[i] = function methodWrap(method) { + return function methodWrapReturnFunction() { + return stream[method].apply(stream, arguments); + }; + }(i); + } + } // proxy certain important events. + + + for (var n = 0; n < kProxyEvents.length; n++) { + stream.on(kProxyEvents[n], this.emit.bind(this, kProxyEvents[n])); + } // when we try to consume some more bytes, simply unpause the + // underlying stream. + + + this._read = function (n) { + debug('wrapped _read', n); + + if (paused) { + paused = false; + stream.resume(); + } + }; + + return this; +}; + +if (typeof Symbol === 'function') { + Readable.prototype[Symbol.asyncIterator] = function () { + if (createReadableStreamAsyncIterator === undefined) { + createReadableStreamAsyncIterator = require('./internal/streams/async_iterator'); + } + + return createReadableStreamAsyncIterator(this); + }; +} + +Object.defineProperty(Readable.prototype, 'readableHighWaterMark', { + // making it explicit this property is not enumerable + // because otherwise some prototype manipulation in + // userland will fail + enumerable: false, + get: function get() { + return this._readableState.highWaterMark; + } +}); +Object.defineProperty(Readable.prototype, 'readableBuffer', { + // making it explicit this property is not enumerable + // because otherwise some prototype manipulation in + // userland will fail + enumerable: false, + get: function get() { + return this._readableState && this._readableState.buffer; + } +}); +Object.defineProperty(Readable.prototype, 'readableFlowing', { + // making it explicit this property is not enumerable + // because otherwise some prototype manipulation in + // userland will fail + enumerable: false, + get: function get() { + return this._readableState.flowing; + }, + set: function set(state) { + if (this._readableState) { + this._readableState.flowing = state; + } + } +}); // exposed for testing purposes only. + +Readable._fromList = fromList; +Object.defineProperty(Readable.prototype, 'readableLength', { + // making it explicit this property is not enumerable + // because otherwise some prototype manipulation in + // userland will fail + enumerable: false, + get: function get() { + return this._readableState.length; + } +}); // Pluck off n bytes from an array of buffers. +// Length is the combined lengths of all the buffers in the list. +// This function is designed to be inlinable, so please take care when making +// changes to the function body. + +function fromList(n, state) { + // nothing buffered + if (state.length === 0) return null; + var ret; + if (state.objectMode) ret = state.buffer.shift();else if (!n || n >= state.length) { + // read it all, truncate the list + if (state.decoder) ret = state.buffer.join('');else if (state.buffer.length === 1) ret = state.buffer.first();else ret = state.buffer.concat(state.length); + state.buffer.clear(); + } else { + // read part of list + ret = state.buffer.consume(n, state.decoder); + } + return ret; +} + +function endReadable(stream) { + var state = stream._readableState; + debug('endReadable', state.endEmitted); + + if (!state.endEmitted) { + state.ended = true; + process.nextTick(endReadableNT, state, stream); + } +} + +function endReadableNT(state, stream) { + debug('endReadableNT', state.endEmitted, state.length); // Check that we didn't get one last unshift. + + if (!state.endEmitted && state.length === 0) { + state.endEmitted = true; + stream.readable = false; + stream.emit('end'); + + if (state.autoDestroy) { + // In case of duplex streams we need a way to detect + // if the writable side is ready for autoDestroy as well + var wState = stream._writableState; + + if (!wState || wState.autoDestroy && wState.finished) { + stream.destroy(); + } + } + } +} + +if (typeof Symbol === 'function') { + Readable.from = function (iterable, opts) { + if (from === undefined) { + from = require('./internal/streams/from'); + } + + return from(Readable, iterable, opts); + }; +} + +function indexOf(xs, x) { + for (var i = 0, l = xs.length; i < l; i++) { + if (xs[i] === x) return i; + } + + return -1; +} +}).call(this)}).call(this,require('_process'),typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) +},{"../errors":47,"./_stream_duplex":48,"./internal/streams/async_iterator":53,"./internal/streams/buffer_list":54,"./internal/streams/destroy":55,"./internal/streams/from":57,"./internal/streams/state":59,"./internal/streams/stream":60,"_process":149,"buffer":63,"events":100,"inherits":132,"string_decoder/":185,"util":19}],51:[function(require,module,exports){ +// Copyright Joyent, Inc. and other Node contributors. +// +// 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. +// a transform stream is a readable/writable stream where you do +// something with the data. Sometimes it's called a "filter", +// but that's not a great name for it, since that implies a thing where +// some bits pass through, and others are simply ignored. (That would +// be a valid example of a transform, of course.) +// +// While the output is causally related to the input, it's not a +// necessarily symmetric or synchronous transformation. For example, +// a zlib stream might take multiple plain-text writes(), and then +// emit a single compressed chunk some time in the future. +// +// Here's how this works: +// +// The Transform stream has all the aspects of the readable and writable +// stream classes. When you write(chunk), that calls _write(chunk,cb) +// internally, and returns false if there's a lot of pending writes +// buffered up. When you call read(), that calls _read(n) until +// there's enough pending readable data buffered up. +// +// In a transform stream, the written data is placed in a buffer. When +// _read(n) is called, it transforms the queued up data, calling the +// buffered _write cb's as it consumes chunks. If consuming a single +// written chunk would result in multiple output chunks, then the first +// outputted bit calls the readcb, and subsequent chunks just go into +// the read buffer, and will cause it to emit 'readable' if necessary. +// +// This way, back-pressure is actually determined by the reading side, +// since _read has to be called to start processing a new chunk. However, +// a pathological inflate type of transform can cause excessive buffering +// here. For example, imagine a stream where every byte of input is +// interpreted as an integer from 0-255, and then results in that many +// bytes of output. Writing the 4 bytes {ff,ff,ff,ff} would result in +// 1kb of data being output. In this case, you could write a very small +// amount of input, and end up with a very large amount of output. In +// such a pathological inflating mechanism, there'd be no way to tell +// the system to stop doing the transform. A single 4MB write could +// cause the system to run out of memory. +// +// However, even in such a pathological case, only a single written chunk +// would be consumed, and then the rest would wait (un-transformed) until +// the results of the previous transformed chunk were consumed. +'use strict'; + +module.exports = Transform; + +var _require$codes = require('../errors').codes, + ERR_METHOD_NOT_IMPLEMENTED = _require$codes.ERR_METHOD_NOT_IMPLEMENTED, + ERR_MULTIPLE_CALLBACK = _require$codes.ERR_MULTIPLE_CALLBACK, + ERR_TRANSFORM_ALREADY_TRANSFORMING = _require$codes.ERR_TRANSFORM_ALREADY_TRANSFORMING, + ERR_TRANSFORM_WITH_LENGTH_0 = _require$codes.ERR_TRANSFORM_WITH_LENGTH_0; + +var Duplex = require('./_stream_duplex'); + +require('inherits')(Transform, Duplex); + +function afterTransform(er, data) { + var ts = this._transformState; + ts.transforming = false; + var cb = ts.writecb; + + if (cb === null) { + return this.emit('error', new ERR_MULTIPLE_CALLBACK()); + } + + ts.writechunk = null; + ts.writecb = null; + if (data != null) // single equals check for both `null` and `undefined` + this.push(data); + cb(er); + var rs = this._readableState; + rs.reading = false; + + if (rs.needReadable || rs.length < rs.highWaterMark) { + this._read(rs.highWaterMark); + } +} + +function Transform(options) { + if (!(this instanceof Transform)) return new Transform(options); + Duplex.call(this, options); + this._transformState = { + afterTransform: afterTransform.bind(this), + needTransform: false, + transforming: false, + writecb: null, + writechunk: null, + writeencoding: null + }; // start out asking for a readable event once data is transformed. + + this._readableState.needReadable = true; // we have implemented the _read method, and done the other things + // that Readable wants before the first _read call, so unset the + // sync guard flag. + + this._readableState.sync = false; + + if (options) { + if (typeof options.transform === 'function') this._transform = options.transform; + if (typeof options.flush === 'function') this._flush = options.flush; + } // When the writable side finishes, then flush out anything remaining. + + + this.on('prefinish', prefinish); +} + +function prefinish() { + var _this = this; + + if (typeof this._flush === 'function' && !this._readableState.destroyed) { + this._flush(function (er, data) { + done(_this, er, data); + }); + } else { + done(this, null, null); + } +} + +Transform.prototype.push = function (chunk, encoding) { + this._transformState.needTransform = false; + return Duplex.prototype.push.call(this, chunk, encoding); +}; // This is the part where you do stuff! +// override this function in implementation classes. +// 'chunk' is an input chunk. +// +// Call `push(newChunk)` to pass along transformed output +// to the readable side. You may call 'push' zero or more times. +// +// Call `cb(err)` when you are done with this chunk. If you pass +// an error, then that'll put the hurt on the whole operation. If you +// never call cb(), then you'll never get another chunk. + + +Transform.prototype._transform = function (chunk, encoding, cb) { + cb(new ERR_METHOD_NOT_IMPLEMENTED('_transform()')); +}; + +Transform.prototype._write = function (chunk, encoding, cb) { + var ts = this._transformState; + ts.writecb = cb; + ts.writechunk = chunk; + ts.writeencoding = encoding; + + if (!ts.transforming) { + var rs = this._readableState; + if (ts.needTransform || rs.needReadable || rs.length < rs.highWaterMark) this._read(rs.highWaterMark); + } +}; // Doesn't matter what the args are here. +// _transform does all the work. +// That we got here means that the readable side wants more data. + + +Transform.prototype._read = function (n) { + var ts = this._transformState; + + if (ts.writechunk !== null && !ts.transforming) { + ts.transforming = true; + + this._transform(ts.writechunk, ts.writeencoding, ts.afterTransform); + } else { + // mark that we need a transform, so that any data that comes in + // will get processed, now that we've asked for it. + ts.needTransform = true; + } +}; + +Transform.prototype._destroy = function (err, cb) { + Duplex.prototype._destroy.call(this, err, function (err2) { + cb(err2); + }); +}; + +function done(stream, er, data) { + if (er) return stream.emit('error', er); + if (data != null) // single equals check for both `null` and `undefined` + stream.push(data); // TODO(BridgeAR): Write a test for these two error cases + // if there's nothing in the write buffer, then that means + // that nothing more will ever be provided + + if (stream._writableState.length) throw new ERR_TRANSFORM_WITH_LENGTH_0(); + if (stream._transformState.transforming) throw new ERR_TRANSFORM_ALREADY_TRANSFORMING(); + return stream.push(null); +} +},{"../errors":47,"./_stream_duplex":48,"inherits":132}],52:[function(require,module,exports){ +(function (process,global){(function (){ +// Copyright Joyent, Inc. and other Node contributors. +// +// 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. +// A bit simpler than readable streams. +// Implement an async ._write(chunk, encoding, cb), and it'll handle all +// the drain event emission and buffering. +'use strict'; + +module.exports = Writable; +/* */ + +function WriteReq(chunk, encoding, cb) { + this.chunk = chunk; + this.encoding = encoding; + this.callback = cb; + this.next = null; +} // It seems a linked list but it is not +// there will be only 2 of these for each stream + + +function CorkedRequest(state) { + var _this = this; + + this.next = null; + this.entry = null; + + this.finish = function () { + onCorkedFinish(_this, state); + }; +} +/* */ + +/**/ + + +var Duplex; +/**/ + +Writable.WritableState = WritableState; +/**/ + +var internalUtil = { + deprecate: require('util-deprecate') +}; +/**/ + +/**/ + +var Stream = require('./internal/streams/stream'); +/**/ + + +var Buffer = require('buffer').Buffer; + +var OurUint8Array = global.Uint8Array || function () {}; + +function _uint8ArrayToBuffer(chunk) { + return Buffer.from(chunk); +} + +function _isUint8Array(obj) { + return Buffer.isBuffer(obj) || obj instanceof OurUint8Array; +} + +var destroyImpl = require('./internal/streams/destroy'); + +var _require = require('./internal/streams/state'), + getHighWaterMark = _require.getHighWaterMark; + +var _require$codes = require('../errors').codes, + ERR_INVALID_ARG_TYPE = _require$codes.ERR_INVALID_ARG_TYPE, + ERR_METHOD_NOT_IMPLEMENTED = _require$codes.ERR_METHOD_NOT_IMPLEMENTED, + ERR_MULTIPLE_CALLBACK = _require$codes.ERR_MULTIPLE_CALLBACK, + ERR_STREAM_CANNOT_PIPE = _require$codes.ERR_STREAM_CANNOT_PIPE, + ERR_STREAM_DESTROYED = _require$codes.ERR_STREAM_DESTROYED, + ERR_STREAM_NULL_VALUES = _require$codes.ERR_STREAM_NULL_VALUES, + ERR_STREAM_WRITE_AFTER_END = _require$codes.ERR_STREAM_WRITE_AFTER_END, + ERR_UNKNOWN_ENCODING = _require$codes.ERR_UNKNOWN_ENCODING; + +var errorOrDestroy = destroyImpl.errorOrDestroy; + +require('inherits')(Writable, Stream); + +function nop() {} + +function WritableState(options, stream, isDuplex) { + Duplex = Duplex || require('./_stream_duplex'); + options = options || {}; // Duplex streams are both readable and writable, but share + // the same options object. + // However, some cases require setting options to different + // values for the readable and the writable sides of the duplex stream, + // e.g. options.readableObjectMode vs. options.writableObjectMode, etc. + + if (typeof isDuplex !== 'boolean') isDuplex = stream instanceof Duplex; // object stream flag to indicate whether or not this stream + // contains buffers or objects. + + this.objectMode = !!options.objectMode; + if (isDuplex) this.objectMode = this.objectMode || !!options.writableObjectMode; // the point at which write() starts returning false + // Note: 0 is a valid value, means that we always return false if + // the entire buffer is not flushed immediately on write() + + this.highWaterMark = getHighWaterMark(this, options, 'writableHighWaterMark', isDuplex); // if _final has been called + + this.finalCalled = false; // drain event flag. + + this.needDrain = false; // at the start of calling end() + + this.ending = false; // when end() has been called, and returned + + this.ended = false; // when 'finish' is emitted + + this.finished = false; // has it been destroyed + + this.destroyed = false; // should we decode strings into buffers before passing to _write? + // this is here so that some node-core streams can optimize string + // handling at a lower level. + + var noDecode = options.decodeStrings === false; + this.decodeStrings = !noDecode; // Crypto is kind of old and crusty. Historically, its default string + // encoding is 'binary' so we have to make this configurable. + // Everything else in the universe uses 'utf8', though. + + this.defaultEncoding = options.defaultEncoding || 'utf8'; // not an actual buffer we keep track of, but a measurement + // of how much we're waiting to get pushed to some underlying + // socket or file. + + this.length = 0; // a flag to see when we're in the middle of a write. + + this.writing = false; // when true all writes will be buffered until .uncork() call + + this.corked = 0; // a flag to be able to tell if the onwrite cb is called immediately, + // or on a later tick. We set this to true at first, because any + // actions that shouldn't happen until "later" should generally also + // not happen before the first write call. + + this.sync = true; // a flag to know if we're processing previously buffered items, which + // may call the _write() callback in the same tick, so that we don't + // end up in an overlapped onwrite situation. + + this.bufferProcessing = false; // the callback that's passed to _write(chunk,cb) + + this.onwrite = function (er) { + onwrite(stream, er); + }; // the callback that the user supplies to write(chunk,encoding,cb) + + + this.writecb = null; // the amount that is being written when _write is called. + + this.writelen = 0; + this.bufferedRequest = null; + this.lastBufferedRequest = null; // number of pending user-supplied write callbacks + // this must be 0 before 'finish' can be emitted + + this.pendingcb = 0; // emit prefinish if the only thing we're waiting for is _write cbs + // This is relevant for synchronous Transform streams + + this.prefinished = false; // True if the error was already emitted and should not be thrown again + + this.errorEmitted = false; // Should close be emitted on destroy. Defaults to true. + + this.emitClose = options.emitClose !== false; // Should .destroy() be called after 'finish' (and potentially 'end') + + this.autoDestroy = !!options.autoDestroy; // count buffered requests + + this.bufferedRequestCount = 0; // allocate the first CorkedRequest, there is always + // one allocated and free to use, and we maintain at most two + + this.corkedRequestsFree = new CorkedRequest(this); +} + +WritableState.prototype.getBuffer = function getBuffer() { + var current = this.bufferedRequest; + var out = []; + + while (current) { + out.push(current); + current = current.next; + } + + return out; +}; + +(function () { + try { + Object.defineProperty(WritableState.prototype, 'buffer', { + get: internalUtil.deprecate(function writableStateBufferGetter() { + return this.getBuffer(); + }, '_writableState.buffer is deprecated. Use _writableState.getBuffer ' + 'instead.', 'DEP0003') + }); + } catch (_) {} +})(); // Test _writableState for inheritance to account for Duplex streams, +// whose prototype chain only points to Readable. + + +var realHasInstance; + +if (typeof Symbol === 'function' && Symbol.hasInstance && typeof Function.prototype[Symbol.hasInstance] === 'function') { + realHasInstance = Function.prototype[Symbol.hasInstance]; + Object.defineProperty(Writable, Symbol.hasInstance, { + value: function value(object) { + if (realHasInstance.call(this, object)) return true; + if (this !== Writable) return false; + return object && object._writableState instanceof WritableState; + } + }); +} else { + realHasInstance = function realHasInstance(object) { + return object instanceof this; + }; +} + +function Writable(options) { + Duplex = Duplex || require('./_stream_duplex'); // Writable ctor is applied to Duplexes, too. + // `realHasInstance` is necessary because using plain `instanceof` + // would return false, as no `_writableState` property is attached. + // Trying to use the custom `instanceof` for Writable here will also break the + // Node.js LazyTransform implementation, which has a non-trivial getter for + // `_writableState` that would lead to infinite recursion. + // Checking for a Stream.Duplex instance is faster here instead of inside + // the WritableState constructor, at least with V8 6.5 + + var isDuplex = this instanceof Duplex; + if (!isDuplex && !realHasInstance.call(Writable, this)) return new Writable(options); + this._writableState = new WritableState(options, this, isDuplex); // legacy. + + this.writable = true; + + if (options) { + if (typeof options.write === 'function') this._write = options.write; + if (typeof options.writev === 'function') this._writev = options.writev; + if (typeof options.destroy === 'function') this._destroy = options.destroy; + if (typeof options.final === 'function') this._final = options.final; + } + + Stream.call(this); +} // Otherwise people can pipe Writable streams, which is just wrong. + + +Writable.prototype.pipe = function () { + errorOrDestroy(this, new ERR_STREAM_CANNOT_PIPE()); +}; + +function writeAfterEnd(stream, cb) { + var er = new ERR_STREAM_WRITE_AFTER_END(); // TODO: defer error events consistently everywhere, not just the cb + + errorOrDestroy(stream, er); + process.nextTick(cb, er); +} // Checks that a user-supplied chunk is valid, especially for the particular +// mode the stream is in. Currently this means that `null` is never accepted +// and undefined/non-string values are only allowed in object mode. + + +function validChunk(stream, state, chunk, cb) { + var er; + + if (chunk === null) { + er = new ERR_STREAM_NULL_VALUES(); + } else if (typeof chunk !== 'string' && !state.objectMode) { + er = new ERR_INVALID_ARG_TYPE('chunk', ['string', 'Buffer'], chunk); + } + + if (er) { + errorOrDestroy(stream, er); + process.nextTick(cb, er); + return false; + } + + return true; +} + +Writable.prototype.write = function (chunk, encoding, cb) { + var state = this._writableState; + var ret = false; + + var isBuf = !state.objectMode && _isUint8Array(chunk); + + if (isBuf && !Buffer.isBuffer(chunk)) { + chunk = _uint8ArrayToBuffer(chunk); + } + + if (typeof encoding === 'function') { + cb = encoding; + encoding = null; + } + + if (isBuf) encoding = 'buffer';else if (!encoding) encoding = state.defaultEncoding; + if (typeof cb !== 'function') cb = nop; + if (state.ending) writeAfterEnd(this, cb);else if (isBuf || validChunk(this, state, chunk, cb)) { + state.pendingcb++; + ret = writeOrBuffer(this, state, isBuf, chunk, encoding, cb); + } + return ret; +}; + +Writable.prototype.cork = function () { + this._writableState.corked++; +}; + +Writable.prototype.uncork = function () { + var state = this._writableState; + + if (state.corked) { + state.corked--; + if (!state.writing && !state.corked && !state.bufferProcessing && state.bufferedRequest) clearBuffer(this, state); + } +}; + +Writable.prototype.setDefaultEncoding = function setDefaultEncoding(encoding) { + // node::ParseEncoding() requires lower case. + if (typeof encoding === 'string') encoding = encoding.toLowerCase(); + if (!(['hex', 'utf8', 'utf-8', 'ascii', 'binary', 'base64', 'ucs2', 'ucs-2', 'utf16le', 'utf-16le', 'raw'].indexOf((encoding + '').toLowerCase()) > -1)) throw new ERR_UNKNOWN_ENCODING(encoding); + this._writableState.defaultEncoding = encoding; + return this; +}; + +Object.defineProperty(Writable.prototype, 'writableBuffer', { + // making it explicit this property is not enumerable + // because otherwise some prototype manipulation in + // userland will fail + enumerable: false, + get: function get() { + return this._writableState && this._writableState.getBuffer(); + } +}); + +function decodeChunk(state, chunk, encoding) { + if (!state.objectMode && state.decodeStrings !== false && typeof chunk === 'string') { + chunk = Buffer.from(chunk, encoding); + } + + return chunk; +} + +Object.defineProperty(Writable.prototype, 'writableHighWaterMark', { + // making it explicit this property is not enumerable + // because otherwise some prototype manipulation in + // userland will fail + enumerable: false, + get: function get() { + return this._writableState.highWaterMark; + } +}); // if we're already writing something, then just put this +// in the queue, and wait our turn. Otherwise, call _write +// If we return false, then we need a drain event, so set that flag. + +function writeOrBuffer(stream, state, isBuf, chunk, encoding, cb) { + if (!isBuf) { + var newChunk = decodeChunk(state, chunk, encoding); + + if (chunk !== newChunk) { + isBuf = true; + encoding = 'buffer'; + chunk = newChunk; + } + } + + var len = state.objectMode ? 1 : chunk.length; + state.length += len; + var ret = state.length < state.highWaterMark; // we must ensure that previous needDrain will not be reset to false. + + if (!ret) state.needDrain = true; + + if (state.writing || state.corked) { + var last = state.lastBufferedRequest; + state.lastBufferedRequest = { + chunk: chunk, + encoding: encoding, + isBuf: isBuf, + callback: cb, + next: null + }; + + if (last) { + last.next = state.lastBufferedRequest; + } else { + state.bufferedRequest = state.lastBufferedRequest; + } + + state.bufferedRequestCount += 1; + } else { + doWrite(stream, state, false, len, chunk, encoding, cb); + } + + return ret; +} + +function doWrite(stream, state, writev, len, chunk, encoding, cb) { + state.writelen = len; + state.writecb = cb; + state.writing = true; + state.sync = true; + if (state.destroyed) state.onwrite(new ERR_STREAM_DESTROYED('write'));else if (writev) stream._writev(chunk, state.onwrite);else stream._write(chunk, encoding, state.onwrite); + state.sync = false; +} + +function onwriteError(stream, state, sync, er, cb) { + --state.pendingcb; + + if (sync) { + // defer the callback if we are being called synchronously + // to avoid piling up things on the stack + process.nextTick(cb, er); // this can emit finish, and it will always happen + // after error + + process.nextTick(finishMaybe, stream, state); + stream._writableState.errorEmitted = true; + errorOrDestroy(stream, er); + } else { + // the caller expect this to happen before if + // it is async + cb(er); + stream._writableState.errorEmitted = true; + errorOrDestroy(stream, er); // this can emit finish, but finish must + // always follow error + + finishMaybe(stream, state); + } +} + +function onwriteStateUpdate(state) { + state.writing = false; + state.writecb = null; + state.length -= state.writelen; + state.writelen = 0; +} + +function onwrite(stream, er) { + var state = stream._writableState; + var sync = state.sync; + var cb = state.writecb; + if (typeof cb !== 'function') throw new ERR_MULTIPLE_CALLBACK(); + onwriteStateUpdate(state); + if (er) onwriteError(stream, state, sync, er, cb);else { + // Check if we're actually ready to finish, but don't emit yet + var finished = needFinish(state) || stream.destroyed; + + if (!finished && !state.corked && !state.bufferProcessing && state.bufferedRequest) { + clearBuffer(stream, state); + } + + if (sync) { + process.nextTick(afterWrite, stream, state, finished, cb); + } else { + afterWrite(stream, state, finished, cb); + } + } +} + +function afterWrite(stream, state, finished, cb) { + if (!finished) onwriteDrain(stream, state); + state.pendingcb--; + cb(); + finishMaybe(stream, state); +} // Must force callback to be called on nextTick, so that we don't +// emit 'drain' before the write() consumer gets the 'false' return +// value, and has a chance to attach a 'drain' listener. + + +function onwriteDrain(stream, state) { + if (state.length === 0 && state.needDrain) { + state.needDrain = false; + stream.emit('drain'); + } +} // if there's something in the buffer waiting, then process it + + +function clearBuffer(stream, state) { + state.bufferProcessing = true; + var entry = state.bufferedRequest; + + if (stream._writev && entry && entry.next) { + // Fast case, write everything using _writev() + var l = state.bufferedRequestCount; + var buffer = new Array(l); + var holder = state.corkedRequestsFree; + holder.entry = entry; + var count = 0; + var allBuffers = true; + + while (entry) { + buffer[count] = entry; + if (!entry.isBuf) allBuffers = false; + entry = entry.next; + count += 1; + } + + buffer.allBuffers = allBuffers; + doWrite(stream, state, true, state.length, buffer, '', holder.finish); // doWrite is almost always async, defer these to save a bit of time + // as the hot path ends with doWrite + + state.pendingcb++; + state.lastBufferedRequest = null; + + if (holder.next) { + state.corkedRequestsFree = holder.next; + holder.next = null; + } else { + state.corkedRequestsFree = new CorkedRequest(state); + } + + state.bufferedRequestCount = 0; + } else { + // Slow case, write chunks one-by-one + while (entry) { + var chunk = entry.chunk; + var encoding = entry.encoding; + var cb = entry.callback; + var len = state.objectMode ? 1 : chunk.length; + doWrite(stream, state, false, len, chunk, encoding, cb); + entry = entry.next; + state.bufferedRequestCount--; // if we didn't call the onwrite immediately, then + // it means that we need to wait until it does. + // also, that means that the chunk and cb are currently + // being processed, so move the buffer counter past them. + + if (state.writing) { + break; + } + } + + if (entry === null) state.lastBufferedRequest = null; + } + + state.bufferedRequest = entry; + state.bufferProcessing = false; +} + +Writable.prototype._write = function (chunk, encoding, cb) { + cb(new ERR_METHOD_NOT_IMPLEMENTED('_write()')); +}; + +Writable.prototype._writev = null; + +Writable.prototype.end = function (chunk, encoding, cb) { + var state = this._writableState; + + if (typeof chunk === 'function') { + cb = chunk; + chunk = null; + encoding = null; + } else if (typeof encoding === 'function') { + cb = encoding; + encoding = null; + } + + if (chunk !== null && chunk !== undefined) this.write(chunk, encoding); // .end() fully uncorks + + if (state.corked) { + state.corked = 1; + this.uncork(); + } // ignore unnecessary end() calls. + + + if (!state.ending) endWritable(this, state, cb); + return this; +}; + +Object.defineProperty(Writable.prototype, 'writableLength', { + // making it explicit this property is not enumerable + // because otherwise some prototype manipulation in + // userland will fail + enumerable: false, + get: function get() { + return this._writableState.length; + } +}); + +function needFinish(state) { + return state.ending && state.length === 0 && state.bufferedRequest === null && !state.finished && !state.writing; +} + +function callFinal(stream, state) { + stream._final(function (err) { + state.pendingcb--; + + if (err) { + errorOrDestroy(stream, err); + } + + state.prefinished = true; + stream.emit('prefinish'); + finishMaybe(stream, state); + }); +} + +function prefinish(stream, state) { + if (!state.prefinished && !state.finalCalled) { + if (typeof stream._final === 'function' && !state.destroyed) { + state.pendingcb++; + state.finalCalled = true; + process.nextTick(callFinal, stream, state); + } else { + state.prefinished = true; + stream.emit('prefinish'); + } + } +} + +function finishMaybe(stream, state) { + var need = needFinish(state); + + if (need) { + prefinish(stream, state); + + if (state.pendingcb === 0) { + state.finished = true; + stream.emit('finish'); + + if (state.autoDestroy) { + // In case of duplex streams we need a way to detect + // if the readable side is ready for autoDestroy as well + var rState = stream._readableState; + + if (!rState || rState.autoDestroy && rState.endEmitted) { + stream.destroy(); + } + } + } + } + + return need; +} + +function endWritable(stream, state, cb) { + state.ending = true; + finishMaybe(stream, state); + + if (cb) { + if (state.finished) process.nextTick(cb);else stream.once('finish', cb); + } + + state.ended = true; + stream.writable = false; +} + +function onCorkedFinish(corkReq, state, err) { + var entry = corkReq.entry; + corkReq.entry = null; + + while (entry) { + var cb = entry.callback; + state.pendingcb--; + cb(err); + entry = entry.next; + } // reuse the free corkReq. + + + state.corkedRequestsFree.next = corkReq; +} + +Object.defineProperty(Writable.prototype, 'destroyed', { + // making it explicit this property is not enumerable + // because otherwise some prototype manipulation in + // userland will fail + enumerable: false, + get: function get() { + if (this._writableState === undefined) { + return false; + } + + return this._writableState.destroyed; + }, + set: function set(value) { + // we ignore the value if the stream + // has not been initialized yet + if (!this._writableState) { + return; + } // backward compatibility, the user is explicitly + // managing destroyed + + + this._writableState.destroyed = value; + } +}); +Writable.prototype.destroy = destroyImpl.destroy; +Writable.prototype._undestroy = destroyImpl.undestroy; + +Writable.prototype._destroy = function (err, cb) { + cb(err); +}; +}).call(this)}).call(this,require('_process'),typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) +},{"../errors":47,"./_stream_duplex":48,"./internal/streams/destroy":55,"./internal/streams/state":59,"./internal/streams/stream":60,"_process":149,"buffer":63,"inherits":132,"util-deprecate":186}],53:[function(require,module,exports){ +(function (process){(function (){ +'use strict'; + +var _Object$setPrototypeO; + +function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; } + +var finished = require('./end-of-stream'); + +var kLastResolve = Symbol('lastResolve'); +var kLastReject = Symbol('lastReject'); +var kError = Symbol('error'); +var kEnded = Symbol('ended'); +var kLastPromise = Symbol('lastPromise'); +var kHandlePromise = Symbol('handlePromise'); +var kStream = Symbol('stream'); + +function createIterResult(value, done) { + return { + value: value, + done: done + }; +} + +function readAndResolve(iter) { + var resolve = iter[kLastResolve]; + + if (resolve !== null) { + var data = iter[kStream].read(); // we defer if data is null + // we can be expecting either 'end' or + // 'error' + + if (data !== null) { + iter[kLastPromise] = null; + iter[kLastResolve] = null; + iter[kLastReject] = null; + resolve(createIterResult(data, false)); + } + } +} + +function onReadable(iter) { + // we wait for the next tick, because it might + // emit an error with process.nextTick + process.nextTick(readAndResolve, iter); +} + +function wrapForNext(lastPromise, iter) { + return function (resolve, reject) { + lastPromise.then(function () { + if (iter[kEnded]) { + resolve(createIterResult(undefined, true)); + return; + } + + iter[kHandlePromise](resolve, reject); + }, reject); + }; +} + +var AsyncIteratorPrototype = Object.getPrototypeOf(function () {}); +var ReadableStreamAsyncIteratorPrototype = Object.setPrototypeOf((_Object$setPrototypeO = { + get stream() { + return this[kStream]; + }, + + next: function next() { + var _this = this; + + // if we have detected an error in the meanwhile + // reject straight away + var error = this[kError]; + + if (error !== null) { + return Promise.reject(error); + } + + if (this[kEnded]) { + return Promise.resolve(createIterResult(undefined, true)); + } + + if (this[kStream].destroyed) { + // We need to defer via nextTick because if .destroy(err) is + // called, the error will be emitted via nextTick, and + // we cannot guarantee that there is no error lingering around + // waiting to be emitted. + return new Promise(function (resolve, reject) { + process.nextTick(function () { + if (_this[kError]) { + reject(_this[kError]); + } else { + resolve(createIterResult(undefined, true)); + } + }); + }); + } // if we have multiple next() calls + // we will wait for the previous Promise to finish + // this logic is optimized to support for await loops, + // where next() is only called once at a time + + + var lastPromise = this[kLastPromise]; + var promise; + + if (lastPromise) { + promise = new Promise(wrapForNext(lastPromise, this)); + } else { + // fast path needed to support multiple this.push() + // without triggering the next() queue + var data = this[kStream].read(); + + if (data !== null) { + return Promise.resolve(createIterResult(data, false)); + } + + promise = new Promise(this[kHandlePromise]); + } + + this[kLastPromise] = promise; + return promise; + } +}, _defineProperty(_Object$setPrototypeO, Symbol.asyncIterator, function () { + return this; +}), _defineProperty(_Object$setPrototypeO, "return", function _return() { + var _this2 = this; + + // destroy(err, cb) is a private API + // we can guarantee we have that here, because we control the + // Readable class this is attached to + return new Promise(function (resolve, reject) { + _this2[kStream].destroy(null, function (err) { + if (err) { + reject(err); + return; + } + + resolve(createIterResult(undefined, true)); + }); + }); +}), _Object$setPrototypeO), AsyncIteratorPrototype); + +var createReadableStreamAsyncIterator = function createReadableStreamAsyncIterator(stream) { + var _Object$create; + + var iterator = Object.create(ReadableStreamAsyncIteratorPrototype, (_Object$create = {}, _defineProperty(_Object$create, kStream, { + value: stream, + writable: true + }), _defineProperty(_Object$create, kLastResolve, { + value: null, + writable: true + }), _defineProperty(_Object$create, kLastReject, { + value: null, + writable: true + }), _defineProperty(_Object$create, kError, { + value: null, + writable: true + }), _defineProperty(_Object$create, kEnded, { + value: stream._readableState.endEmitted, + writable: true + }), _defineProperty(_Object$create, kHandlePromise, { + value: function value(resolve, reject) { + var data = iterator[kStream].read(); + + if (data) { + iterator[kLastPromise] = null; + iterator[kLastResolve] = null; + iterator[kLastReject] = null; + resolve(createIterResult(data, false)); + } else { + iterator[kLastResolve] = resolve; + iterator[kLastReject] = reject; + } + }, + writable: true + }), _Object$create)); + iterator[kLastPromise] = null; + finished(stream, function (err) { + if (err && err.code !== 'ERR_STREAM_PREMATURE_CLOSE') { + var reject = iterator[kLastReject]; // reject if we are waiting for data in the Promise + // returned by next() and store the error + + if (reject !== null) { + iterator[kLastPromise] = null; + iterator[kLastResolve] = null; + iterator[kLastReject] = null; + reject(err); + } + + iterator[kError] = err; + return; + } + + var resolve = iterator[kLastResolve]; + + if (resolve !== null) { + iterator[kLastPromise] = null; + iterator[kLastResolve] = null; + iterator[kLastReject] = null; + resolve(createIterResult(undefined, true)); + } + + iterator[kEnded] = true; + }); + stream.on('readable', onReadable.bind(null, iterator)); + return iterator; +}; + +module.exports = createReadableStreamAsyncIterator; +}).call(this)}).call(this,require('_process')) +},{"./end-of-stream":56,"_process":149}],54:[function(require,module,exports){ +'use strict'; + +function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); keys.push.apply(keys, symbols); } return keys; } + +function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys(Object(source), true).forEach(function (key) { _defineProperty(target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } } return target; } + +function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; } + +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } + +function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } + +function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; } + +var _require = require('buffer'), + Buffer = _require.Buffer; + +var _require2 = require('util'), + inspect = _require2.inspect; + +var custom = inspect && inspect.custom || 'inspect'; + +function copyBuffer(src, target, offset) { + Buffer.prototype.copy.call(src, target, offset); +} + +module.exports = +/*#__PURE__*/ +function () { + function BufferList() { + _classCallCheck(this, BufferList); + + this.head = null; + this.tail = null; + this.length = 0; + } + + _createClass(BufferList, [{ + key: "push", + value: function push(v) { + var entry = { + data: v, + next: null + }; + if (this.length > 0) this.tail.next = entry;else this.head = entry; + this.tail = entry; + ++this.length; + } + }, { + key: "unshift", + value: function unshift(v) { + var entry = { + data: v, + next: this.head + }; + if (this.length === 0) this.tail = entry; + this.head = entry; + ++this.length; + } + }, { + key: "shift", + value: function shift() { + if (this.length === 0) return; + var ret = this.head.data; + if (this.length === 1) this.head = this.tail = null;else this.head = this.head.next; + --this.length; + return ret; + } + }, { + key: "clear", + value: function clear() { + this.head = this.tail = null; + this.length = 0; + } + }, { + key: "join", + value: function join(s) { + if (this.length === 0) return ''; + var p = this.head; + var ret = '' + p.data; + + while (p = p.next) { + ret += s + p.data; + } + + return ret; + } + }, { + key: "concat", + value: function concat(n) { + if (this.length === 0) return Buffer.alloc(0); + var ret = Buffer.allocUnsafe(n >>> 0); + var p = this.head; + var i = 0; + + while (p) { + copyBuffer(p.data, ret, i); + i += p.data.length; + p = p.next; + } + + return ret; + } // Consumes a specified amount of bytes or characters from the buffered data. + + }, { + key: "consume", + value: function consume(n, hasStrings) { + var ret; + + if (n < this.head.data.length) { + // `slice` is the same for buffers and strings. + ret = this.head.data.slice(0, n); + this.head.data = this.head.data.slice(n); + } else if (n === this.head.data.length) { + // First chunk is a perfect match. + ret = this.shift(); + } else { + // Result spans more than one buffer. + ret = hasStrings ? this._getString(n) : this._getBuffer(n); + } + + return ret; + } + }, { + key: "first", + value: function first() { + return this.head.data; + } // Consumes a specified amount of characters from the buffered data. + + }, { + key: "_getString", + value: function _getString(n) { + var p = this.head; + var c = 1; + var ret = p.data; + n -= ret.length; + + while (p = p.next) { + var str = p.data; + var nb = n > str.length ? str.length : n; + if (nb === str.length) ret += str;else ret += str.slice(0, n); + n -= nb; + + if (n === 0) { + if (nb === str.length) { + ++c; + if (p.next) this.head = p.next;else this.head = this.tail = null; + } else { + this.head = p; + p.data = str.slice(nb); + } + + break; + } + + ++c; + } + + this.length -= c; + return ret; + } // Consumes a specified amount of bytes from the buffered data. + + }, { + key: "_getBuffer", + value: function _getBuffer(n) { + var ret = Buffer.allocUnsafe(n); + var p = this.head; + var c = 1; + p.data.copy(ret); + n -= p.data.length; + + while (p = p.next) { + var buf = p.data; + var nb = n > buf.length ? buf.length : n; + buf.copy(ret, ret.length - n, 0, nb); + n -= nb; + + if (n === 0) { + if (nb === buf.length) { + ++c; + if (p.next) this.head = p.next;else this.head = this.tail = null; + } else { + this.head = p; + p.data = buf.slice(nb); + } + + break; + } + + ++c; + } + + this.length -= c; + return ret; + } // Make sure the linked list only shows the minimal necessary information. + + }, { + key: custom, + value: function value(_, options) { + return inspect(this, _objectSpread({}, options, { + // Only inspect one level. + depth: 0, + // It should not recurse. + customInspect: false + })); + } + }]); + + return BufferList; +}(); +},{"buffer":63,"util":19}],55:[function(require,module,exports){ +(function (process){(function (){ +'use strict'; // undocumented cb() API, needed for core, not for public API + +function destroy(err, cb) { + var _this = this; + + var readableDestroyed = this._readableState && this._readableState.destroyed; + var writableDestroyed = this._writableState && this._writableState.destroyed; + + if (readableDestroyed || writableDestroyed) { + if (cb) { + cb(err); + } else if (err) { + if (!this._writableState) { + process.nextTick(emitErrorNT, this, err); + } else if (!this._writableState.errorEmitted) { + this._writableState.errorEmitted = true; + process.nextTick(emitErrorNT, this, err); + } + } + + return this; + } // we set destroyed to true before firing error callbacks in order + // to make it re-entrance safe in case destroy() is called within callbacks + + + if (this._readableState) { + this._readableState.destroyed = true; + } // if this is a duplex stream mark the writable part as destroyed as well + + + if (this._writableState) { + this._writableState.destroyed = true; + } + + this._destroy(err || null, function (err) { + if (!cb && err) { + if (!_this._writableState) { + process.nextTick(emitErrorAndCloseNT, _this, err); + } else if (!_this._writableState.errorEmitted) { + _this._writableState.errorEmitted = true; + process.nextTick(emitErrorAndCloseNT, _this, err); + } else { + process.nextTick(emitCloseNT, _this); + } + } else if (cb) { + process.nextTick(emitCloseNT, _this); + cb(err); + } else { + process.nextTick(emitCloseNT, _this); + } + }); + + return this; +} + +function emitErrorAndCloseNT(self, err) { + emitErrorNT(self, err); + emitCloseNT(self); +} + +function emitCloseNT(self) { + if (self._writableState && !self._writableState.emitClose) return; + if (self._readableState && !self._readableState.emitClose) return; + self.emit('close'); +} + +function undestroy() { + if (this._readableState) { + this._readableState.destroyed = false; + this._readableState.reading = false; + this._readableState.ended = false; + this._readableState.endEmitted = false; + } + + if (this._writableState) { + this._writableState.destroyed = false; + this._writableState.ended = false; + this._writableState.ending = false; + this._writableState.finalCalled = false; + this._writableState.prefinished = false; + this._writableState.finished = false; + this._writableState.errorEmitted = false; + } +} + +function emitErrorNT(self, err) { + self.emit('error', err); +} + +function errorOrDestroy(stream, err) { + // We have tests that rely on errors being emitted + // in the same tick, so changing this is semver major. + // For now when you opt-in to autoDestroy we allow + // the error to be emitted nextTick. In a future + // semver major update we should change the default to this. + var rState = stream._readableState; + var wState = stream._writableState; + if (rState && rState.autoDestroy || wState && wState.autoDestroy) stream.destroy(err);else stream.emit('error', err); +} + +module.exports = { + destroy: destroy, + undestroy: undestroy, + errorOrDestroy: errorOrDestroy +}; +}).call(this)}).call(this,require('_process')) +},{"_process":149}],56:[function(require,module,exports){ +// Ported from https://github.com/mafintosh/end-of-stream with +// permission from the author, Mathias Buus (@mafintosh). +'use strict'; + +var ERR_STREAM_PREMATURE_CLOSE = require('../../../errors').codes.ERR_STREAM_PREMATURE_CLOSE; + +function once(callback) { + var called = false; + return function () { + if (called) return; + called = true; + + for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) { + args[_key] = arguments[_key]; + } + + callback.apply(this, args); + }; +} + +function noop() {} + +function isRequest(stream) { + return stream.setHeader && typeof stream.abort === 'function'; +} + +function eos(stream, opts, callback) { + if (typeof opts === 'function') return eos(stream, null, opts); + if (!opts) opts = {}; + callback = once(callback || noop); + var readable = opts.readable || opts.readable !== false && stream.readable; + var writable = opts.writable || opts.writable !== false && stream.writable; + + var onlegacyfinish = function onlegacyfinish() { + if (!stream.writable) onfinish(); + }; + + var writableEnded = stream._writableState && stream._writableState.finished; + + var onfinish = function onfinish() { + writable = false; + writableEnded = true; + if (!readable) callback.call(stream); + }; + + var readableEnded = stream._readableState && stream._readableState.endEmitted; + + var onend = function onend() { + readable = false; + readableEnded = true; + if (!writable) callback.call(stream); + }; + + var onerror = function onerror(err) { + callback.call(stream, err); + }; + + var onclose = function onclose() { + var err; + + if (readable && !readableEnded) { + if (!stream._readableState || !stream._readableState.ended) err = new ERR_STREAM_PREMATURE_CLOSE(); + return callback.call(stream, err); + } + + if (writable && !writableEnded) { + if (!stream._writableState || !stream._writableState.ended) err = new ERR_STREAM_PREMATURE_CLOSE(); + return callback.call(stream, err); + } + }; + + var onrequest = function onrequest() { + stream.req.on('finish', onfinish); + }; + + if (isRequest(stream)) { + stream.on('complete', onfinish); + stream.on('abort', onclose); + if (stream.req) onrequest();else stream.on('request', onrequest); + } else if (writable && !stream._writableState) { + // legacy streams + stream.on('end', onlegacyfinish); + stream.on('close', onlegacyfinish); + } + + stream.on('end', onend); + stream.on('finish', onfinish); + if (opts.error !== false) stream.on('error', onerror); + stream.on('close', onclose); + return function () { + stream.removeListener('complete', onfinish); + stream.removeListener('abort', onclose); + stream.removeListener('request', onrequest); + if (stream.req) stream.req.removeListener('finish', onfinish); + stream.removeListener('end', onlegacyfinish); + stream.removeListener('close', onlegacyfinish); + stream.removeListener('finish', onfinish); + stream.removeListener('end', onend); + stream.removeListener('error', onerror); + stream.removeListener('close', onclose); + }; +} + +module.exports = eos; +},{"../../../errors":47}],57:[function(require,module,exports){ +module.exports = function () { + throw new Error('Readable.from is not available in the browser') +}; + +},{}],58:[function(require,module,exports){ +// Ported from https://github.com/mafintosh/pump with +// permission from the author, Mathias Buus (@mafintosh). +'use strict'; + +var eos; + +function once(callback) { + var called = false; + return function () { + if (called) return; + called = true; + callback.apply(void 0, arguments); + }; +} + +var _require$codes = require('../../../errors').codes, + ERR_MISSING_ARGS = _require$codes.ERR_MISSING_ARGS, + ERR_STREAM_DESTROYED = _require$codes.ERR_STREAM_DESTROYED; + +function noop(err) { + // Rethrow the error if it exists to avoid swallowing it + if (err) throw err; +} + +function isRequest(stream) { + return stream.setHeader && typeof stream.abort === 'function'; +} + +function destroyer(stream, reading, writing, callback) { + callback = once(callback); + var closed = false; + stream.on('close', function () { + closed = true; + }); + if (eos === undefined) eos = require('./end-of-stream'); + eos(stream, { + readable: reading, + writable: writing + }, function (err) { + if (err) return callback(err); + closed = true; + callback(); + }); + var destroyed = false; + return function (err) { + if (closed) return; + if (destroyed) return; + destroyed = true; // request.destroy just do .end - .abort is what we want + + if (isRequest(stream)) return stream.abort(); + if (typeof stream.destroy === 'function') return stream.destroy(); + callback(err || new ERR_STREAM_DESTROYED('pipe')); + }; +} + +function call(fn) { + fn(); +} + +function pipe(from, to) { + return from.pipe(to); +} + +function popCallback(streams) { + if (!streams.length) return noop; + if (typeof streams[streams.length - 1] !== 'function') return noop; + return streams.pop(); +} + +function pipeline() { + for (var _len = arguments.length, streams = new Array(_len), _key = 0; _key < _len; _key++) { + streams[_key] = arguments[_key]; + } + + var callback = popCallback(streams); + if (Array.isArray(streams[0])) streams = streams[0]; + + if (streams.length < 2) { + throw new ERR_MISSING_ARGS('streams'); + } + + var error; + var destroys = streams.map(function (stream, i) { + var reading = i < streams.length - 1; + var writing = i > 0; + return destroyer(stream, reading, writing, function (err) { + if (!error) error = err; + if (err) destroys.forEach(call); + if (reading) return; + destroys.forEach(call); + callback(error); + }); + }); + return streams.reduce(pipe); +} + +module.exports = pipeline; +},{"../../../errors":47,"./end-of-stream":56}],59:[function(require,module,exports){ +'use strict'; + +var ERR_INVALID_OPT_VALUE = require('../../../errors').codes.ERR_INVALID_OPT_VALUE; + +function highWaterMarkFrom(options, isDuplex, duplexKey) { + return options.highWaterMark != null ? options.highWaterMark : isDuplex ? options[duplexKey] : null; +} + +function getHighWaterMark(state, options, duplexKey, isDuplex) { + var hwm = highWaterMarkFrom(options, isDuplex, duplexKey); + + if (hwm != null) { + if (!(isFinite(hwm) && Math.floor(hwm) === hwm) || hwm < 0) { + var name = isDuplex ? duplexKey : 'highWaterMark'; + throw new ERR_INVALID_OPT_VALUE(name, hwm); + } + + return Math.floor(hwm); + } // Default value + + + return state.objectMode ? 16 : 16 * 1024; +} + +module.exports = { + getHighWaterMark: getHighWaterMark +}; +},{"../../../errors":47}],60:[function(require,module,exports){ +module.exports = require('events').EventEmitter; + +},{"events":100}],61:[function(require,module,exports){ +exports = module.exports = require('./lib/_stream_readable.js'); +exports.Stream = exports; +exports.Readable = exports; +exports.Writable = require('./lib/_stream_writable.js'); +exports.Duplex = require('./lib/_stream_duplex.js'); +exports.Transform = require('./lib/_stream_transform.js'); +exports.PassThrough = require('./lib/_stream_passthrough.js'); +exports.finished = require('./lib/internal/streams/end-of-stream.js'); +exports.pipeline = require('./lib/internal/streams/pipeline.js'); + +},{"./lib/_stream_duplex.js":48,"./lib/_stream_passthrough.js":49,"./lib/_stream_readable.js":50,"./lib/_stream_transform.js":51,"./lib/_stream_writable.js":52,"./lib/internal/streams/end-of-stream.js":56,"./lib/internal/streams/pipeline.js":58}],62:[function(require,module,exports){ +(function (Buffer){(function (){ +module.exports = function xor (a, b) { + var length = Math.min(a.length, b.length) + var buffer = new Buffer(length) + + for (var i = 0; i < length; ++i) { + buffer[i] = a[i] ^ b[i] + } + + return buffer +} + +}).call(this)}).call(this,require("buffer").Buffer) +},{"buffer":63}],63:[function(require,module,exports){ +(function (Buffer){(function (){ +/*! + * The buffer module from node.js, for the browser. + * + * @author Feross Aboukhadijeh + * @license MIT + */ +/* eslint-disable no-proto */ + +'use strict' + +var base64 = require('base64-js') +var ieee754 = require('ieee754') + +exports.Buffer = Buffer +exports.SlowBuffer = SlowBuffer +exports.INSPECT_MAX_BYTES = 50 + +var K_MAX_LENGTH = 0x7fffffff +exports.kMaxLength = K_MAX_LENGTH + +/** + * If `Buffer.TYPED_ARRAY_SUPPORT`: + * === true Use Uint8Array implementation (fastest) + * === false Print warning and recommend using `buffer` v4.x which has an Object + * implementation (most compatible, even IE6) + * + * Browsers that support typed arrays are IE 10+, Firefox 4+, Chrome 7+, Safari 5.1+, + * Opera 11.6+, iOS 4.2+. + * + * We report that the browser does not support typed arrays if the are not subclassable + * using __proto__. Firefox 4-29 lacks support for adding new properties to `Uint8Array` + * (See: https://bugzilla.mozilla.org/show_bug.cgi?id=695438). IE 10 lacks support + * for __proto__ and has a buggy typed array implementation. + */ +Buffer.TYPED_ARRAY_SUPPORT = typedArraySupport() + +if (!Buffer.TYPED_ARRAY_SUPPORT && typeof console !== 'undefined' && + typeof console.error === 'function') { + console.error( + 'This browser lacks typed array (Uint8Array) support which is required by ' + + '`buffer` v5.x. Use `buffer` v4.x if you require old browser support.' + ) +} + +function typedArraySupport () { + // Can typed array instances can be augmented? + try { + var arr = new Uint8Array(1) + arr.__proto__ = { __proto__: Uint8Array.prototype, foo: function () { return 42 } } + return arr.foo() === 42 + } catch (e) { + return false + } +} + +Object.defineProperty(Buffer.prototype, 'parent', { + enumerable: true, + get: function () { + if (!Buffer.isBuffer(this)) return undefined + return this.buffer + } +}) + +Object.defineProperty(Buffer.prototype, 'offset', { + enumerable: true, + get: function () { + if (!Buffer.isBuffer(this)) return undefined + return this.byteOffset + } +}) + +function createBuffer (length) { + if (length > K_MAX_LENGTH) { + throw new RangeError('The value "' + length + '" is invalid for option "size"') + } + // Return an augmented `Uint8Array` instance + var buf = new Uint8Array(length) + buf.__proto__ = Buffer.prototype + return buf +} + +/** + * The Buffer constructor returns instances of `Uint8Array` that have their + * prototype changed to `Buffer.prototype`. Furthermore, `Buffer` is a subclass of + * `Uint8Array`, so the returned instances will have all the node `Buffer` methods + * and the `Uint8Array` methods. Square bracket notation works as expected -- it + * returns a single octet. + * + * The `Uint8Array` prototype remains unmodified. + */ + +function Buffer (arg, encodingOrOffset, length) { + // Common case. + if (typeof arg === 'number') { + if (typeof encodingOrOffset === 'string') { + throw new TypeError( + 'The "string" argument must be of type string. Received type number' + ) + } + return allocUnsafe(arg) + } + return from(arg, encodingOrOffset, length) +} + +// Fix subarray() in ES2016. See: https://github.com/feross/buffer/pull/97 +if (typeof Symbol !== 'undefined' && Symbol.species != null && + Buffer[Symbol.species] === Buffer) { + Object.defineProperty(Buffer, Symbol.species, { + value: null, + configurable: true, + enumerable: false, + writable: false + }) +} + +Buffer.poolSize = 8192 // not used by this implementation + +function from (value, encodingOrOffset, length) { + if (typeof value === 'string') { + return fromString(value, encodingOrOffset) + } + + if (ArrayBuffer.isView(value)) { + return fromArrayLike(value) + } + + if (value == null) { + throw TypeError( + 'The first argument must be one of type string, Buffer, ArrayBuffer, Array, ' + + 'or Array-like Object. Received type ' + (typeof value) + ) + } + + if (isInstance(value, ArrayBuffer) || + (value && isInstance(value.buffer, ArrayBuffer))) { + return fromArrayBuffer(value, encodingOrOffset, length) + } + + if (typeof value === 'number') { + throw new TypeError( + 'The "value" argument must not be of type number. Received type number' + ) + } + + var valueOf = value.valueOf && value.valueOf() + if (valueOf != null && valueOf !== value) { + return Buffer.from(valueOf, encodingOrOffset, length) + } + + var b = fromObject(value) + if (b) return b + + if (typeof Symbol !== 'undefined' && Symbol.toPrimitive != null && + typeof value[Symbol.toPrimitive] === 'function') { + return Buffer.from( + value[Symbol.toPrimitive]('string'), encodingOrOffset, length + ) + } + + throw new TypeError( + 'The first argument must be one of type string, Buffer, ArrayBuffer, Array, ' + + 'or Array-like Object. Received type ' + (typeof value) + ) +} + +/** + * Functionally equivalent to Buffer(arg, encoding) but throws a TypeError + * if value is a number. + * Buffer.from(str[, encoding]) + * Buffer.from(array) + * Buffer.from(buffer) + * Buffer.from(arrayBuffer[, byteOffset[, length]]) + **/ +Buffer.from = function (value, encodingOrOffset, length) { + return from(value, encodingOrOffset, length) +} + +// Note: Change prototype *after* Buffer.from is defined to workaround Chrome bug: +// https://github.com/feross/buffer/pull/148 +Buffer.prototype.__proto__ = Uint8Array.prototype +Buffer.__proto__ = Uint8Array + +function assertSize (size) { + if (typeof size !== 'number') { + throw new TypeError('"size" argument must be of type number') + } else if (size < 0) { + throw new RangeError('The value "' + size + '" is invalid for option "size"') + } +} + +function alloc (size, fill, encoding) { + assertSize(size) + if (size <= 0) { + return createBuffer(size) + } + if (fill !== undefined) { + // Only pay attention to encoding if it's a string. This + // prevents accidentally sending in a number that would + // be interpretted as a start offset. + return typeof encoding === 'string' + ? createBuffer(size).fill(fill, encoding) + : createBuffer(size).fill(fill) + } + return createBuffer(size) +} + +/** + * Creates a new filled Buffer instance. + * alloc(size[, fill[, encoding]]) + **/ +Buffer.alloc = function (size, fill, encoding) { + return alloc(size, fill, encoding) +} + +function allocUnsafe (size) { + assertSize(size) + return createBuffer(size < 0 ? 0 : checked(size) | 0) +} + +/** + * Equivalent to Buffer(num), by default creates a non-zero-filled Buffer instance. + * */ +Buffer.allocUnsafe = function (size) { + return allocUnsafe(size) +} +/** + * Equivalent to SlowBuffer(num), by default creates a non-zero-filled Buffer instance. + */ +Buffer.allocUnsafeSlow = function (size) { + return allocUnsafe(size) +} + +function fromString (string, encoding) { + if (typeof encoding !== 'string' || encoding === '') { + encoding = 'utf8' + } + + if (!Buffer.isEncoding(encoding)) { + throw new TypeError('Unknown encoding: ' + encoding) + } + + var length = byteLength(string, encoding) | 0 + var buf = createBuffer(length) + + var actual = buf.write(string, encoding) + + if (actual !== length) { + // Writing a hex string, for example, that contains invalid characters will + // cause everything after the first invalid character to be ignored. (e.g. + // 'abxxcd' will be treated as 'ab') + buf = buf.slice(0, actual) + } + + return buf +} + +function fromArrayLike (array) { + var length = array.length < 0 ? 0 : checked(array.length) | 0 + var buf = createBuffer(length) + for (var i = 0; i < length; i += 1) { + buf[i] = array[i] & 255 + } + return buf +} + +function fromArrayBuffer (array, byteOffset, length) { + if (byteOffset < 0 || array.byteLength < byteOffset) { + throw new RangeError('"offset" is outside of buffer bounds') + } + + if (array.byteLength < byteOffset + (length || 0)) { + throw new RangeError('"length" is outside of buffer bounds') + } + + var buf + if (byteOffset === undefined && length === undefined) { + buf = new Uint8Array(array) + } else if (length === undefined) { + buf = new Uint8Array(array, byteOffset) + } else { + buf = new Uint8Array(array, byteOffset, length) + } + + // Return an augmented `Uint8Array` instance + buf.__proto__ = Buffer.prototype + return buf +} + +function fromObject (obj) { + if (Buffer.isBuffer(obj)) { + var len = checked(obj.length) | 0 + var buf = createBuffer(len) + + if (buf.length === 0) { + return buf + } + + obj.copy(buf, 0, 0, len) + return buf + } + + if (obj.length !== undefined) { + if (typeof obj.length !== 'number' || numberIsNaN(obj.length)) { + return createBuffer(0) + } + return fromArrayLike(obj) + } + + if (obj.type === 'Buffer' && Array.isArray(obj.data)) { + return fromArrayLike(obj.data) + } +} + +function checked (length) { + // Note: cannot use `length < K_MAX_LENGTH` here because that fails when + // length is NaN (which is otherwise coerced to zero.) + if (length >= K_MAX_LENGTH) { + throw new RangeError('Attempt to allocate Buffer larger than maximum ' + + 'size: 0x' + K_MAX_LENGTH.toString(16) + ' bytes') + } + return length | 0 +} + +function SlowBuffer (length) { + if (+length != length) { // eslint-disable-line eqeqeq + length = 0 + } + return Buffer.alloc(+length) +} + +Buffer.isBuffer = function isBuffer (b) { + return b != null && b._isBuffer === true && + b !== Buffer.prototype // so Buffer.isBuffer(Buffer.prototype) will be false +} + +Buffer.compare = function compare (a, b) { + if (isInstance(a, Uint8Array)) a = Buffer.from(a, a.offset, a.byteLength) + if (isInstance(b, Uint8Array)) b = Buffer.from(b, b.offset, b.byteLength) + if (!Buffer.isBuffer(a) || !Buffer.isBuffer(b)) { + throw new TypeError( + 'The "buf1", "buf2" arguments must be one of type Buffer or Uint8Array' + ) + } + + if (a === b) return 0 + + var x = a.length + var y = b.length + + for (var i = 0, len = Math.min(x, y); i < len; ++i) { + if (a[i] !== b[i]) { + x = a[i] + y = b[i] + break + } + } + + if (x < y) return -1 + if (y < x) return 1 + return 0 +} + +Buffer.isEncoding = function isEncoding (encoding) { + switch (String(encoding).toLowerCase()) { + case 'hex': + case 'utf8': + case 'utf-8': + case 'ascii': + case 'latin1': + case 'binary': + case 'base64': + case 'ucs2': + case 'ucs-2': + case 'utf16le': + case 'utf-16le': + return true + default: + return false + } +} + +Buffer.concat = function concat (list, length) { + if (!Array.isArray(list)) { + throw new TypeError('"list" argument must be an Array of Buffers') + } + + if (list.length === 0) { + return Buffer.alloc(0) + } + + var i + if (length === undefined) { + length = 0 + for (i = 0; i < list.length; ++i) { + length += list[i].length + } + } + + var buffer = Buffer.allocUnsafe(length) + var pos = 0 + for (i = 0; i < list.length; ++i) { + var buf = list[i] + if (isInstance(buf, Uint8Array)) { + buf = Buffer.from(buf) + } + if (!Buffer.isBuffer(buf)) { + throw new TypeError('"list" argument must be an Array of Buffers') + } + buf.copy(buffer, pos) + pos += buf.length + } + return buffer +} + +function byteLength (string, encoding) { + if (Buffer.isBuffer(string)) { + return string.length + } + if (ArrayBuffer.isView(string) || isInstance(string, ArrayBuffer)) { + return string.byteLength + } + if (typeof string !== 'string') { + throw new TypeError( + 'The "string" argument must be one of type string, Buffer, or ArrayBuffer. ' + + 'Received type ' + typeof string + ) + } + + var len = string.length + var mustMatch = (arguments.length > 2 && arguments[2] === true) + if (!mustMatch && len === 0) return 0 + + // Use a for loop to avoid recursion + var loweredCase = false + for (;;) { + switch (encoding) { + case 'ascii': + case 'latin1': + case 'binary': + return len + case 'utf8': + case 'utf-8': + return utf8ToBytes(string).length + case 'ucs2': + case 'ucs-2': + case 'utf16le': + case 'utf-16le': + return len * 2 + case 'hex': + return len >>> 1 + case 'base64': + return base64ToBytes(string).length + default: + if (loweredCase) { + return mustMatch ? -1 : utf8ToBytes(string).length // assume utf8 + } + encoding = ('' + encoding).toLowerCase() + loweredCase = true + } + } +} +Buffer.byteLength = byteLength + +function slowToString (encoding, start, end) { + var loweredCase = false + + // No need to verify that "this.length <= MAX_UINT32" since it's a read-only + // property of a typed array. + + // This behaves neither like String nor Uint8Array in that we set start/end + // to their upper/lower bounds if the value passed is out of range. + // undefined is handled specially as per ECMA-262 6th Edition, + // Section 13.3.3.7 Runtime Semantics: KeyedBindingInitialization. + if (start === undefined || start < 0) { + start = 0 + } + // Return early if start > this.length. Done here to prevent potential uint32 + // coercion fail below. + if (start > this.length) { + return '' + } + + if (end === undefined || end > this.length) { + end = this.length + } + + if (end <= 0) { + return '' + } + + // Force coersion to uint32. This will also coerce falsey/NaN values to 0. + end >>>= 0 + start >>>= 0 + + if (end <= start) { + return '' + } + + if (!encoding) encoding = 'utf8' + + while (true) { + switch (encoding) { + case 'hex': + return hexSlice(this, start, end) + + case 'utf8': + case 'utf-8': + return utf8Slice(this, start, end) + + case 'ascii': + return asciiSlice(this, start, end) + + case 'latin1': + case 'binary': + return latin1Slice(this, start, end) + + case 'base64': + return base64Slice(this, start, end) + + case 'ucs2': + case 'ucs-2': + case 'utf16le': + case 'utf-16le': + return utf16leSlice(this, start, end) + + default: + if (loweredCase) throw new TypeError('Unknown encoding: ' + encoding) + encoding = (encoding + '').toLowerCase() + loweredCase = true + } + } +} + +// This property is used by `Buffer.isBuffer` (and the `is-buffer` npm package) +// to detect a Buffer instance. It's not possible to use `instanceof Buffer` +// reliably in a browserify context because there could be multiple different +// copies of the 'buffer' package in use. This method works even for Buffer +// instances that were created from another copy of the `buffer` package. +// See: https://github.com/feross/buffer/issues/154 +Buffer.prototype._isBuffer = true + +function swap (b, n, m) { + var i = b[n] + b[n] = b[m] + b[m] = i +} + +Buffer.prototype.swap16 = function swap16 () { + var len = this.length + if (len % 2 !== 0) { + throw new RangeError('Buffer size must be a multiple of 16-bits') + } + for (var i = 0; i < len; i += 2) { + swap(this, i, i + 1) + } + return this +} + +Buffer.prototype.swap32 = function swap32 () { + var len = this.length + if (len % 4 !== 0) { + throw new RangeError('Buffer size must be a multiple of 32-bits') + } + for (var i = 0; i < len; i += 4) { + swap(this, i, i + 3) + swap(this, i + 1, i + 2) + } + return this +} + +Buffer.prototype.swap64 = function swap64 () { + var len = this.length + if (len % 8 !== 0) { + throw new RangeError('Buffer size must be a multiple of 64-bits') + } + for (var i = 0; i < len; i += 8) { + swap(this, i, i + 7) + swap(this, i + 1, i + 6) + swap(this, i + 2, i + 5) + swap(this, i + 3, i + 4) + } + return this +} + +Buffer.prototype.toString = function toString () { + var length = this.length + if (length === 0) return '' + if (arguments.length === 0) return utf8Slice(this, 0, length) + return slowToString.apply(this, arguments) +} + +Buffer.prototype.toLocaleString = Buffer.prototype.toString + +Buffer.prototype.equals = function equals (b) { + if (!Buffer.isBuffer(b)) throw new TypeError('Argument must be a Buffer') + if (this === b) return true + return Buffer.compare(this, b) === 0 +} + +Buffer.prototype.inspect = function inspect () { + var str = '' + var max = exports.INSPECT_MAX_BYTES + str = this.toString('hex', 0, max).replace(/(.{2})/g, '$1 ').trim() + if (this.length > max) str += ' ... ' + return '' +} + +Buffer.prototype.compare = function compare (target, start, end, thisStart, thisEnd) { + if (isInstance(target, Uint8Array)) { + target = Buffer.from(target, target.offset, target.byteLength) + } + if (!Buffer.isBuffer(target)) { + throw new TypeError( + 'The "target" argument must be one of type Buffer or Uint8Array. ' + + 'Received type ' + (typeof target) + ) + } + + if (start === undefined) { + start = 0 + } + if (end === undefined) { + end = target ? target.length : 0 + } + if (thisStart === undefined) { + thisStart = 0 + } + if (thisEnd === undefined) { + thisEnd = this.length + } + + if (start < 0 || end > target.length || thisStart < 0 || thisEnd > this.length) { + throw new RangeError('out of range index') + } + + if (thisStart >= thisEnd && start >= end) { + return 0 + } + if (thisStart >= thisEnd) { + return -1 + } + if (start >= end) { + return 1 + } + + start >>>= 0 + end >>>= 0 + thisStart >>>= 0 + thisEnd >>>= 0 + + if (this === target) return 0 + + var x = thisEnd - thisStart + var y = end - start + var len = Math.min(x, y) + + var thisCopy = this.slice(thisStart, thisEnd) + var targetCopy = target.slice(start, end) + + for (var i = 0; i < len; ++i) { + if (thisCopy[i] !== targetCopy[i]) { + x = thisCopy[i] + y = targetCopy[i] + break + } + } + + if (x < y) return -1 + if (y < x) return 1 + return 0 +} + +// Finds either the first index of `val` in `buffer` at offset >= `byteOffset`, +// OR the last index of `val` in `buffer` at offset <= `byteOffset`. +// +// Arguments: +// - buffer - a Buffer to search +// - val - a string, Buffer, or number +// - byteOffset - an index into `buffer`; will be clamped to an int32 +// - encoding - an optional encoding, relevant is val is a string +// - dir - true for indexOf, false for lastIndexOf +function bidirectionalIndexOf (buffer, val, byteOffset, encoding, dir) { + // Empty buffer means no match + if (buffer.length === 0) return -1 + + // Normalize byteOffset + if (typeof byteOffset === 'string') { + encoding = byteOffset + byteOffset = 0 + } else if (byteOffset > 0x7fffffff) { + byteOffset = 0x7fffffff + } else if (byteOffset < -0x80000000) { + byteOffset = -0x80000000 + } + byteOffset = +byteOffset // Coerce to Number. + if (numberIsNaN(byteOffset)) { + // byteOffset: it it's undefined, null, NaN, "foo", etc, search whole buffer + byteOffset = dir ? 0 : (buffer.length - 1) + } + + // Normalize byteOffset: negative offsets start from the end of the buffer + if (byteOffset < 0) byteOffset = buffer.length + byteOffset + if (byteOffset >= buffer.length) { + if (dir) return -1 + else byteOffset = buffer.length - 1 + } else if (byteOffset < 0) { + if (dir) byteOffset = 0 + else return -1 + } + + // Normalize val + if (typeof val === 'string') { + val = Buffer.from(val, encoding) + } + + // Finally, search either indexOf (if dir is true) or lastIndexOf + if (Buffer.isBuffer(val)) { + // Special case: looking for empty string/buffer always fails + if (val.length === 0) { + return -1 + } + return arrayIndexOf(buffer, val, byteOffset, encoding, dir) + } else if (typeof val === 'number') { + val = val & 0xFF // Search for a byte value [0-255] + if (typeof Uint8Array.prototype.indexOf === 'function') { + if (dir) { + return Uint8Array.prototype.indexOf.call(buffer, val, byteOffset) + } else { + return Uint8Array.prototype.lastIndexOf.call(buffer, val, byteOffset) + } + } + return arrayIndexOf(buffer, [ val ], byteOffset, encoding, dir) + } + + throw new TypeError('val must be string, number or Buffer') +} + +function arrayIndexOf (arr, val, byteOffset, encoding, dir) { + var indexSize = 1 + var arrLength = arr.length + var valLength = val.length + + if (encoding !== undefined) { + encoding = String(encoding).toLowerCase() + if (encoding === 'ucs2' || encoding === 'ucs-2' || + encoding === 'utf16le' || encoding === 'utf-16le') { + if (arr.length < 2 || val.length < 2) { + return -1 + } + indexSize = 2 + arrLength /= 2 + valLength /= 2 + byteOffset /= 2 + } + } + + function read (buf, i) { + if (indexSize === 1) { + return buf[i] + } else { + return buf.readUInt16BE(i * indexSize) + } + } + + var i + if (dir) { + var foundIndex = -1 + for (i = byteOffset; i < arrLength; i++) { + if (read(arr, i) === read(val, foundIndex === -1 ? 0 : i - foundIndex)) { + if (foundIndex === -1) foundIndex = i + if (i - foundIndex + 1 === valLength) return foundIndex * indexSize + } else { + if (foundIndex !== -1) i -= i - foundIndex + foundIndex = -1 + } + } + } else { + if (byteOffset + valLength > arrLength) byteOffset = arrLength - valLength + for (i = byteOffset; i >= 0; i--) { + var found = true + for (var j = 0; j < valLength; j++) { + if (read(arr, i + j) !== read(val, j)) { + found = false + break + } + } + if (found) return i + } + } + + return -1 +} + +Buffer.prototype.includes = function includes (val, byteOffset, encoding) { + return this.indexOf(val, byteOffset, encoding) !== -1 +} + +Buffer.prototype.indexOf = function indexOf (val, byteOffset, encoding) { + return bidirectionalIndexOf(this, val, byteOffset, encoding, true) +} + +Buffer.prototype.lastIndexOf = function lastIndexOf (val, byteOffset, encoding) { + return bidirectionalIndexOf(this, val, byteOffset, encoding, false) +} + +function hexWrite (buf, string, offset, length) { + offset = Number(offset) || 0 + var remaining = buf.length - offset + if (!length) { + length = remaining + } else { + length = Number(length) + if (length > remaining) { + length = remaining + } + } + + var strLen = string.length + + if (length > strLen / 2) { + length = strLen / 2 + } + for (var i = 0; i < length; ++i) { + var parsed = parseInt(string.substr(i * 2, 2), 16) + if (numberIsNaN(parsed)) return i + buf[offset + i] = parsed + } + return i +} + +function utf8Write (buf, string, offset, length) { + return blitBuffer(utf8ToBytes(string, buf.length - offset), buf, offset, length) +} + +function asciiWrite (buf, string, offset, length) { + return blitBuffer(asciiToBytes(string), buf, offset, length) +} + +function latin1Write (buf, string, offset, length) { + return asciiWrite(buf, string, offset, length) +} + +function base64Write (buf, string, offset, length) { + return blitBuffer(base64ToBytes(string), buf, offset, length) +} + +function ucs2Write (buf, string, offset, length) { + return blitBuffer(utf16leToBytes(string, buf.length - offset), buf, offset, length) +} + +Buffer.prototype.write = function write (string, offset, length, encoding) { + // Buffer#write(string) + if (offset === undefined) { + encoding = 'utf8' + length = this.length + offset = 0 + // Buffer#write(string, encoding) + } else if (length === undefined && typeof offset === 'string') { + encoding = offset + length = this.length + offset = 0 + // Buffer#write(string, offset[, length][, encoding]) + } else if (isFinite(offset)) { + offset = offset >>> 0 + if (isFinite(length)) { + length = length >>> 0 + if (encoding === undefined) encoding = 'utf8' + } else { + encoding = length + length = undefined + } + } else { + throw new Error( + 'Buffer.write(string, encoding, offset[, length]) is no longer supported' + ) + } + + var remaining = this.length - offset + if (length === undefined || length > remaining) length = remaining + + if ((string.length > 0 && (length < 0 || offset < 0)) || offset > this.length) { + throw new RangeError('Attempt to write outside buffer bounds') + } + + if (!encoding) encoding = 'utf8' + + var loweredCase = false + for (;;) { + switch (encoding) { + case 'hex': + return hexWrite(this, string, offset, length) + + case 'utf8': + case 'utf-8': + return utf8Write(this, string, offset, length) + + case 'ascii': + return asciiWrite(this, string, offset, length) + + case 'latin1': + case 'binary': + return latin1Write(this, string, offset, length) + + case 'base64': + // Warning: maxLength not taken into account in base64Write + return base64Write(this, string, offset, length) + + case 'ucs2': + case 'ucs-2': + case 'utf16le': + case 'utf-16le': + return ucs2Write(this, string, offset, length) + + default: + if (loweredCase) throw new TypeError('Unknown encoding: ' + encoding) + encoding = ('' + encoding).toLowerCase() + loweredCase = true + } + } +} + +Buffer.prototype.toJSON = function toJSON () { + return { + type: 'Buffer', + data: Array.prototype.slice.call(this._arr || this, 0) + } +} + +function base64Slice (buf, start, end) { + if (start === 0 && end === buf.length) { + return base64.fromByteArray(buf) + } else { + return base64.fromByteArray(buf.slice(start, end)) + } +} + +function utf8Slice (buf, start, end) { + end = Math.min(buf.length, end) + var res = [] + + var i = start + while (i < end) { + var firstByte = buf[i] + var codePoint = null + var bytesPerSequence = (firstByte > 0xEF) ? 4 + : (firstByte > 0xDF) ? 3 + : (firstByte > 0xBF) ? 2 + : 1 + + if (i + bytesPerSequence <= end) { + var secondByte, thirdByte, fourthByte, tempCodePoint + + switch (bytesPerSequence) { + case 1: + if (firstByte < 0x80) { + codePoint = firstByte + } + break + case 2: + secondByte = buf[i + 1] + if ((secondByte & 0xC0) === 0x80) { + tempCodePoint = (firstByte & 0x1F) << 0x6 | (secondByte & 0x3F) + if (tempCodePoint > 0x7F) { + codePoint = tempCodePoint + } + } + break + case 3: + secondByte = buf[i + 1] + thirdByte = buf[i + 2] + if ((secondByte & 0xC0) === 0x80 && (thirdByte & 0xC0) === 0x80) { + tempCodePoint = (firstByte & 0xF) << 0xC | (secondByte & 0x3F) << 0x6 | (thirdByte & 0x3F) + if (tempCodePoint > 0x7FF && (tempCodePoint < 0xD800 || tempCodePoint > 0xDFFF)) { + codePoint = tempCodePoint + } + } + break + case 4: + secondByte = buf[i + 1] + thirdByte = buf[i + 2] + fourthByte = buf[i + 3] + if ((secondByte & 0xC0) === 0x80 && (thirdByte & 0xC0) === 0x80 && (fourthByte & 0xC0) === 0x80) { + tempCodePoint = (firstByte & 0xF) << 0x12 | (secondByte & 0x3F) << 0xC | (thirdByte & 0x3F) << 0x6 | (fourthByte & 0x3F) + if (tempCodePoint > 0xFFFF && tempCodePoint < 0x110000) { + codePoint = tempCodePoint + } + } + } + } + + if (codePoint === null) { + // we did not generate a valid codePoint so insert a + // replacement char (U+FFFD) and advance only 1 byte + codePoint = 0xFFFD + bytesPerSequence = 1 + } else if (codePoint > 0xFFFF) { + // encode to utf16 (surrogate pair dance) + codePoint -= 0x10000 + res.push(codePoint >>> 10 & 0x3FF | 0xD800) + codePoint = 0xDC00 | codePoint & 0x3FF + } + + res.push(codePoint) + i += bytesPerSequence + } + + return decodeCodePointsArray(res) +} + +// Based on http://stackoverflow.com/a/22747272/680742, the browser with +// the lowest limit is Chrome, with 0x10000 args. +// We go 1 magnitude less, for safety +var MAX_ARGUMENTS_LENGTH = 0x1000 + +function decodeCodePointsArray (codePoints) { + var len = codePoints.length + if (len <= MAX_ARGUMENTS_LENGTH) { + return String.fromCharCode.apply(String, codePoints) // avoid extra slice() + } + + // Decode in chunks to avoid "call stack size exceeded". + var res = '' + var i = 0 + while (i < len) { + res += String.fromCharCode.apply( + String, + codePoints.slice(i, i += MAX_ARGUMENTS_LENGTH) + ) + } + return res +} + +function asciiSlice (buf, start, end) { + var ret = '' + end = Math.min(buf.length, end) + + for (var i = start; i < end; ++i) { + ret += String.fromCharCode(buf[i] & 0x7F) + } + return ret +} + +function latin1Slice (buf, start, end) { + var ret = '' + end = Math.min(buf.length, end) + + for (var i = start; i < end; ++i) { + ret += String.fromCharCode(buf[i]) + } + return ret +} + +function hexSlice (buf, start, end) { + var len = buf.length + + if (!start || start < 0) start = 0 + if (!end || end < 0 || end > len) end = len + + var out = '' + for (var i = start; i < end; ++i) { + out += toHex(buf[i]) + } + return out +} + +function utf16leSlice (buf, start, end) { + var bytes = buf.slice(start, end) + var res = '' + for (var i = 0; i < bytes.length; i += 2) { + res += String.fromCharCode(bytes[i] + (bytes[i + 1] * 256)) + } + return res +} + +Buffer.prototype.slice = function slice (start, end) { + var len = this.length + start = ~~start + end = end === undefined ? len : ~~end + + if (start < 0) { + start += len + if (start < 0) start = 0 + } else if (start > len) { + start = len + } + + if (end < 0) { + end += len + if (end < 0) end = 0 + } else if (end > len) { + end = len + } + + if (end < start) end = start + + var newBuf = this.subarray(start, end) + // Return an augmented `Uint8Array` instance + newBuf.__proto__ = Buffer.prototype + return newBuf +} + +/* + * Need to make sure that buffer isn't trying to write out of bounds. + */ +function checkOffset (offset, ext, length) { + if ((offset % 1) !== 0 || offset < 0) throw new RangeError('offset is not uint') + if (offset + ext > length) throw new RangeError('Trying to access beyond buffer length') +} + +Buffer.prototype.readUIntLE = function readUIntLE (offset, byteLength, noAssert) { + offset = offset >>> 0 + byteLength = byteLength >>> 0 + if (!noAssert) checkOffset(offset, byteLength, this.length) + + var val = this[offset] + var mul = 1 + var i = 0 + while (++i < byteLength && (mul *= 0x100)) { + val += this[offset + i] * mul + } + + return val +} + +Buffer.prototype.readUIntBE = function readUIntBE (offset, byteLength, noAssert) { + offset = offset >>> 0 + byteLength = byteLength >>> 0 + if (!noAssert) { + checkOffset(offset, byteLength, this.length) + } + + var val = this[offset + --byteLength] + var mul = 1 + while (byteLength > 0 && (mul *= 0x100)) { + val += this[offset + --byteLength] * mul + } + + return val +} + +Buffer.prototype.readUInt8 = function readUInt8 (offset, noAssert) { + offset = offset >>> 0 + if (!noAssert) checkOffset(offset, 1, this.length) + return this[offset] +} + +Buffer.prototype.readUInt16LE = function readUInt16LE (offset, noAssert) { + offset = offset >>> 0 + if (!noAssert) checkOffset(offset, 2, this.length) + return this[offset] | (this[offset + 1] << 8) +} + +Buffer.prototype.readUInt16BE = function readUInt16BE (offset, noAssert) { + offset = offset >>> 0 + if (!noAssert) checkOffset(offset, 2, this.length) + return (this[offset] << 8) | this[offset + 1] +} + +Buffer.prototype.readUInt32LE = function readUInt32LE (offset, noAssert) { + offset = offset >>> 0 + if (!noAssert) checkOffset(offset, 4, this.length) + + return ((this[offset]) | + (this[offset + 1] << 8) | + (this[offset + 2] << 16)) + + (this[offset + 3] * 0x1000000) +} + +Buffer.prototype.readUInt32BE = function readUInt32BE (offset, noAssert) { + offset = offset >>> 0 + if (!noAssert) checkOffset(offset, 4, this.length) + + return (this[offset] * 0x1000000) + + ((this[offset + 1] << 16) | + (this[offset + 2] << 8) | + this[offset + 3]) +} + +Buffer.prototype.readIntLE = function readIntLE (offset, byteLength, noAssert) { + offset = offset >>> 0 + byteLength = byteLength >>> 0 + if (!noAssert) checkOffset(offset, byteLength, this.length) + + var val = this[offset] + var mul = 1 + var i = 0 + while (++i < byteLength && (mul *= 0x100)) { + val += this[offset + i] * mul + } + mul *= 0x80 + + if (val >= mul) val -= Math.pow(2, 8 * byteLength) + + return val +} + +Buffer.prototype.readIntBE = function readIntBE (offset, byteLength, noAssert) { + offset = offset >>> 0 + byteLength = byteLength >>> 0 + if (!noAssert) checkOffset(offset, byteLength, this.length) + + var i = byteLength + var mul = 1 + var val = this[offset + --i] + while (i > 0 && (mul *= 0x100)) { + val += this[offset + --i] * mul + } + mul *= 0x80 + + if (val >= mul) val -= Math.pow(2, 8 * byteLength) + + return val +} + +Buffer.prototype.readInt8 = function readInt8 (offset, noAssert) { + offset = offset >>> 0 + if (!noAssert) checkOffset(offset, 1, this.length) + if (!(this[offset] & 0x80)) return (this[offset]) + return ((0xff - this[offset] + 1) * -1) +} + +Buffer.prototype.readInt16LE = function readInt16LE (offset, noAssert) { + offset = offset >>> 0 + if (!noAssert) checkOffset(offset, 2, this.length) + var val = this[offset] | (this[offset + 1] << 8) + return (val & 0x8000) ? val | 0xFFFF0000 : val +} + +Buffer.prototype.readInt16BE = function readInt16BE (offset, noAssert) { + offset = offset >>> 0 + if (!noAssert) checkOffset(offset, 2, this.length) + var val = this[offset + 1] | (this[offset] << 8) + return (val & 0x8000) ? val | 0xFFFF0000 : val +} + +Buffer.prototype.readInt32LE = function readInt32LE (offset, noAssert) { + offset = offset >>> 0 + if (!noAssert) checkOffset(offset, 4, this.length) + + return (this[offset]) | + (this[offset + 1] << 8) | + (this[offset + 2] << 16) | + (this[offset + 3] << 24) +} + +Buffer.prototype.readInt32BE = function readInt32BE (offset, noAssert) { + offset = offset >>> 0 + if (!noAssert) checkOffset(offset, 4, this.length) + + return (this[offset] << 24) | + (this[offset + 1] << 16) | + (this[offset + 2] << 8) | + (this[offset + 3]) +} + +Buffer.prototype.readFloatLE = function readFloatLE (offset, noAssert) { + offset = offset >>> 0 + if (!noAssert) checkOffset(offset, 4, this.length) + return ieee754.read(this, offset, true, 23, 4) +} + +Buffer.prototype.readFloatBE = function readFloatBE (offset, noAssert) { + offset = offset >>> 0 + if (!noAssert) checkOffset(offset, 4, this.length) + return ieee754.read(this, offset, false, 23, 4) +} + +Buffer.prototype.readDoubleLE = function readDoubleLE (offset, noAssert) { + offset = offset >>> 0 + if (!noAssert) checkOffset(offset, 8, this.length) + return ieee754.read(this, offset, true, 52, 8) +} + +Buffer.prototype.readDoubleBE = function readDoubleBE (offset, noAssert) { + offset = offset >>> 0 + if (!noAssert) checkOffset(offset, 8, this.length) + return ieee754.read(this, offset, false, 52, 8) +} + +function checkInt (buf, value, offset, ext, max, min) { + if (!Buffer.isBuffer(buf)) throw new TypeError('"buffer" argument must be a Buffer instance') + if (value > max || value < min) throw new RangeError('"value" argument is out of bounds') + if (offset + ext > buf.length) throw new RangeError('Index out of range') +} + +Buffer.prototype.writeUIntLE = function writeUIntLE (value, offset, byteLength, noAssert) { + value = +value + offset = offset >>> 0 + byteLength = byteLength >>> 0 + if (!noAssert) { + var maxBytes = Math.pow(2, 8 * byteLength) - 1 + checkInt(this, value, offset, byteLength, maxBytes, 0) + } + + var mul = 1 + var i = 0 + this[offset] = value & 0xFF + while (++i < byteLength && (mul *= 0x100)) { + this[offset + i] = (value / mul) & 0xFF + } + + return offset + byteLength +} + +Buffer.prototype.writeUIntBE = function writeUIntBE (value, offset, byteLength, noAssert) { + value = +value + offset = offset >>> 0 + byteLength = byteLength >>> 0 + if (!noAssert) { + var maxBytes = Math.pow(2, 8 * byteLength) - 1 + checkInt(this, value, offset, byteLength, maxBytes, 0) + } + + var i = byteLength - 1 + var mul = 1 + this[offset + i] = value & 0xFF + while (--i >= 0 && (mul *= 0x100)) { + this[offset + i] = (value / mul) & 0xFF + } + + return offset + byteLength +} + +Buffer.prototype.writeUInt8 = function writeUInt8 (value, offset, noAssert) { + value = +value + offset = offset >>> 0 + if (!noAssert) checkInt(this, value, offset, 1, 0xff, 0) + this[offset] = (value & 0xff) + return offset + 1 +} + +Buffer.prototype.writeUInt16LE = function writeUInt16LE (value, offset, noAssert) { + value = +value + offset = offset >>> 0 + if (!noAssert) checkInt(this, value, offset, 2, 0xffff, 0) + this[offset] = (value & 0xff) + this[offset + 1] = (value >>> 8) + return offset + 2 +} + +Buffer.prototype.writeUInt16BE = function writeUInt16BE (value, offset, noAssert) { + value = +value + offset = offset >>> 0 + if (!noAssert) checkInt(this, value, offset, 2, 0xffff, 0) + this[offset] = (value >>> 8) + this[offset + 1] = (value & 0xff) + return offset + 2 +} + +Buffer.prototype.writeUInt32LE = function writeUInt32LE (value, offset, noAssert) { + value = +value + offset = offset >>> 0 + if (!noAssert) checkInt(this, value, offset, 4, 0xffffffff, 0) + this[offset + 3] = (value >>> 24) + this[offset + 2] = (value >>> 16) + this[offset + 1] = (value >>> 8) + this[offset] = (value & 0xff) + return offset + 4 +} + +Buffer.prototype.writeUInt32BE = function writeUInt32BE (value, offset, noAssert) { + value = +value + offset = offset >>> 0 + if (!noAssert) checkInt(this, value, offset, 4, 0xffffffff, 0) + this[offset] = (value >>> 24) + this[offset + 1] = (value >>> 16) + this[offset + 2] = (value >>> 8) + this[offset + 3] = (value & 0xff) + return offset + 4 +} + +Buffer.prototype.writeIntLE = function writeIntLE (value, offset, byteLength, noAssert) { + value = +value + offset = offset >>> 0 + if (!noAssert) { + var limit = Math.pow(2, (8 * byteLength) - 1) + + checkInt(this, value, offset, byteLength, limit - 1, -limit) + } + + var i = 0 + var mul = 1 + var sub = 0 + this[offset] = value & 0xFF + while (++i < byteLength && (mul *= 0x100)) { + if (value < 0 && sub === 0 && this[offset + i - 1] !== 0) { + sub = 1 + } + this[offset + i] = ((value / mul) >> 0) - sub & 0xFF + } + + return offset + byteLength +} + +Buffer.prototype.writeIntBE = function writeIntBE (value, offset, byteLength, noAssert) { + value = +value + offset = offset >>> 0 + if (!noAssert) { + var limit = Math.pow(2, (8 * byteLength) - 1) + + checkInt(this, value, offset, byteLength, limit - 1, -limit) + } + + var i = byteLength - 1 + var mul = 1 + var sub = 0 + this[offset + i] = value & 0xFF + while (--i >= 0 && (mul *= 0x100)) { + if (value < 0 && sub === 0 && this[offset + i + 1] !== 0) { + sub = 1 + } + this[offset + i] = ((value / mul) >> 0) - sub & 0xFF + } + + return offset + byteLength +} + +Buffer.prototype.writeInt8 = function writeInt8 (value, offset, noAssert) { + value = +value + offset = offset >>> 0 + if (!noAssert) checkInt(this, value, offset, 1, 0x7f, -0x80) + if (value < 0) value = 0xff + value + 1 + this[offset] = (value & 0xff) + return offset + 1 +} + +Buffer.prototype.writeInt16LE = function writeInt16LE (value, offset, noAssert) { + value = +value + offset = offset >>> 0 + if (!noAssert) checkInt(this, value, offset, 2, 0x7fff, -0x8000) + this[offset] = (value & 0xff) + this[offset + 1] = (value >>> 8) + return offset + 2 +} + +Buffer.prototype.writeInt16BE = function writeInt16BE (value, offset, noAssert) { + value = +value + offset = offset >>> 0 + if (!noAssert) checkInt(this, value, offset, 2, 0x7fff, -0x8000) + this[offset] = (value >>> 8) + this[offset + 1] = (value & 0xff) + return offset + 2 +} + +Buffer.prototype.writeInt32LE = function writeInt32LE (value, offset, noAssert) { + value = +value + offset = offset >>> 0 + if (!noAssert) checkInt(this, value, offset, 4, 0x7fffffff, -0x80000000) + this[offset] = (value & 0xff) + this[offset + 1] = (value >>> 8) + this[offset + 2] = (value >>> 16) + this[offset + 3] = (value >>> 24) + return offset + 4 +} + +Buffer.prototype.writeInt32BE = function writeInt32BE (value, offset, noAssert) { + value = +value + offset = offset >>> 0 + if (!noAssert) checkInt(this, value, offset, 4, 0x7fffffff, -0x80000000) + if (value < 0) value = 0xffffffff + value + 1 + this[offset] = (value >>> 24) + this[offset + 1] = (value >>> 16) + this[offset + 2] = (value >>> 8) + this[offset + 3] = (value & 0xff) + return offset + 4 +} + +function checkIEEE754 (buf, value, offset, ext, max, min) { + if (offset + ext > buf.length) throw new RangeError('Index out of range') + if (offset < 0) throw new RangeError('Index out of range') +} + +function writeFloat (buf, value, offset, littleEndian, noAssert) { + value = +value + offset = offset >>> 0 + if (!noAssert) { + checkIEEE754(buf, value, offset, 4, 3.4028234663852886e+38, -3.4028234663852886e+38) + } + ieee754.write(buf, value, offset, littleEndian, 23, 4) + return offset + 4 +} + +Buffer.prototype.writeFloatLE = function writeFloatLE (value, offset, noAssert) { + return writeFloat(this, value, offset, true, noAssert) +} + +Buffer.prototype.writeFloatBE = function writeFloatBE (value, offset, noAssert) { + return writeFloat(this, value, offset, false, noAssert) +} + +function writeDouble (buf, value, offset, littleEndian, noAssert) { + value = +value + offset = offset >>> 0 + if (!noAssert) { + checkIEEE754(buf, value, offset, 8, 1.7976931348623157E+308, -1.7976931348623157E+308) + } + ieee754.write(buf, value, offset, littleEndian, 52, 8) + return offset + 8 +} + +Buffer.prototype.writeDoubleLE = function writeDoubleLE (value, offset, noAssert) { + return writeDouble(this, value, offset, true, noAssert) +} + +Buffer.prototype.writeDoubleBE = function writeDoubleBE (value, offset, noAssert) { + return writeDouble(this, value, offset, false, noAssert) +} + +// copy(targetBuffer, targetStart=0, sourceStart=0, sourceEnd=buffer.length) +Buffer.prototype.copy = function copy (target, targetStart, start, end) { + if (!Buffer.isBuffer(target)) throw new TypeError('argument should be a Buffer') + if (!start) start = 0 + if (!end && end !== 0) end = this.length + if (targetStart >= target.length) targetStart = target.length + if (!targetStart) targetStart = 0 + if (end > 0 && end < start) end = start + + // Copy 0 bytes; we're done + if (end === start) return 0 + if (target.length === 0 || this.length === 0) return 0 + + // Fatal error conditions + if (targetStart < 0) { + throw new RangeError('targetStart out of bounds') + } + if (start < 0 || start >= this.length) throw new RangeError('Index out of range') + if (end < 0) throw new RangeError('sourceEnd out of bounds') + + // Are we oob? + if (end > this.length) end = this.length + if (target.length - targetStart < end - start) { + end = target.length - targetStart + start + } + + var len = end - start + + if (this === target && typeof Uint8Array.prototype.copyWithin === 'function') { + // Use built-in when available, missing from IE11 + this.copyWithin(targetStart, start, end) + } else if (this === target && start < targetStart && targetStart < end) { + // descending copy from end + for (var i = len - 1; i >= 0; --i) { + target[i + targetStart] = this[i + start] + } + } else { + Uint8Array.prototype.set.call( + target, + this.subarray(start, end), + targetStart + ) + } + + return len +} + +// Usage: +// buffer.fill(number[, offset[, end]]) +// buffer.fill(buffer[, offset[, end]]) +// buffer.fill(string[, offset[, end]][, encoding]) +Buffer.prototype.fill = function fill (val, start, end, encoding) { + // Handle string cases: + if (typeof val === 'string') { + if (typeof start === 'string') { + encoding = start + start = 0 + end = this.length + } else if (typeof end === 'string') { + encoding = end + end = this.length + } + if (encoding !== undefined && typeof encoding !== 'string') { + throw new TypeError('encoding must be a string') + } + if (typeof encoding === 'string' && !Buffer.isEncoding(encoding)) { + throw new TypeError('Unknown encoding: ' + encoding) + } + if (val.length === 1) { + var code = val.charCodeAt(0) + if ((encoding === 'utf8' && code < 128) || + encoding === 'latin1') { + // Fast path: If `val` fits into a single byte, use that numeric value. + val = code + } + } + } else if (typeof val === 'number') { + val = val & 255 + } + + // Invalid ranges are not set to a default, so can range check early. + if (start < 0 || this.length < start || this.length < end) { + throw new RangeError('Out of range index') + } + + if (end <= start) { + return this + } + + start = start >>> 0 + end = end === undefined ? this.length : end >>> 0 + + if (!val) val = 0 + + var i + if (typeof val === 'number') { + for (i = start; i < end; ++i) { + this[i] = val + } + } else { + var bytes = Buffer.isBuffer(val) + ? val + : Buffer.from(val, encoding) + var len = bytes.length + if (len === 0) { + throw new TypeError('The value "' + val + + '" is invalid for argument "value"') + } + for (i = 0; i < end - start; ++i) { + this[i + start] = bytes[i % len] + } + } + + return this +} + +// HELPER FUNCTIONS +// ================ + +var INVALID_BASE64_RE = /[^+/0-9A-Za-z-_]/g + +function base64clean (str) { + // Node takes equal signs as end of the Base64 encoding + str = str.split('=')[0] + // Node strips out invalid characters like \n and \t from the string, base64-js does not + str = str.trim().replace(INVALID_BASE64_RE, '') + // Node converts strings with length < 2 to '' + if (str.length < 2) return '' + // Node allows for non-padded base64 strings (missing trailing ===), base64-js does not + while (str.length % 4 !== 0) { + str = str + '=' + } + return str +} + +function toHex (n) { + if (n < 16) return '0' + n.toString(16) + return n.toString(16) +} + +function utf8ToBytes (string, units) { + units = units || Infinity + var codePoint + var length = string.length + var leadSurrogate = null + var bytes = [] + + for (var i = 0; i < length; ++i) { + codePoint = string.charCodeAt(i) + + // is surrogate component + if (codePoint > 0xD7FF && codePoint < 0xE000) { + // last char was a lead + if (!leadSurrogate) { + // no lead yet + if (codePoint > 0xDBFF) { + // unexpected trail + if ((units -= 3) > -1) bytes.push(0xEF, 0xBF, 0xBD) + continue + } else if (i + 1 === length) { + // unpaired lead + if ((units -= 3) > -1) bytes.push(0xEF, 0xBF, 0xBD) + continue + } + + // valid lead + leadSurrogate = codePoint + + continue + } + + // 2 leads in a row + if (codePoint < 0xDC00) { + if ((units -= 3) > -1) bytes.push(0xEF, 0xBF, 0xBD) + leadSurrogate = codePoint + continue + } + + // valid surrogate pair + codePoint = (leadSurrogate - 0xD800 << 10 | codePoint - 0xDC00) + 0x10000 + } else if (leadSurrogate) { + // valid bmp char, but last char was a lead + if ((units -= 3) > -1) bytes.push(0xEF, 0xBF, 0xBD) + } + + leadSurrogate = null + + // encode utf8 + if (codePoint < 0x80) { + if ((units -= 1) < 0) break + bytes.push(codePoint) + } else if (codePoint < 0x800) { + if ((units -= 2) < 0) break + bytes.push( + codePoint >> 0x6 | 0xC0, + codePoint & 0x3F | 0x80 + ) + } else if (codePoint < 0x10000) { + if ((units -= 3) < 0) break + bytes.push( + codePoint >> 0xC | 0xE0, + codePoint >> 0x6 & 0x3F | 0x80, + codePoint & 0x3F | 0x80 + ) + } else if (codePoint < 0x110000) { + if ((units -= 4) < 0) break + bytes.push( + codePoint >> 0x12 | 0xF0, + codePoint >> 0xC & 0x3F | 0x80, + codePoint >> 0x6 & 0x3F | 0x80, + codePoint & 0x3F | 0x80 + ) + } else { + throw new Error('Invalid code point') + } + } + + return bytes +} + +function asciiToBytes (str) { + var byteArray = [] + for (var i = 0; i < str.length; ++i) { + // Node's code seems to be doing this and not & 0x7F.. + byteArray.push(str.charCodeAt(i) & 0xFF) + } + return byteArray +} + +function utf16leToBytes (str, units) { + var c, hi, lo + var byteArray = [] + for (var i = 0; i < str.length; ++i) { + if ((units -= 2) < 0) break + + c = str.charCodeAt(i) + hi = c >> 8 + lo = c % 256 + byteArray.push(lo) + byteArray.push(hi) + } + + return byteArray +} + +function base64ToBytes (str) { + return base64.toByteArray(base64clean(str)) +} + +function blitBuffer (src, dst, offset, length) { + for (var i = 0; i < length; ++i) { + if ((i + offset >= dst.length) || (i >= src.length)) break + dst[i + offset] = src[i] + } + return i +} + +// ArrayBuffer or Uint8Array objects from other contexts (i.e. iframes) do not pass +// the `instanceof` check but they should be treated as of that type. +// See: https://github.com/feross/buffer/issues/166 +function isInstance (obj, type) { + return obj instanceof type || + (obj != null && obj.constructor != null && obj.constructor.name != null && + obj.constructor.name === type.name) +} +function numberIsNaN (obj) { + // For IE11 support + return obj !== obj // eslint-disable-line no-self-compare +} + +}).call(this)}).call(this,require("buffer").Buffer) +},{"base64-js":16,"buffer":63,"ieee754":131}],64:[function(require,module,exports){ +var Buffer = require('safe-buffer').Buffer +var Transform = require('stream').Transform +var StringDecoder = require('string_decoder').StringDecoder +var inherits = require('inherits') + +function CipherBase (hashMode) { + Transform.call(this) + this.hashMode = typeof hashMode === 'string' + if (this.hashMode) { + this[hashMode] = this._finalOrDigest + } else { + this.final = this._finalOrDigest + } + if (this._final) { + this.__final = this._final + this._final = null + } + this._decoder = null + this._encoding = null +} +inherits(CipherBase, Transform) + +CipherBase.prototype.update = function (data, inputEnc, outputEnc) { + if (typeof data === 'string') { + data = Buffer.from(data, inputEnc) + } + + var outData = this._update(data) + if (this.hashMode) return this + + if (outputEnc) { + outData = this._toString(outData, outputEnc) + } + + return outData +} + +CipherBase.prototype.setAutoPadding = function () {} +CipherBase.prototype.getAuthTag = function () { + throw new Error('trying to get auth tag in unsupported state') +} + +CipherBase.prototype.setAuthTag = function () { + throw new Error('trying to set auth tag in unsupported state') +} + +CipherBase.prototype.setAAD = function () { + throw new Error('trying to set aad in unsupported state') +} + +CipherBase.prototype._transform = function (data, _, next) { + var err + try { + if (this.hashMode) { + this._update(data) + } else { + this.push(this._update(data)) + } + } catch (e) { + err = e + } finally { + next(err) + } +} +CipherBase.prototype._flush = function (done) { + var err + try { + this.push(this.__final()) + } catch (e) { + err = e + } + + done(err) +} +CipherBase.prototype._finalOrDigest = function (outputEnc) { + var outData = this.__final() || Buffer.alloc(0) + if (outputEnc) { + outData = this._toString(outData, outputEnc, true) + } + return outData +} + +CipherBase.prototype._toString = function (value, enc, fin) { + if (!this._decoder) { + this._decoder = new StringDecoder(enc) + this._encoding = enc + } + + if (this._encoding !== enc) throw new Error('can\'t switch encodings') + + var out = this._decoder.write(value) + if (fin) { + out += this._decoder.end() + } + + return out +} + +module.exports = CipherBase + +},{"inherits":132,"safe-buffer":160,"stream":170,"string_decoder":185}],65:[function(require,module,exports){ +(function (Buffer){(function (){ +var elliptic = require('elliptic') +var BN = require('bn.js') + +module.exports = function createECDH (curve) { + return new ECDH(curve) +} + +var aliases = { + secp256k1: { + name: 'secp256k1', + byteLength: 32 + }, + secp224r1: { + name: 'p224', + byteLength: 28 + }, + prime256v1: { + name: 'p256', + byteLength: 32 + }, + prime192v1: { + name: 'p192', + byteLength: 24 + }, + ed25519: { + name: 'ed25519', + byteLength: 32 + }, + secp384r1: { + name: 'p384', + byteLength: 48 + }, + secp521r1: { + name: 'p521', + byteLength: 66 + } +} + +aliases.p224 = aliases.secp224r1 +aliases.p256 = aliases.secp256r1 = aliases.prime256v1 +aliases.p192 = aliases.secp192r1 = aliases.prime192v1 +aliases.p384 = aliases.secp384r1 +aliases.p521 = aliases.secp521r1 + +function ECDH (curve) { + this.curveType = aliases[curve] + if (!this.curveType) { + this.curveType = { + name: curve + } + } + this.curve = new elliptic.ec(this.curveType.name) // eslint-disable-line new-cap + this.keys = void 0 +} + +ECDH.prototype.generateKeys = function (enc, format) { + this.keys = this.curve.genKeyPair() + return this.getPublicKey(enc, format) +} + +ECDH.prototype.computeSecret = function (other, inenc, enc) { + inenc = inenc || 'utf8' + if (!Buffer.isBuffer(other)) { + other = new Buffer(other, inenc) + } + var otherPub = this.curve.keyFromPublic(other).getPublic() + var out = otherPub.mul(this.keys.getPrivate()).getX() + return formatReturnValue(out, enc, this.curveType.byteLength) +} + +ECDH.prototype.getPublicKey = function (enc, format) { + var key = this.keys.getPublic(format === 'compressed', true) + if (format === 'hybrid') { + if (key[key.length - 1] % 2) { + key[0] = 7 + } else { + key[0] = 6 + } + } + return formatReturnValue(key, enc) +} + +ECDH.prototype.getPrivateKey = function (enc) { + return formatReturnValue(this.keys.getPrivate(), enc) +} + +ECDH.prototype.setPublicKey = function (pub, enc) { + enc = enc || 'utf8' + if (!Buffer.isBuffer(pub)) { + pub = new Buffer(pub, enc) + } + this.keys._importPublic(pub) + return this +} + +ECDH.prototype.setPrivateKey = function (priv, enc) { + enc = enc || 'utf8' + if (!Buffer.isBuffer(priv)) { + priv = new Buffer(priv, enc) + } + + var _priv = new BN(priv) + _priv = _priv.toString(16) + this.keys = this.curve.genKeyPair() + this.keys._importPrivate(_priv) + return this +} + +function formatReturnValue (bn, enc, len) { + if (!Array.isArray(bn)) { + bn = bn.toArray() + } + var buf = new Buffer(bn) + if (len && buf.length < len) { + var zeros = new Buffer(len - buf.length) + zeros.fill(0) + buf = Buffer.concat([zeros, buf]) + } + if (!enc) { + return buf + } else { + return buf.toString(enc) + } +} + +}).call(this)}).call(this,require("buffer").Buffer) +},{"bn.js":66,"buffer":63,"elliptic":83}],66:[function(require,module,exports){ +arguments[4][15][0].apply(exports,arguments) +},{"buffer":19,"dup":15}],67:[function(require,module,exports){ +'use strict' +var inherits = require('inherits') +var MD5 = require('md5.js') +var RIPEMD160 = require('ripemd160') +var sha = require('sha.js') +var Base = require('cipher-base') + +function Hash (hash) { + Base.call(this, 'digest') + + this._hash = hash +} + +inherits(Hash, Base) + +Hash.prototype._update = function (data) { + this._hash.update(data) +} + +Hash.prototype._final = function () { + return this._hash.digest() +} + +module.exports = function createHash (alg) { + alg = alg.toLowerCase() + if (alg === 'md5') return new MD5() + if (alg === 'rmd160' || alg === 'ripemd160') return new RIPEMD160() + + return new Hash(sha(alg)) +} + +},{"cipher-base":64,"inherits":132,"md5.js":133,"ripemd160":159,"sha.js":163}],68:[function(require,module,exports){ +var MD5 = require('md5.js') + +module.exports = function (buffer) { + return new MD5().update(buffer).digest() +} + +},{"md5.js":133}],69:[function(require,module,exports){ +'use strict' +var inherits = require('inherits') +var Legacy = require('./legacy') +var Base = require('cipher-base') +var Buffer = require('safe-buffer').Buffer +var md5 = require('create-hash/md5') +var RIPEMD160 = require('ripemd160') + +var sha = require('sha.js') + +var ZEROS = Buffer.alloc(128) + +function Hmac (alg, key) { + Base.call(this, 'digest') + if (typeof key === 'string') { + key = Buffer.from(key) + } + + var blocksize = (alg === 'sha512' || alg === 'sha384') ? 128 : 64 + + this._alg = alg + this._key = key + if (key.length > blocksize) { + var hash = alg === 'rmd160' ? new RIPEMD160() : sha(alg) + key = hash.update(key).digest() + } else if (key.length < blocksize) { + key = Buffer.concat([key, ZEROS], blocksize) + } + + var ipad = this._ipad = Buffer.allocUnsafe(blocksize) + var opad = this._opad = Buffer.allocUnsafe(blocksize) + + for (var i = 0; i < blocksize; i++) { + ipad[i] = key[i] ^ 0x36 + opad[i] = key[i] ^ 0x5C + } + this._hash = alg === 'rmd160' ? new RIPEMD160() : sha(alg) + this._hash.update(ipad) +} + +inherits(Hmac, Base) + +Hmac.prototype._update = function (data) { + this._hash.update(data) +} + +Hmac.prototype._final = function () { + var h = this._hash.digest() + var hash = this._alg === 'rmd160' ? new RIPEMD160() : sha(this._alg) + return hash.update(this._opad).update(h).digest() +} + +module.exports = function createHmac (alg, key) { + alg = alg.toLowerCase() + if (alg === 'rmd160' || alg === 'ripemd160') { + return new Hmac('rmd160', key) + } + if (alg === 'md5') { + return new Legacy(md5, key) + } + return new Hmac(alg, key) +} + +},{"./legacy":70,"cipher-base":64,"create-hash/md5":68,"inherits":132,"ripemd160":159,"safe-buffer":160,"sha.js":163}],70:[function(require,module,exports){ +'use strict' +var inherits = require('inherits') +var Buffer = require('safe-buffer').Buffer + +var Base = require('cipher-base') + +var ZEROS = Buffer.alloc(128) +var blocksize = 64 + +function Hmac (alg, key) { + Base.call(this, 'digest') + if (typeof key === 'string') { + key = Buffer.from(key) + } + + this._alg = alg + this._key = key + + if (key.length > blocksize) { + key = alg(key) + } else if (key.length < blocksize) { + key = Buffer.concat([key, ZEROS], blocksize) + } + + var ipad = this._ipad = Buffer.allocUnsafe(blocksize) + var opad = this._opad = Buffer.allocUnsafe(blocksize) + + for (var i = 0; i < blocksize; i++) { + ipad[i] = key[i] ^ 0x36 + opad[i] = key[i] ^ 0x5C + } + + this._hash = [ipad] +} + +inherits(Hmac, Base) + +Hmac.prototype._update = function (data) { + this._hash.push(data) +} + +Hmac.prototype._final = function () { + var h = this._alg(Buffer.concat(this._hash)) + return this._alg(Buffer.concat([this._opad, h])) +} +module.exports = Hmac + +},{"cipher-base":64,"inherits":132,"safe-buffer":160}],71:[function(require,module,exports){ +'use strict' + +exports.randomBytes = exports.rng = exports.pseudoRandomBytes = exports.prng = require('randombytes') +exports.createHash = exports.Hash = require('create-hash') +exports.createHmac = exports.Hmac = require('create-hmac') + +var algos = require('browserify-sign/algos') +var algoKeys = Object.keys(algos) +var hashes = ['sha1', 'sha224', 'sha256', 'sha384', 'sha512', 'md5', 'rmd160'].concat(algoKeys) +exports.getHashes = function () { + return hashes +} + +var p = require('pbkdf2') +exports.pbkdf2 = p.pbkdf2 +exports.pbkdf2Sync = p.pbkdf2Sync + +var aes = require('browserify-cipher') + +exports.Cipher = aes.Cipher +exports.createCipher = aes.createCipher +exports.Cipheriv = aes.Cipheriv +exports.createCipheriv = aes.createCipheriv +exports.Decipher = aes.Decipher +exports.createDecipher = aes.createDecipher +exports.Decipheriv = aes.Decipheriv +exports.createDecipheriv = aes.createDecipheriv +exports.getCiphers = aes.getCiphers +exports.listCiphers = aes.listCiphers + +var dh = require('diffie-hellman') + +exports.DiffieHellmanGroup = dh.DiffieHellmanGroup +exports.createDiffieHellmanGroup = dh.createDiffieHellmanGroup +exports.getDiffieHellman = dh.getDiffieHellman +exports.createDiffieHellman = dh.createDiffieHellman +exports.DiffieHellman = dh.DiffieHellman + +var sign = require('browserify-sign') + +exports.createSign = sign.createSign +exports.Sign = sign.Sign +exports.createVerify = sign.createVerify +exports.Verify = sign.Verify + +exports.createECDH = require('create-ecdh') + +var publicEncrypt = require('public-encrypt') + +exports.publicEncrypt = publicEncrypt.publicEncrypt +exports.privateEncrypt = publicEncrypt.privateEncrypt +exports.publicDecrypt = publicEncrypt.publicDecrypt +exports.privateDecrypt = publicEncrypt.privateDecrypt + +// the least I can do is make error messages for the rest of the node.js/crypto api. +// ;[ +// 'createCredentials' +// ].forEach(function (name) { +// exports[name] = function () { +// throw new Error([ +// 'sorry, ' + name + ' is not implemented yet', +// 'we accept pull requests', +// 'https://github.com/crypto-browserify/crypto-browserify' +// ].join('\n')) +// } +// }) + +var rf = require('randomfill') + +exports.randomFill = rf.randomFill +exports.randomFillSync = rf.randomFillSync + +exports.createCredentials = function () { + throw new Error([ + 'sorry, createCredentials is not implemented yet', + 'we accept pull requests', + 'https://github.com/crypto-browserify/crypto-browserify' + ].join('\n')) +} + +exports.constants = { + 'DH_CHECK_P_NOT_SAFE_PRIME': 2, + 'DH_CHECK_P_NOT_PRIME': 1, + 'DH_UNABLE_TO_CHECK_GENERATOR': 4, + 'DH_NOT_SUITABLE_GENERATOR': 8, + 'NPN_ENABLED': 1, + 'ALPN_ENABLED': 1, + 'RSA_PKCS1_PADDING': 1, + 'RSA_SSLV23_PADDING': 2, + 'RSA_NO_PADDING': 3, + 'RSA_PKCS1_OAEP_PADDING': 4, + 'RSA_X931_PADDING': 5, + 'RSA_PKCS1_PSS_PADDING': 6, + 'POINT_CONVERSION_COMPRESSED': 2, + 'POINT_CONVERSION_UNCOMPRESSED': 4, + 'POINT_CONVERSION_HYBRID': 6 +} + +},{"browserify-cipher":37,"browserify-sign":44,"browserify-sign/algos":41,"create-ecdh":65,"create-hash":67,"create-hmac":69,"diffie-hellman":78,"pbkdf2":143,"public-encrypt":150,"randombytes":157,"randomfill":158}],72:[function(require,module,exports){ +'use strict'; + +exports.utils = require('./des/utils'); +exports.Cipher = require('./des/cipher'); +exports.DES = require('./des/des'); +exports.CBC = require('./des/cbc'); +exports.EDE = require('./des/ede'); + +},{"./des/cbc":73,"./des/cipher":74,"./des/des":75,"./des/ede":76,"./des/utils":77}],73:[function(require,module,exports){ +'use strict'; + +var assert = require('minimalistic-assert'); +var inherits = require('inherits'); + +var proto = {}; + +function CBCState(iv) { + assert.equal(iv.length, 8, 'Invalid IV length'); + + this.iv = new Array(8); + for (var i = 0; i < this.iv.length; i++) + this.iv[i] = iv[i]; +} + +function instantiate(Base) { + function CBC(options) { + Base.call(this, options); + this._cbcInit(); + } + inherits(CBC, Base); + + var keys = Object.keys(proto); + for (var i = 0; i < keys.length; i++) { + var key = keys[i]; + CBC.prototype[key] = proto[key]; + } + + CBC.create = function create(options) { + return new CBC(options); + }; + + return CBC; +} + +exports.instantiate = instantiate; + +proto._cbcInit = function _cbcInit() { + var state = new CBCState(this.options.iv); + this._cbcState = state; +}; + +proto._update = function _update(inp, inOff, out, outOff) { + var state = this._cbcState; + var superProto = this.constructor.super_.prototype; + + var iv = state.iv; + if (this.type === 'encrypt') { + for (var i = 0; i < this.blockSize; i++) + iv[i] ^= inp[inOff + i]; + + superProto._update.call(this, iv, 0, out, outOff); + + for (var i = 0; i < this.blockSize; i++) + iv[i] = out[outOff + i]; + } else { + superProto._update.call(this, inp, inOff, out, outOff); + + for (var i = 0; i < this.blockSize; i++) + out[outOff + i] ^= iv[i]; + + for (var i = 0; i < this.blockSize; i++) + iv[i] = inp[inOff + i]; + } +}; + +},{"inherits":132,"minimalistic-assert":136}],74:[function(require,module,exports){ +'use strict'; + +var assert = require('minimalistic-assert'); + +function Cipher(options) { + this.options = options; + + this.type = this.options.type; + this.blockSize = 8; + this._init(); + + this.buffer = new Array(this.blockSize); + this.bufferOff = 0; +} +module.exports = Cipher; + +Cipher.prototype._init = function _init() { + // Might be overrided +}; + +Cipher.prototype.update = function update(data) { + if (data.length === 0) + return []; + + if (this.type === 'decrypt') + return this._updateDecrypt(data); + else + return this._updateEncrypt(data); +}; + +Cipher.prototype._buffer = function _buffer(data, off) { + // Append data to buffer + var min = Math.min(this.buffer.length - this.bufferOff, data.length - off); + for (var i = 0; i < min; i++) + this.buffer[this.bufferOff + i] = data[off + i]; + this.bufferOff += min; + + // Shift next + return min; +}; + +Cipher.prototype._flushBuffer = function _flushBuffer(out, off) { + this._update(this.buffer, 0, out, off); + this.bufferOff = 0; + return this.blockSize; +}; + +Cipher.prototype._updateEncrypt = function _updateEncrypt(data) { + var inputOff = 0; + var outputOff = 0; + + var count = ((this.bufferOff + data.length) / this.blockSize) | 0; + var out = new Array(count * this.blockSize); + + if (this.bufferOff !== 0) { + inputOff += this._buffer(data, inputOff); + + if (this.bufferOff === this.buffer.length) + outputOff += this._flushBuffer(out, outputOff); + } + + // Write blocks + var max = data.length - ((data.length - inputOff) % this.blockSize); + for (; inputOff < max; inputOff += this.blockSize) { + this._update(data, inputOff, out, outputOff); + outputOff += this.blockSize; + } + + // Queue rest + for (; inputOff < data.length; inputOff++, this.bufferOff++) + this.buffer[this.bufferOff] = data[inputOff]; + + return out; +}; + +Cipher.prototype._updateDecrypt = function _updateDecrypt(data) { + var inputOff = 0; + var outputOff = 0; + + var count = Math.ceil((this.bufferOff + data.length) / this.blockSize) - 1; + var out = new Array(count * this.blockSize); + + // TODO(indutny): optimize it, this is far from optimal + for (; count > 0; count--) { + inputOff += this._buffer(data, inputOff); + outputOff += this._flushBuffer(out, outputOff); + } + + // Buffer rest of the input + inputOff += this._buffer(data, inputOff); + + return out; +}; + +Cipher.prototype.final = function final(buffer) { + var first; + if (buffer) + first = this.update(buffer); + + var last; + if (this.type === 'encrypt') + last = this._finalEncrypt(); + else + last = this._finalDecrypt(); + + if (first) + return first.concat(last); + else + return last; +}; + +Cipher.prototype._pad = function _pad(buffer, off) { + if (off === 0) + return false; + + while (off < buffer.length) + buffer[off++] = 0; + + return true; +}; + +Cipher.prototype._finalEncrypt = function _finalEncrypt() { + if (!this._pad(this.buffer, this.bufferOff)) + return []; + + var out = new Array(this.blockSize); + this._update(this.buffer, 0, out, 0); + return out; +}; + +Cipher.prototype._unpad = function _unpad(buffer) { + return buffer; +}; + +Cipher.prototype._finalDecrypt = function _finalDecrypt() { + assert.equal(this.bufferOff, this.blockSize, 'Not enough data to decrypt'); + var out = new Array(this.blockSize); + this._flushBuffer(out, 0); + + return this._unpad(out); +}; + +},{"minimalistic-assert":136}],75:[function(require,module,exports){ +'use strict'; + +var assert = require('minimalistic-assert'); +var inherits = require('inherits'); + +var utils = require('./utils'); +var Cipher = require('./cipher'); + +function DESState() { + this.tmp = new Array(2); + this.keys = null; +} + +function DES(options) { + Cipher.call(this, options); + + var state = new DESState(); + this._desState = state; + + this.deriveKeys(state, options.key); +} +inherits(DES, Cipher); +module.exports = DES; + +DES.create = function create(options) { + return new DES(options); +}; + +var shiftTable = [ + 1, 1, 2, 2, 2, 2, 2, 2, + 1, 2, 2, 2, 2, 2, 2, 1 +]; + +DES.prototype.deriveKeys = function deriveKeys(state, key) { + state.keys = new Array(16 * 2); + + assert.equal(key.length, this.blockSize, 'Invalid key length'); + + var kL = utils.readUInt32BE(key, 0); + var kR = utils.readUInt32BE(key, 4); + + utils.pc1(kL, kR, state.tmp, 0); + kL = state.tmp[0]; + kR = state.tmp[1]; + for (var i = 0; i < state.keys.length; i += 2) { + var shift = shiftTable[i >>> 1]; + kL = utils.r28shl(kL, shift); + kR = utils.r28shl(kR, shift); + utils.pc2(kL, kR, state.keys, i); + } +}; + +DES.prototype._update = function _update(inp, inOff, out, outOff) { + var state = this._desState; + + var l = utils.readUInt32BE(inp, inOff); + var r = utils.readUInt32BE(inp, inOff + 4); + + // Initial Permutation + utils.ip(l, r, state.tmp, 0); + l = state.tmp[0]; + r = state.tmp[1]; + + if (this.type === 'encrypt') + this._encrypt(state, l, r, state.tmp, 0); + else + this._decrypt(state, l, r, state.tmp, 0); + + l = state.tmp[0]; + r = state.tmp[1]; + + utils.writeUInt32BE(out, l, outOff); + utils.writeUInt32BE(out, r, outOff + 4); +}; + +DES.prototype._pad = function _pad(buffer, off) { + var value = buffer.length - off; + for (var i = off; i < buffer.length; i++) + buffer[i] = value; + + return true; +}; + +DES.prototype._unpad = function _unpad(buffer) { + var pad = buffer[buffer.length - 1]; + for (var i = buffer.length - pad; i < buffer.length; i++) + assert.equal(buffer[i], pad); + + return buffer.slice(0, buffer.length - pad); +}; + +DES.prototype._encrypt = function _encrypt(state, lStart, rStart, out, off) { + var l = lStart; + var r = rStart; + + // Apply f() x16 times + for (var i = 0; i < state.keys.length; i += 2) { + var keyL = state.keys[i]; + var keyR = state.keys[i + 1]; + + // f(r, k) + utils.expand(r, state.tmp, 0); + + keyL ^= state.tmp[0]; + keyR ^= state.tmp[1]; + var s = utils.substitute(keyL, keyR); + var f = utils.permute(s); + + var t = r; + r = (l ^ f) >>> 0; + l = t; + } + + // Reverse Initial Permutation + utils.rip(r, l, out, off); +}; + +DES.prototype._decrypt = function _decrypt(state, lStart, rStart, out, off) { + var l = rStart; + var r = lStart; + + // Apply f() x16 times + for (var i = state.keys.length - 2; i >= 0; i -= 2) { + var keyL = state.keys[i]; + var keyR = state.keys[i + 1]; + + // f(r, k) + utils.expand(l, state.tmp, 0); + + keyL ^= state.tmp[0]; + keyR ^= state.tmp[1]; + var s = utils.substitute(keyL, keyR); + var f = utils.permute(s); + + var t = l; + l = (r ^ f) >>> 0; + r = t; + } + + // Reverse Initial Permutation + utils.rip(l, r, out, off); +}; + +},{"./cipher":74,"./utils":77,"inherits":132,"minimalistic-assert":136}],76:[function(require,module,exports){ +'use strict'; + +var assert = require('minimalistic-assert'); +var inherits = require('inherits'); + +var Cipher = require('./cipher'); +var DES = require('./des'); + +function EDEState(type, key) { + assert.equal(key.length, 24, 'Invalid key length'); + + var k1 = key.slice(0, 8); + var k2 = key.slice(8, 16); + var k3 = key.slice(16, 24); + + if (type === 'encrypt') { + this.ciphers = [ + DES.create({ type: 'encrypt', key: k1 }), + DES.create({ type: 'decrypt', key: k2 }), + DES.create({ type: 'encrypt', key: k3 }) + ]; + } else { + this.ciphers = [ + DES.create({ type: 'decrypt', key: k3 }), + DES.create({ type: 'encrypt', key: k2 }), + DES.create({ type: 'decrypt', key: k1 }) + ]; + } +} + +function EDE(options) { + Cipher.call(this, options); + + var state = new EDEState(this.type, this.options.key); + this._edeState = state; +} +inherits(EDE, Cipher); + +module.exports = EDE; + +EDE.create = function create(options) { + return new EDE(options); +}; + +EDE.prototype._update = function _update(inp, inOff, out, outOff) { + var state = this._edeState; + + state.ciphers[0]._update(inp, inOff, out, outOff); + state.ciphers[1]._update(out, outOff, out, outOff); + state.ciphers[2]._update(out, outOff, out, outOff); +}; + +EDE.prototype._pad = DES.prototype._pad; +EDE.prototype._unpad = DES.prototype._unpad; + +},{"./cipher":74,"./des":75,"inherits":132,"minimalistic-assert":136}],77:[function(require,module,exports){ +'use strict'; + +exports.readUInt32BE = function readUInt32BE(bytes, off) { + var res = (bytes[0 + off] << 24) | + (bytes[1 + off] << 16) | + (bytes[2 + off] << 8) | + bytes[3 + off]; + return res >>> 0; +}; + +exports.writeUInt32BE = function writeUInt32BE(bytes, value, off) { + bytes[0 + off] = value >>> 24; + bytes[1 + off] = (value >>> 16) & 0xff; + bytes[2 + off] = (value >>> 8) & 0xff; + bytes[3 + off] = value & 0xff; +}; + +exports.ip = function ip(inL, inR, out, off) { + var outL = 0; + var outR = 0; + + for (var i = 6; i >= 0; i -= 2) { + for (var j = 0; j <= 24; j += 8) { + outL <<= 1; + outL |= (inR >>> (j + i)) & 1; + } + for (var j = 0; j <= 24; j += 8) { + outL <<= 1; + outL |= (inL >>> (j + i)) & 1; + } + } + + for (var i = 6; i >= 0; i -= 2) { + for (var j = 1; j <= 25; j += 8) { + outR <<= 1; + outR |= (inR >>> (j + i)) & 1; + } + for (var j = 1; j <= 25; j += 8) { + outR <<= 1; + outR |= (inL >>> (j + i)) & 1; + } + } + + out[off + 0] = outL >>> 0; + out[off + 1] = outR >>> 0; +}; + +exports.rip = function rip(inL, inR, out, off) { + var outL = 0; + var outR = 0; + + for (var i = 0; i < 4; i++) { + for (var j = 24; j >= 0; j -= 8) { + outL <<= 1; + outL |= (inR >>> (j + i)) & 1; + outL <<= 1; + outL |= (inL >>> (j + i)) & 1; + } + } + for (var i = 4; i < 8; i++) { + for (var j = 24; j >= 0; j -= 8) { + outR <<= 1; + outR |= (inR >>> (j + i)) & 1; + outR <<= 1; + outR |= (inL >>> (j + i)) & 1; + } + } + + out[off + 0] = outL >>> 0; + out[off + 1] = outR >>> 0; +}; + +exports.pc1 = function pc1(inL, inR, out, off) { + var outL = 0; + var outR = 0; + + // 7, 15, 23, 31, 39, 47, 55, 63 + // 6, 14, 22, 30, 39, 47, 55, 63 + // 5, 13, 21, 29, 39, 47, 55, 63 + // 4, 12, 20, 28 + for (var i = 7; i >= 5; i--) { + for (var j = 0; j <= 24; j += 8) { + outL <<= 1; + outL |= (inR >> (j + i)) & 1; + } + for (var j = 0; j <= 24; j += 8) { + outL <<= 1; + outL |= (inL >> (j + i)) & 1; + } + } + for (var j = 0; j <= 24; j += 8) { + outL <<= 1; + outL |= (inR >> (j + i)) & 1; + } + + // 1, 9, 17, 25, 33, 41, 49, 57 + // 2, 10, 18, 26, 34, 42, 50, 58 + // 3, 11, 19, 27, 35, 43, 51, 59 + // 36, 44, 52, 60 + for (var i = 1; i <= 3; i++) { + for (var j = 0; j <= 24; j += 8) { + outR <<= 1; + outR |= (inR >> (j + i)) & 1; + } + for (var j = 0; j <= 24; j += 8) { + outR <<= 1; + outR |= (inL >> (j + i)) & 1; + } + } + for (var j = 0; j <= 24; j += 8) { + outR <<= 1; + outR |= (inL >> (j + i)) & 1; + } + + out[off + 0] = outL >>> 0; + out[off + 1] = outR >>> 0; +}; + +exports.r28shl = function r28shl(num, shift) { + return ((num << shift) & 0xfffffff) | (num >>> (28 - shift)); +}; + +var pc2table = [ + // inL => outL + 14, 11, 17, 4, 27, 23, 25, 0, + 13, 22, 7, 18, 5, 9, 16, 24, + 2, 20, 12, 21, 1, 8, 15, 26, + + // inR => outR + 15, 4, 25, 19, 9, 1, 26, 16, + 5, 11, 23, 8, 12, 7, 17, 0, + 22, 3, 10, 14, 6, 20, 27, 24 +]; + +exports.pc2 = function pc2(inL, inR, out, off) { + var outL = 0; + var outR = 0; + + var len = pc2table.length >>> 1; + for (var i = 0; i < len; i++) { + outL <<= 1; + outL |= (inL >>> pc2table[i]) & 0x1; + } + for (var i = len; i < pc2table.length; i++) { + outR <<= 1; + outR |= (inR >>> pc2table[i]) & 0x1; + } + + out[off + 0] = outL >>> 0; + out[off + 1] = outR >>> 0; +}; + +exports.expand = function expand(r, out, off) { + var outL = 0; + var outR = 0; + + outL = ((r & 1) << 5) | (r >>> 27); + for (var i = 23; i >= 15; i -= 4) { + outL <<= 6; + outL |= (r >>> i) & 0x3f; + } + for (var i = 11; i >= 3; i -= 4) { + outR |= (r >>> i) & 0x3f; + outR <<= 6; + } + outR |= ((r & 0x1f) << 1) | (r >>> 31); + + out[off + 0] = outL >>> 0; + out[off + 1] = outR >>> 0; +}; + +var sTable = [ + 14, 0, 4, 15, 13, 7, 1, 4, 2, 14, 15, 2, 11, 13, 8, 1, + 3, 10, 10, 6, 6, 12, 12, 11, 5, 9, 9, 5, 0, 3, 7, 8, + 4, 15, 1, 12, 14, 8, 8, 2, 13, 4, 6, 9, 2, 1, 11, 7, + 15, 5, 12, 11, 9, 3, 7, 14, 3, 10, 10, 0, 5, 6, 0, 13, + + 15, 3, 1, 13, 8, 4, 14, 7, 6, 15, 11, 2, 3, 8, 4, 14, + 9, 12, 7, 0, 2, 1, 13, 10, 12, 6, 0, 9, 5, 11, 10, 5, + 0, 13, 14, 8, 7, 10, 11, 1, 10, 3, 4, 15, 13, 4, 1, 2, + 5, 11, 8, 6, 12, 7, 6, 12, 9, 0, 3, 5, 2, 14, 15, 9, + + 10, 13, 0, 7, 9, 0, 14, 9, 6, 3, 3, 4, 15, 6, 5, 10, + 1, 2, 13, 8, 12, 5, 7, 14, 11, 12, 4, 11, 2, 15, 8, 1, + 13, 1, 6, 10, 4, 13, 9, 0, 8, 6, 15, 9, 3, 8, 0, 7, + 11, 4, 1, 15, 2, 14, 12, 3, 5, 11, 10, 5, 14, 2, 7, 12, + + 7, 13, 13, 8, 14, 11, 3, 5, 0, 6, 6, 15, 9, 0, 10, 3, + 1, 4, 2, 7, 8, 2, 5, 12, 11, 1, 12, 10, 4, 14, 15, 9, + 10, 3, 6, 15, 9, 0, 0, 6, 12, 10, 11, 1, 7, 13, 13, 8, + 15, 9, 1, 4, 3, 5, 14, 11, 5, 12, 2, 7, 8, 2, 4, 14, + + 2, 14, 12, 11, 4, 2, 1, 12, 7, 4, 10, 7, 11, 13, 6, 1, + 8, 5, 5, 0, 3, 15, 15, 10, 13, 3, 0, 9, 14, 8, 9, 6, + 4, 11, 2, 8, 1, 12, 11, 7, 10, 1, 13, 14, 7, 2, 8, 13, + 15, 6, 9, 15, 12, 0, 5, 9, 6, 10, 3, 4, 0, 5, 14, 3, + + 12, 10, 1, 15, 10, 4, 15, 2, 9, 7, 2, 12, 6, 9, 8, 5, + 0, 6, 13, 1, 3, 13, 4, 14, 14, 0, 7, 11, 5, 3, 11, 8, + 9, 4, 14, 3, 15, 2, 5, 12, 2, 9, 8, 5, 12, 15, 3, 10, + 7, 11, 0, 14, 4, 1, 10, 7, 1, 6, 13, 0, 11, 8, 6, 13, + + 4, 13, 11, 0, 2, 11, 14, 7, 15, 4, 0, 9, 8, 1, 13, 10, + 3, 14, 12, 3, 9, 5, 7, 12, 5, 2, 10, 15, 6, 8, 1, 6, + 1, 6, 4, 11, 11, 13, 13, 8, 12, 1, 3, 4, 7, 10, 14, 7, + 10, 9, 15, 5, 6, 0, 8, 15, 0, 14, 5, 2, 9, 3, 2, 12, + + 13, 1, 2, 15, 8, 13, 4, 8, 6, 10, 15, 3, 11, 7, 1, 4, + 10, 12, 9, 5, 3, 6, 14, 11, 5, 0, 0, 14, 12, 9, 7, 2, + 7, 2, 11, 1, 4, 14, 1, 7, 9, 4, 12, 10, 14, 8, 2, 13, + 0, 15, 6, 12, 10, 9, 13, 0, 15, 3, 3, 5, 5, 6, 8, 11 +]; + +exports.substitute = function substitute(inL, inR) { + var out = 0; + for (var i = 0; i < 4; i++) { + var b = (inL >>> (18 - i * 6)) & 0x3f; + var sb = sTable[i * 0x40 + b]; + + out <<= 4; + out |= sb; + } + for (var i = 0; i < 4; i++) { + var b = (inR >>> (18 - i * 6)) & 0x3f; + var sb = sTable[4 * 0x40 + i * 0x40 + b]; + + out <<= 4; + out |= sb; + } + return out >>> 0; +}; + +var permuteTable = [ + 16, 25, 12, 11, 3, 20, 4, 15, 31, 17, 9, 6, 27, 14, 1, 22, + 30, 24, 8, 18, 0, 5, 29, 23, 13, 19, 2, 26, 10, 21, 28, 7 +]; + +exports.permute = function permute(num) { + var out = 0; + for (var i = 0; i < permuteTable.length; i++) { + out <<= 1; + out |= (num >>> permuteTable[i]) & 0x1; + } + return out >>> 0; +}; + +exports.padSplit = function padSplit(num, size, group) { + var str = num.toString(2); + while (str.length < size) + str = '0' + str; + + var out = []; + for (var i = 0; i < size; i += group) + out.push(str.slice(i, i + group)); + return out.join(' '); +}; + +},{}],78:[function(require,module,exports){ +(function (Buffer){(function (){ +var generatePrime = require('./lib/generatePrime') +var primes = require('./lib/primes.json') + +var DH = require('./lib/dh') + +function getDiffieHellman (mod) { + var prime = new Buffer(primes[mod].prime, 'hex') + var gen = new Buffer(primes[mod].gen, 'hex') + + return new DH(prime, gen) +} + +var ENCODINGS = { + 'binary': true, 'hex': true, 'base64': true +} + +function createDiffieHellman (prime, enc, generator, genc) { + if (Buffer.isBuffer(enc) || ENCODINGS[enc] === undefined) { + return createDiffieHellman(prime, 'binary', enc, generator) + } + + enc = enc || 'binary' + genc = genc || 'binary' + generator = generator || new Buffer([2]) + + if (!Buffer.isBuffer(generator)) { + generator = new Buffer(generator, genc) + } + + if (typeof prime === 'number') { + return new DH(generatePrime(prime, generator), generator, true) + } + + if (!Buffer.isBuffer(prime)) { + prime = new Buffer(prime, enc) + } + + return new DH(prime, generator, true) +} + +exports.DiffieHellmanGroup = exports.createDiffieHellmanGroup = exports.getDiffieHellman = getDiffieHellman +exports.createDiffieHellman = exports.DiffieHellman = createDiffieHellman + +}).call(this)}).call(this,require("buffer").Buffer) +},{"./lib/dh":79,"./lib/generatePrime":80,"./lib/primes.json":81,"buffer":63}],79:[function(require,module,exports){ +(function (Buffer){(function (){ +var BN = require('bn.js'); +var MillerRabin = require('miller-rabin'); +var millerRabin = new MillerRabin(); +var TWENTYFOUR = new BN(24); +var ELEVEN = new BN(11); +var TEN = new BN(10); +var THREE = new BN(3); +var SEVEN = new BN(7); +var primes = require('./generatePrime'); +var randomBytes = require('randombytes'); +module.exports = DH; + +function setPublicKey(pub, enc) { + enc = enc || 'utf8'; + if (!Buffer.isBuffer(pub)) { + pub = new Buffer(pub, enc); + } + this._pub = new BN(pub); + return this; +} + +function setPrivateKey(priv, enc) { + enc = enc || 'utf8'; + if (!Buffer.isBuffer(priv)) { + priv = new Buffer(priv, enc); + } + this._priv = new BN(priv); + return this; +} + +var primeCache = {}; +function checkPrime(prime, generator) { + var gen = generator.toString('hex'); + var hex = [gen, prime.toString(16)].join('_'); + if (hex in primeCache) { + return primeCache[hex]; + } + var error = 0; + + if (prime.isEven() || + !primes.simpleSieve || + !primes.fermatTest(prime) || + !millerRabin.test(prime)) { + //not a prime so +1 + error += 1; + + if (gen === '02' || gen === '05') { + // we'd be able to check the generator + // it would fail so +8 + error += 8; + } else { + //we wouldn't be able to test the generator + // so +4 + error += 4; + } + primeCache[hex] = error; + return error; + } + if (!millerRabin.test(prime.shrn(1))) { + //not a safe prime + error += 2; + } + var rem; + switch (gen) { + case '02': + if (prime.mod(TWENTYFOUR).cmp(ELEVEN)) { + // unsuidable generator + error += 8; + } + break; + case '05': + rem = prime.mod(TEN); + if (rem.cmp(THREE) && rem.cmp(SEVEN)) { + // prime mod 10 needs to equal 3 or 7 + error += 8; + } + break; + default: + error += 4; + } + primeCache[hex] = error; + return error; +} + +function DH(prime, generator, malleable) { + this.setGenerator(generator); + this.__prime = new BN(prime); + this._prime = BN.mont(this.__prime); + this._primeLen = prime.length; + this._pub = undefined; + this._priv = undefined; + this._primeCode = undefined; + if (malleable) { + this.setPublicKey = setPublicKey; + this.setPrivateKey = setPrivateKey; + } else { + this._primeCode = 8; + } +} +Object.defineProperty(DH.prototype, 'verifyError', { + enumerable: true, + get: function () { + if (typeof this._primeCode !== 'number') { + this._primeCode = checkPrime(this.__prime, this.__gen); + } + return this._primeCode; + } +}); +DH.prototype.generateKeys = function () { + if (!this._priv) { + this._priv = new BN(randomBytes(this._primeLen)); + } + this._pub = this._gen.toRed(this._prime).redPow(this._priv).fromRed(); + return this.getPublicKey(); +}; + +DH.prototype.computeSecret = function (other) { + other = new BN(other); + other = other.toRed(this._prime); + var secret = other.redPow(this._priv).fromRed(); + var out = new Buffer(secret.toArray()); + var prime = this.getPrime(); + if (out.length < prime.length) { + var front = new Buffer(prime.length - out.length); + front.fill(0); + out = Buffer.concat([front, out]); + } + return out; +}; + +DH.prototype.getPublicKey = function getPublicKey(enc) { + return formatReturnValue(this._pub, enc); +}; + +DH.prototype.getPrivateKey = function getPrivateKey(enc) { + return formatReturnValue(this._priv, enc); +}; + +DH.prototype.getPrime = function (enc) { + return formatReturnValue(this.__prime, enc); +}; + +DH.prototype.getGenerator = function (enc) { + return formatReturnValue(this._gen, enc); +}; + +DH.prototype.setGenerator = function (gen, enc) { + enc = enc || 'utf8'; + if (!Buffer.isBuffer(gen)) { + gen = new Buffer(gen, enc); + } + this.__gen = gen; + this._gen = new BN(gen); + return this; +}; + +function formatReturnValue(bn, enc) { + var buf = new Buffer(bn.toArray()); + if (!enc) { + return buf; + } else { + return buf.toString(enc); + } +} + +}).call(this)}).call(this,require("buffer").Buffer) +},{"./generatePrime":80,"bn.js":82,"buffer":63,"miller-rabin":134,"randombytes":157}],80:[function(require,module,exports){ +var randomBytes = require('randombytes'); +module.exports = findPrime; +findPrime.simpleSieve = simpleSieve; +findPrime.fermatTest = fermatTest; +var BN = require('bn.js'); +var TWENTYFOUR = new BN(24); +var MillerRabin = require('miller-rabin'); +var millerRabin = new MillerRabin(); +var ONE = new BN(1); +var TWO = new BN(2); +var FIVE = new BN(5); +var SIXTEEN = new BN(16); +var EIGHT = new BN(8); +var TEN = new BN(10); +var THREE = new BN(3); +var SEVEN = new BN(7); +var ELEVEN = new BN(11); +var FOUR = new BN(4); +var TWELVE = new BN(12); +var primes = null; + +function _getPrimes() { + if (primes !== null) + return primes; + + var limit = 0x100000; + var res = []; + res[0] = 2; + for (var i = 1, k = 3; k < limit; k += 2) { + var sqrt = Math.ceil(Math.sqrt(k)); + for (var j = 0; j < i && res[j] <= sqrt; j++) + if (k % res[j] === 0) + break; + + if (i !== j && res[j] <= sqrt) + continue; + + res[i++] = k; + } + primes = res; + return res; +} + +function simpleSieve(p) { + var primes = _getPrimes(); + + for (var i = 0; i < primes.length; i++) + if (p.modn(primes[i]) === 0) { + if (p.cmpn(primes[i]) === 0) { + return true; + } else { + return false; + } + } + + return true; +} + +function fermatTest(p) { + var red = BN.mont(p); + return TWO.toRed(red).redPow(p.subn(1)).fromRed().cmpn(1) === 0; +} + +function findPrime(bits, gen) { + if (bits < 16) { + // this is what openssl does + if (gen === 2 || gen === 5) { + return new BN([0x8c, 0x7b]); + } else { + return new BN([0x8c, 0x27]); + } + } + gen = new BN(gen); + + var num, n2; + + while (true) { + num = new BN(randomBytes(Math.ceil(bits / 8))); + while (num.bitLength() > bits) { + num.ishrn(1); + } + if (num.isEven()) { + num.iadd(ONE); + } + if (!num.testn(1)) { + num.iadd(TWO); + } + if (!gen.cmp(TWO)) { + while (num.mod(TWENTYFOUR).cmp(ELEVEN)) { + num.iadd(FOUR); + } + } else if (!gen.cmp(FIVE)) { + while (num.mod(TEN).cmp(THREE)) { + num.iadd(FOUR); + } + } + n2 = num.shrn(1); + if (simpleSieve(n2) && simpleSieve(num) && + fermatTest(n2) && fermatTest(num) && + millerRabin.test(n2) && millerRabin.test(num)) { + return num; + } + } + +} + +},{"bn.js":82,"miller-rabin":134,"randombytes":157}],81:[function(require,module,exports){ +module.exports={ + "modp1": { + "gen": "02", + "prime": "ffffffffffffffffc90fdaa22168c234c4c6628b80dc1cd129024e088a67cc74020bbea63b139b22514a08798e3404ddef9519b3cd3a431b302b0a6df25f14374fe1356d6d51c245e485b576625e7ec6f44c42e9a63a3620ffffffffffffffff" + }, + "modp2": { + "gen": "02", + "prime": "ffffffffffffffffc90fdaa22168c234c4c6628b80dc1cd129024e088a67cc74020bbea63b139b22514a08798e3404ddef9519b3cd3a431b302b0a6df25f14374fe1356d6d51c245e485b576625e7ec6f44c42e9a637ed6b0bff5cb6f406b7edee386bfb5a899fa5ae9f24117c4b1fe649286651ece65381ffffffffffffffff" + }, + "modp5": { + "gen": "02", + "prime": "ffffffffffffffffc90fdaa22168c234c4c6628b80dc1cd129024e088a67cc74020bbea63b139b22514a08798e3404ddef9519b3cd3a431b302b0a6df25f14374fe1356d6d51c245e485b576625e7ec6f44c42e9a637ed6b0bff5cb6f406b7edee386bfb5a899fa5ae9f24117c4b1fe649286651ece45b3dc2007cb8a163bf0598da48361c55d39a69163fa8fd24cf5f83655d23dca3ad961c62f356208552bb9ed529077096966d670c354e4abc9804f1746c08ca237327ffffffffffffffff" + }, + "modp14": { + "gen": "02", + "prime": "ffffffffffffffffc90fdaa22168c234c4c6628b80dc1cd129024e088a67cc74020bbea63b139b22514a08798e3404ddef9519b3cd3a431b302b0a6df25f14374fe1356d6d51c245e485b576625e7ec6f44c42e9a637ed6b0bff5cb6f406b7edee386bfb5a899fa5ae9f24117c4b1fe649286651ece45b3dc2007cb8a163bf0598da48361c55d39a69163fa8fd24cf5f83655d23dca3ad961c62f356208552bb9ed529077096966d670c354e4abc9804f1746c08ca18217c32905e462e36ce3be39e772c180e86039b2783a2ec07a28fb5c55df06f4c52c9de2bcbf6955817183995497cea956ae515d2261898fa051015728e5a8aacaa68ffffffffffffffff" + }, + "modp15": { + "gen": "02", + "prime": "ffffffffffffffffc90fdaa22168c234c4c6628b80dc1cd129024e088a67cc74020bbea63b139b22514a08798e3404ddef9519b3cd3a431b302b0a6df25f14374fe1356d6d51c245e485b576625e7ec6f44c42e9a637ed6b0bff5cb6f406b7edee386bfb5a899fa5ae9f24117c4b1fe649286651ece45b3dc2007cb8a163bf0598da48361c55d39a69163fa8fd24cf5f83655d23dca3ad961c62f356208552bb9ed529077096966d670c354e4abc9804f1746c08ca18217c32905e462e36ce3be39e772c180e86039b2783a2ec07a28fb5c55df06f4c52c9de2bcbf6955817183995497cea956ae515d2261898fa051015728e5a8aaac42dad33170d04507a33a85521abdf1cba64ecfb850458dbef0a8aea71575d060c7db3970f85a6e1e4c7abf5ae8cdb0933d71e8c94e04a25619dcee3d2261ad2ee6bf12ffa06d98a0864d87602733ec86a64521f2b18177b200cbbe117577a615d6c770988c0bad946e208e24fa074e5ab3143db5bfce0fd108e4b82d120a93ad2caffffffffffffffff" + }, + "modp16": { + "gen": "02", + "prime": "ffffffffffffffffc90fdaa22168c234c4c6628b80dc1cd129024e088a67cc74020bbea63b139b22514a08798e3404ddef9519b3cd3a431b302b0a6df25f14374fe1356d6d51c245e485b576625e7ec6f44c42e9a637ed6b0bff5cb6f406b7edee386bfb5a899fa5ae9f24117c4b1fe649286651ece45b3dc2007cb8a163bf0598da48361c55d39a69163fa8fd24cf5f83655d23dca3ad961c62f356208552bb9ed529077096966d670c354e4abc9804f1746c08ca18217c32905e462e36ce3be39e772c180e86039b2783a2ec07a28fb5c55df06f4c52c9de2bcbf6955817183995497cea956ae515d2261898fa051015728e5a8aaac42dad33170d04507a33a85521abdf1cba64ecfb850458dbef0a8aea71575d060c7db3970f85a6e1e4c7abf5ae8cdb0933d71e8c94e04a25619dcee3d2261ad2ee6bf12ffa06d98a0864d87602733ec86a64521f2b18177b200cbbe117577a615d6c770988c0bad946e208e24fa074e5ab3143db5bfce0fd108e4b82d120a92108011a723c12a787e6d788719a10bdba5b2699c327186af4e23c1a946834b6150bda2583e9ca2ad44ce8dbbbc2db04de8ef92e8efc141fbecaa6287c59474e6bc05d99b2964fa090c3a2233ba186515be7ed1f612970cee2d7afb81bdd762170481cd0069127d5b05aa993b4ea988d8fddc186ffb7dc90a6c08f4df435c934063199ffffffffffffffff" + }, + "modp17": { + "gen": "02", + "prime": "ffffffffffffffffc90fdaa22168c234c4c6628b80dc1cd129024e088a67cc74020bbea63b139b22514a08798e3404ddef9519b3cd3a431b302b0a6df25f14374fe1356d6d51c245e485b576625e7ec6f44c42e9a637ed6b0bff5cb6f406b7edee386bfb5a899fa5ae9f24117c4b1fe649286651ece45b3dc2007cb8a163bf0598da48361c55d39a69163fa8fd24cf5f83655d23dca3ad961c62f356208552bb9ed529077096966d670c354e4abc9804f1746c08ca18217c32905e462e36ce3be39e772c180e86039b2783a2ec07a28fb5c55df06f4c52c9de2bcbf6955817183995497cea956ae515d2261898fa051015728e5a8aaac42dad33170d04507a33a85521abdf1cba64ecfb850458dbef0a8aea71575d060c7db3970f85a6e1e4c7abf5ae8cdb0933d71e8c94e04a25619dcee3d2261ad2ee6bf12ffa06d98a0864d87602733ec86a64521f2b18177b200cbbe117577a615d6c770988c0bad946e208e24fa074e5ab3143db5bfce0fd108e4b82d120a92108011a723c12a787e6d788719a10bdba5b2699c327186af4e23c1a946834b6150bda2583e9ca2ad44ce8dbbbc2db04de8ef92e8efc141fbecaa6287c59474e6bc05d99b2964fa090c3a2233ba186515be7ed1f612970cee2d7afb81bdd762170481cd0069127d5b05aa993b4ea988d8fddc186ffb7dc90a6c08f4df435c93402849236c3fab4d27c7026c1d4dcb2602646dec9751e763dba37bdf8ff9406ad9e530ee5db382f413001aeb06a53ed9027d831179727b0865a8918da3edbebcf9b14ed44ce6cbaced4bb1bdb7f1447e6cc254b332051512bd7af426fb8f401378cd2bf5983ca01c64b92ecf032ea15d1721d03f482d7ce6e74fef6d55e702f46980c82b5a84031900b1c9e59e7c97fbec7e8f323a97a7e36cc88be0f1d45b7ff585ac54bd407b22b4154aacc8f6d7ebf48e1d814cc5ed20f8037e0a79715eef29be32806a1d58bb7c5da76f550aa3d8a1fbff0eb19ccb1a313d55cda56c9ec2ef29632387fe8d76e3c0468043e8f663f4860ee12bf2d5b0b7474d6e694f91e6dcc4024ffffffffffffffff" + }, + "modp18": { + "gen": "02", + "prime": "ffffffffffffffffc90fdaa22168c234c4c6628b80dc1cd129024e088a67cc74020bbea63b139b22514a08798e3404ddef9519b3cd3a431b302b0a6df25f14374fe1356d6d51c245e485b576625e7ec6f44c42e9a637ed6b0bff5cb6f406b7edee386bfb5a899fa5ae9f24117c4b1fe649286651ece45b3dc2007cb8a163bf0598da48361c55d39a69163fa8fd24cf5f83655d23dca3ad961c62f356208552bb9ed529077096966d670c354e4abc9804f1746c08ca18217c32905e462e36ce3be39e772c180e86039b2783a2ec07a28fb5c55df06f4c52c9de2bcbf6955817183995497cea956ae515d2261898fa051015728e5a8aaac42dad33170d04507a33a85521abdf1cba64ecfb850458dbef0a8aea71575d060c7db3970f85a6e1e4c7abf5ae8cdb0933d71e8c94e04a25619dcee3d2261ad2ee6bf12ffa06d98a0864d87602733ec86a64521f2b18177b200cbbe117577a615d6c770988c0bad946e208e24fa074e5ab3143db5bfce0fd108e4b82d120a92108011a723c12a787e6d788719a10bdba5b2699c327186af4e23c1a946834b6150bda2583e9ca2ad44ce8dbbbc2db04de8ef92e8efc141fbecaa6287c59474e6bc05d99b2964fa090c3a2233ba186515be7ed1f612970cee2d7afb81bdd762170481cd0069127d5b05aa993b4ea988d8fddc186ffb7dc90a6c08f4df435c93402849236c3fab4d27c7026c1d4dcb2602646dec9751e763dba37bdf8ff9406ad9e530ee5db382f413001aeb06a53ed9027d831179727b0865a8918da3edbebcf9b14ed44ce6cbaced4bb1bdb7f1447e6cc254b332051512bd7af426fb8f401378cd2bf5983ca01c64b92ecf032ea15d1721d03f482d7ce6e74fef6d55e702f46980c82b5a84031900b1c9e59e7c97fbec7e8f323a97a7e36cc88be0f1d45b7ff585ac54bd407b22b4154aacc8f6d7ebf48e1d814cc5ed20f8037e0a79715eef29be32806a1d58bb7c5da76f550aa3d8a1fbff0eb19ccb1a313d55cda56c9ec2ef29632387fe8d76e3c0468043e8f663f4860ee12bf2d5b0b7474d6e694f91e6dbe115974a3926f12fee5e438777cb6a932df8cd8bec4d073b931ba3bc832b68d9dd300741fa7bf8afc47ed2576f6936ba424663aab639c5ae4f5683423b4742bf1c978238f16cbe39d652de3fdb8befc848ad922222e04a4037c0713eb57a81a23f0c73473fc646cea306b4bcbc8862f8385ddfa9d4b7fa2c087e879683303ed5bdd3a062b3cf5b3a278a66d2a13f83f44f82ddf310ee074ab6a364597e899a0255dc164f31cc50846851df9ab48195ded7ea1b1d510bd7ee74d73faf36bc31ecfa268359046f4eb879f924009438b481c6cd7889a002ed5ee382bc9190da6fc026e479558e4475677e9aa9e3050e2765694dfc81f56e880b96e7160c980dd98edd3dfffffffffffffffff" + } +} +},{}],82:[function(require,module,exports){ +arguments[4][15][0].apply(exports,arguments) +},{"buffer":19,"dup":15}],83:[function(require,module,exports){ +'use strict'; + +var elliptic = exports; + +elliptic.version = require('../package.json').version; +elliptic.utils = require('./elliptic/utils'); +elliptic.rand = require('brorand'); +elliptic.curve = require('./elliptic/curve'); +elliptic.curves = require('./elliptic/curves'); + +// Protocols +elliptic.ec = require('./elliptic/ec'); +elliptic.eddsa = require('./elliptic/eddsa'); + +},{"../package.json":99,"./elliptic/curve":86,"./elliptic/curves":89,"./elliptic/ec":90,"./elliptic/eddsa":93,"./elliptic/utils":97,"brorand":18}],84:[function(require,module,exports){ +'use strict'; + +var BN = require('bn.js'); +var utils = require('../utils'); +var getNAF = utils.getNAF; +var getJSF = utils.getJSF; +var assert = utils.assert; + +function BaseCurve(type, conf) { + this.type = type; + this.p = new BN(conf.p, 16); + + // Use Montgomery, when there is no fast reduction for the prime + this.red = conf.prime ? BN.red(conf.prime) : BN.mont(this.p); + + // Useful for many curves + this.zero = new BN(0).toRed(this.red); + this.one = new BN(1).toRed(this.red); + this.two = new BN(2).toRed(this.red); + + // Curve configuration, optional + this.n = conf.n && new BN(conf.n, 16); + this.g = conf.g && this.pointFromJSON(conf.g, conf.gRed); + + // Temporary arrays + this._wnafT1 = new Array(4); + this._wnafT2 = new Array(4); + this._wnafT3 = new Array(4); + this._wnafT4 = new Array(4); + + this._bitLength = this.n ? this.n.bitLength() : 0; + + // Generalized Greg Maxwell's trick + var adjustCount = this.n && this.p.div(this.n); + if (!adjustCount || adjustCount.cmpn(100) > 0) { + this.redN = null; + } else { + this._maxwellTrick = true; + this.redN = this.n.toRed(this.red); + } +} +module.exports = BaseCurve; + +BaseCurve.prototype.point = function point() { + throw new Error('Not implemented'); +}; + +BaseCurve.prototype.validate = function validate() { + throw new Error('Not implemented'); +}; + +BaseCurve.prototype._fixedNafMul = function _fixedNafMul(p, k) { + assert(p.precomputed); + var doubles = p._getDoubles(); + + var naf = getNAF(k, 1, this._bitLength); + var I = (1 << (doubles.step + 1)) - (doubles.step % 2 === 0 ? 2 : 1); + I /= 3; + + // Translate into more windowed form + var repr = []; + var j; + var nafW; + for (j = 0; j < naf.length; j += doubles.step) { + nafW = 0; + for (var l = j + doubles.step - 1; l >= j; l--) + nafW = (nafW << 1) + naf[l]; + repr.push(nafW); + } + + var a = this.jpoint(null, null, null); + var b = this.jpoint(null, null, null); + for (var i = I; i > 0; i--) { + for (j = 0; j < repr.length; j++) { + nafW = repr[j]; + if (nafW === i) + b = b.mixedAdd(doubles.points[j]); + else if (nafW === -i) + b = b.mixedAdd(doubles.points[j].neg()); + } + a = a.add(b); + } + return a.toP(); +}; + +BaseCurve.prototype._wnafMul = function _wnafMul(p, k) { + var w = 4; + + // Precompute window + var nafPoints = p._getNAFPoints(w); + w = nafPoints.wnd; + var wnd = nafPoints.points; + + // Get NAF form + var naf = getNAF(k, w, this._bitLength); + + // Add `this`*(N+1) for every w-NAF index + var acc = this.jpoint(null, null, null); + for (var i = naf.length - 1; i >= 0; i--) { + // Count zeroes + for (var l = 0; i >= 0 && naf[i] === 0; i--) + l++; + if (i >= 0) + l++; + acc = acc.dblp(l); + + if (i < 0) + break; + var z = naf[i]; + assert(z !== 0); + if (p.type === 'affine') { + // J +- P + if (z > 0) + acc = acc.mixedAdd(wnd[(z - 1) >> 1]); + else + acc = acc.mixedAdd(wnd[(-z - 1) >> 1].neg()); + } else { + // J +- J + if (z > 0) + acc = acc.add(wnd[(z - 1) >> 1]); + else + acc = acc.add(wnd[(-z - 1) >> 1].neg()); + } + } + return p.type === 'affine' ? acc.toP() : acc; +}; + +BaseCurve.prototype._wnafMulAdd = function _wnafMulAdd(defW, + points, + coeffs, + len, + jacobianResult) { + var wndWidth = this._wnafT1; + var wnd = this._wnafT2; + var naf = this._wnafT3; + + // Fill all arrays + var max = 0; + var i; + var j; + var p; + for (i = 0; i < len; i++) { + p = points[i]; + var nafPoints = p._getNAFPoints(defW); + wndWidth[i] = nafPoints.wnd; + wnd[i] = nafPoints.points; + } + + // Comb small window NAFs + for (i = len - 1; i >= 1; i -= 2) { + var a = i - 1; + var b = i; + if (wndWidth[a] !== 1 || wndWidth[b] !== 1) { + naf[a] = getNAF(coeffs[a], wndWidth[a], this._bitLength); + naf[b] = getNAF(coeffs[b], wndWidth[b], this._bitLength); + max = Math.max(naf[a].length, max); + max = Math.max(naf[b].length, max); + continue; + } + + var comb = [ + points[a], /* 1 */ + null, /* 3 */ + null, /* 5 */ + points[b], /* 7 */ + ]; + + // Try to avoid Projective points, if possible + if (points[a].y.cmp(points[b].y) === 0) { + comb[1] = points[a].add(points[b]); + comb[2] = points[a].toJ().mixedAdd(points[b].neg()); + } else if (points[a].y.cmp(points[b].y.redNeg()) === 0) { + comb[1] = points[a].toJ().mixedAdd(points[b]); + comb[2] = points[a].add(points[b].neg()); + } else { + comb[1] = points[a].toJ().mixedAdd(points[b]); + comb[2] = points[a].toJ().mixedAdd(points[b].neg()); + } + + var index = [ + -3, /* -1 -1 */ + -1, /* -1 0 */ + -5, /* -1 1 */ + -7, /* 0 -1 */ + 0, /* 0 0 */ + 7, /* 0 1 */ + 5, /* 1 -1 */ + 1, /* 1 0 */ + 3, /* 1 1 */ + ]; + + var jsf = getJSF(coeffs[a], coeffs[b]); + max = Math.max(jsf[0].length, max); + naf[a] = new Array(max); + naf[b] = new Array(max); + for (j = 0; j < max; j++) { + var ja = jsf[0][j] | 0; + var jb = jsf[1][j] | 0; + + naf[a][j] = index[(ja + 1) * 3 + (jb + 1)]; + naf[b][j] = 0; + wnd[a] = comb; + } + } + + var acc = this.jpoint(null, null, null); + var tmp = this._wnafT4; + for (i = max; i >= 0; i--) { + var k = 0; + + while (i >= 0) { + var zero = true; + for (j = 0; j < len; j++) { + tmp[j] = naf[j][i] | 0; + if (tmp[j] !== 0) + zero = false; + } + if (!zero) + break; + k++; + i--; + } + if (i >= 0) + k++; + acc = acc.dblp(k); + if (i < 0) + break; + + for (j = 0; j < len; j++) { + var z = tmp[j]; + p; + if (z === 0) + continue; + else if (z > 0) + p = wnd[j][(z - 1) >> 1]; + else if (z < 0) + p = wnd[j][(-z - 1) >> 1].neg(); + + if (p.type === 'affine') + acc = acc.mixedAdd(p); + else + acc = acc.add(p); + } + } + // Zeroify references + for (i = 0; i < len; i++) + wnd[i] = null; + + if (jacobianResult) + return acc; + else + return acc.toP(); +}; + +function BasePoint(curve, type) { + this.curve = curve; + this.type = type; + this.precomputed = null; +} +BaseCurve.BasePoint = BasePoint; + +BasePoint.prototype.eq = function eq(/*other*/) { + throw new Error('Not implemented'); +}; + +BasePoint.prototype.validate = function validate() { + return this.curve.validate(this); +}; + +BaseCurve.prototype.decodePoint = function decodePoint(bytes, enc) { + bytes = utils.toArray(bytes, enc); + + var len = this.p.byteLength(); + + // uncompressed, hybrid-odd, hybrid-even + if ((bytes[0] === 0x04 || bytes[0] === 0x06 || bytes[0] === 0x07) && + bytes.length - 1 === 2 * len) { + if (bytes[0] === 0x06) + assert(bytes[bytes.length - 1] % 2 === 0); + else if (bytes[0] === 0x07) + assert(bytes[bytes.length - 1] % 2 === 1); + + var res = this.point(bytes.slice(1, 1 + len), + bytes.slice(1 + len, 1 + 2 * len)); + + return res; + } else if ((bytes[0] === 0x02 || bytes[0] === 0x03) && + bytes.length - 1 === len) { + return this.pointFromX(bytes.slice(1, 1 + len), bytes[0] === 0x03); + } + throw new Error('Unknown point format'); +}; + +BasePoint.prototype.encodeCompressed = function encodeCompressed(enc) { + return this.encode(enc, true); +}; + +BasePoint.prototype._encode = function _encode(compact) { + var len = this.curve.p.byteLength(); + var x = this.getX().toArray('be', len); + + if (compact) + return [ this.getY().isEven() ? 0x02 : 0x03 ].concat(x); + + return [ 0x04 ].concat(x, this.getY().toArray('be', len)); +}; + +BasePoint.prototype.encode = function encode(enc, compact) { + return utils.encode(this._encode(compact), enc); +}; + +BasePoint.prototype.precompute = function precompute(power) { + if (this.precomputed) + return this; + + var precomputed = { + doubles: null, + naf: null, + beta: null, + }; + precomputed.naf = this._getNAFPoints(8); + precomputed.doubles = this._getDoubles(4, power); + precomputed.beta = this._getBeta(); + this.precomputed = precomputed; + + return this; +}; + +BasePoint.prototype._hasDoubles = function _hasDoubles(k) { + if (!this.precomputed) + return false; + + var doubles = this.precomputed.doubles; + if (!doubles) + return false; + + return doubles.points.length >= Math.ceil((k.bitLength() + 1) / doubles.step); +}; + +BasePoint.prototype._getDoubles = function _getDoubles(step, power) { + if (this.precomputed && this.precomputed.doubles) + return this.precomputed.doubles; + + var doubles = [ this ]; + var acc = this; + for (var i = 0; i < power; i += step) { + for (var j = 0; j < step; j++) + acc = acc.dbl(); + doubles.push(acc); + } + return { + step: step, + points: doubles, + }; +}; + +BasePoint.prototype._getNAFPoints = function _getNAFPoints(wnd) { + if (this.precomputed && this.precomputed.naf) + return this.precomputed.naf; + + var res = [ this ]; + var max = (1 << wnd) - 1; + var dbl = max === 1 ? null : this.dbl(); + for (var i = 1; i < max; i++) + res[i] = res[i - 1].add(dbl); + return { + wnd: wnd, + points: res, + }; +}; + +BasePoint.prototype._getBeta = function _getBeta() { + return null; +}; + +BasePoint.prototype.dblp = function dblp(k) { + var r = this; + for (var i = 0; i < k; i++) + r = r.dbl(); + return r; +}; + +},{"../utils":97,"bn.js":98}],85:[function(require,module,exports){ +'use strict'; + +var utils = require('../utils'); +var BN = require('bn.js'); +var inherits = require('inherits'); +var Base = require('./base'); + +var assert = utils.assert; + +function EdwardsCurve(conf) { + // NOTE: Important as we are creating point in Base.call() + this.twisted = (conf.a | 0) !== 1; + this.mOneA = this.twisted && (conf.a | 0) === -1; + this.extended = this.mOneA; + + Base.call(this, 'edwards', conf); + + this.a = new BN(conf.a, 16).umod(this.red.m); + this.a = this.a.toRed(this.red); + this.c = new BN(conf.c, 16).toRed(this.red); + this.c2 = this.c.redSqr(); + this.d = new BN(conf.d, 16).toRed(this.red); + this.dd = this.d.redAdd(this.d); + + assert(!this.twisted || this.c.fromRed().cmpn(1) === 0); + this.oneC = (conf.c | 0) === 1; +} +inherits(EdwardsCurve, Base); +module.exports = EdwardsCurve; + +EdwardsCurve.prototype._mulA = function _mulA(num) { + if (this.mOneA) + return num.redNeg(); + else + return this.a.redMul(num); +}; + +EdwardsCurve.prototype._mulC = function _mulC(num) { + if (this.oneC) + return num; + else + return this.c.redMul(num); +}; + +// Just for compatibility with Short curve +EdwardsCurve.prototype.jpoint = function jpoint(x, y, z, t) { + return this.point(x, y, z, t); +}; + +EdwardsCurve.prototype.pointFromX = function pointFromX(x, odd) { + x = new BN(x, 16); + if (!x.red) + x = x.toRed(this.red); + + var x2 = x.redSqr(); + var rhs = this.c2.redSub(this.a.redMul(x2)); + var lhs = this.one.redSub(this.c2.redMul(this.d).redMul(x2)); + + var y2 = rhs.redMul(lhs.redInvm()); + var y = y2.redSqrt(); + if (y.redSqr().redSub(y2).cmp(this.zero) !== 0) + throw new Error('invalid point'); + + var isOdd = y.fromRed().isOdd(); + if (odd && !isOdd || !odd && isOdd) + y = y.redNeg(); + + return this.point(x, y); +}; + +EdwardsCurve.prototype.pointFromY = function pointFromY(y, odd) { + y = new BN(y, 16); + if (!y.red) + y = y.toRed(this.red); + + // x^2 = (y^2 - c^2) / (c^2 d y^2 - a) + var y2 = y.redSqr(); + var lhs = y2.redSub(this.c2); + var rhs = y2.redMul(this.d).redMul(this.c2).redSub(this.a); + var x2 = lhs.redMul(rhs.redInvm()); + + if (x2.cmp(this.zero) === 0) { + if (odd) + throw new Error('invalid point'); + else + return this.point(this.zero, y); + } + + var x = x2.redSqrt(); + if (x.redSqr().redSub(x2).cmp(this.zero) !== 0) + throw new Error('invalid point'); + + if (x.fromRed().isOdd() !== odd) + x = x.redNeg(); + + return this.point(x, y); +}; + +EdwardsCurve.prototype.validate = function validate(point) { + if (point.isInfinity()) + return true; + + // Curve: A * X^2 + Y^2 = C^2 * (1 + D * X^2 * Y^2) + point.normalize(); + + var x2 = point.x.redSqr(); + var y2 = point.y.redSqr(); + var lhs = x2.redMul(this.a).redAdd(y2); + var rhs = this.c2.redMul(this.one.redAdd(this.d.redMul(x2).redMul(y2))); + + return lhs.cmp(rhs) === 0; +}; + +function Point(curve, x, y, z, t) { + Base.BasePoint.call(this, curve, 'projective'); + if (x === null && y === null && z === null) { + this.x = this.curve.zero; + this.y = this.curve.one; + this.z = this.curve.one; + this.t = this.curve.zero; + this.zOne = true; + } else { + this.x = new BN(x, 16); + this.y = new BN(y, 16); + this.z = z ? new BN(z, 16) : this.curve.one; + this.t = t && new BN(t, 16); + if (!this.x.red) + this.x = this.x.toRed(this.curve.red); + if (!this.y.red) + this.y = this.y.toRed(this.curve.red); + if (!this.z.red) + this.z = this.z.toRed(this.curve.red); + if (this.t && !this.t.red) + this.t = this.t.toRed(this.curve.red); + this.zOne = this.z === this.curve.one; + + // Use extended coordinates + if (this.curve.extended && !this.t) { + this.t = this.x.redMul(this.y); + if (!this.zOne) + this.t = this.t.redMul(this.z.redInvm()); + } + } +} +inherits(Point, Base.BasePoint); + +EdwardsCurve.prototype.pointFromJSON = function pointFromJSON(obj) { + return Point.fromJSON(this, obj); +}; + +EdwardsCurve.prototype.point = function point(x, y, z, t) { + return new Point(this, x, y, z, t); +}; + +Point.fromJSON = function fromJSON(curve, obj) { + return new Point(curve, obj[0], obj[1], obj[2]); +}; + +Point.prototype.inspect = function inspect() { + if (this.isInfinity()) + return ''; + return ''; +}; + +Point.prototype.isInfinity = function isInfinity() { + // XXX This code assumes that zero is always zero in red + return this.x.cmpn(0) === 0 && + (this.y.cmp(this.z) === 0 || + (this.zOne && this.y.cmp(this.curve.c) === 0)); +}; + +Point.prototype._extDbl = function _extDbl() { + // hyperelliptic.org/EFD/g1p/auto-twisted-extended-1.html + // #doubling-dbl-2008-hwcd + // 4M + 4S + + // A = X1^2 + var a = this.x.redSqr(); + // B = Y1^2 + var b = this.y.redSqr(); + // C = 2 * Z1^2 + var c = this.z.redSqr(); + c = c.redIAdd(c); + // D = a * A + var d = this.curve._mulA(a); + // E = (X1 + Y1)^2 - A - B + var e = this.x.redAdd(this.y).redSqr().redISub(a).redISub(b); + // G = D + B + var g = d.redAdd(b); + // F = G - C + var f = g.redSub(c); + // H = D - B + var h = d.redSub(b); + // X3 = E * F + var nx = e.redMul(f); + // Y3 = G * H + var ny = g.redMul(h); + // T3 = E * H + var nt = e.redMul(h); + // Z3 = F * G + var nz = f.redMul(g); + return this.curve.point(nx, ny, nz, nt); +}; + +Point.prototype._projDbl = function _projDbl() { + // hyperelliptic.org/EFD/g1p/auto-twisted-projective.html + // #doubling-dbl-2008-bbjlp + // #doubling-dbl-2007-bl + // and others + // Generally 3M + 4S or 2M + 4S + + // B = (X1 + Y1)^2 + var b = this.x.redAdd(this.y).redSqr(); + // C = X1^2 + var c = this.x.redSqr(); + // D = Y1^2 + var d = this.y.redSqr(); + + var nx; + var ny; + var nz; + var e; + var h; + var j; + if (this.curve.twisted) { + // E = a * C + e = this.curve._mulA(c); + // F = E + D + var f = e.redAdd(d); + if (this.zOne) { + // X3 = (B - C - D) * (F - 2) + nx = b.redSub(c).redSub(d).redMul(f.redSub(this.curve.two)); + // Y3 = F * (E - D) + ny = f.redMul(e.redSub(d)); + // Z3 = F^2 - 2 * F + nz = f.redSqr().redSub(f).redSub(f); + } else { + // H = Z1^2 + h = this.z.redSqr(); + // J = F - 2 * H + j = f.redSub(h).redISub(h); + // X3 = (B-C-D)*J + nx = b.redSub(c).redISub(d).redMul(j); + // Y3 = F * (E - D) + ny = f.redMul(e.redSub(d)); + // Z3 = F * J + nz = f.redMul(j); + } + } else { + // E = C + D + e = c.redAdd(d); + // H = (c * Z1)^2 + h = this.curve._mulC(this.z).redSqr(); + // J = E - 2 * H + j = e.redSub(h).redSub(h); + // X3 = c * (B - E) * J + nx = this.curve._mulC(b.redISub(e)).redMul(j); + // Y3 = c * E * (C - D) + ny = this.curve._mulC(e).redMul(c.redISub(d)); + // Z3 = E * J + nz = e.redMul(j); + } + return this.curve.point(nx, ny, nz); +}; + +Point.prototype.dbl = function dbl() { + if (this.isInfinity()) + return this; + + // Double in extended coordinates + if (this.curve.extended) + return this._extDbl(); + else + return this._projDbl(); +}; + +Point.prototype._extAdd = function _extAdd(p) { + // hyperelliptic.org/EFD/g1p/auto-twisted-extended-1.html + // #addition-add-2008-hwcd-3 + // 8M + + // A = (Y1 - X1) * (Y2 - X2) + var a = this.y.redSub(this.x).redMul(p.y.redSub(p.x)); + // B = (Y1 + X1) * (Y2 + X2) + var b = this.y.redAdd(this.x).redMul(p.y.redAdd(p.x)); + // C = T1 * k * T2 + var c = this.t.redMul(this.curve.dd).redMul(p.t); + // D = Z1 * 2 * Z2 + var d = this.z.redMul(p.z.redAdd(p.z)); + // E = B - A + var e = b.redSub(a); + // F = D - C + var f = d.redSub(c); + // G = D + C + var g = d.redAdd(c); + // H = B + A + var h = b.redAdd(a); + // X3 = E * F + var nx = e.redMul(f); + // Y3 = G * H + var ny = g.redMul(h); + // T3 = E * H + var nt = e.redMul(h); + // Z3 = F * G + var nz = f.redMul(g); + return this.curve.point(nx, ny, nz, nt); +}; + +Point.prototype._projAdd = function _projAdd(p) { + // hyperelliptic.org/EFD/g1p/auto-twisted-projective.html + // #addition-add-2008-bbjlp + // #addition-add-2007-bl + // 10M + 1S + + // A = Z1 * Z2 + var a = this.z.redMul(p.z); + // B = A^2 + var b = a.redSqr(); + // C = X1 * X2 + var c = this.x.redMul(p.x); + // D = Y1 * Y2 + var d = this.y.redMul(p.y); + // E = d * C * D + var e = this.curve.d.redMul(c).redMul(d); + // F = B - E + var f = b.redSub(e); + // G = B + E + var g = b.redAdd(e); + // X3 = A * F * ((X1 + Y1) * (X2 + Y2) - C - D) + var tmp = this.x.redAdd(this.y).redMul(p.x.redAdd(p.y)).redISub(c).redISub(d); + var nx = a.redMul(f).redMul(tmp); + var ny; + var nz; + if (this.curve.twisted) { + // Y3 = A * G * (D - a * C) + ny = a.redMul(g).redMul(d.redSub(this.curve._mulA(c))); + // Z3 = F * G + nz = f.redMul(g); + } else { + // Y3 = A * G * (D - C) + ny = a.redMul(g).redMul(d.redSub(c)); + // Z3 = c * F * G + nz = this.curve._mulC(f).redMul(g); + } + return this.curve.point(nx, ny, nz); +}; + +Point.prototype.add = function add(p) { + if (this.isInfinity()) + return p; + if (p.isInfinity()) + return this; + + if (this.curve.extended) + return this._extAdd(p); + else + return this._projAdd(p); +}; + +Point.prototype.mul = function mul(k) { + if (this._hasDoubles(k)) + return this.curve._fixedNafMul(this, k); + else + return this.curve._wnafMul(this, k); +}; + +Point.prototype.mulAdd = function mulAdd(k1, p, k2) { + return this.curve._wnafMulAdd(1, [ this, p ], [ k1, k2 ], 2, false); +}; + +Point.prototype.jmulAdd = function jmulAdd(k1, p, k2) { + return this.curve._wnafMulAdd(1, [ this, p ], [ k1, k2 ], 2, true); +}; + +Point.prototype.normalize = function normalize() { + if (this.zOne) + return this; + + // Normalize coordinates + var zi = this.z.redInvm(); + this.x = this.x.redMul(zi); + this.y = this.y.redMul(zi); + if (this.t) + this.t = this.t.redMul(zi); + this.z = this.curve.one; + this.zOne = true; + return this; +}; + +Point.prototype.neg = function neg() { + return this.curve.point(this.x.redNeg(), + this.y, + this.z, + this.t && this.t.redNeg()); +}; + +Point.prototype.getX = function getX() { + this.normalize(); + return this.x.fromRed(); +}; + +Point.prototype.getY = function getY() { + this.normalize(); + return this.y.fromRed(); +}; + +Point.prototype.eq = function eq(other) { + return this === other || + this.getX().cmp(other.getX()) === 0 && + this.getY().cmp(other.getY()) === 0; +}; + +Point.prototype.eqXToP = function eqXToP(x) { + var rx = x.toRed(this.curve.red).redMul(this.z); + if (this.x.cmp(rx) === 0) + return true; + + var xc = x.clone(); + var t = this.curve.redN.redMul(this.z); + for (;;) { + xc.iadd(this.curve.n); + if (xc.cmp(this.curve.p) >= 0) + return false; + + rx.redIAdd(t); + if (this.x.cmp(rx) === 0) + return true; + } +}; + +// Compatibility with BaseCurve +Point.prototype.toP = Point.prototype.normalize; +Point.prototype.mixedAdd = Point.prototype.add; + +},{"../utils":97,"./base":84,"bn.js":98,"inherits":132}],86:[function(require,module,exports){ +'use strict'; + +var curve = exports; + +curve.base = require('./base'); +curve.short = require('./short'); +curve.mont = require('./mont'); +curve.edwards = require('./edwards'); + +},{"./base":84,"./edwards":85,"./mont":87,"./short":88}],87:[function(require,module,exports){ +'use strict'; + +var BN = require('bn.js'); +var inherits = require('inherits'); +var Base = require('./base'); + +var utils = require('../utils'); + +function MontCurve(conf) { + Base.call(this, 'mont', conf); + + this.a = new BN(conf.a, 16).toRed(this.red); + this.b = new BN(conf.b, 16).toRed(this.red); + this.i4 = new BN(4).toRed(this.red).redInvm(); + this.two = new BN(2).toRed(this.red); + this.a24 = this.i4.redMul(this.a.redAdd(this.two)); +} +inherits(MontCurve, Base); +module.exports = MontCurve; + +MontCurve.prototype.validate = function validate(point) { + var x = point.normalize().x; + var x2 = x.redSqr(); + var rhs = x2.redMul(x).redAdd(x2.redMul(this.a)).redAdd(x); + var y = rhs.redSqrt(); + + return y.redSqr().cmp(rhs) === 0; +}; + +function Point(curve, x, z) { + Base.BasePoint.call(this, curve, 'projective'); + if (x === null && z === null) { + this.x = this.curve.one; + this.z = this.curve.zero; + } else { + this.x = new BN(x, 16); + this.z = new BN(z, 16); + if (!this.x.red) + this.x = this.x.toRed(this.curve.red); + if (!this.z.red) + this.z = this.z.toRed(this.curve.red); + } +} +inherits(Point, Base.BasePoint); + +MontCurve.prototype.decodePoint = function decodePoint(bytes, enc) { + return this.point(utils.toArray(bytes, enc), 1); +}; + +MontCurve.prototype.point = function point(x, z) { + return new Point(this, x, z); +}; + +MontCurve.prototype.pointFromJSON = function pointFromJSON(obj) { + return Point.fromJSON(this, obj); +}; + +Point.prototype.precompute = function precompute() { + // No-op +}; + +Point.prototype._encode = function _encode() { + return this.getX().toArray('be', this.curve.p.byteLength()); +}; + +Point.fromJSON = function fromJSON(curve, obj) { + return new Point(curve, obj[0], obj[1] || curve.one); +}; + +Point.prototype.inspect = function inspect() { + if (this.isInfinity()) + return ''; + return ''; +}; + +Point.prototype.isInfinity = function isInfinity() { + // XXX This code assumes that zero is always zero in red + return this.z.cmpn(0) === 0; +}; + +Point.prototype.dbl = function dbl() { + // http://hyperelliptic.org/EFD/g1p/auto-montgom-xz.html#doubling-dbl-1987-m-3 + // 2M + 2S + 4A + + // A = X1 + Z1 + var a = this.x.redAdd(this.z); + // AA = A^2 + var aa = a.redSqr(); + // B = X1 - Z1 + var b = this.x.redSub(this.z); + // BB = B^2 + var bb = b.redSqr(); + // C = AA - BB + var c = aa.redSub(bb); + // X3 = AA * BB + var nx = aa.redMul(bb); + // Z3 = C * (BB + A24 * C) + var nz = c.redMul(bb.redAdd(this.curve.a24.redMul(c))); + return this.curve.point(nx, nz); +}; + +Point.prototype.add = function add() { + throw new Error('Not supported on Montgomery curve'); +}; + +Point.prototype.diffAdd = function diffAdd(p, diff) { + // http://hyperelliptic.org/EFD/g1p/auto-montgom-xz.html#diffadd-dadd-1987-m-3 + // 4M + 2S + 6A + + // A = X2 + Z2 + var a = this.x.redAdd(this.z); + // B = X2 - Z2 + var b = this.x.redSub(this.z); + // C = X3 + Z3 + var c = p.x.redAdd(p.z); + // D = X3 - Z3 + var d = p.x.redSub(p.z); + // DA = D * A + var da = d.redMul(a); + // CB = C * B + var cb = c.redMul(b); + // X5 = Z1 * (DA + CB)^2 + var nx = diff.z.redMul(da.redAdd(cb).redSqr()); + // Z5 = X1 * (DA - CB)^2 + var nz = diff.x.redMul(da.redISub(cb).redSqr()); + return this.curve.point(nx, nz); +}; + +Point.prototype.mul = function mul(k) { + var t = k.clone(); + var a = this; // (N / 2) * Q + Q + var b = this.curve.point(null, null); // (N / 2) * Q + var c = this; // Q + + for (var bits = []; t.cmpn(0) !== 0; t.iushrn(1)) + bits.push(t.andln(1)); + + for (var i = bits.length - 1; i >= 0; i--) { + if (bits[i] === 0) { + // N * Q + Q = ((N / 2) * Q + Q)) + (N / 2) * Q + a = a.diffAdd(b, c); + // N * Q = 2 * ((N / 2) * Q + Q)) + b = b.dbl(); + } else { + // N * Q = ((N / 2) * Q + Q) + ((N / 2) * Q) + b = a.diffAdd(b, c); + // N * Q + Q = 2 * ((N / 2) * Q + Q) + a = a.dbl(); + } + } + return b; +}; + +Point.prototype.mulAdd = function mulAdd() { + throw new Error('Not supported on Montgomery curve'); +}; + +Point.prototype.jumlAdd = function jumlAdd() { + throw new Error('Not supported on Montgomery curve'); +}; + +Point.prototype.eq = function eq(other) { + return this.getX().cmp(other.getX()) === 0; +}; + +Point.prototype.normalize = function normalize() { + this.x = this.x.redMul(this.z.redInvm()); + this.z = this.curve.one; + return this; +}; + +Point.prototype.getX = function getX() { + // Normalize coordinates + this.normalize(); + + return this.x.fromRed(); +}; + +},{"../utils":97,"./base":84,"bn.js":98,"inherits":132}],88:[function(require,module,exports){ +'use strict'; + +var utils = require('../utils'); +var BN = require('bn.js'); +var inherits = require('inherits'); +var Base = require('./base'); + +var assert = utils.assert; + +function ShortCurve(conf) { + Base.call(this, 'short', conf); + + this.a = new BN(conf.a, 16).toRed(this.red); + this.b = new BN(conf.b, 16).toRed(this.red); + this.tinv = this.two.redInvm(); + + this.zeroA = this.a.fromRed().cmpn(0) === 0; + this.threeA = this.a.fromRed().sub(this.p).cmpn(-3) === 0; + + // If the curve is endomorphic, precalculate beta and lambda + this.endo = this._getEndomorphism(conf); + this._endoWnafT1 = new Array(4); + this._endoWnafT2 = new Array(4); +} +inherits(ShortCurve, Base); +module.exports = ShortCurve; + +ShortCurve.prototype._getEndomorphism = function _getEndomorphism(conf) { + // No efficient endomorphism + if (!this.zeroA || !this.g || !this.n || this.p.modn(3) !== 1) + return; + + // Compute beta and lambda, that lambda * P = (beta * Px; Py) + var beta; + var lambda; + if (conf.beta) { + beta = new BN(conf.beta, 16).toRed(this.red); + } else { + var betas = this._getEndoRoots(this.p); + // Choose the smallest beta + beta = betas[0].cmp(betas[1]) < 0 ? betas[0] : betas[1]; + beta = beta.toRed(this.red); + } + if (conf.lambda) { + lambda = new BN(conf.lambda, 16); + } else { + // Choose the lambda that is matching selected beta + var lambdas = this._getEndoRoots(this.n); + if (this.g.mul(lambdas[0]).x.cmp(this.g.x.redMul(beta)) === 0) { + lambda = lambdas[0]; + } else { + lambda = lambdas[1]; + assert(this.g.mul(lambda).x.cmp(this.g.x.redMul(beta)) === 0); + } + } + + // Get basis vectors, used for balanced length-two representation + var basis; + if (conf.basis) { + basis = conf.basis.map(function(vec) { + return { + a: new BN(vec.a, 16), + b: new BN(vec.b, 16), + }; + }); + } else { + basis = this._getEndoBasis(lambda); + } + + return { + beta: beta, + lambda: lambda, + basis: basis, + }; +}; + +ShortCurve.prototype._getEndoRoots = function _getEndoRoots(num) { + // Find roots of for x^2 + x + 1 in F + // Root = (-1 +- Sqrt(-3)) / 2 + // + var red = num === this.p ? this.red : BN.mont(num); + var tinv = new BN(2).toRed(red).redInvm(); + var ntinv = tinv.redNeg(); + + var s = new BN(3).toRed(red).redNeg().redSqrt().redMul(tinv); + + var l1 = ntinv.redAdd(s).fromRed(); + var l2 = ntinv.redSub(s).fromRed(); + return [ l1, l2 ]; +}; + +ShortCurve.prototype._getEndoBasis = function _getEndoBasis(lambda) { + // aprxSqrt >= sqrt(this.n) + var aprxSqrt = this.n.ushrn(Math.floor(this.n.bitLength() / 2)); + + // 3.74 + // Run EGCD, until r(L + 1) < aprxSqrt + var u = lambda; + var v = this.n.clone(); + var x1 = new BN(1); + var y1 = new BN(0); + var x2 = new BN(0); + var y2 = new BN(1); + + // NOTE: all vectors are roots of: a + b * lambda = 0 (mod n) + var a0; + var b0; + // First vector + var a1; + var b1; + // Second vector + var a2; + var b2; + + var prevR; + var i = 0; + var r; + var x; + while (u.cmpn(0) !== 0) { + var q = v.div(u); + r = v.sub(q.mul(u)); + x = x2.sub(q.mul(x1)); + var y = y2.sub(q.mul(y1)); + + if (!a1 && r.cmp(aprxSqrt) < 0) { + a0 = prevR.neg(); + b0 = x1; + a1 = r.neg(); + b1 = x; + } else if (a1 && ++i === 2) { + break; + } + prevR = r; + + v = u; + u = r; + x2 = x1; + x1 = x; + y2 = y1; + y1 = y; + } + a2 = r.neg(); + b2 = x; + + var len1 = a1.sqr().add(b1.sqr()); + var len2 = a2.sqr().add(b2.sqr()); + if (len2.cmp(len1) >= 0) { + a2 = a0; + b2 = b0; + } + + // Normalize signs + if (a1.negative) { + a1 = a1.neg(); + b1 = b1.neg(); + } + if (a2.negative) { + a2 = a2.neg(); + b2 = b2.neg(); + } + + return [ + { a: a1, b: b1 }, + { a: a2, b: b2 }, + ]; +}; + +ShortCurve.prototype._endoSplit = function _endoSplit(k) { + var basis = this.endo.basis; + var v1 = basis[0]; + var v2 = basis[1]; + + var c1 = v2.b.mul(k).divRound(this.n); + var c2 = v1.b.neg().mul(k).divRound(this.n); + + var p1 = c1.mul(v1.a); + var p2 = c2.mul(v2.a); + var q1 = c1.mul(v1.b); + var q2 = c2.mul(v2.b); + + // Calculate answer + var k1 = k.sub(p1).sub(p2); + var k2 = q1.add(q2).neg(); + return { k1: k1, k2: k2 }; +}; + +ShortCurve.prototype.pointFromX = function pointFromX(x, odd) { + x = new BN(x, 16); + if (!x.red) + x = x.toRed(this.red); + + var y2 = x.redSqr().redMul(x).redIAdd(x.redMul(this.a)).redIAdd(this.b); + var y = y2.redSqrt(); + if (y.redSqr().redSub(y2).cmp(this.zero) !== 0) + throw new Error('invalid point'); + + // XXX Is there any way to tell if the number is odd without converting it + // to non-red form? + var isOdd = y.fromRed().isOdd(); + if (odd && !isOdd || !odd && isOdd) + y = y.redNeg(); + + return this.point(x, y); +}; + +ShortCurve.prototype.validate = function validate(point) { + if (point.inf) + return true; + + var x = point.x; + var y = point.y; + + var ax = this.a.redMul(x); + var rhs = x.redSqr().redMul(x).redIAdd(ax).redIAdd(this.b); + return y.redSqr().redISub(rhs).cmpn(0) === 0; +}; + +ShortCurve.prototype._endoWnafMulAdd = + function _endoWnafMulAdd(points, coeffs, jacobianResult) { + var npoints = this._endoWnafT1; + var ncoeffs = this._endoWnafT2; + for (var i = 0; i < points.length; i++) { + var split = this._endoSplit(coeffs[i]); + var p = points[i]; + var beta = p._getBeta(); + + if (split.k1.negative) { + split.k1.ineg(); + p = p.neg(true); + } + if (split.k2.negative) { + split.k2.ineg(); + beta = beta.neg(true); + } + + npoints[i * 2] = p; + npoints[i * 2 + 1] = beta; + ncoeffs[i * 2] = split.k1; + ncoeffs[i * 2 + 1] = split.k2; + } + var res = this._wnafMulAdd(1, npoints, ncoeffs, i * 2, jacobianResult); + + // Clean-up references to points and coefficients + for (var j = 0; j < i * 2; j++) { + npoints[j] = null; + ncoeffs[j] = null; + } + return res; + }; + +function Point(curve, x, y, isRed) { + Base.BasePoint.call(this, curve, 'affine'); + if (x === null && y === null) { + this.x = null; + this.y = null; + this.inf = true; + } else { + this.x = new BN(x, 16); + this.y = new BN(y, 16); + // Force redgomery representation when loading from JSON + if (isRed) { + this.x.forceRed(this.curve.red); + this.y.forceRed(this.curve.red); + } + if (!this.x.red) + this.x = this.x.toRed(this.curve.red); + if (!this.y.red) + this.y = this.y.toRed(this.curve.red); + this.inf = false; + } +} +inherits(Point, Base.BasePoint); + +ShortCurve.prototype.point = function point(x, y, isRed) { + return new Point(this, x, y, isRed); +}; + +ShortCurve.prototype.pointFromJSON = function pointFromJSON(obj, red) { + return Point.fromJSON(this, obj, red); +}; + +Point.prototype._getBeta = function _getBeta() { + if (!this.curve.endo) + return; + + var pre = this.precomputed; + if (pre && pre.beta) + return pre.beta; + + var beta = this.curve.point(this.x.redMul(this.curve.endo.beta), this.y); + if (pre) { + var curve = this.curve; + var endoMul = function(p) { + return curve.point(p.x.redMul(curve.endo.beta), p.y); + }; + pre.beta = beta; + beta.precomputed = { + beta: null, + naf: pre.naf && { + wnd: pre.naf.wnd, + points: pre.naf.points.map(endoMul), + }, + doubles: pre.doubles && { + step: pre.doubles.step, + points: pre.doubles.points.map(endoMul), + }, + }; + } + return beta; +}; + +Point.prototype.toJSON = function toJSON() { + if (!this.precomputed) + return [ this.x, this.y ]; + + return [ this.x, this.y, this.precomputed && { + doubles: this.precomputed.doubles && { + step: this.precomputed.doubles.step, + points: this.precomputed.doubles.points.slice(1), + }, + naf: this.precomputed.naf && { + wnd: this.precomputed.naf.wnd, + points: this.precomputed.naf.points.slice(1), + }, + } ]; +}; + +Point.fromJSON = function fromJSON(curve, obj, red) { + if (typeof obj === 'string') + obj = JSON.parse(obj); + var res = curve.point(obj[0], obj[1], red); + if (!obj[2]) + return res; + + function obj2point(obj) { + return curve.point(obj[0], obj[1], red); + } + + var pre = obj[2]; + res.precomputed = { + beta: null, + doubles: pre.doubles && { + step: pre.doubles.step, + points: [ res ].concat(pre.doubles.points.map(obj2point)), + }, + naf: pre.naf && { + wnd: pre.naf.wnd, + points: [ res ].concat(pre.naf.points.map(obj2point)), + }, + }; + return res; +}; + +Point.prototype.inspect = function inspect() { + if (this.isInfinity()) + return ''; + return ''; +}; + +Point.prototype.isInfinity = function isInfinity() { + return this.inf; +}; + +Point.prototype.add = function add(p) { + // O + P = P + if (this.inf) + return p; + + // P + O = P + if (p.inf) + return this; + + // P + P = 2P + if (this.eq(p)) + return this.dbl(); + + // P + (-P) = O + if (this.neg().eq(p)) + return this.curve.point(null, null); + + // P + Q = O + if (this.x.cmp(p.x) === 0) + return this.curve.point(null, null); + + var c = this.y.redSub(p.y); + if (c.cmpn(0) !== 0) + c = c.redMul(this.x.redSub(p.x).redInvm()); + var nx = c.redSqr().redISub(this.x).redISub(p.x); + var ny = c.redMul(this.x.redSub(nx)).redISub(this.y); + return this.curve.point(nx, ny); +}; + +Point.prototype.dbl = function dbl() { + if (this.inf) + return this; + + // 2P = O + var ys1 = this.y.redAdd(this.y); + if (ys1.cmpn(0) === 0) + return this.curve.point(null, null); + + var a = this.curve.a; + + var x2 = this.x.redSqr(); + var dyinv = ys1.redInvm(); + var c = x2.redAdd(x2).redIAdd(x2).redIAdd(a).redMul(dyinv); + + var nx = c.redSqr().redISub(this.x.redAdd(this.x)); + var ny = c.redMul(this.x.redSub(nx)).redISub(this.y); + return this.curve.point(nx, ny); +}; + +Point.prototype.getX = function getX() { + return this.x.fromRed(); +}; + +Point.prototype.getY = function getY() { + return this.y.fromRed(); +}; + +Point.prototype.mul = function mul(k) { + k = new BN(k, 16); + if (this.isInfinity()) + return this; + else if (this._hasDoubles(k)) + return this.curve._fixedNafMul(this, k); + else if (this.curve.endo) + return this.curve._endoWnafMulAdd([ this ], [ k ]); + else + return this.curve._wnafMul(this, k); +}; + +Point.prototype.mulAdd = function mulAdd(k1, p2, k2) { + var points = [ this, p2 ]; + var coeffs = [ k1, k2 ]; + if (this.curve.endo) + return this.curve._endoWnafMulAdd(points, coeffs); + else + return this.curve._wnafMulAdd(1, points, coeffs, 2); +}; + +Point.prototype.jmulAdd = function jmulAdd(k1, p2, k2) { + var points = [ this, p2 ]; + var coeffs = [ k1, k2 ]; + if (this.curve.endo) + return this.curve._endoWnafMulAdd(points, coeffs, true); + else + return this.curve._wnafMulAdd(1, points, coeffs, 2, true); +}; + +Point.prototype.eq = function eq(p) { + return this === p || + this.inf === p.inf && + (this.inf || this.x.cmp(p.x) === 0 && this.y.cmp(p.y) === 0); +}; + +Point.prototype.neg = function neg(_precompute) { + if (this.inf) + return this; + + var res = this.curve.point(this.x, this.y.redNeg()); + if (_precompute && this.precomputed) { + var pre = this.precomputed; + var negate = function(p) { + return p.neg(); + }; + res.precomputed = { + naf: pre.naf && { + wnd: pre.naf.wnd, + points: pre.naf.points.map(negate), + }, + doubles: pre.doubles && { + step: pre.doubles.step, + points: pre.doubles.points.map(negate), + }, + }; + } + return res; +}; + +Point.prototype.toJ = function toJ() { + if (this.inf) + return this.curve.jpoint(null, null, null); + + var res = this.curve.jpoint(this.x, this.y, this.curve.one); + return res; +}; + +function JPoint(curve, x, y, z) { + Base.BasePoint.call(this, curve, 'jacobian'); + if (x === null && y === null && z === null) { + this.x = this.curve.one; + this.y = this.curve.one; + this.z = new BN(0); + } else { + this.x = new BN(x, 16); + this.y = new BN(y, 16); + this.z = new BN(z, 16); + } + if (!this.x.red) + this.x = this.x.toRed(this.curve.red); + if (!this.y.red) + this.y = this.y.toRed(this.curve.red); + if (!this.z.red) + this.z = this.z.toRed(this.curve.red); + + this.zOne = this.z === this.curve.one; +} +inherits(JPoint, Base.BasePoint); + +ShortCurve.prototype.jpoint = function jpoint(x, y, z) { + return new JPoint(this, x, y, z); +}; + +JPoint.prototype.toP = function toP() { + if (this.isInfinity()) + return this.curve.point(null, null); + + var zinv = this.z.redInvm(); + var zinv2 = zinv.redSqr(); + var ax = this.x.redMul(zinv2); + var ay = this.y.redMul(zinv2).redMul(zinv); + + return this.curve.point(ax, ay); +}; + +JPoint.prototype.neg = function neg() { + return this.curve.jpoint(this.x, this.y.redNeg(), this.z); +}; + +JPoint.prototype.add = function add(p) { + // O + P = P + if (this.isInfinity()) + return p; + + // P + O = P + if (p.isInfinity()) + return this; + + // 12M + 4S + 7A + var pz2 = p.z.redSqr(); + var z2 = this.z.redSqr(); + var u1 = this.x.redMul(pz2); + var u2 = p.x.redMul(z2); + var s1 = this.y.redMul(pz2.redMul(p.z)); + var s2 = p.y.redMul(z2.redMul(this.z)); + + var h = u1.redSub(u2); + var r = s1.redSub(s2); + if (h.cmpn(0) === 0) { + if (r.cmpn(0) !== 0) + return this.curve.jpoint(null, null, null); + else + return this.dbl(); + } + + var h2 = h.redSqr(); + var h3 = h2.redMul(h); + var v = u1.redMul(h2); + + var nx = r.redSqr().redIAdd(h3).redISub(v).redISub(v); + var ny = r.redMul(v.redISub(nx)).redISub(s1.redMul(h3)); + var nz = this.z.redMul(p.z).redMul(h); + + return this.curve.jpoint(nx, ny, nz); +}; + +JPoint.prototype.mixedAdd = function mixedAdd(p) { + // O + P = P + if (this.isInfinity()) + return p.toJ(); + + // P + O = P + if (p.isInfinity()) + return this; + + // 8M + 3S + 7A + var z2 = this.z.redSqr(); + var u1 = this.x; + var u2 = p.x.redMul(z2); + var s1 = this.y; + var s2 = p.y.redMul(z2).redMul(this.z); + + var h = u1.redSub(u2); + var r = s1.redSub(s2); + if (h.cmpn(0) === 0) { + if (r.cmpn(0) !== 0) + return this.curve.jpoint(null, null, null); + else + return this.dbl(); + } + + var h2 = h.redSqr(); + var h3 = h2.redMul(h); + var v = u1.redMul(h2); + + var nx = r.redSqr().redIAdd(h3).redISub(v).redISub(v); + var ny = r.redMul(v.redISub(nx)).redISub(s1.redMul(h3)); + var nz = this.z.redMul(h); + + return this.curve.jpoint(nx, ny, nz); +}; + +JPoint.prototype.dblp = function dblp(pow) { + if (pow === 0) + return this; + if (this.isInfinity()) + return this; + if (!pow) + return this.dbl(); + + var i; + if (this.curve.zeroA || this.curve.threeA) { + var r = this; + for (i = 0; i < pow; i++) + r = r.dbl(); + return r; + } + + // 1M + 2S + 1A + N * (4S + 5M + 8A) + // N = 1 => 6M + 6S + 9A + var a = this.curve.a; + var tinv = this.curve.tinv; + + var jx = this.x; + var jy = this.y; + var jz = this.z; + var jz4 = jz.redSqr().redSqr(); + + // Reuse results + var jyd = jy.redAdd(jy); + for (i = 0; i < pow; i++) { + var jx2 = jx.redSqr(); + var jyd2 = jyd.redSqr(); + var jyd4 = jyd2.redSqr(); + var c = jx2.redAdd(jx2).redIAdd(jx2).redIAdd(a.redMul(jz4)); + + var t1 = jx.redMul(jyd2); + var nx = c.redSqr().redISub(t1.redAdd(t1)); + var t2 = t1.redISub(nx); + var dny = c.redMul(t2); + dny = dny.redIAdd(dny).redISub(jyd4); + var nz = jyd.redMul(jz); + if (i + 1 < pow) + jz4 = jz4.redMul(jyd4); + + jx = nx; + jz = nz; + jyd = dny; + } + + return this.curve.jpoint(jx, jyd.redMul(tinv), jz); +}; + +JPoint.prototype.dbl = function dbl() { + if (this.isInfinity()) + return this; + + if (this.curve.zeroA) + return this._zeroDbl(); + else if (this.curve.threeA) + return this._threeDbl(); + else + return this._dbl(); +}; + +JPoint.prototype._zeroDbl = function _zeroDbl() { + var nx; + var ny; + var nz; + // Z = 1 + if (this.zOne) { + // hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html + // #doubling-mdbl-2007-bl + // 1M + 5S + 14A + + // XX = X1^2 + var xx = this.x.redSqr(); + // YY = Y1^2 + var yy = this.y.redSqr(); + // YYYY = YY^2 + var yyyy = yy.redSqr(); + // S = 2 * ((X1 + YY)^2 - XX - YYYY) + var s = this.x.redAdd(yy).redSqr().redISub(xx).redISub(yyyy); + s = s.redIAdd(s); + // M = 3 * XX + a; a = 0 + var m = xx.redAdd(xx).redIAdd(xx); + // T = M ^ 2 - 2*S + var t = m.redSqr().redISub(s).redISub(s); + + // 8 * YYYY + var yyyy8 = yyyy.redIAdd(yyyy); + yyyy8 = yyyy8.redIAdd(yyyy8); + yyyy8 = yyyy8.redIAdd(yyyy8); + + // X3 = T + nx = t; + // Y3 = M * (S - T) - 8 * YYYY + ny = m.redMul(s.redISub(t)).redISub(yyyy8); + // Z3 = 2*Y1 + nz = this.y.redAdd(this.y); + } else { + // hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html + // #doubling-dbl-2009-l + // 2M + 5S + 13A + + // A = X1^2 + var a = this.x.redSqr(); + // B = Y1^2 + var b = this.y.redSqr(); + // C = B^2 + var c = b.redSqr(); + // D = 2 * ((X1 + B)^2 - A - C) + var d = this.x.redAdd(b).redSqr().redISub(a).redISub(c); + d = d.redIAdd(d); + // E = 3 * A + var e = a.redAdd(a).redIAdd(a); + // F = E^2 + var f = e.redSqr(); + + // 8 * C + var c8 = c.redIAdd(c); + c8 = c8.redIAdd(c8); + c8 = c8.redIAdd(c8); + + // X3 = F - 2 * D + nx = f.redISub(d).redISub(d); + // Y3 = E * (D - X3) - 8 * C + ny = e.redMul(d.redISub(nx)).redISub(c8); + // Z3 = 2 * Y1 * Z1 + nz = this.y.redMul(this.z); + nz = nz.redIAdd(nz); + } + + return this.curve.jpoint(nx, ny, nz); +}; + +JPoint.prototype._threeDbl = function _threeDbl() { + var nx; + var ny; + var nz; + // Z = 1 + if (this.zOne) { + // hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-3.html + // #doubling-mdbl-2007-bl + // 1M + 5S + 15A + + // XX = X1^2 + var xx = this.x.redSqr(); + // YY = Y1^2 + var yy = this.y.redSqr(); + // YYYY = YY^2 + var yyyy = yy.redSqr(); + // S = 2 * ((X1 + YY)^2 - XX - YYYY) + var s = this.x.redAdd(yy).redSqr().redISub(xx).redISub(yyyy); + s = s.redIAdd(s); + // M = 3 * XX + a + var m = xx.redAdd(xx).redIAdd(xx).redIAdd(this.curve.a); + // T = M^2 - 2 * S + var t = m.redSqr().redISub(s).redISub(s); + // X3 = T + nx = t; + // Y3 = M * (S - T) - 8 * YYYY + var yyyy8 = yyyy.redIAdd(yyyy); + yyyy8 = yyyy8.redIAdd(yyyy8); + yyyy8 = yyyy8.redIAdd(yyyy8); + ny = m.redMul(s.redISub(t)).redISub(yyyy8); + // Z3 = 2 * Y1 + nz = this.y.redAdd(this.y); + } else { + // hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-3.html#doubling-dbl-2001-b + // 3M + 5S + + // delta = Z1^2 + var delta = this.z.redSqr(); + // gamma = Y1^2 + var gamma = this.y.redSqr(); + // beta = X1 * gamma + var beta = this.x.redMul(gamma); + // alpha = 3 * (X1 - delta) * (X1 + delta) + var alpha = this.x.redSub(delta).redMul(this.x.redAdd(delta)); + alpha = alpha.redAdd(alpha).redIAdd(alpha); + // X3 = alpha^2 - 8 * beta + var beta4 = beta.redIAdd(beta); + beta4 = beta4.redIAdd(beta4); + var beta8 = beta4.redAdd(beta4); + nx = alpha.redSqr().redISub(beta8); + // Z3 = (Y1 + Z1)^2 - gamma - delta + nz = this.y.redAdd(this.z).redSqr().redISub(gamma).redISub(delta); + // Y3 = alpha * (4 * beta - X3) - 8 * gamma^2 + var ggamma8 = gamma.redSqr(); + ggamma8 = ggamma8.redIAdd(ggamma8); + ggamma8 = ggamma8.redIAdd(ggamma8); + ggamma8 = ggamma8.redIAdd(ggamma8); + ny = alpha.redMul(beta4.redISub(nx)).redISub(ggamma8); + } + + return this.curve.jpoint(nx, ny, nz); +}; + +JPoint.prototype._dbl = function _dbl() { + var a = this.curve.a; + + // 4M + 6S + 10A + var jx = this.x; + var jy = this.y; + var jz = this.z; + var jz4 = jz.redSqr().redSqr(); + + var jx2 = jx.redSqr(); + var jy2 = jy.redSqr(); + + var c = jx2.redAdd(jx2).redIAdd(jx2).redIAdd(a.redMul(jz4)); + + var jxd4 = jx.redAdd(jx); + jxd4 = jxd4.redIAdd(jxd4); + var t1 = jxd4.redMul(jy2); + var nx = c.redSqr().redISub(t1.redAdd(t1)); + var t2 = t1.redISub(nx); + + var jyd8 = jy2.redSqr(); + jyd8 = jyd8.redIAdd(jyd8); + jyd8 = jyd8.redIAdd(jyd8); + jyd8 = jyd8.redIAdd(jyd8); + var ny = c.redMul(t2).redISub(jyd8); + var nz = jy.redAdd(jy).redMul(jz); + + return this.curve.jpoint(nx, ny, nz); +}; + +JPoint.prototype.trpl = function trpl() { + if (!this.curve.zeroA) + return this.dbl().add(this); + + // hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html#tripling-tpl-2007-bl + // 5M + 10S + ... + + // XX = X1^2 + var xx = this.x.redSqr(); + // YY = Y1^2 + var yy = this.y.redSqr(); + // ZZ = Z1^2 + var zz = this.z.redSqr(); + // YYYY = YY^2 + var yyyy = yy.redSqr(); + // M = 3 * XX + a * ZZ2; a = 0 + var m = xx.redAdd(xx).redIAdd(xx); + // MM = M^2 + var mm = m.redSqr(); + // E = 6 * ((X1 + YY)^2 - XX - YYYY) - MM + var e = this.x.redAdd(yy).redSqr().redISub(xx).redISub(yyyy); + e = e.redIAdd(e); + e = e.redAdd(e).redIAdd(e); + e = e.redISub(mm); + // EE = E^2 + var ee = e.redSqr(); + // T = 16*YYYY + var t = yyyy.redIAdd(yyyy); + t = t.redIAdd(t); + t = t.redIAdd(t); + t = t.redIAdd(t); + // U = (M + E)^2 - MM - EE - T + var u = m.redIAdd(e).redSqr().redISub(mm).redISub(ee).redISub(t); + // X3 = 4 * (X1 * EE - 4 * YY * U) + var yyu4 = yy.redMul(u); + yyu4 = yyu4.redIAdd(yyu4); + yyu4 = yyu4.redIAdd(yyu4); + var nx = this.x.redMul(ee).redISub(yyu4); + nx = nx.redIAdd(nx); + nx = nx.redIAdd(nx); + // Y3 = 8 * Y1 * (U * (T - U) - E * EE) + var ny = this.y.redMul(u.redMul(t.redISub(u)).redISub(e.redMul(ee))); + ny = ny.redIAdd(ny); + ny = ny.redIAdd(ny); + ny = ny.redIAdd(ny); + // Z3 = (Z1 + E)^2 - ZZ - EE + var nz = this.z.redAdd(e).redSqr().redISub(zz).redISub(ee); + + return this.curve.jpoint(nx, ny, nz); +}; + +JPoint.prototype.mul = function mul(k, kbase) { + k = new BN(k, kbase); + + return this.curve._wnafMul(this, k); +}; + +JPoint.prototype.eq = function eq(p) { + if (p.type === 'affine') + return this.eq(p.toJ()); + + if (this === p) + return true; + + // x1 * z2^2 == x2 * z1^2 + var z2 = this.z.redSqr(); + var pz2 = p.z.redSqr(); + if (this.x.redMul(pz2).redISub(p.x.redMul(z2)).cmpn(0) !== 0) + return false; + + // y1 * z2^3 == y2 * z1^3 + var z3 = z2.redMul(this.z); + var pz3 = pz2.redMul(p.z); + return this.y.redMul(pz3).redISub(p.y.redMul(z3)).cmpn(0) === 0; +}; + +JPoint.prototype.eqXToP = function eqXToP(x) { + var zs = this.z.redSqr(); + var rx = x.toRed(this.curve.red).redMul(zs); + if (this.x.cmp(rx) === 0) + return true; + + var xc = x.clone(); + var t = this.curve.redN.redMul(zs); + for (;;) { + xc.iadd(this.curve.n); + if (xc.cmp(this.curve.p) >= 0) + return false; + + rx.redIAdd(t); + if (this.x.cmp(rx) === 0) + return true; + } +}; + +JPoint.prototype.inspect = function inspect() { + if (this.isInfinity()) + return ''; + return ''; +}; + +JPoint.prototype.isInfinity = function isInfinity() { + // XXX This code assumes that zero is always zero in red + return this.z.cmpn(0) === 0; +}; + +},{"../utils":97,"./base":84,"bn.js":98,"inherits":132}],89:[function(require,module,exports){ +'use strict'; + +var curves = exports; + +var hash = require('hash.js'); +var curve = require('./curve'); +var utils = require('./utils'); + +var assert = utils.assert; + +function PresetCurve(options) { + if (options.type === 'short') + this.curve = new curve.short(options); + else if (options.type === 'edwards') + this.curve = new curve.edwards(options); + else + this.curve = new curve.mont(options); + this.g = this.curve.g; + this.n = this.curve.n; + this.hash = options.hash; + + assert(this.g.validate(), 'Invalid curve'); + assert(this.g.mul(this.n).isInfinity(), 'Invalid curve, G*N != O'); +} +curves.PresetCurve = PresetCurve; + +function defineCurve(name, options) { + Object.defineProperty(curves, name, { + configurable: true, + enumerable: true, + get: function() { + var curve = new PresetCurve(options); + Object.defineProperty(curves, name, { + configurable: true, + enumerable: true, + value: curve, + }); + return curve; + }, + }); +} + +defineCurve('p192', { + type: 'short', + prime: 'p192', + p: 'ffffffff ffffffff ffffffff fffffffe ffffffff ffffffff', + a: 'ffffffff ffffffff ffffffff fffffffe ffffffff fffffffc', + b: '64210519 e59c80e7 0fa7e9ab 72243049 feb8deec c146b9b1', + n: 'ffffffff ffffffff ffffffff 99def836 146bc9b1 b4d22831', + hash: hash.sha256, + gRed: false, + g: [ + '188da80e b03090f6 7cbf20eb 43a18800 f4ff0afd 82ff1012', + '07192b95 ffc8da78 631011ed 6b24cdd5 73f977a1 1e794811', + ], +}); + +defineCurve('p224', { + type: 'short', + prime: 'p224', + p: 'ffffffff ffffffff ffffffff ffffffff 00000000 00000000 00000001', + a: 'ffffffff ffffffff ffffffff fffffffe ffffffff ffffffff fffffffe', + b: 'b4050a85 0c04b3ab f5413256 5044b0b7 d7bfd8ba 270b3943 2355ffb4', + n: 'ffffffff ffffffff ffffffff ffff16a2 e0b8f03e 13dd2945 5c5c2a3d', + hash: hash.sha256, + gRed: false, + g: [ + 'b70e0cbd 6bb4bf7f 321390b9 4a03c1d3 56c21122 343280d6 115c1d21', + 'bd376388 b5f723fb 4c22dfe6 cd4375a0 5a074764 44d58199 85007e34', + ], +}); + +defineCurve('p256', { + type: 'short', + prime: null, + p: 'ffffffff 00000001 00000000 00000000 00000000 ffffffff ffffffff ffffffff', + a: 'ffffffff 00000001 00000000 00000000 00000000 ffffffff ffffffff fffffffc', + b: '5ac635d8 aa3a93e7 b3ebbd55 769886bc 651d06b0 cc53b0f6 3bce3c3e 27d2604b', + n: 'ffffffff 00000000 ffffffff ffffffff bce6faad a7179e84 f3b9cac2 fc632551', + hash: hash.sha256, + gRed: false, + g: [ + '6b17d1f2 e12c4247 f8bce6e5 63a440f2 77037d81 2deb33a0 f4a13945 d898c296', + '4fe342e2 fe1a7f9b 8ee7eb4a 7c0f9e16 2bce3357 6b315ece cbb64068 37bf51f5', + ], +}); + +defineCurve('p384', { + type: 'short', + prime: null, + p: 'ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ' + + 'fffffffe ffffffff 00000000 00000000 ffffffff', + a: 'ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ' + + 'fffffffe ffffffff 00000000 00000000 fffffffc', + b: 'b3312fa7 e23ee7e4 988e056b e3f82d19 181d9c6e fe814112 0314088f ' + + '5013875a c656398d 8a2ed19d 2a85c8ed d3ec2aef', + n: 'ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff c7634d81 ' + + 'f4372ddf 581a0db2 48b0a77a ecec196a ccc52973', + hash: hash.sha384, + gRed: false, + g: [ + 'aa87ca22 be8b0537 8eb1c71e f320ad74 6e1d3b62 8ba79b98 59f741e0 82542a38 ' + + '5502f25d bf55296c 3a545e38 72760ab7', + '3617de4a 96262c6f 5d9e98bf 9292dc29 f8f41dbd 289a147c e9da3113 b5f0b8c0 ' + + '0a60b1ce 1d7e819d 7a431d7c 90ea0e5f', + ], +}); + +defineCurve('p521', { + type: 'short', + prime: null, + p: '000001ff ffffffff ffffffff ffffffff ffffffff ffffffff ' + + 'ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ' + + 'ffffffff ffffffff ffffffff ffffffff ffffffff', + a: '000001ff ffffffff ffffffff ffffffff ffffffff ffffffff ' + + 'ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ' + + 'ffffffff ffffffff ffffffff ffffffff fffffffc', + b: '00000051 953eb961 8e1c9a1f 929a21a0 b68540ee a2da725b ' + + '99b315f3 b8b48991 8ef109e1 56193951 ec7e937b 1652c0bd ' + + '3bb1bf07 3573df88 3d2c34f1 ef451fd4 6b503f00', + n: '000001ff ffffffff ffffffff ffffffff ffffffff ffffffff ' + + 'ffffffff ffffffff fffffffa 51868783 bf2f966b 7fcc0148 ' + + 'f709a5d0 3bb5c9b8 899c47ae bb6fb71e 91386409', + hash: hash.sha512, + gRed: false, + g: [ + '000000c6 858e06b7 0404e9cd 9e3ecb66 2395b442 9c648139 ' + + '053fb521 f828af60 6b4d3dba a14b5e77 efe75928 fe1dc127 ' + + 'a2ffa8de 3348b3c1 856a429b f97e7e31 c2e5bd66', + '00000118 39296a78 9a3bc004 5c8a5fb4 2c7d1bd9 98f54449 ' + + '579b4468 17afbd17 273e662c 97ee7299 5ef42640 c550b901 ' + + '3fad0761 353c7086 a272c240 88be9476 9fd16650', + ], +}); + +defineCurve('curve25519', { + type: 'mont', + prime: 'p25519', + p: '7fffffffffffffff ffffffffffffffff ffffffffffffffff ffffffffffffffed', + a: '76d06', + b: '1', + n: '1000000000000000 0000000000000000 14def9dea2f79cd6 5812631a5cf5d3ed', + hash: hash.sha256, + gRed: false, + g: [ + '9', + ], +}); + +defineCurve('ed25519', { + type: 'edwards', + prime: 'p25519', + p: '7fffffffffffffff ffffffffffffffff ffffffffffffffff ffffffffffffffed', + a: '-1', + c: '1', + // -121665 * (121666^(-1)) (mod P) + d: '52036cee2b6ffe73 8cc740797779e898 00700a4d4141d8ab 75eb4dca135978a3', + n: '1000000000000000 0000000000000000 14def9dea2f79cd6 5812631a5cf5d3ed', + hash: hash.sha256, + gRed: false, + g: [ + '216936d3cd6e53fec0a4e231fdd6dc5c692cc7609525a7b2c9562d608f25d51a', + + // 4/5 + '6666666666666666666666666666666666666666666666666666666666666658', + ], +}); + +var pre; +try { + pre = require('./precomputed/secp256k1'); +} catch (e) { + pre = undefined; +} + +defineCurve('secp256k1', { + type: 'short', + prime: 'k256', + p: 'ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff fffffffe fffffc2f', + a: '0', + b: '7', + n: 'ffffffff ffffffff ffffffff fffffffe baaedce6 af48a03b bfd25e8c d0364141', + h: '1', + hash: hash.sha256, + + // Precomputed endomorphism + beta: '7ae96a2b657c07106e64479eac3434e99cf0497512f58995c1396c28719501ee', + lambda: '5363ad4cc05c30e0a5261c028812645a122e22ea20816678df02967c1b23bd72', + basis: [ + { + a: '3086d221a7d46bcde86c90e49284eb15', + b: '-e4437ed6010e88286f547fa90abfe4c3', + }, + { + a: '114ca50f7a8e2f3f657c1108d9d44cfd8', + b: '3086d221a7d46bcde86c90e49284eb15', + }, + ], + + gRed: false, + g: [ + '79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798', + '483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8', + pre, + ], +}); + +},{"./curve":86,"./precomputed/secp256k1":96,"./utils":97,"hash.js":118}],90:[function(require,module,exports){ +'use strict'; + +var BN = require('bn.js'); +var HmacDRBG = require('hmac-drbg'); +var utils = require('../utils'); +var curves = require('../curves'); +var rand = require('brorand'); +var assert = utils.assert; + +var KeyPair = require('./key'); +var Signature = require('./signature'); + +function EC(options) { + if (!(this instanceof EC)) + return new EC(options); + + // Shortcut `elliptic.ec(curve-name)` + if (typeof options === 'string') { + assert(Object.prototype.hasOwnProperty.call(curves, options), + 'Unknown curve ' + options); + + options = curves[options]; + } + + // Shortcut for `elliptic.ec(elliptic.curves.curveName)` + if (options instanceof curves.PresetCurve) + options = { curve: options }; + + this.curve = options.curve.curve; + this.n = this.curve.n; + this.nh = this.n.ushrn(1); + this.g = this.curve.g; + + // Point on curve + this.g = options.curve.g; + this.g.precompute(options.curve.n.bitLength() + 1); + + // Hash for function for DRBG + this.hash = options.hash || options.curve.hash; +} +module.exports = EC; + +EC.prototype.keyPair = function keyPair(options) { + return new KeyPair(this, options); +}; + +EC.prototype.keyFromPrivate = function keyFromPrivate(priv, enc) { + return KeyPair.fromPrivate(this, priv, enc); +}; + +EC.prototype.keyFromPublic = function keyFromPublic(pub, enc) { + return KeyPair.fromPublic(this, pub, enc); +}; + +EC.prototype.genKeyPair = function genKeyPair(options) { + if (!options) + options = {}; + + // Instantiate Hmac_DRBG + var drbg = new HmacDRBG({ + hash: this.hash, + pers: options.pers, + persEnc: options.persEnc || 'utf8', + entropy: options.entropy || rand(this.hash.hmacStrength), + entropyEnc: options.entropy && options.entropyEnc || 'utf8', + nonce: this.n.toArray(), + }); + + var bytes = this.n.byteLength(); + var ns2 = this.n.sub(new BN(2)); + for (;;) { + var priv = new BN(drbg.generate(bytes)); + if (priv.cmp(ns2) > 0) + continue; + + priv.iaddn(1); + return this.keyFromPrivate(priv); + } +}; + +EC.prototype._truncateToN = function _truncateToN(msg, truncOnly) { + var delta = msg.byteLength() * 8 - this.n.bitLength(); + if (delta > 0) + msg = msg.ushrn(delta); + if (!truncOnly && msg.cmp(this.n) >= 0) + return msg.sub(this.n); + else + return msg; +}; + +EC.prototype.sign = function sign(msg, key, enc, options) { + if (typeof enc === 'object') { + options = enc; + enc = null; + } + if (!options) + options = {}; + + key = this.keyFromPrivate(key, enc); + msg = this._truncateToN(new BN(msg, 16)); + + // Zero-extend key to provide enough entropy + var bytes = this.n.byteLength(); + var bkey = key.getPrivate().toArray('be', bytes); + + // Zero-extend nonce to have the same byte size as N + var nonce = msg.toArray('be', bytes); + + // Instantiate Hmac_DRBG + var drbg = new HmacDRBG({ + hash: this.hash, + entropy: bkey, + nonce: nonce, + pers: options.pers, + persEnc: options.persEnc || 'utf8', + }); + + // Number of bytes to generate + var ns1 = this.n.sub(new BN(1)); + + for (var iter = 0; ; iter++) { + var k = options.k ? + options.k(iter) : + new BN(drbg.generate(this.n.byteLength())); + k = this._truncateToN(k, true); + if (k.cmpn(1) <= 0 || k.cmp(ns1) >= 0) + continue; + + var kp = this.g.mul(k); + if (kp.isInfinity()) + continue; + + var kpX = kp.getX(); + var r = kpX.umod(this.n); + if (r.cmpn(0) === 0) + continue; + + var s = k.invm(this.n).mul(r.mul(key.getPrivate()).iadd(msg)); + s = s.umod(this.n); + if (s.cmpn(0) === 0) + continue; + + var recoveryParam = (kp.getY().isOdd() ? 1 : 0) | + (kpX.cmp(r) !== 0 ? 2 : 0); + + // Use complement of `s`, if it is > `n / 2` + if (options.canonical && s.cmp(this.nh) > 0) { + s = this.n.sub(s); + recoveryParam ^= 1; + } + + return new Signature({ r: r, s: s, recoveryParam: recoveryParam }); + } +}; + +EC.prototype.verify = function verify(msg, signature, key, enc) { + msg = this._truncateToN(new BN(msg, 16)); + key = this.keyFromPublic(key, enc); + signature = new Signature(signature, 'hex'); + + // Perform primitive values validation + var r = signature.r; + var s = signature.s; + if (r.cmpn(1) < 0 || r.cmp(this.n) >= 0) + return false; + if (s.cmpn(1) < 0 || s.cmp(this.n) >= 0) + return false; + + // Validate signature + var sinv = s.invm(this.n); + var u1 = sinv.mul(msg).umod(this.n); + var u2 = sinv.mul(r).umod(this.n); + var p; + + if (!this.curve._maxwellTrick) { + p = this.g.mulAdd(u1, key.getPublic(), u2); + if (p.isInfinity()) + return false; + + return p.getX().umod(this.n).cmp(r) === 0; + } + + // NOTE: Greg Maxwell's trick, inspired by: + // https://git.io/vad3K + + p = this.g.jmulAdd(u1, key.getPublic(), u2); + if (p.isInfinity()) + return false; + + // Compare `p.x` of Jacobian point with `r`, + // this will do `p.x == r * p.z^2` instead of multiplying `p.x` by the + // inverse of `p.z^2` + return p.eqXToP(r); +}; + +EC.prototype.recoverPubKey = function(msg, signature, j, enc) { + assert((3 & j) === j, 'The recovery param is more than two bits'); + signature = new Signature(signature, enc); + + var n = this.n; + var e = new BN(msg); + var r = signature.r; + var s = signature.s; + + // A set LSB signifies that the y-coordinate is odd + var isYOdd = j & 1; + var isSecondKey = j >> 1; + if (r.cmp(this.curve.p.umod(this.curve.n)) >= 0 && isSecondKey) + throw new Error('Unable to find sencond key candinate'); + + // 1.1. Let x = r + jn. + if (isSecondKey) + r = this.curve.pointFromX(r.add(this.curve.n), isYOdd); + else + r = this.curve.pointFromX(r, isYOdd); + + var rInv = signature.r.invm(n); + var s1 = n.sub(e).mul(rInv).umod(n); + var s2 = s.mul(rInv).umod(n); + + // 1.6.1 Compute Q = r^-1 (sR - eG) + // Q = r^-1 (sR + -eG) + return this.g.mulAdd(s1, r, s2); +}; + +EC.prototype.getKeyRecoveryParam = function(e, signature, Q, enc) { + signature = new Signature(signature, enc); + if (signature.recoveryParam !== null) + return signature.recoveryParam; + + for (var i = 0; i < 4; i++) { + var Qprime; + try { + Qprime = this.recoverPubKey(e, signature, i); + } catch (e) { + continue; + } + + if (Qprime.eq(Q)) + return i; + } + throw new Error('Unable to find valid recovery factor'); +}; + +},{"../curves":89,"../utils":97,"./key":91,"./signature":92,"bn.js":98,"brorand":18,"hmac-drbg":130}],91:[function(require,module,exports){ +'use strict'; + +var BN = require('bn.js'); +var utils = require('../utils'); +var assert = utils.assert; + +function KeyPair(ec, options) { + this.ec = ec; + this.priv = null; + this.pub = null; + + // KeyPair(ec, { priv: ..., pub: ... }) + if (options.priv) + this._importPrivate(options.priv, options.privEnc); + if (options.pub) + this._importPublic(options.pub, options.pubEnc); +} +module.exports = KeyPair; + +KeyPair.fromPublic = function fromPublic(ec, pub, enc) { + if (pub instanceof KeyPair) + return pub; + + return new KeyPair(ec, { + pub: pub, + pubEnc: enc, + }); +}; + +KeyPair.fromPrivate = function fromPrivate(ec, priv, enc) { + if (priv instanceof KeyPair) + return priv; + + return new KeyPair(ec, { + priv: priv, + privEnc: enc, + }); +}; + +KeyPair.prototype.validate = function validate() { + var pub = this.getPublic(); + + if (pub.isInfinity()) + return { result: false, reason: 'Invalid public key' }; + if (!pub.validate()) + return { result: false, reason: 'Public key is not a point' }; + if (!pub.mul(this.ec.curve.n).isInfinity()) + return { result: false, reason: 'Public key * N != O' }; + + return { result: true, reason: null }; +}; + +KeyPair.prototype.getPublic = function getPublic(compact, enc) { + // compact is optional argument + if (typeof compact === 'string') { + enc = compact; + compact = null; + } + + if (!this.pub) + this.pub = this.ec.g.mul(this.priv); + + if (!enc) + return this.pub; + + return this.pub.encode(enc, compact); +}; + +KeyPair.prototype.getPrivate = function getPrivate(enc) { + if (enc === 'hex') + return this.priv.toString(16, 2); + else + return this.priv; +}; + +KeyPair.prototype._importPrivate = function _importPrivate(key, enc) { + this.priv = new BN(key, enc || 16); + + // Ensure that the priv won't be bigger than n, otherwise we may fail + // in fixed multiplication method + this.priv = this.priv.umod(this.ec.curve.n); +}; + +KeyPair.prototype._importPublic = function _importPublic(key, enc) { + if (key.x || key.y) { + // Montgomery points only have an `x` coordinate. + // Weierstrass/Edwards points on the other hand have both `x` and + // `y` coordinates. + if (this.ec.curve.type === 'mont') { + assert(key.x, 'Need x coordinate'); + } else if (this.ec.curve.type === 'short' || + this.ec.curve.type === 'edwards') { + assert(key.x && key.y, 'Need both x and y coordinate'); + } + this.pub = this.ec.curve.point(key.x, key.y); + return; + } + this.pub = this.ec.curve.decodePoint(key, enc); +}; + +// ECDH +KeyPair.prototype.derive = function derive(pub) { + if(!pub.validate()) { + assert(pub.validate(), 'public point not validated'); + } + return pub.mul(this.priv).getX(); +}; + +// ECDSA +KeyPair.prototype.sign = function sign(msg, enc, options) { + return this.ec.sign(msg, this, enc, options); +}; + +KeyPair.prototype.verify = function verify(msg, signature) { + return this.ec.verify(msg, signature, this); +}; + +KeyPair.prototype.inspect = function inspect() { + return ''; +}; + +},{"../utils":97,"bn.js":98}],92:[function(require,module,exports){ +'use strict'; + +var BN = require('bn.js'); + +var utils = require('../utils'); +var assert = utils.assert; + +function Signature(options, enc) { + if (options instanceof Signature) + return options; + + if (this._importDER(options, enc)) + return; + + assert(options.r && options.s, 'Signature without r or s'); + this.r = new BN(options.r, 16); + this.s = new BN(options.s, 16); + if (options.recoveryParam === undefined) + this.recoveryParam = null; + else + this.recoveryParam = options.recoveryParam; +} +module.exports = Signature; + +function Position() { + this.place = 0; +} + +function getLength(buf, p) { + var initial = buf[p.place++]; + if (!(initial & 0x80)) { + return initial; + } + var octetLen = initial & 0xf; + + // Indefinite length or overflow + if (octetLen === 0 || octetLen > 4) { + return false; + } + + var val = 0; + for (var i = 0, off = p.place; i < octetLen; i++, off++) { + val <<= 8; + val |= buf[off]; + val >>>= 0; + } + + // Leading zeroes + if (val <= 0x7f) { + return false; + } + + p.place = off; + return val; +} + +function rmPadding(buf) { + var i = 0; + var len = buf.length - 1; + while (!buf[i] && !(buf[i + 1] & 0x80) && i < len) { + i++; + } + if (i === 0) { + return buf; + } + return buf.slice(i); +} + +Signature.prototype._importDER = function _importDER(data, enc) { + data = utils.toArray(data, enc); + var p = new Position(); + if (data[p.place++] !== 0x30) { + return false; + } + var len = getLength(data, p); + if (len === false) { + return false; + } + if ((len + p.place) !== data.length) { + return false; + } + if (data[p.place++] !== 0x02) { + return false; + } + var rlen = getLength(data, p); + if (rlen === false) { + return false; + } + var r = data.slice(p.place, rlen + p.place); + p.place += rlen; + if (data[p.place++] !== 0x02) { + return false; + } + var slen = getLength(data, p); + if (slen === false) { + return false; + } + if (data.length !== slen + p.place) { + return false; + } + var s = data.slice(p.place, slen + p.place); + if (r[0] === 0) { + if (r[1] & 0x80) { + r = r.slice(1); + } else { + // Leading zeroes + return false; + } + } + if (s[0] === 0) { + if (s[1] & 0x80) { + s = s.slice(1); + } else { + // Leading zeroes + return false; + } + } + + this.r = new BN(r); + this.s = new BN(s); + this.recoveryParam = null; + + return true; +}; + +function constructLength(arr, len) { + if (len < 0x80) { + arr.push(len); + return; + } + var octets = 1 + (Math.log(len) / Math.LN2 >>> 3); + arr.push(octets | 0x80); + while (--octets) { + arr.push((len >>> (octets << 3)) & 0xff); + } + arr.push(len); +} + +Signature.prototype.toDER = function toDER(enc) { + var r = this.r.toArray(); + var s = this.s.toArray(); + + // Pad values + if (r[0] & 0x80) + r = [ 0 ].concat(r); + // Pad values + if (s[0] & 0x80) + s = [ 0 ].concat(s); + + r = rmPadding(r); + s = rmPadding(s); + + while (!s[0] && !(s[1] & 0x80)) { + s = s.slice(1); + } + var arr = [ 0x02 ]; + constructLength(arr, r.length); + arr = arr.concat(r); + arr.push(0x02); + constructLength(arr, s.length); + var backHalf = arr.concat(s); + var res = [ 0x30 ]; + constructLength(res, backHalf.length); + res = res.concat(backHalf); + return utils.encode(res, enc); +}; + +},{"../utils":97,"bn.js":98}],93:[function(require,module,exports){ +'use strict'; + +var hash = require('hash.js'); +var curves = require('../curves'); +var utils = require('../utils'); +var assert = utils.assert; +var parseBytes = utils.parseBytes; +var KeyPair = require('./key'); +var Signature = require('./signature'); + +function EDDSA(curve) { + assert(curve === 'ed25519', 'only tested with ed25519 so far'); + + if (!(this instanceof EDDSA)) + return new EDDSA(curve); + + curve = curves[curve].curve; + this.curve = curve; + this.g = curve.g; + this.g.precompute(curve.n.bitLength() + 1); + + this.pointClass = curve.point().constructor; + this.encodingLength = Math.ceil(curve.n.bitLength() / 8); + this.hash = hash.sha512; +} + +module.exports = EDDSA; + +/** +* @param {Array|String} message - message bytes +* @param {Array|String|KeyPair} secret - secret bytes or a keypair +* @returns {Signature} - signature +*/ +EDDSA.prototype.sign = function sign(message, secret) { + message = parseBytes(message); + var key = this.keyFromSecret(secret); + var r = this.hashInt(key.messagePrefix(), message); + var R = this.g.mul(r); + var Rencoded = this.encodePoint(R); + var s_ = this.hashInt(Rencoded, key.pubBytes(), message) + .mul(key.priv()); + var S = r.add(s_).umod(this.curve.n); + return this.makeSignature({ R: R, S: S, Rencoded: Rencoded }); +}; + +/** +* @param {Array} message - message bytes +* @param {Array|String|Signature} sig - sig bytes +* @param {Array|String|Point|KeyPair} pub - public key +* @returns {Boolean} - true if public key matches sig of message +*/ +EDDSA.prototype.verify = function verify(message, sig, pub) { + message = parseBytes(message); + sig = this.makeSignature(sig); + var key = this.keyFromPublic(pub); + var h = this.hashInt(sig.Rencoded(), key.pubBytes(), message); + var SG = this.g.mul(sig.S()); + var RplusAh = sig.R().add(key.pub().mul(h)); + return RplusAh.eq(SG); +}; + +EDDSA.prototype.hashInt = function hashInt() { + var hash = this.hash(); + for (var i = 0; i < arguments.length; i++) + hash.update(arguments[i]); + return utils.intFromLE(hash.digest()).umod(this.curve.n); +}; + +EDDSA.prototype.keyFromPublic = function keyFromPublic(pub) { + return KeyPair.fromPublic(this, pub); +}; + +EDDSA.prototype.keyFromSecret = function keyFromSecret(secret) { + return KeyPair.fromSecret(this, secret); +}; + +EDDSA.prototype.makeSignature = function makeSignature(sig) { + if (sig instanceof Signature) + return sig; + return new Signature(this, sig); +}; + +/** +* * https://tools.ietf.org/html/draft-josefsson-eddsa-ed25519-03#section-5.2 +* +* EDDSA defines methods for encoding and decoding points and integers. These are +* helper convenience methods, that pass along to utility functions implied +* parameters. +* +*/ +EDDSA.prototype.encodePoint = function encodePoint(point) { + var enc = point.getY().toArray('le', this.encodingLength); + enc[this.encodingLength - 1] |= point.getX().isOdd() ? 0x80 : 0; + return enc; +}; + +EDDSA.prototype.decodePoint = function decodePoint(bytes) { + bytes = utils.parseBytes(bytes); + + var lastIx = bytes.length - 1; + var normed = bytes.slice(0, lastIx).concat(bytes[lastIx] & ~0x80); + var xIsOdd = (bytes[lastIx] & 0x80) !== 0; + + var y = utils.intFromLE(normed); + return this.curve.pointFromY(y, xIsOdd); +}; + +EDDSA.prototype.encodeInt = function encodeInt(num) { + return num.toArray('le', this.encodingLength); +}; + +EDDSA.prototype.decodeInt = function decodeInt(bytes) { + return utils.intFromLE(bytes); +}; + +EDDSA.prototype.isPoint = function isPoint(val) { + return val instanceof this.pointClass; +}; + +},{"../curves":89,"../utils":97,"./key":94,"./signature":95,"hash.js":118}],94:[function(require,module,exports){ +'use strict'; + +var utils = require('../utils'); +var assert = utils.assert; +var parseBytes = utils.parseBytes; +var cachedProperty = utils.cachedProperty; + +/** +* @param {EDDSA} eddsa - instance +* @param {Object} params - public/private key parameters +* +* @param {Array} [params.secret] - secret seed bytes +* @param {Point} [params.pub] - public key point (aka `A` in eddsa terms) +* @param {Array} [params.pub] - public key point encoded as bytes +* +*/ +function KeyPair(eddsa, params) { + this.eddsa = eddsa; + this._secret = parseBytes(params.secret); + if (eddsa.isPoint(params.pub)) + this._pub = params.pub; + else + this._pubBytes = parseBytes(params.pub); +} + +KeyPair.fromPublic = function fromPublic(eddsa, pub) { + if (pub instanceof KeyPair) + return pub; + return new KeyPair(eddsa, { pub: pub }); +}; + +KeyPair.fromSecret = function fromSecret(eddsa, secret) { + if (secret instanceof KeyPair) + return secret; + return new KeyPair(eddsa, { secret: secret }); +}; + +KeyPair.prototype.secret = function secret() { + return this._secret; +}; + +cachedProperty(KeyPair, 'pubBytes', function pubBytes() { + return this.eddsa.encodePoint(this.pub()); +}); + +cachedProperty(KeyPair, 'pub', function pub() { + if (this._pubBytes) + return this.eddsa.decodePoint(this._pubBytes); + return this.eddsa.g.mul(this.priv()); +}); + +cachedProperty(KeyPair, 'privBytes', function privBytes() { + var eddsa = this.eddsa; + var hash = this.hash(); + var lastIx = eddsa.encodingLength - 1; + + var a = hash.slice(0, eddsa.encodingLength); + a[0] &= 248; + a[lastIx] &= 127; + a[lastIx] |= 64; + + return a; +}); + +cachedProperty(KeyPair, 'priv', function priv() { + return this.eddsa.decodeInt(this.privBytes()); +}); + +cachedProperty(KeyPair, 'hash', function hash() { + return this.eddsa.hash().update(this.secret()).digest(); +}); + +cachedProperty(KeyPair, 'messagePrefix', function messagePrefix() { + return this.hash().slice(this.eddsa.encodingLength); +}); + +KeyPair.prototype.sign = function sign(message) { + assert(this._secret, 'KeyPair can only verify'); + return this.eddsa.sign(message, this); +}; + +KeyPair.prototype.verify = function verify(message, sig) { + return this.eddsa.verify(message, sig, this); +}; + +KeyPair.prototype.getSecret = function getSecret(enc) { + assert(this._secret, 'KeyPair is public only'); + return utils.encode(this.secret(), enc); +}; + +KeyPair.prototype.getPublic = function getPublic(enc) { + return utils.encode(this.pubBytes(), enc); +}; + +module.exports = KeyPair; + +},{"../utils":97}],95:[function(require,module,exports){ +'use strict'; + +var BN = require('bn.js'); +var utils = require('../utils'); +var assert = utils.assert; +var cachedProperty = utils.cachedProperty; +var parseBytes = utils.parseBytes; + +/** +* @param {EDDSA} eddsa - eddsa instance +* @param {Array|Object} sig - +* @param {Array|Point} [sig.R] - R point as Point or bytes +* @param {Array|bn} [sig.S] - S scalar as bn or bytes +* @param {Array} [sig.Rencoded] - R point encoded +* @param {Array} [sig.Sencoded] - S scalar encoded +*/ +function Signature(eddsa, sig) { + this.eddsa = eddsa; + + if (typeof sig !== 'object') + sig = parseBytes(sig); + + if (Array.isArray(sig)) { + sig = { + R: sig.slice(0, eddsa.encodingLength), + S: sig.slice(eddsa.encodingLength), + }; + } + + assert(sig.R && sig.S, 'Signature without R or S'); + + if (eddsa.isPoint(sig.R)) + this._R = sig.R; + if (sig.S instanceof BN) + this._S = sig.S; + + this._Rencoded = Array.isArray(sig.R) ? sig.R : sig.Rencoded; + this._Sencoded = Array.isArray(sig.S) ? sig.S : sig.Sencoded; +} + +cachedProperty(Signature, 'S', function S() { + return this.eddsa.decodeInt(this.Sencoded()); +}); + +cachedProperty(Signature, 'R', function R() { + return this.eddsa.decodePoint(this.Rencoded()); +}); + +cachedProperty(Signature, 'Rencoded', function Rencoded() { + return this.eddsa.encodePoint(this.R()); +}); + +cachedProperty(Signature, 'Sencoded', function Sencoded() { + return this.eddsa.encodeInt(this.S()); +}); + +Signature.prototype.toBytes = function toBytes() { + return this.Rencoded().concat(this.Sencoded()); +}; + +Signature.prototype.toHex = function toHex() { + return utils.encode(this.toBytes(), 'hex').toUpperCase(); +}; + +module.exports = Signature; + +},{"../utils":97,"bn.js":98}],96:[function(require,module,exports){ +module.exports = { + doubles: { + step: 4, + points: [ + [ + 'e60fce93b59e9ec53011aabc21c23e97b2a31369b87a5ae9c44ee89e2a6dec0a', + 'f7e3507399e595929db99f34f57937101296891e44d23f0be1f32cce69616821', + ], + [ + '8282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508', + '11f8a8098557dfe45e8256e830b60ace62d613ac2f7b17bed31b6eaff6e26caf', + ], + [ + '175e159f728b865a72f99cc6c6fc846de0b93833fd2222ed73fce5b551e5b739', + 'd3506e0d9e3c79eba4ef97a51ff71f5eacb5955add24345c6efa6ffee9fed695', + ], + [ + '363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640', + '4e273adfc732221953b445397f3363145b9a89008199ecb62003c7f3bee9de9', + ], + [ + '8b4b5f165df3c2be8c6244b5b745638843e4a781a15bcd1b69f79a55dffdf80c', + '4aad0a6f68d308b4b3fbd7813ab0da04f9e336546162ee56b3eff0c65fd4fd36', + ], + [ + '723cbaa6e5db996d6bf771c00bd548c7b700dbffa6c0e77bcb6115925232fcda', + '96e867b5595cc498a921137488824d6e2660a0653779494801dc069d9eb39f5f', + ], + [ + 'eebfa4d493bebf98ba5feec812c2d3b50947961237a919839a533eca0e7dd7fa', + '5d9a8ca3970ef0f269ee7edaf178089d9ae4cdc3a711f712ddfd4fdae1de8999', + ], + [ + '100f44da696e71672791d0a09b7bde459f1215a29b3c03bfefd7835b39a48db0', + 'cdd9e13192a00b772ec8f3300c090666b7ff4a18ff5195ac0fbd5cd62bc65a09', + ], + [ + 'e1031be262c7ed1b1dc9227a4a04c017a77f8d4464f3b3852c8acde6e534fd2d', + '9d7061928940405e6bb6a4176597535af292dd419e1ced79a44f18f29456a00d', + ], + [ + 'feea6cae46d55b530ac2839f143bd7ec5cf8b266a41d6af52d5e688d9094696d', + 'e57c6b6c97dce1bab06e4e12bf3ecd5c981c8957cc41442d3155debf18090088', + ], + [ + 'da67a91d91049cdcb367be4be6ffca3cfeed657d808583de33fa978bc1ec6cb1', + '9bacaa35481642bc41f463f7ec9780e5dec7adc508f740a17e9ea8e27a68be1d', + ], + [ + '53904faa0b334cdda6e000935ef22151ec08d0f7bb11069f57545ccc1a37b7c0', + '5bc087d0bc80106d88c9eccac20d3c1c13999981e14434699dcb096b022771c8', + ], + [ + '8e7bcd0bd35983a7719cca7764ca906779b53a043a9b8bcaeff959f43ad86047', + '10b7770b2a3da4b3940310420ca9514579e88e2e47fd68b3ea10047e8460372a', + ], + [ + '385eed34c1cdff21e6d0818689b81bde71a7f4f18397e6690a841e1599c43862', + '283bebc3e8ea23f56701de19e9ebf4576b304eec2086dc8cc0458fe5542e5453', + ], + [ + '6f9d9b803ecf191637c73a4413dfa180fddf84a5947fbc9c606ed86c3fac3a7', + '7c80c68e603059ba69b8e2a30e45c4d47ea4dd2f5c281002d86890603a842160', + ], + [ + '3322d401243c4e2582a2147c104d6ecbf774d163db0f5e5313b7e0e742d0e6bd', + '56e70797e9664ef5bfb019bc4ddaf9b72805f63ea2873af624f3a2e96c28b2a0', + ], + [ + '85672c7d2de0b7da2bd1770d89665868741b3f9af7643397721d74d28134ab83', + '7c481b9b5b43b2eb6374049bfa62c2e5e77f17fcc5298f44c8e3094f790313a6', + ], + [ + '948bf809b1988a46b06c9f1919413b10f9226c60f668832ffd959af60c82a0a', + '53a562856dcb6646dc6b74c5d1c3418c6d4dff08c97cd2bed4cb7f88d8c8e589', + ], + [ + '6260ce7f461801c34f067ce0f02873a8f1b0e44dfc69752accecd819f38fd8e8', + 'bc2da82b6fa5b571a7f09049776a1ef7ecd292238051c198c1a84e95b2b4ae17', + ], + [ + 'e5037de0afc1d8d43d8348414bbf4103043ec8f575bfdc432953cc8d2037fa2d', + '4571534baa94d3b5f9f98d09fb990bddbd5f5b03ec481f10e0e5dc841d755bda', + ], + [ + 'e06372b0f4a207adf5ea905e8f1771b4e7e8dbd1c6a6c5b725866a0ae4fce725', + '7a908974bce18cfe12a27bb2ad5a488cd7484a7787104870b27034f94eee31dd', + ], + [ + '213c7a715cd5d45358d0bbf9dc0ce02204b10bdde2a3f58540ad6908d0559754', + '4b6dad0b5ae462507013ad06245ba190bb4850f5f36a7eeddff2c27534b458f2', + ], + [ + '4e7c272a7af4b34e8dbb9352a5419a87e2838c70adc62cddf0cc3a3b08fbd53c', + '17749c766c9d0b18e16fd09f6def681b530b9614bff7dd33e0b3941817dcaae6', + ], + [ + 'fea74e3dbe778b1b10f238ad61686aa5c76e3db2be43057632427e2840fb27b6', + '6e0568db9b0b13297cf674deccb6af93126b596b973f7b77701d3db7f23cb96f', + ], + [ + '76e64113f677cf0e10a2570d599968d31544e179b760432952c02a4417bdde39', + 'c90ddf8dee4e95cf577066d70681f0d35e2a33d2b56d2032b4b1752d1901ac01', + ], + [ + 'c738c56b03b2abe1e8281baa743f8f9a8f7cc643df26cbee3ab150242bcbb891', + '893fb578951ad2537f718f2eacbfbbbb82314eef7880cfe917e735d9699a84c3', + ], + [ + 'd895626548b65b81e264c7637c972877d1d72e5f3a925014372e9f6588f6c14b', + 'febfaa38f2bc7eae728ec60818c340eb03428d632bb067e179363ed75d7d991f', + ], + [ + 'b8da94032a957518eb0f6433571e8761ceffc73693e84edd49150a564f676e03', + '2804dfa44805a1e4d7c99cc9762808b092cc584d95ff3b511488e4e74efdf6e7', + ], + [ + 'e80fea14441fb33a7d8adab9475d7fab2019effb5156a792f1a11778e3c0df5d', + 'eed1de7f638e00771e89768ca3ca94472d155e80af322ea9fcb4291b6ac9ec78', + ], + [ + 'a301697bdfcd704313ba48e51d567543f2a182031efd6915ddc07bbcc4e16070', + '7370f91cfb67e4f5081809fa25d40f9b1735dbf7c0a11a130c0d1a041e177ea1', + ], + [ + '90ad85b389d6b936463f9d0512678de208cc330b11307fffab7ac63e3fb04ed4', + 'e507a3620a38261affdcbd9427222b839aefabe1582894d991d4d48cb6ef150', + ], + [ + '8f68b9d2f63b5f339239c1ad981f162ee88c5678723ea3351b7b444c9ec4c0da', + '662a9f2dba063986de1d90c2b6be215dbbea2cfe95510bfdf23cbf79501fff82', + ], + [ + 'e4f3fb0176af85d65ff99ff9198c36091f48e86503681e3e6686fd5053231e11', + '1e63633ad0ef4f1c1661a6d0ea02b7286cc7e74ec951d1c9822c38576feb73bc', + ], + [ + '8c00fa9b18ebf331eb961537a45a4266c7034f2f0d4e1d0716fb6eae20eae29e', + 'efa47267fea521a1a9dc343a3736c974c2fadafa81e36c54e7d2a4c66702414b', + ], + [ + 'e7a26ce69dd4829f3e10cec0a9e98ed3143d084f308b92c0997fddfc60cb3e41', + '2a758e300fa7984b471b006a1aafbb18d0a6b2c0420e83e20e8a9421cf2cfd51', + ], + [ + 'b6459e0ee3662ec8d23540c223bcbdc571cbcb967d79424f3cf29eb3de6b80ef', + '67c876d06f3e06de1dadf16e5661db3c4b3ae6d48e35b2ff30bf0b61a71ba45', + ], + [ + 'd68a80c8280bb840793234aa118f06231d6f1fc67e73c5a5deda0f5b496943e8', + 'db8ba9fff4b586d00c4b1f9177b0e28b5b0e7b8f7845295a294c84266b133120', + ], + [ + '324aed7df65c804252dc0270907a30b09612aeb973449cea4095980fc28d3d5d', + '648a365774b61f2ff130c0c35aec1f4f19213b0c7e332843967224af96ab7c84', + ], + [ + '4df9c14919cde61f6d51dfdbe5fee5dceec4143ba8d1ca888e8bd373fd054c96', + '35ec51092d8728050974c23a1d85d4b5d506cdc288490192ebac06cad10d5d', + ], + [ + '9c3919a84a474870faed8a9c1cc66021523489054d7f0308cbfc99c8ac1f98cd', + 'ddb84f0f4a4ddd57584f044bf260e641905326f76c64c8e6be7e5e03d4fc599d', + ], + [ + '6057170b1dd12fdf8de05f281d8e06bb91e1493a8b91d4cc5a21382120a959e5', + '9a1af0b26a6a4807add9a2daf71df262465152bc3ee24c65e899be932385a2a8', + ], + [ + 'a576df8e23a08411421439a4518da31880cef0fba7d4df12b1a6973eecb94266', + '40a6bf20e76640b2c92b97afe58cd82c432e10a7f514d9f3ee8be11ae1b28ec8', + ], + [ + '7778a78c28dec3e30a05fe9629de8c38bb30d1f5cf9a3a208f763889be58ad71', + '34626d9ab5a5b22ff7098e12f2ff580087b38411ff24ac563b513fc1fd9f43ac', + ], + [ + '928955ee637a84463729fd30e7afd2ed5f96274e5ad7e5cb09eda9c06d903ac', + 'c25621003d3f42a827b78a13093a95eeac3d26efa8a8d83fc5180e935bcd091f', + ], + [ + '85d0fef3ec6db109399064f3a0e3b2855645b4a907ad354527aae75163d82751', + '1f03648413a38c0be29d496e582cf5663e8751e96877331582c237a24eb1f962', + ], + [ + 'ff2b0dce97eece97c1c9b6041798b85dfdfb6d8882da20308f5404824526087e', + '493d13fef524ba188af4c4dc54d07936c7b7ed6fb90e2ceb2c951e01f0c29907', + ], + [ + '827fbbe4b1e880ea9ed2b2e6301b212b57f1ee148cd6dd28780e5e2cf856e241', + 'c60f9c923c727b0b71bef2c67d1d12687ff7a63186903166d605b68baec293ec', + ], + [ + 'eaa649f21f51bdbae7be4ae34ce6e5217a58fdce7f47f9aa7f3b58fa2120e2b3', + 'be3279ed5bbbb03ac69a80f89879aa5a01a6b965f13f7e59d47a5305ba5ad93d', + ], + [ + 'e4a42d43c5cf169d9391df6decf42ee541b6d8f0c9a137401e23632dda34d24f', + '4d9f92e716d1c73526fc99ccfb8ad34ce886eedfa8d8e4f13a7f7131deba9414', + ], + [ + '1ec80fef360cbdd954160fadab352b6b92b53576a88fea4947173b9d4300bf19', + 'aeefe93756b5340d2f3a4958a7abbf5e0146e77f6295a07b671cdc1cc107cefd', + ], + [ + '146a778c04670c2f91b00af4680dfa8bce3490717d58ba889ddb5928366642be', + 'b318e0ec3354028add669827f9d4b2870aaa971d2f7e5ed1d0b297483d83efd0', + ], + [ + 'fa50c0f61d22e5f07e3acebb1aa07b128d0012209a28b9776d76a8793180eef9', + '6b84c6922397eba9b72cd2872281a68a5e683293a57a213b38cd8d7d3f4f2811', + ], + [ + 'da1d61d0ca721a11b1a5bf6b7d88e8421a288ab5d5bba5220e53d32b5f067ec2', + '8157f55a7c99306c79c0766161c91e2966a73899d279b48a655fba0f1ad836f1', + ], + [ + 'a8e282ff0c9706907215ff98e8fd416615311de0446f1e062a73b0610d064e13', + '7f97355b8db81c09abfb7f3c5b2515888b679a3e50dd6bd6cef7c73111f4cc0c', + ], + [ + '174a53b9c9a285872d39e56e6913cab15d59b1fa512508c022f382de8319497c', + 'ccc9dc37abfc9c1657b4155f2c47f9e6646b3a1d8cb9854383da13ac079afa73', + ], + [ + '959396981943785c3d3e57edf5018cdbe039e730e4918b3d884fdff09475b7ba', + '2e7e552888c331dd8ba0386a4b9cd6849c653f64c8709385e9b8abf87524f2fd', + ], + [ + 'd2a63a50ae401e56d645a1153b109a8fcca0a43d561fba2dbb51340c9d82b151', + 'e82d86fb6443fcb7565aee58b2948220a70f750af484ca52d4142174dcf89405', + ], + [ + '64587e2335471eb890ee7896d7cfdc866bacbdbd3839317b3436f9b45617e073', + 'd99fcdd5bf6902e2ae96dd6447c299a185b90a39133aeab358299e5e9faf6589', + ], + [ + '8481bde0e4e4d885b3a546d3e549de042f0aa6cea250e7fd358d6c86dd45e458', + '38ee7b8cba5404dd84a25bf39cecb2ca900a79c42b262e556d64b1b59779057e', + ], + [ + '13464a57a78102aa62b6979ae817f4637ffcfed3c4b1ce30bcd6303f6caf666b', + '69be159004614580ef7e433453ccb0ca48f300a81d0942e13f495a907f6ecc27', + ], + [ + 'bc4a9df5b713fe2e9aef430bcc1dc97a0cd9ccede2f28588cada3a0d2d83f366', + 'd3a81ca6e785c06383937adf4b798caa6e8a9fbfa547b16d758d666581f33c1', + ], + [ + '8c28a97bf8298bc0d23d8c749452a32e694b65e30a9472a3954ab30fe5324caa', + '40a30463a3305193378fedf31f7cc0eb7ae784f0451cb9459e71dc73cbef9482', + ], + [ + '8ea9666139527a8c1dd94ce4f071fd23c8b350c5a4bb33748c4ba111faccae0', + '620efabbc8ee2782e24e7c0cfb95c5d735b783be9cf0f8e955af34a30e62b945', + ], + [ + 'dd3625faef5ba06074669716bbd3788d89bdde815959968092f76cc4eb9a9787', + '7a188fa3520e30d461da2501045731ca941461982883395937f68d00c644a573', + ], + [ + 'f710d79d9eb962297e4f6232b40e8f7feb2bc63814614d692c12de752408221e', + 'ea98e67232d3b3295d3b535532115ccac8612c721851617526ae47a9c77bfc82', + ], + ], + }, + naf: { + wnd: 7, + points: [ + [ + 'f9308a019258c31049344f85f89d5229b531c845836f99b08601f113bce036f9', + '388f7b0f632de8140fe337e62a37f3566500a99934c2231b6cb9fd7584b8e672', + ], + [ + '2f8bde4d1a07209355b4a7250a5c5128e88b84bddc619ab7cba8d569b240efe4', + 'd8ac222636e5e3d6d4dba9dda6c9c426f788271bab0d6840dca87d3aa6ac62d6', + ], + [ + '5cbdf0646e5db4eaa398f365f2ea7a0e3d419b7e0330e39ce92bddedcac4f9bc', + '6aebca40ba255960a3178d6d861a54dba813d0b813fde7b5a5082628087264da', + ], + [ + 'acd484e2f0c7f65309ad178a9f559abde09796974c57e714c35f110dfc27ccbe', + 'cc338921b0a7d9fd64380971763b61e9add888a4375f8e0f05cc262ac64f9c37', + ], + [ + '774ae7f858a9411e5ef4246b70c65aac5649980be5c17891bbec17895da008cb', + 'd984a032eb6b5e190243dd56d7b7b365372db1e2dff9d6a8301d74c9c953c61b', + ], + [ + 'f28773c2d975288bc7d1d205c3748651b075fbc6610e58cddeeddf8f19405aa8', + 'ab0902e8d880a89758212eb65cdaf473a1a06da521fa91f29b5cb52db03ed81', + ], + [ + 'd7924d4f7d43ea965a465ae3095ff41131e5946f3c85f79e44adbcf8e27e080e', + '581e2872a86c72a683842ec228cc6defea40af2bd896d3a5c504dc9ff6a26b58', + ], + [ + 'defdea4cdb677750a420fee807eacf21eb9898ae79b9768766e4faa04a2d4a34', + '4211ab0694635168e997b0ead2a93daeced1f4a04a95c0f6cfb199f69e56eb77', + ], + [ + '2b4ea0a797a443d293ef5cff444f4979f06acfebd7e86d277475656138385b6c', + '85e89bc037945d93b343083b5a1c86131a01f60c50269763b570c854e5c09b7a', + ], + [ + '352bbf4a4cdd12564f93fa332ce333301d9ad40271f8107181340aef25be59d5', + '321eb4075348f534d59c18259dda3e1f4a1b3b2e71b1039c67bd3d8bcf81998c', + ], + [ + '2fa2104d6b38d11b0230010559879124e42ab8dfeff5ff29dc9cdadd4ecacc3f', + '2de1068295dd865b64569335bd5dd80181d70ecfc882648423ba76b532b7d67', + ], + [ + '9248279b09b4d68dab21a9b066edda83263c3d84e09572e269ca0cd7f5453714', + '73016f7bf234aade5d1aa71bdea2b1ff3fc0de2a887912ffe54a32ce97cb3402', + ], + [ + 'daed4f2be3a8bf278e70132fb0beb7522f570e144bf615c07e996d443dee8729', + 'a69dce4a7d6c98e8d4a1aca87ef8d7003f83c230f3afa726ab40e52290be1c55', + ], + [ + 'c44d12c7065d812e8acf28d7cbb19f9011ecd9e9fdf281b0e6a3b5e87d22e7db', + '2119a460ce326cdc76c45926c982fdac0e106e861edf61c5a039063f0e0e6482', + ], + [ + '6a245bf6dc698504c89a20cfded60853152b695336c28063b61c65cbd269e6b4', + 'e022cf42c2bd4a708b3f5126f16a24ad8b33ba48d0423b6efd5e6348100d8a82', + ], + [ + '1697ffa6fd9de627c077e3d2fe541084ce13300b0bec1146f95ae57f0d0bd6a5', + 'b9c398f186806f5d27561506e4557433a2cf15009e498ae7adee9d63d01b2396', + ], + [ + '605bdb019981718b986d0f07e834cb0d9deb8360ffb7f61df982345ef27a7479', + '2972d2de4f8d20681a78d93ec96fe23c26bfae84fb14db43b01e1e9056b8c49', + ], + [ + '62d14dab4150bf497402fdc45a215e10dcb01c354959b10cfe31c7e9d87ff33d', + '80fc06bd8cc5b01098088a1950eed0db01aa132967ab472235f5642483b25eaf', + ], + [ + '80c60ad0040f27dade5b4b06c408e56b2c50e9f56b9b8b425e555c2f86308b6f', + '1c38303f1cc5c30f26e66bad7fe72f70a65eed4cbe7024eb1aa01f56430bd57a', + ], + [ + '7a9375ad6167ad54aa74c6348cc54d344cc5dc9487d847049d5eabb0fa03c8fb', + 'd0e3fa9eca8726909559e0d79269046bdc59ea10c70ce2b02d499ec224dc7f7', + ], + [ + 'd528ecd9b696b54c907a9ed045447a79bb408ec39b68df504bb51f459bc3ffc9', + 'eecf41253136e5f99966f21881fd656ebc4345405c520dbc063465b521409933', + ], + [ + '49370a4b5f43412ea25f514e8ecdad05266115e4a7ecb1387231808f8b45963', + '758f3f41afd6ed428b3081b0512fd62a54c3f3afbb5b6764b653052a12949c9a', + ], + [ + '77f230936ee88cbbd73df930d64702ef881d811e0e1498e2f1c13eb1fc345d74', + '958ef42a7886b6400a08266e9ba1b37896c95330d97077cbbe8eb3c7671c60d6', + ], + [ + 'f2dac991cc4ce4b9ea44887e5c7c0bce58c80074ab9d4dbaeb28531b7739f530', + 'e0dedc9b3b2f8dad4da1f32dec2531df9eb5fbeb0598e4fd1a117dba703a3c37', + ], + [ + '463b3d9f662621fb1b4be8fbbe2520125a216cdfc9dae3debcba4850c690d45b', + '5ed430d78c296c3543114306dd8622d7c622e27c970a1de31cb377b01af7307e', + ], + [ + 'f16f804244e46e2a09232d4aff3b59976b98fac14328a2d1a32496b49998f247', + 'cedabd9b82203f7e13d206fcdf4e33d92a6c53c26e5cce26d6579962c4e31df6', + ], + [ + 'caf754272dc84563b0352b7a14311af55d245315ace27c65369e15f7151d41d1', + 'cb474660ef35f5f2a41b643fa5e460575f4fa9b7962232a5c32f908318a04476', + ], + [ + '2600ca4b282cb986f85d0f1709979d8b44a09c07cb86d7c124497bc86f082120', + '4119b88753c15bd6a693b03fcddbb45d5ac6be74ab5f0ef44b0be9475a7e4b40', + ], + [ + '7635ca72d7e8432c338ec53cd12220bc01c48685e24f7dc8c602a7746998e435', + '91b649609489d613d1d5e590f78e6d74ecfc061d57048bad9e76f302c5b9c61', + ], + [ + '754e3239f325570cdbbf4a87deee8a66b7f2b33479d468fbc1a50743bf56cc18', + '673fb86e5bda30fb3cd0ed304ea49a023ee33d0197a695d0c5d98093c536683', + ], + [ + 'e3e6bd1071a1e96aff57859c82d570f0330800661d1c952f9fe2694691d9b9e8', + '59c9e0bba394e76f40c0aa58379a3cb6a5a2283993e90c4167002af4920e37f5', + ], + [ + '186b483d056a033826ae73d88f732985c4ccb1f32ba35f4b4cc47fdcf04aa6eb', + '3b952d32c67cf77e2e17446e204180ab21fb8090895138b4a4a797f86e80888b', + ], + [ + 'df9d70a6b9876ce544c98561f4be4f725442e6d2b737d9c91a8321724ce0963f', + '55eb2dafd84d6ccd5f862b785dc39d4ab157222720ef9da217b8c45cf2ba2417', + ], + [ + '5edd5cc23c51e87a497ca815d5dce0f8ab52554f849ed8995de64c5f34ce7143', + 'efae9c8dbc14130661e8cec030c89ad0c13c66c0d17a2905cdc706ab7399a868', + ], + [ + '290798c2b6476830da12fe02287e9e777aa3fba1c355b17a722d362f84614fba', + 'e38da76dcd440621988d00bcf79af25d5b29c094db2a23146d003afd41943e7a', + ], + [ + 'af3c423a95d9f5b3054754efa150ac39cd29552fe360257362dfdecef4053b45', + 'f98a3fd831eb2b749a93b0e6f35cfb40c8cd5aa667a15581bc2feded498fd9c6', + ], + [ + '766dbb24d134e745cccaa28c99bf274906bb66b26dcf98df8d2fed50d884249a', + '744b1152eacbe5e38dcc887980da38b897584a65fa06cedd2c924f97cbac5996', + ], + [ + '59dbf46f8c94759ba21277c33784f41645f7b44f6c596a58ce92e666191abe3e', + 'c534ad44175fbc300f4ea6ce648309a042ce739a7919798cd85e216c4a307f6e', + ], + [ + 'f13ada95103c4537305e691e74e9a4a8dd647e711a95e73cb62dc6018cfd87b8', + 'e13817b44ee14de663bf4bc808341f326949e21a6a75c2570778419bdaf5733d', + ], + [ + '7754b4fa0e8aced06d4167a2c59cca4cda1869c06ebadfb6488550015a88522c', + '30e93e864e669d82224b967c3020b8fa8d1e4e350b6cbcc537a48b57841163a2', + ], + [ + '948dcadf5990e048aa3874d46abef9d701858f95de8041d2a6828c99e2262519', + 'e491a42537f6e597d5d28a3224b1bc25df9154efbd2ef1d2cbba2cae5347d57e', + ], + [ + '7962414450c76c1689c7b48f8202ec37fb224cf5ac0bfa1570328a8a3d7c77ab', + '100b610ec4ffb4760d5c1fc133ef6f6b12507a051f04ac5760afa5b29db83437', + ], + [ + '3514087834964b54b15b160644d915485a16977225b8847bb0dd085137ec47ca', + 'ef0afbb2056205448e1652c48e8127fc6039e77c15c2378b7e7d15a0de293311', + ], + [ + 'd3cc30ad6b483e4bc79ce2c9dd8bc54993e947eb8df787b442943d3f7b527eaf', + '8b378a22d827278d89c5e9be8f9508ae3c2ad46290358630afb34db04eede0a4', + ], + [ + '1624d84780732860ce1c78fcbfefe08b2b29823db913f6493975ba0ff4847610', + '68651cf9b6da903e0914448c6cd9d4ca896878f5282be4c8cc06e2a404078575', + ], + [ + '733ce80da955a8a26902c95633e62a985192474b5af207da6df7b4fd5fc61cd4', + 'f5435a2bd2badf7d485a4d8b8db9fcce3e1ef8e0201e4578c54673bc1dc5ea1d', + ], + [ + '15d9441254945064cf1a1c33bbd3b49f8966c5092171e699ef258dfab81c045c', + 'd56eb30b69463e7234f5137b73b84177434800bacebfc685fc37bbe9efe4070d', + ], + [ + 'a1d0fcf2ec9de675b612136e5ce70d271c21417c9d2b8aaaac138599d0717940', + 'edd77f50bcb5a3cab2e90737309667f2641462a54070f3d519212d39c197a629', + ], + [ + 'e22fbe15c0af8ccc5780c0735f84dbe9a790badee8245c06c7ca37331cb36980', + 'a855babad5cd60c88b430a69f53a1a7a38289154964799be43d06d77d31da06', + ], + [ + '311091dd9860e8e20ee13473c1155f5f69635e394704eaa74009452246cfa9b3', + '66db656f87d1f04fffd1f04788c06830871ec5a64feee685bd80f0b1286d8374', + ], + [ + '34c1fd04d301be89b31c0442d3e6ac24883928b45a9340781867d4232ec2dbdf', + '9414685e97b1b5954bd46f730174136d57f1ceeb487443dc5321857ba73abee', + ], + [ + 'f219ea5d6b54701c1c14de5b557eb42a8d13f3abbcd08affcc2a5e6b049b8d63', + '4cb95957e83d40b0f73af4544cccf6b1f4b08d3c07b27fb8d8c2962a400766d1', + ], + [ + 'd7b8740f74a8fbaab1f683db8f45de26543a5490bca627087236912469a0b448', + 'fa77968128d9c92ee1010f337ad4717eff15db5ed3c049b3411e0315eaa4593b', + ], + [ + '32d31c222f8f6f0ef86f7c98d3a3335ead5bcd32abdd94289fe4d3091aa824bf', + '5f3032f5892156e39ccd3d7915b9e1da2e6dac9e6f26e961118d14b8462e1661', + ], + [ + '7461f371914ab32671045a155d9831ea8793d77cd59592c4340f86cbc18347b5', + '8ec0ba238b96bec0cbdddcae0aa442542eee1ff50c986ea6b39847b3cc092ff6', + ], + [ + 'ee079adb1df1860074356a25aa38206a6d716b2c3e67453d287698bad7b2b2d6', + '8dc2412aafe3be5c4c5f37e0ecc5f9f6a446989af04c4e25ebaac479ec1c8c1e', + ], + [ + '16ec93e447ec83f0467b18302ee620f7e65de331874c9dc72bfd8616ba9da6b5', + '5e4631150e62fb40d0e8c2a7ca5804a39d58186a50e497139626778e25b0674d', + ], + [ + 'eaa5f980c245f6f038978290afa70b6bd8855897f98b6aa485b96065d537bd99', + 'f65f5d3e292c2e0819a528391c994624d784869d7e6ea67fb18041024edc07dc', + ], + [ + '78c9407544ac132692ee1910a02439958ae04877151342ea96c4b6b35a49f51', + 'f3e0319169eb9b85d5404795539a5e68fa1fbd583c064d2462b675f194a3ddb4', + ], + [ + '494f4be219a1a77016dcd838431aea0001cdc8ae7a6fc688726578d9702857a5', + '42242a969283a5f339ba7f075e36ba2af925ce30d767ed6e55f4b031880d562c', + ], + [ + 'a598a8030da6d86c6bc7f2f5144ea549d28211ea58faa70ebf4c1e665c1fe9b5', + '204b5d6f84822c307e4b4a7140737aec23fc63b65b35f86a10026dbd2d864e6b', + ], + [ + 'c41916365abb2b5d09192f5f2dbeafec208f020f12570a184dbadc3e58595997', + '4f14351d0087efa49d245b328984989d5caf9450f34bfc0ed16e96b58fa9913', + ], + [ + '841d6063a586fa475a724604da03bc5b92a2e0d2e0a36acfe4c73a5514742881', + '73867f59c0659e81904f9a1c7543698e62562d6744c169ce7a36de01a8d6154', + ], + [ + '5e95bb399a6971d376026947f89bde2f282b33810928be4ded112ac4d70e20d5', + '39f23f366809085beebfc71181313775a99c9aed7d8ba38b161384c746012865', + ], + [ + '36e4641a53948fd476c39f8a99fd974e5ec07564b5315d8bf99471bca0ef2f66', + 'd2424b1b1abe4eb8164227b085c9aa9456ea13493fd563e06fd51cf5694c78fc', + ], + [ + '336581ea7bfbbb290c191a2f507a41cf5643842170e914faeab27c2c579f726', + 'ead12168595fe1be99252129b6e56b3391f7ab1410cd1e0ef3dcdcabd2fda224', + ], + [ + '8ab89816dadfd6b6a1f2634fcf00ec8403781025ed6890c4849742706bd43ede', + '6fdcef09f2f6d0a044e654aef624136f503d459c3e89845858a47a9129cdd24e', + ], + [ + '1e33f1a746c9c5778133344d9299fcaa20b0938e8acff2544bb40284b8c5fb94', + '60660257dd11b3aa9c8ed618d24edff2306d320f1d03010e33a7d2057f3b3b6', + ], + [ + '85b7c1dcb3cec1b7ee7f30ded79dd20a0ed1f4cc18cbcfcfa410361fd8f08f31', + '3d98a9cdd026dd43f39048f25a8847f4fcafad1895d7a633c6fed3c35e999511', + ], + [ + '29df9fbd8d9e46509275f4b125d6d45d7fbe9a3b878a7af872a2800661ac5f51', + 'b4c4fe99c775a606e2d8862179139ffda61dc861c019e55cd2876eb2a27d84b', + ], + [ + 'a0b1cae06b0a847a3fea6e671aaf8adfdfe58ca2f768105c8082b2e449fce252', + 'ae434102edde0958ec4b19d917a6a28e6b72da1834aff0e650f049503a296cf2', + ], + [ + '4e8ceafb9b3e9a136dc7ff67e840295b499dfb3b2133e4ba113f2e4c0e121e5', + 'cf2174118c8b6d7a4b48f6d534ce5c79422c086a63460502b827ce62a326683c', + ], + [ + 'd24a44e047e19b6f5afb81c7ca2f69080a5076689a010919f42725c2b789a33b', + '6fb8d5591b466f8fc63db50f1c0f1c69013f996887b8244d2cdec417afea8fa3', + ], + [ + 'ea01606a7a6c9cdd249fdfcfacb99584001edd28abbab77b5104e98e8e3b35d4', + '322af4908c7312b0cfbfe369f7a7b3cdb7d4494bc2823700cfd652188a3ea98d', + ], + [ + 'af8addbf2b661c8a6c6328655eb96651252007d8c5ea31be4ad196de8ce2131f', + '6749e67c029b85f52a034eafd096836b2520818680e26ac8f3dfbcdb71749700', + ], + [ + 'e3ae1974566ca06cc516d47e0fb165a674a3dabcfca15e722f0e3450f45889', + '2aeabe7e4531510116217f07bf4d07300de97e4874f81f533420a72eeb0bd6a4', + ], + [ + '591ee355313d99721cf6993ffed1e3e301993ff3ed258802075ea8ced397e246', + 'b0ea558a113c30bea60fc4775460c7901ff0b053d25ca2bdeee98f1a4be5d196', + ], + [ + '11396d55fda54c49f19aa97318d8da61fa8584e47b084945077cf03255b52984', + '998c74a8cd45ac01289d5833a7beb4744ff536b01b257be4c5767bea93ea57a4', + ], + [ + '3c5d2a1ba39c5a1790000738c9e0c40b8dcdfd5468754b6405540157e017aa7a', + 'b2284279995a34e2f9d4de7396fc18b80f9b8b9fdd270f6661f79ca4c81bd257', + ], + [ + 'cc8704b8a60a0defa3a99a7299f2e9c3fbc395afb04ac078425ef8a1793cc030', + 'bdd46039feed17881d1e0862db347f8cf395b74fc4bcdc4e940b74e3ac1f1b13', + ], + [ + 'c533e4f7ea8555aacd9777ac5cad29b97dd4defccc53ee7ea204119b2889b197', + '6f0a256bc5efdf429a2fb6242f1a43a2d9b925bb4a4b3a26bb8e0f45eb596096', + ], + [ + 'c14f8f2ccb27d6f109f6d08d03cc96a69ba8c34eec07bbcf566d48e33da6593', + 'c359d6923bb398f7fd4473e16fe1c28475b740dd098075e6c0e8649113dc3a38', + ], + [ + 'a6cbc3046bc6a450bac24789fa17115a4c9739ed75f8f21ce441f72e0b90e6ef', + '21ae7f4680e889bb130619e2c0f95a360ceb573c70603139862afd617fa9b9f', + ], + [ + '347d6d9a02c48927ebfb86c1359b1caf130a3c0267d11ce6344b39f99d43cc38', + '60ea7f61a353524d1c987f6ecec92f086d565ab687870cb12689ff1e31c74448', + ], + [ + 'da6545d2181db8d983f7dcb375ef5866d47c67b1bf31c8cf855ef7437b72656a', + '49b96715ab6878a79e78f07ce5680c5d6673051b4935bd897fea824b77dc208a', + ], + [ + 'c40747cc9d012cb1a13b8148309c6de7ec25d6945d657146b9d5994b8feb1111', + '5ca560753be2a12fc6de6caf2cb489565db936156b9514e1bb5e83037e0fa2d4', + ], + [ + '4e42c8ec82c99798ccf3a610be870e78338c7f713348bd34c8203ef4037f3502', + '7571d74ee5e0fb92a7a8b33a07783341a5492144cc54bcc40a94473693606437', + ], + [ + '3775ab7089bc6af823aba2e1af70b236d251cadb0c86743287522a1b3b0dedea', + 'be52d107bcfa09d8bcb9736a828cfa7fac8db17bf7a76a2c42ad961409018cf7', + ], + [ + 'cee31cbf7e34ec379d94fb814d3d775ad954595d1314ba8846959e3e82f74e26', + '8fd64a14c06b589c26b947ae2bcf6bfa0149ef0be14ed4d80f448a01c43b1c6d', + ], + [ + 'b4f9eaea09b6917619f6ea6a4eb5464efddb58fd45b1ebefcdc1a01d08b47986', + '39e5c9925b5a54b07433a4f18c61726f8bb131c012ca542eb24a8ac07200682a', + ], + [ + 'd4263dfc3d2df923a0179a48966d30ce84e2515afc3dccc1b77907792ebcc60e', + '62dfaf07a0f78feb30e30d6295853ce189e127760ad6cf7fae164e122a208d54', + ], + [ + '48457524820fa65a4f8d35eb6930857c0032acc0a4a2de422233eeda897612c4', + '25a748ab367979d98733c38a1fa1c2e7dc6cc07db2d60a9ae7a76aaa49bd0f77', + ], + [ + 'dfeeef1881101f2cb11644f3a2afdfc2045e19919152923f367a1767c11cceda', + 'ecfb7056cf1de042f9420bab396793c0c390bde74b4bbdff16a83ae09a9a7517', + ], + [ + '6d7ef6b17543f8373c573f44e1f389835d89bcbc6062ced36c82df83b8fae859', + 'cd450ec335438986dfefa10c57fea9bcc521a0959b2d80bbf74b190dca712d10', + ], + [ + 'e75605d59102a5a2684500d3b991f2e3f3c88b93225547035af25af66e04541f', + 'f5c54754a8f71ee540b9b48728473e314f729ac5308b06938360990e2bfad125', + ], + [ + 'eb98660f4c4dfaa06a2be453d5020bc99a0c2e60abe388457dd43fefb1ed620c', + '6cb9a8876d9cb8520609af3add26cd20a0a7cd8a9411131ce85f44100099223e', + ], + [ + '13e87b027d8514d35939f2e6892b19922154596941888336dc3563e3b8dba942', + 'fef5a3c68059a6dec5d624114bf1e91aac2b9da568d6abeb2570d55646b8adf1', + ], + [ + 'ee163026e9fd6fe017c38f06a5be6fc125424b371ce2708e7bf4491691e5764a', + '1acb250f255dd61c43d94ccc670d0f58f49ae3fa15b96623e5430da0ad6c62b2', + ], + [ + 'b268f5ef9ad51e4d78de3a750c2dc89b1e626d43505867999932e5db33af3d80', + '5f310d4b3c99b9ebb19f77d41c1dee018cf0d34fd4191614003e945a1216e423', + ], + [ + 'ff07f3118a9df035e9fad85eb6c7bfe42b02f01ca99ceea3bf7ffdba93c4750d', + '438136d603e858a3a5c440c38eccbaddc1d2942114e2eddd4740d098ced1f0d8', + ], + [ + '8d8b9855c7c052a34146fd20ffb658bea4b9f69e0d825ebec16e8c3ce2b526a1', + 'cdb559eedc2d79f926baf44fb84ea4d44bcf50fee51d7ceb30e2e7f463036758', + ], + [ + '52db0b5384dfbf05bfa9d472d7ae26dfe4b851ceca91b1eba54263180da32b63', + 'c3b997d050ee5d423ebaf66a6db9f57b3180c902875679de924b69d84a7b375', + ], + [ + 'e62f9490d3d51da6395efd24e80919cc7d0f29c3f3fa48c6fff543becbd43352', + '6d89ad7ba4876b0b22c2ca280c682862f342c8591f1daf5170e07bfd9ccafa7d', + ], + [ + '7f30ea2476b399b4957509c88f77d0191afa2ff5cb7b14fd6d8e7d65aaab1193', + 'ca5ef7d4b231c94c3b15389a5f6311e9daff7bb67b103e9880ef4bff637acaec', + ], + [ + '5098ff1e1d9f14fb46a210fada6c903fef0fb7b4a1dd1d9ac60a0361800b7a00', + '9731141d81fc8f8084d37c6e7542006b3ee1b40d60dfe5362a5b132fd17ddc0', + ], + [ + '32b78c7de9ee512a72895be6b9cbefa6e2f3c4ccce445c96b9f2c81e2778ad58', + 'ee1849f513df71e32efc3896ee28260c73bb80547ae2275ba497237794c8753c', + ], + [ + 'e2cb74fddc8e9fbcd076eef2a7c72b0ce37d50f08269dfc074b581550547a4f7', + 'd3aa2ed71c9dd2247a62df062736eb0baddea9e36122d2be8641abcb005cc4a4', + ], + [ + '8438447566d4d7bedadc299496ab357426009a35f235cb141be0d99cd10ae3a8', + 'c4e1020916980a4da5d01ac5e6ad330734ef0d7906631c4f2390426b2edd791f', + ], + [ + '4162d488b89402039b584c6fc6c308870587d9c46f660b878ab65c82c711d67e', + '67163e903236289f776f22c25fb8a3afc1732f2b84b4e95dbda47ae5a0852649', + ], + [ + '3fad3fa84caf0f34f0f89bfd2dcf54fc175d767aec3e50684f3ba4a4bf5f683d', + 'cd1bc7cb6cc407bb2f0ca647c718a730cf71872e7d0d2a53fa20efcdfe61826', + ], + [ + '674f2600a3007a00568c1a7ce05d0816c1fb84bf1370798f1c69532faeb1a86b', + '299d21f9413f33b3edf43b257004580b70db57da0b182259e09eecc69e0d38a5', + ], + [ + 'd32f4da54ade74abb81b815ad1fb3b263d82d6c692714bcff87d29bd5ee9f08f', + 'f9429e738b8e53b968e99016c059707782e14f4535359d582fc416910b3eea87', + ], + [ + '30e4e670435385556e593657135845d36fbb6931f72b08cb1ed954f1e3ce3ff6', + '462f9bce619898638499350113bbc9b10a878d35da70740dc695a559eb88db7b', + ], + [ + 'be2062003c51cc3004682904330e4dee7f3dcd10b01e580bf1971b04d4cad297', + '62188bc49d61e5428573d48a74e1c655b1c61090905682a0d5558ed72dccb9bc', + ], + [ + '93144423ace3451ed29e0fb9ac2af211cb6e84a601df5993c419859fff5df04a', + '7c10dfb164c3425f5c71a3f9d7992038f1065224f72bb9d1d902a6d13037b47c', + ], + [ + 'b015f8044f5fcbdcf21ca26d6c34fb8197829205c7b7d2a7cb66418c157b112c', + 'ab8c1e086d04e813744a655b2df8d5f83b3cdc6faa3088c1d3aea1454e3a1d5f', + ], + [ + 'd5e9e1da649d97d89e4868117a465a3a4f8a18de57a140d36b3f2af341a21b52', + '4cb04437f391ed73111a13cc1d4dd0db1693465c2240480d8955e8592f27447a', + ], + [ + 'd3ae41047dd7ca065dbf8ed77b992439983005cd72e16d6f996a5316d36966bb', + 'bd1aeb21ad22ebb22a10f0303417c6d964f8cdd7df0aca614b10dc14d125ac46', + ], + [ + '463e2763d885f958fc66cdd22800f0a487197d0a82e377b49f80af87c897b065', + 'bfefacdb0e5d0fd7df3a311a94de062b26b80c61fbc97508b79992671ef7ca7f', + ], + [ + '7985fdfd127c0567c6f53ec1bb63ec3158e597c40bfe747c83cddfc910641917', + '603c12daf3d9862ef2b25fe1de289aed24ed291e0ec6708703a5bd567f32ed03', + ], + [ + '74a1ad6b5f76e39db2dd249410eac7f99e74c59cb83d2d0ed5ff1543da7703e9', + 'cc6157ef18c9c63cd6193d83631bbea0093e0968942e8c33d5737fd790e0db08', + ], + [ + '30682a50703375f602d416664ba19b7fc9bab42c72747463a71d0896b22f6da3', + '553e04f6b018b4fa6c8f39e7f311d3176290d0e0f19ca73f17714d9977a22ff8', + ], + [ + '9e2158f0d7c0d5f26c3791efefa79597654e7a2b2464f52b1ee6c1347769ef57', + '712fcdd1b9053f09003a3481fa7762e9ffd7c8ef35a38509e2fbf2629008373', + ], + [ + '176e26989a43c9cfeba4029c202538c28172e566e3c4fce7322857f3be327d66', + 'ed8cc9d04b29eb877d270b4878dc43c19aefd31f4eee09ee7b47834c1fa4b1c3', + ], + [ + '75d46efea3771e6e68abb89a13ad747ecf1892393dfc4f1b7004788c50374da8', + '9852390a99507679fd0b86fd2b39a868d7efc22151346e1a3ca4726586a6bed8', + ], + [ + '809a20c67d64900ffb698c4c825f6d5f2310fb0451c869345b7319f645605721', + '9e994980d9917e22b76b061927fa04143d096ccc54963e6a5ebfa5f3f8e286c1', + ], + [ + '1b38903a43f7f114ed4500b4eac7083fdefece1cf29c63528d563446f972c180', + '4036edc931a60ae889353f77fd53de4a2708b26b6f5da72ad3394119daf408f9', + ], + ], + }, +}; + +},{}],97:[function(require,module,exports){ +'use strict'; + +var utils = exports; +var BN = require('bn.js'); +var minAssert = require('minimalistic-assert'); +var minUtils = require('minimalistic-crypto-utils'); + +utils.assert = minAssert; +utils.toArray = minUtils.toArray; +utils.zero2 = minUtils.zero2; +utils.toHex = minUtils.toHex; +utils.encode = minUtils.encode; + +// Represent num in a w-NAF form +function getNAF(num, w, bits) { + var naf = new Array(Math.max(num.bitLength(), bits) + 1); + naf.fill(0); + + var ws = 1 << (w + 1); + var k = num.clone(); + + for (var i = 0; i < naf.length; i++) { + var z; + var mod = k.andln(ws - 1); + if (k.isOdd()) { + if (mod > (ws >> 1) - 1) + z = (ws >> 1) - mod; + else + z = mod; + k.isubn(z); + } else { + z = 0; + } + + naf[i] = z; + k.iushrn(1); + } + + return naf; +} +utils.getNAF = getNAF; + +// Represent k1, k2 in a Joint Sparse Form +function getJSF(k1, k2) { + var jsf = [ + [], + [], + ]; + + k1 = k1.clone(); + k2 = k2.clone(); + var d1 = 0; + var d2 = 0; + var m8; + while (k1.cmpn(-d1) > 0 || k2.cmpn(-d2) > 0) { + // First phase + var m14 = (k1.andln(3) + d1) & 3; + var m24 = (k2.andln(3) + d2) & 3; + if (m14 === 3) + m14 = -1; + if (m24 === 3) + m24 = -1; + var u1; + if ((m14 & 1) === 0) { + u1 = 0; + } else { + m8 = (k1.andln(7) + d1) & 7; + if ((m8 === 3 || m8 === 5) && m24 === 2) + u1 = -m14; + else + u1 = m14; + } + jsf[0].push(u1); + + var u2; + if ((m24 & 1) === 0) { + u2 = 0; + } else { + m8 = (k2.andln(7) + d2) & 7; + if ((m8 === 3 || m8 === 5) && m14 === 2) + u2 = -m24; + else + u2 = m24; + } + jsf[1].push(u2); + + // Second phase + if (2 * d1 === u1 + 1) + d1 = 1 - d1; + if (2 * d2 === u2 + 1) + d2 = 1 - d2; + k1.iushrn(1); + k2.iushrn(1); + } + + return jsf; +} +utils.getJSF = getJSF; + +function cachedProperty(obj, name, computer) { + var key = '_' + name; + obj.prototype[name] = function cachedProperty() { + return this[key] !== undefined ? this[key] : + this[key] = computer.call(this); + }; +} +utils.cachedProperty = cachedProperty; + +function parseBytes(bytes) { + return typeof bytes === 'string' ? utils.toArray(bytes, 'hex') : + bytes; +} +utils.parseBytes = parseBytes; + +function intFromLE(bytes) { + return new BN(bytes, 'hex', 'le'); +} +utils.intFromLE = intFromLE; + + +},{"bn.js":98,"minimalistic-assert":136,"minimalistic-crypto-utils":137}],98:[function(require,module,exports){ +arguments[4][15][0].apply(exports,arguments) +},{"buffer":19,"dup":15}],99:[function(require,module,exports){ +module.exports={ + "_from": "elliptic@^6.5.3", + "_id": "elliptic@6.5.4", + "_inBundle": false, + "_integrity": "sha512-iLhC6ULemrljPZb+QutR5TQGB+pdW6KGD5RSegS+8sorOZT+rdQFbsQFJgvN3eRqNALqJer4oQ16YvJHlU8hzQ==", + "_location": "/browserify/elliptic", + "_phantomChildren": {}, + "_requested": { + "type": "range", + "registry": true, + "raw": "elliptic@^6.5.3", + "name": "elliptic", + "escapedName": "elliptic", + "rawSpec": "^6.5.3", + "saveSpec": null, + "fetchSpec": "^6.5.3" + }, + "_requiredBy": [ + "/browserify/browserify-sign", + "/browserify/create-ecdh" + ], + "_resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.5.4.tgz", + "_shasum": "da37cebd31e79a1367e941b592ed1fbebd58abbb", + "_spec": "elliptic@^6.5.3", + "_where": "/home/default2/.nvm/versions/node/v14.16.1/lib/node_modules/browserify/node_modules/browserify-sign", + "author": { + "name": "Fedor Indutny", + "email": "fedor@indutny.com" + }, + "bugs": { + "url": "https://github.com/indutny/elliptic/issues" + }, + "bundleDependencies": false, + "dependencies": { + "bn.js": "^4.11.9", + "brorand": "^1.1.0", + "hash.js": "^1.0.0", + "hmac-drbg": "^1.0.1", + "inherits": "^2.0.4", + "minimalistic-assert": "^1.0.1", + "minimalistic-crypto-utils": "^1.0.1" + }, + "deprecated": false, + "description": "EC cryptography", + "devDependencies": { + "brfs": "^2.0.2", + "coveralls": "^3.1.0", + "eslint": "^7.6.0", + "grunt": "^1.2.1", + "grunt-browserify": "^5.3.0", + "grunt-cli": "^1.3.2", + "grunt-contrib-connect": "^3.0.0", + "grunt-contrib-copy": "^1.0.0", + "grunt-contrib-uglify": "^5.0.0", + "grunt-mocha-istanbul": "^5.0.2", + "grunt-saucelabs": "^9.0.1", + "istanbul": "^0.4.5", + "mocha": "^8.0.1" + }, + "files": [ + "lib" + ], + "homepage": "https://github.com/indutny/elliptic", + "keywords": [ + "EC", + "Elliptic", + "curve", + "Cryptography" + ], + "license": "MIT", + "main": "lib/elliptic.js", + "name": "elliptic", + "repository": { + "type": "git", + "url": "git+ssh://git@github.com/indutny/elliptic.git" + }, + "scripts": { + "lint": "eslint lib test", + "lint:fix": "npm run lint -- --fix", + "test": "npm run lint && npm run unit", + "unit": "istanbul test _mocha --reporter=spec test/index.js", + "version": "grunt dist && git add dist/" + }, + "version": "6.5.4" +} + +},{}],100:[function(require,module,exports){ +// Copyright Joyent, Inc. and other Node contributors. +// +// 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. + +'use strict'; + +var R = typeof Reflect === 'object' ? Reflect : null +var ReflectApply = R && typeof R.apply === 'function' + ? R.apply + : function ReflectApply(target, receiver, args) { + return Function.prototype.apply.call(target, receiver, args); + } + +var ReflectOwnKeys +if (R && typeof R.ownKeys === 'function') { + ReflectOwnKeys = R.ownKeys +} else if (Object.getOwnPropertySymbols) { + ReflectOwnKeys = function ReflectOwnKeys(target) { + return Object.getOwnPropertyNames(target) + .concat(Object.getOwnPropertySymbols(target)); + }; +} else { + ReflectOwnKeys = function ReflectOwnKeys(target) { + return Object.getOwnPropertyNames(target); + }; +} + +function ProcessEmitWarning(warning) { + if (console && console.warn) console.warn(warning); +} + +var NumberIsNaN = Number.isNaN || function NumberIsNaN(value) { + return value !== value; +} + +function EventEmitter() { + EventEmitter.init.call(this); +} +module.exports = EventEmitter; +module.exports.once = once; + +// Backwards-compat with node 0.10.x +EventEmitter.EventEmitter = EventEmitter; + +EventEmitter.prototype._events = undefined; +EventEmitter.prototype._eventsCount = 0; +EventEmitter.prototype._maxListeners = undefined; + +// By default EventEmitters will print a warning if more than 10 listeners are +// added to it. This is a useful default which helps finding memory leaks. +var defaultMaxListeners = 10; + +function checkListener(listener) { + if (typeof listener !== 'function') { + throw new TypeError('The "listener" argument must be of type Function. Received type ' + typeof listener); + } +} + +Object.defineProperty(EventEmitter, 'defaultMaxListeners', { + enumerable: true, + get: function() { + return defaultMaxListeners; + }, + set: function(arg) { + if (typeof arg !== 'number' || arg < 0 || NumberIsNaN(arg)) { + throw new RangeError('The value of "defaultMaxListeners" is out of range. It must be a non-negative number. Received ' + arg + '.'); + } + defaultMaxListeners = arg; + } +}); + +EventEmitter.init = function() { + + if (this._events === undefined || + this._events === Object.getPrototypeOf(this)._events) { + this._events = Object.create(null); + this._eventsCount = 0; + } + + this._maxListeners = this._maxListeners || undefined; +}; + +// Obviously not all Emitters should be limited to 10. This function allows +// that to be increased. Set to zero for unlimited. +EventEmitter.prototype.setMaxListeners = function setMaxListeners(n) { + if (typeof n !== 'number' || n < 0 || NumberIsNaN(n)) { + throw new RangeError('The value of "n" is out of range. It must be a non-negative number. Received ' + n + '.'); + } + this._maxListeners = n; + return this; +}; + +function _getMaxListeners(that) { + if (that._maxListeners === undefined) + return EventEmitter.defaultMaxListeners; + return that._maxListeners; +} + +EventEmitter.prototype.getMaxListeners = function getMaxListeners() { + return _getMaxListeners(this); +}; + +EventEmitter.prototype.emit = function emit(type) { + var args = []; + for (var i = 1; i < arguments.length; i++) args.push(arguments[i]); + var doError = (type === 'error'); + + var events = this._events; + if (events !== undefined) + doError = (doError && events.error === undefined); + else if (!doError) + return false; + + // If there is no 'error' event listener then throw. + if (doError) { + var er; + if (args.length > 0) + er = args[0]; + if (er instanceof Error) { + // Note: The comments on the `throw` lines are intentional, they show + // up in Node's output if this results in an unhandled exception. + throw er; // Unhandled 'error' event + } + // At least give some kind of context to the user + var err = new Error('Unhandled error.' + (er ? ' (' + er.message + ')' : '')); + err.context = er; + throw err; // Unhandled 'error' event + } + + var handler = events[type]; + + if (handler === undefined) + return false; + + if (typeof handler === 'function') { + ReflectApply(handler, this, args); + } else { + var len = handler.length; + var listeners = arrayClone(handler, len); + for (var i = 0; i < len; ++i) + ReflectApply(listeners[i], this, args); + } + + return true; +}; + +function _addListener(target, type, listener, prepend) { + var m; + var events; + var existing; + + checkListener(listener); + + events = target._events; + if (events === undefined) { + events = target._events = Object.create(null); + target._eventsCount = 0; + } else { + // To avoid recursion in the case that type === "newListener"! Before + // adding it to the listeners, first emit "newListener". + if (events.newListener !== undefined) { + target.emit('newListener', type, + listener.listener ? listener.listener : listener); + + // Re-assign `events` because a newListener handler could have caused the + // this._events to be assigned to a new object + events = target._events; + } + existing = events[type]; + } + + if (existing === undefined) { + // Optimize the case of one listener. Don't need the extra array object. + existing = events[type] = listener; + ++target._eventsCount; + } else { + if (typeof existing === 'function') { + // Adding the second element, need to change to array. + existing = events[type] = + prepend ? [listener, existing] : [existing, listener]; + // If we've already got an array, just append. + } else if (prepend) { + existing.unshift(listener); + } else { + existing.push(listener); + } + + // Check for listener leak + m = _getMaxListeners(target); + if (m > 0 && existing.length > m && !existing.warned) { + existing.warned = true; + // No error code for this since it is a Warning + // eslint-disable-next-line no-restricted-syntax + var w = new Error('Possible EventEmitter memory leak detected. ' + + existing.length + ' ' + String(type) + ' listeners ' + + 'added. Use emitter.setMaxListeners() to ' + + 'increase limit'); + w.name = 'MaxListenersExceededWarning'; + w.emitter = target; + w.type = type; + w.count = existing.length; + ProcessEmitWarning(w); + } + } + + return target; +} + +EventEmitter.prototype.addListener = function addListener(type, listener) { + return _addListener(this, type, listener, false); +}; + +EventEmitter.prototype.on = EventEmitter.prototype.addListener; + +EventEmitter.prototype.prependListener = + function prependListener(type, listener) { + return _addListener(this, type, listener, true); + }; + +function onceWrapper() { + if (!this.fired) { + this.target.removeListener(this.type, this.wrapFn); + this.fired = true; + if (arguments.length === 0) + return this.listener.call(this.target); + return this.listener.apply(this.target, arguments); + } +} + +function _onceWrap(target, type, listener) { + var state = { fired: false, wrapFn: undefined, target: target, type: type, listener: listener }; + var wrapped = onceWrapper.bind(state); + wrapped.listener = listener; + state.wrapFn = wrapped; + return wrapped; +} + +EventEmitter.prototype.once = function once(type, listener) { + checkListener(listener); + this.on(type, _onceWrap(this, type, listener)); + return this; +}; + +EventEmitter.prototype.prependOnceListener = + function prependOnceListener(type, listener) { + checkListener(listener); + this.prependListener(type, _onceWrap(this, type, listener)); + return this; + }; + +// Emits a 'removeListener' event if and only if the listener was removed. +EventEmitter.prototype.removeListener = + function removeListener(type, listener) { + var list, events, position, i, originalListener; + + checkListener(listener); + + events = this._events; + if (events === undefined) + return this; + + list = events[type]; + if (list === undefined) + return this; + + if (list === listener || list.listener === listener) { + if (--this._eventsCount === 0) + this._events = Object.create(null); + else { + delete events[type]; + if (events.removeListener) + this.emit('removeListener', type, list.listener || listener); + } + } else if (typeof list !== 'function') { + position = -1; + + for (i = list.length - 1; i >= 0; i--) { + if (list[i] === listener || list[i].listener === listener) { + originalListener = list[i].listener; + position = i; + break; + } + } + + if (position < 0) + return this; + + if (position === 0) + list.shift(); + else { + spliceOne(list, position); + } + + if (list.length === 1) + events[type] = list[0]; + + if (events.removeListener !== undefined) + this.emit('removeListener', type, originalListener || listener); + } + + return this; + }; + +EventEmitter.prototype.off = EventEmitter.prototype.removeListener; + +EventEmitter.prototype.removeAllListeners = + function removeAllListeners(type) { + var listeners, events, i; + + events = this._events; + if (events === undefined) + return this; + + // not listening for removeListener, no need to emit + if (events.removeListener === undefined) { + if (arguments.length === 0) { + this._events = Object.create(null); + this._eventsCount = 0; + } else if (events[type] !== undefined) { + if (--this._eventsCount === 0) + this._events = Object.create(null); + else + delete events[type]; + } + return this; + } + + // emit removeListener for all listeners on all events + if (arguments.length === 0) { + var keys = Object.keys(events); + var key; + for (i = 0; i < keys.length; ++i) { + key = keys[i]; + if (key === 'removeListener') continue; + this.removeAllListeners(key); + } + this.removeAllListeners('removeListener'); + this._events = Object.create(null); + this._eventsCount = 0; + return this; + } + + listeners = events[type]; + + if (typeof listeners === 'function') { + this.removeListener(type, listeners); + } else if (listeners !== undefined) { + // LIFO order + for (i = listeners.length - 1; i >= 0; i--) { + this.removeListener(type, listeners[i]); + } + } + + return this; + }; + +function _listeners(target, type, unwrap) { + var events = target._events; + + if (events === undefined) + return []; + + var evlistener = events[type]; + if (evlistener === undefined) + return []; + + if (typeof evlistener === 'function') + return unwrap ? [evlistener.listener || evlistener] : [evlistener]; + + return unwrap ? + unwrapListeners(evlistener) : arrayClone(evlistener, evlistener.length); +} + +EventEmitter.prototype.listeners = function listeners(type) { + return _listeners(this, type, true); +}; + +EventEmitter.prototype.rawListeners = function rawListeners(type) { + return _listeners(this, type, false); +}; + +EventEmitter.listenerCount = function(emitter, type) { + if (typeof emitter.listenerCount === 'function') { + return emitter.listenerCount(type); + } else { + return listenerCount.call(emitter, type); + } +}; + +EventEmitter.prototype.listenerCount = listenerCount; +function listenerCount(type) { + var events = this._events; + + if (events !== undefined) { + var evlistener = events[type]; + + if (typeof evlistener === 'function') { + return 1; + } else if (evlistener !== undefined) { + return evlistener.length; + } + } + + return 0; +} + +EventEmitter.prototype.eventNames = function eventNames() { + return this._eventsCount > 0 ? ReflectOwnKeys(this._events) : []; +}; + +function arrayClone(arr, n) { + var copy = new Array(n); + for (var i = 0; i < n; ++i) + copy[i] = arr[i]; + return copy; +} + +function spliceOne(list, index) { + for (; index + 1 < list.length; index++) + list[index] = list[index + 1]; + list.pop(); +} + +function unwrapListeners(arr) { + var ret = new Array(arr.length); + for (var i = 0; i < ret.length; ++i) { + ret[i] = arr[i].listener || arr[i]; + } + return ret; +} + +function once(emitter, name) { + return new Promise(function (resolve, reject) { + function errorListener(err) { + emitter.removeListener(name, resolver); + reject(err); + } + + function resolver() { + if (typeof emitter.removeListener === 'function') { + emitter.removeListener('error', errorListener); + } + resolve([].slice.call(arguments)); + }; + + eventTargetAgnosticAddListener(emitter, name, resolver, { once: true }); + if (name !== 'error') { + addErrorHandlerIfEventEmitter(emitter, errorListener, { once: true }); + } + }); +} + +function addErrorHandlerIfEventEmitter(emitter, handler, flags) { + if (typeof emitter.on === 'function') { + eventTargetAgnosticAddListener(emitter, 'error', handler, flags); + } +} + +function eventTargetAgnosticAddListener(emitter, name, listener, flags) { + if (typeof emitter.on === 'function') { + if (flags.once) { + emitter.once(name, listener); + } else { + emitter.on(name, listener); + } + } else if (typeof emitter.addEventListener === 'function') { + // EventTarget does not have `error` event semantics like Node + // EventEmitters, we do not listen for `error` events here. + emitter.addEventListener(name, function wrapListener(arg) { + // IE does not have builtin `{ once: true }` support so we + // have to do it manually. + if (flags.once) { + emitter.removeEventListener(name, wrapListener); + } + listener(arg); + }); + } else { + throw new TypeError('The "emitter" argument must be of type EventEmitter. Received type ' + typeof emitter); + } +} + +},{}],101:[function(require,module,exports){ +var Buffer = require('safe-buffer').Buffer +var MD5 = require('md5.js') + +/* eslint-disable camelcase */ +function EVP_BytesToKey (password, salt, keyBits, ivLen) { + if (!Buffer.isBuffer(password)) password = Buffer.from(password, 'binary') + if (salt) { + if (!Buffer.isBuffer(salt)) salt = Buffer.from(salt, 'binary') + if (salt.length !== 8) throw new RangeError('salt should be Buffer with 8 byte length') + } + + var keyLen = keyBits / 8 + var key = Buffer.alloc(keyLen) + var iv = Buffer.alloc(ivLen || 0) + var tmp = Buffer.alloc(0) + + while (keyLen > 0 || ivLen > 0) { + var hash = new MD5() + hash.update(tmp) + hash.update(password) + if (salt) hash.update(salt) + tmp = hash.digest() + + var used = 0 + + if (keyLen > 0) { + var keyStart = key.length - keyLen + used = Math.min(keyLen, tmp.length) + tmp.copy(key, keyStart, 0, used) + keyLen -= used + } + + if (used < tmp.length && ivLen > 0) { + var ivStart = iv.length - ivLen + var length = Math.min(ivLen, tmp.length - used) + tmp.copy(iv, ivStart, used, used + length) + ivLen -= length + } + } + + tmp.fill(0) + return { key: key, iv: iv } +} + +module.exports = EVP_BytesToKey + +},{"md5.js":133,"safe-buffer":160}],102:[function(require,module,exports){ +'use strict' +var Buffer = require('safe-buffer').Buffer +var Transform = require('readable-stream').Transform +var inherits = require('inherits') + +function throwIfNotStringOrBuffer (val, prefix) { + if (!Buffer.isBuffer(val) && typeof val !== 'string') { + throw new TypeError(prefix + ' must be a string or a buffer') + } +} + +function HashBase (blockSize) { + Transform.call(this) + + this._block = Buffer.allocUnsafe(blockSize) + this._blockSize = blockSize + this._blockOffset = 0 + this._length = [0, 0, 0, 0] + + this._finalized = false +} + +inherits(HashBase, Transform) + +HashBase.prototype._transform = function (chunk, encoding, callback) { + var error = null + try { + this.update(chunk, encoding) + } catch (err) { + error = err + } + + callback(error) +} + +HashBase.prototype._flush = function (callback) { + var error = null + try { + this.push(this.digest()) + } catch (err) { + error = err + } + + callback(error) +} + +HashBase.prototype.update = function (data, encoding) { + throwIfNotStringOrBuffer(data, 'Data') + if (this._finalized) throw new Error('Digest already called') + if (!Buffer.isBuffer(data)) data = Buffer.from(data, encoding) + + // consume data + var block = this._block + var offset = 0 + while (this._blockOffset + data.length - offset >= this._blockSize) { + for (var i = this._blockOffset; i < this._blockSize;) block[i++] = data[offset++] + this._update() + this._blockOffset = 0 + } + while (offset < data.length) block[this._blockOffset++] = data[offset++] + + // update length + for (var j = 0, carry = data.length * 8; carry > 0; ++j) { + this._length[j] += carry + carry = (this._length[j] / 0x0100000000) | 0 + if (carry > 0) this._length[j] -= 0x0100000000 * carry + } + + return this +} + +HashBase.prototype._update = function () { + throw new Error('_update is not implemented') +} + +HashBase.prototype.digest = function (encoding) { + if (this._finalized) throw new Error('Digest already called') + this._finalized = true + + var digest = this._digest() + if (encoding !== undefined) digest = digest.toString(encoding) + + // reset state + this._block.fill(0) + this._blockOffset = 0 + for (var i = 0; i < 4; ++i) this._length[i] = 0 + + return digest +} + +HashBase.prototype._digest = function () { + throw new Error('_digest is not implemented') +} + +module.exports = HashBase + +},{"inherits":132,"readable-stream":117,"safe-buffer":160}],103:[function(require,module,exports){ +arguments[4][47][0].apply(exports,arguments) +},{"dup":47}],104:[function(require,module,exports){ +arguments[4][48][0].apply(exports,arguments) +},{"./_stream_readable":106,"./_stream_writable":108,"_process":149,"dup":48,"inherits":132}],105:[function(require,module,exports){ +arguments[4][49][0].apply(exports,arguments) +},{"./_stream_transform":107,"dup":49,"inherits":132}],106:[function(require,module,exports){ +arguments[4][50][0].apply(exports,arguments) +},{"../errors":103,"./_stream_duplex":104,"./internal/streams/async_iterator":109,"./internal/streams/buffer_list":110,"./internal/streams/destroy":111,"./internal/streams/from":113,"./internal/streams/state":115,"./internal/streams/stream":116,"_process":149,"buffer":63,"dup":50,"events":100,"inherits":132,"string_decoder/":185,"util":19}],107:[function(require,module,exports){ +arguments[4][51][0].apply(exports,arguments) +},{"../errors":103,"./_stream_duplex":104,"dup":51,"inherits":132}],108:[function(require,module,exports){ +arguments[4][52][0].apply(exports,arguments) +},{"../errors":103,"./_stream_duplex":104,"./internal/streams/destroy":111,"./internal/streams/state":115,"./internal/streams/stream":116,"_process":149,"buffer":63,"dup":52,"inherits":132,"util-deprecate":186}],109:[function(require,module,exports){ +arguments[4][53][0].apply(exports,arguments) +},{"./end-of-stream":112,"_process":149,"dup":53}],110:[function(require,module,exports){ +arguments[4][54][0].apply(exports,arguments) +},{"buffer":63,"dup":54,"util":19}],111:[function(require,module,exports){ +arguments[4][55][0].apply(exports,arguments) +},{"_process":149,"dup":55}],112:[function(require,module,exports){ +arguments[4][56][0].apply(exports,arguments) +},{"../../../errors":103,"dup":56}],113:[function(require,module,exports){ +arguments[4][57][0].apply(exports,arguments) +},{"dup":57}],114:[function(require,module,exports){ +arguments[4][58][0].apply(exports,arguments) +},{"../../../errors":103,"./end-of-stream":112,"dup":58}],115:[function(require,module,exports){ +arguments[4][59][0].apply(exports,arguments) +},{"../../../errors":103,"dup":59}],116:[function(require,module,exports){ +arguments[4][60][0].apply(exports,arguments) +},{"dup":60,"events":100}],117:[function(require,module,exports){ +arguments[4][61][0].apply(exports,arguments) +},{"./lib/_stream_duplex.js":104,"./lib/_stream_passthrough.js":105,"./lib/_stream_readable.js":106,"./lib/_stream_transform.js":107,"./lib/_stream_writable.js":108,"./lib/internal/streams/end-of-stream.js":112,"./lib/internal/streams/pipeline.js":114,"dup":61}],118:[function(require,module,exports){ +var hash = exports; + +hash.utils = require('./hash/utils'); +hash.common = require('./hash/common'); +hash.sha = require('./hash/sha'); +hash.ripemd = require('./hash/ripemd'); +hash.hmac = require('./hash/hmac'); + +// Proxy hash functions to the main object +hash.sha1 = hash.sha.sha1; +hash.sha256 = hash.sha.sha256; +hash.sha224 = hash.sha.sha224; +hash.sha384 = hash.sha.sha384; +hash.sha512 = hash.sha.sha512; +hash.ripemd160 = hash.ripemd.ripemd160; + +},{"./hash/common":119,"./hash/hmac":120,"./hash/ripemd":121,"./hash/sha":122,"./hash/utils":129}],119:[function(require,module,exports){ +'use strict'; + +var utils = require('./utils'); +var assert = require('minimalistic-assert'); + +function BlockHash() { + this.pending = null; + this.pendingTotal = 0; + this.blockSize = this.constructor.blockSize; + this.outSize = this.constructor.outSize; + this.hmacStrength = this.constructor.hmacStrength; + this.padLength = this.constructor.padLength / 8; + this.endian = 'big'; + + this._delta8 = this.blockSize / 8; + this._delta32 = this.blockSize / 32; +} +exports.BlockHash = BlockHash; + +BlockHash.prototype.update = function update(msg, enc) { + // Convert message to array, pad it, and join into 32bit blocks + msg = utils.toArray(msg, enc); + if (!this.pending) + this.pending = msg; + else + this.pending = this.pending.concat(msg); + this.pendingTotal += msg.length; + + // Enough data, try updating + if (this.pending.length >= this._delta8) { + msg = this.pending; + + // Process pending data in blocks + var r = msg.length % this._delta8; + this.pending = msg.slice(msg.length - r, msg.length); + if (this.pending.length === 0) + this.pending = null; + + msg = utils.join32(msg, 0, msg.length - r, this.endian); + for (var i = 0; i < msg.length; i += this._delta32) + this._update(msg, i, i + this._delta32); + } + + return this; +}; + +BlockHash.prototype.digest = function digest(enc) { + this.update(this._pad()); + assert(this.pending === null); + + return this._digest(enc); +}; + +BlockHash.prototype._pad = function pad() { + var len = this.pendingTotal; + var bytes = this._delta8; + var k = bytes - ((len + this.padLength) % bytes); + var res = new Array(k + this.padLength); + res[0] = 0x80; + for (var i = 1; i < k; i++) + res[i] = 0; + + // Append length + len <<= 3; + if (this.endian === 'big') { + for (var t = 8; t < this.padLength; t++) + res[i++] = 0; + + res[i++] = 0; + res[i++] = 0; + res[i++] = 0; + res[i++] = 0; + res[i++] = (len >>> 24) & 0xff; + res[i++] = (len >>> 16) & 0xff; + res[i++] = (len >>> 8) & 0xff; + res[i++] = len & 0xff; + } else { + res[i++] = len & 0xff; + res[i++] = (len >>> 8) & 0xff; + res[i++] = (len >>> 16) & 0xff; + res[i++] = (len >>> 24) & 0xff; + res[i++] = 0; + res[i++] = 0; + res[i++] = 0; + res[i++] = 0; + + for (t = 8; t < this.padLength; t++) + res[i++] = 0; + } + + return res; +}; + +},{"./utils":129,"minimalistic-assert":136}],120:[function(require,module,exports){ +'use strict'; + +var utils = require('./utils'); +var assert = require('minimalistic-assert'); + +function Hmac(hash, key, enc) { + if (!(this instanceof Hmac)) + return new Hmac(hash, key, enc); + this.Hash = hash; + this.blockSize = hash.blockSize / 8; + this.outSize = hash.outSize / 8; + this.inner = null; + this.outer = null; + + this._init(utils.toArray(key, enc)); +} +module.exports = Hmac; + +Hmac.prototype._init = function init(key) { + // Shorten key, if needed + if (key.length > this.blockSize) + key = new this.Hash().update(key).digest(); + assert(key.length <= this.blockSize); + + // Add padding to key + for (var i = key.length; i < this.blockSize; i++) + key.push(0); + + for (i = 0; i < key.length; i++) + key[i] ^= 0x36; + this.inner = new this.Hash().update(key); + + // 0x36 ^ 0x5c = 0x6a + for (i = 0; i < key.length; i++) + key[i] ^= 0x6a; + this.outer = new this.Hash().update(key); +}; + +Hmac.prototype.update = function update(msg, enc) { + this.inner.update(msg, enc); + return this; +}; + +Hmac.prototype.digest = function digest(enc) { + this.outer.update(this.inner.digest()); + return this.outer.digest(enc); +}; + +},{"./utils":129,"minimalistic-assert":136}],121:[function(require,module,exports){ +'use strict'; + +var utils = require('./utils'); +var common = require('./common'); + +var rotl32 = utils.rotl32; +var sum32 = utils.sum32; +var sum32_3 = utils.sum32_3; +var sum32_4 = utils.sum32_4; +var BlockHash = common.BlockHash; + +function RIPEMD160() { + if (!(this instanceof RIPEMD160)) + return new RIPEMD160(); + + BlockHash.call(this); + + this.h = [ 0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476, 0xc3d2e1f0 ]; + this.endian = 'little'; +} +utils.inherits(RIPEMD160, BlockHash); +exports.ripemd160 = RIPEMD160; + +RIPEMD160.blockSize = 512; +RIPEMD160.outSize = 160; +RIPEMD160.hmacStrength = 192; +RIPEMD160.padLength = 64; + +RIPEMD160.prototype._update = function update(msg, start) { + var A = this.h[0]; + var B = this.h[1]; + var C = this.h[2]; + var D = this.h[3]; + var E = this.h[4]; + var Ah = A; + var Bh = B; + var Ch = C; + var Dh = D; + var Eh = E; + for (var j = 0; j < 80; j++) { + var T = sum32( + rotl32( + sum32_4(A, f(j, B, C, D), msg[r[j] + start], K(j)), + s[j]), + E); + A = E; + E = D; + D = rotl32(C, 10); + C = B; + B = T; + T = sum32( + rotl32( + sum32_4(Ah, f(79 - j, Bh, Ch, Dh), msg[rh[j] + start], Kh(j)), + sh[j]), + Eh); + Ah = Eh; + Eh = Dh; + Dh = rotl32(Ch, 10); + Ch = Bh; + Bh = T; + } + T = sum32_3(this.h[1], C, Dh); + this.h[1] = sum32_3(this.h[2], D, Eh); + this.h[2] = sum32_3(this.h[3], E, Ah); + this.h[3] = sum32_3(this.h[4], A, Bh); + this.h[4] = sum32_3(this.h[0], B, Ch); + this.h[0] = T; +}; + +RIPEMD160.prototype._digest = function digest(enc) { + if (enc === 'hex') + return utils.toHex32(this.h, 'little'); + else + return utils.split32(this.h, 'little'); +}; + +function f(j, x, y, z) { + if (j <= 15) + return x ^ y ^ z; + else if (j <= 31) + return (x & y) | ((~x) & z); + else if (j <= 47) + return (x | (~y)) ^ z; + else if (j <= 63) + return (x & z) | (y & (~z)); + else + return x ^ (y | (~z)); +} + +function K(j) { + if (j <= 15) + return 0x00000000; + else if (j <= 31) + return 0x5a827999; + else if (j <= 47) + return 0x6ed9eba1; + else if (j <= 63) + return 0x8f1bbcdc; + else + return 0xa953fd4e; +} + +function Kh(j) { + if (j <= 15) + return 0x50a28be6; + else if (j <= 31) + return 0x5c4dd124; + else if (j <= 47) + return 0x6d703ef3; + else if (j <= 63) + return 0x7a6d76e9; + else + return 0x00000000; +} + +var r = [ + 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 rh = [ + 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 s = [ + 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 sh = [ + 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 +]; + +},{"./common":119,"./utils":129}],122:[function(require,module,exports){ +'use strict'; + +exports.sha1 = require('./sha/1'); +exports.sha224 = require('./sha/224'); +exports.sha256 = require('./sha/256'); +exports.sha384 = require('./sha/384'); +exports.sha512 = require('./sha/512'); + +},{"./sha/1":123,"./sha/224":124,"./sha/256":125,"./sha/384":126,"./sha/512":127}],123:[function(require,module,exports){ +'use strict'; + +var utils = require('../utils'); +var common = require('../common'); +var shaCommon = require('./common'); + +var rotl32 = utils.rotl32; +var sum32 = utils.sum32; +var sum32_5 = utils.sum32_5; +var ft_1 = shaCommon.ft_1; +var BlockHash = common.BlockHash; + +var sha1_K = [ + 0x5A827999, 0x6ED9EBA1, + 0x8F1BBCDC, 0xCA62C1D6 +]; + +function SHA1() { + if (!(this instanceof SHA1)) + return new SHA1(); + + BlockHash.call(this); + this.h = [ + 0x67452301, 0xefcdab89, 0x98badcfe, + 0x10325476, 0xc3d2e1f0 ]; + this.W = new Array(80); +} + +utils.inherits(SHA1, BlockHash); +module.exports = SHA1; + +SHA1.blockSize = 512; +SHA1.outSize = 160; +SHA1.hmacStrength = 80; +SHA1.padLength = 64; + +SHA1.prototype._update = function _update(msg, start) { + var W = this.W; + + for (var i = 0; i < 16; i++) + W[i] = msg[start + i]; + + for(; i < W.length; i++) + W[i] = rotl32(W[i - 3] ^ W[i - 8] ^ W[i - 14] ^ W[i - 16], 1); + + var a = this.h[0]; + var b = this.h[1]; + var c = this.h[2]; + var d = this.h[3]; + var e = this.h[4]; + + for (i = 0; i < W.length; i++) { + var s = ~~(i / 20); + var t = sum32_5(rotl32(a, 5), ft_1(s, b, c, d), e, W[i], sha1_K[s]); + e = d; + d = c; + c = rotl32(b, 30); + b = a; + a = t; + } + + this.h[0] = sum32(this.h[0], a); + this.h[1] = sum32(this.h[1], b); + this.h[2] = sum32(this.h[2], c); + this.h[3] = sum32(this.h[3], d); + this.h[4] = sum32(this.h[4], e); +}; + +SHA1.prototype._digest = function digest(enc) { + if (enc === 'hex') + return utils.toHex32(this.h, 'big'); + else + return utils.split32(this.h, 'big'); +}; + +},{"../common":119,"../utils":129,"./common":128}],124:[function(require,module,exports){ +'use strict'; + +var utils = require('../utils'); +var SHA256 = require('./256'); + +function SHA224() { + if (!(this instanceof SHA224)) + return new SHA224(); + + SHA256.call(this); + this.h = [ + 0xc1059ed8, 0x367cd507, 0x3070dd17, 0xf70e5939, + 0xffc00b31, 0x68581511, 0x64f98fa7, 0xbefa4fa4 ]; +} +utils.inherits(SHA224, SHA256); +module.exports = SHA224; + +SHA224.blockSize = 512; +SHA224.outSize = 224; +SHA224.hmacStrength = 192; +SHA224.padLength = 64; + +SHA224.prototype._digest = function digest(enc) { + // Just truncate output + if (enc === 'hex') + return utils.toHex32(this.h.slice(0, 7), 'big'); + else + return utils.split32(this.h.slice(0, 7), 'big'); +}; + + +},{"../utils":129,"./256":125}],125:[function(require,module,exports){ +'use strict'; + +var utils = require('../utils'); +var common = require('../common'); +var shaCommon = require('./common'); +var assert = require('minimalistic-assert'); + +var sum32 = utils.sum32; +var sum32_4 = utils.sum32_4; +var sum32_5 = utils.sum32_5; +var ch32 = shaCommon.ch32; +var maj32 = shaCommon.maj32; +var s0_256 = shaCommon.s0_256; +var s1_256 = shaCommon.s1_256; +var g0_256 = shaCommon.g0_256; +var g1_256 = shaCommon.g1_256; + +var BlockHash = common.BlockHash; + +var sha256_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 +]; + +function SHA256() { + if (!(this instanceof SHA256)) + return new SHA256(); + + BlockHash.call(this); + this.h = [ + 0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, + 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19 + ]; + this.k = sha256_K; + this.W = new Array(64); +} +utils.inherits(SHA256, BlockHash); +module.exports = SHA256; + +SHA256.blockSize = 512; +SHA256.outSize = 256; +SHA256.hmacStrength = 192; +SHA256.padLength = 64; + +SHA256.prototype._update = function _update(msg, start) { + var W = this.W; + + for (var i = 0; i < 16; i++) + W[i] = msg[start + i]; + for (; i < W.length; i++) + W[i] = sum32_4(g1_256(W[i - 2]), W[i - 7], g0_256(W[i - 15]), W[i - 16]); + + var a = this.h[0]; + var b = this.h[1]; + var c = this.h[2]; + var d = this.h[3]; + var e = this.h[4]; + var f = this.h[5]; + var g = this.h[6]; + var h = this.h[7]; + + assert(this.k.length === W.length); + for (i = 0; i < W.length; i++) { + var T1 = sum32_5(h, s1_256(e), ch32(e, f, g), this.k[i], W[i]); + var T2 = sum32(s0_256(a), maj32(a, b, c)); + h = g; + g = f; + f = e; + e = sum32(d, T1); + d = c; + c = b; + b = a; + a = sum32(T1, T2); + } + + this.h[0] = sum32(this.h[0], a); + this.h[1] = sum32(this.h[1], b); + this.h[2] = sum32(this.h[2], c); + this.h[3] = sum32(this.h[3], d); + this.h[4] = sum32(this.h[4], e); + this.h[5] = sum32(this.h[5], f); + this.h[6] = sum32(this.h[6], g); + this.h[7] = sum32(this.h[7], h); +}; + +SHA256.prototype._digest = function digest(enc) { + if (enc === 'hex') + return utils.toHex32(this.h, 'big'); + else + return utils.split32(this.h, 'big'); +}; + +},{"../common":119,"../utils":129,"./common":128,"minimalistic-assert":136}],126:[function(require,module,exports){ +'use strict'; + +var utils = require('../utils'); + +var SHA512 = require('./512'); + +function SHA384() { + if (!(this instanceof SHA384)) + return new SHA384(); + + SHA512.call(this); + this.h = [ + 0xcbbb9d5d, 0xc1059ed8, + 0x629a292a, 0x367cd507, + 0x9159015a, 0x3070dd17, + 0x152fecd8, 0xf70e5939, + 0x67332667, 0xffc00b31, + 0x8eb44a87, 0x68581511, + 0xdb0c2e0d, 0x64f98fa7, + 0x47b5481d, 0xbefa4fa4 ]; +} +utils.inherits(SHA384, SHA512); +module.exports = SHA384; + +SHA384.blockSize = 1024; +SHA384.outSize = 384; +SHA384.hmacStrength = 192; +SHA384.padLength = 128; + +SHA384.prototype._digest = function digest(enc) { + if (enc === 'hex') + return utils.toHex32(this.h.slice(0, 12), 'big'); + else + return utils.split32(this.h.slice(0, 12), 'big'); +}; + +},{"../utils":129,"./512":127}],127:[function(require,module,exports){ +'use strict'; + +var utils = require('../utils'); +var common = require('../common'); +var assert = require('minimalistic-assert'); + +var rotr64_hi = utils.rotr64_hi; +var rotr64_lo = utils.rotr64_lo; +var shr64_hi = utils.shr64_hi; +var shr64_lo = utils.shr64_lo; +var sum64 = utils.sum64; +var sum64_hi = utils.sum64_hi; +var sum64_lo = utils.sum64_lo; +var sum64_4_hi = utils.sum64_4_hi; +var sum64_4_lo = utils.sum64_4_lo; +var sum64_5_hi = utils.sum64_5_hi; +var sum64_5_lo = utils.sum64_5_lo; + +var BlockHash = common.BlockHash; + +var sha512_K = [ + 0x428a2f98, 0xd728ae22, 0x71374491, 0x23ef65cd, + 0xb5c0fbcf, 0xec4d3b2f, 0xe9b5dba5, 0x8189dbbc, + 0x3956c25b, 0xf348b538, 0x59f111f1, 0xb605d019, + 0x923f82a4, 0xaf194f9b, 0xab1c5ed5, 0xda6d8118, + 0xd807aa98, 0xa3030242, 0x12835b01, 0x45706fbe, + 0x243185be, 0x4ee4b28c, 0x550c7dc3, 0xd5ffb4e2, + 0x72be5d74, 0xf27b896f, 0x80deb1fe, 0x3b1696b1, + 0x9bdc06a7, 0x25c71235, 0xc19bf174, 0xcf692694, + 0xe49b69c1, 0x9ef14ad2, 0xefbe4786, 0x384f25e3, + 0x0fc19dc6, 0x8b8cd5b5, 0x240ca1cc, 0x77ac9c65, + 0x2de92c6f, 0x592b0275, 0x4a7484aa, 0x6ea6e483, + 0x5cb0a9dc, 0xbd41fbd4, 0x76f988da, 0x831153b5, + 0x983e5152, 0xee66dfab, 0xa831c66d, 0x2db43210, + 0xb00327c8, 0x98fb213f, 0xbf597fc7, 0xbeef0ee4, + 0xc6e00bf3, 0x3da88fc2, 0xd5a79147, 0x930aa725, + 0x06ca6351, 0xe003826f, 0x14292967, 0x0a0e6e70, + 0x27b70a85, 0x46d22ffc, 0x2e1b2138, 0x5c26c926, + 0x4d2c6dfc, 0x5ac42aed, 0x53380d13, 0x9d95b3df, + 0x650a7354, 0x8baf63de, 0x766a0abb, 0x3c77b2a8, + 0x81c2c92e, 0x47edaee6, 0x92722c85, 0x1482353b, + 0xa2bfe8a1, 0x4cf10364, 0xa81a664b, 0xbc423001, + 0xc24b8b70, 0xd0f89791, 0xc76c51a3, 0x0654be30, + 0xd192e819, 0xd6ef5218, 0xd6990624, 0x5565a910, + 0xf40e3585, 0x5771202a, 0x106aa070, 0x32bbd1b8, + 0x19a4c116, 0xb8d2d0c8, 0x1e376c08, 0x5141ab53, + 0x2748774c, 0xdf8eeb99, 0x34b0bcb5, 0xe19b48a8, + 0x391c0cb3, 0xc5c95a63, 0x4ed8aa4a, 0xe3418acb, + 0x5b9cca4f, 0x7763e373, 0x682e6ff3, 0xd6b2b8a3, + 0x748f82ee, 0x5defb2fc, 0x78a5636f, 0x43172f60, + 0x84c87814, 0xa1f0ab72, 0x8cc70208, 0x1a6439ec, + 0x90befffa, 0x23631e28, 0xa4506ceb, 0xde82bde9, + 0xbef9a3f7, 0xb2c67915, 0xc67178f2, 0xe372532b, + 0xca273ece, 0xea26619c, 0xd186b8c7, 0x21c0c207, + 0xeada7dd6, 0xcde0eb1e, 0xf57d4f7f, 0xee6ed178, + 0x06f067aa, 0x72176fba, 0x0a637dc5, 0xa2c898a6, + 0x113f9804, 0xbef90dae, 0x1b710b35, 0x131c471b, + 0x28db77f5, 0x23047d84, 0x32caab7b, 0x40c72493, + 0x3c9ebe0a, 0x15c9bebc, 0x431d67c4, 0x9c100d4c, + 0x4cc5d4be, 0xcb3e42b6, 0x597f299c, 0xfc657e2a, + 0x5fcb6fab, 0x3ad6faec, 0x6c44198c, 0x4a475817 +]; + +function SHA512() { + if (!(this instanceof SHA512)) + return new SHA512(); + + BlockHash.call(this); + this.h = [ + 0x6a09e667, 0xf3bcc908, + 0xbb67ae85, 0x84caa73b, + 0x3c6ef372, 0xfe94f82b, + 0xa54ff53a, 0x5f1d36f1, + 0x510e527f, 0xade682d1, + 0x9b05688c, 0x2b3e6c1f, + 0x1f83d9ab, 0xfb41bd6b, + 0x5be0cd19, 0x137e2179 ]; + this.k = sha512_K; + this.W = new Array(160); +} +utils.inherits(SHA512, BlockHash); +module.exports = SHA512; + +SHA512.blockSize = 1024; +SHA512.outSize = 512; +SHA512.hmacStrength = 192; +SHA512.padLength = 128; + +SHA512.prototype._prepareBlock = function _prepareBlock(msg, start) { + var W = this.W; + + // 32 x 32bit words + for (var i = 0; i < 32; i++) + W[i] = msg[start + i]; + for (; i < W.length; i += 2) { + var c0_hi = g1_512_hi(W[i - 4], W[i - 3]); // i - 2 + var c0_lo = g1_512_lo(W[i - 4], W[i - 3]); + var c1_hi = W[i - 14]; // i - 7 + var c1_lo = W[i - 13]; + var c2_hi = g0_512_hi(W[i - 30], W[i - 29]); // i - 15 + var c2_lo = g0_512_lo(W[i - 30], W[i - 29]); + var c3_hi = W[i - 32]; // i - 16 + var c3_lo = W[i - 31]; + + W[i] = sum64_4_hi( + c0_hi, c0_lo, + c1_hi, c1_lo, + c2_hi, c2_lo, + c3_hi, c3_lo); + W[i + 1] = sum64_4_lo( + c0_hi, c0_lo, + c1_hi, c1_lo, + c2_hi, c2_lo, + c3_hi, c3_lo); + } +}; + +SHA512.prototype._update = function _update(msg, start) { + this._prepareBlock(msg, start); + + var W = this.W; + + var ah = this.h[0]; + var al = this.h[1]; + var bh = this.h[2]; + var bl = this.h[3]; + var ch = this.h[4]; + var cl = this.h[5]; + var dh = this.h[6]; + var dl = this.h[7]; + var eh = this.h[8]; + var el = this.h[9]; + var fh = this.h[10]; + var fl = this.h[11]; + var gh = this.h[12]; + var gl = this.h[13]; + var hh = this.h[14]; + var hl = this.h[15]; + + assert(this.k.length === W.length); + for (var i = 0; i < W.length; i += 2) { + var c0_hi = hh; + var c0_lo = hl; + var c1_hi = s1_512_hi(eh, el); + var c1_lo = s1_512_lo(eh, el); + var c2_hi = ch64_hi(eh, el, fh, fl, gh, gl); + var c2_lo = ch64_lo(eh, el, fh, fl, gh, gl); + var c3_hi = this.k[i]; + var c3_lo = this.k[i + 1]; + var c4_hi = W[i]; + var c4_lo = W[i + 1]; + + var T1_hi = sum64_5_hi( + c0_hi, c0_lo, + c1_hi, c1_lo, + c2_hi, c2_lo, + c3_hi, c3_lo, + c4_hi, c4_lo); + var T1_lo = sum64_5_lo( + c0_hi, c0_lo, + c1_hi, c1_lo, + c2_hi, c2_lo, + c3_hi, c3_lo, + c4_hi, c4_lo); + + c0_hi = s0_512_hi(ah, al); + c0_lo = s0_512_lo(ah, al); + c1_hi = maj64_hi(ah, al, bh, bl, ch, cl); + c1_lo = maj64_lo(ah, al, bh, bl, ch, cl); + + var T2_hi = sum64_hi(c0_hi, c0_lo, c1_hi, c1_lo); + var T2_lo = sum64_lo(c0_hi, c0_lo, c1_hi, c1_lo); + + hh = gh; + hl = gl; + + gh = fh; + gl = fl; + + fh = eh; + fl = el; + + eh = sum64_hi(dh, dl, T1_hi, T1_lo); + el = sum64_lo(dl, dl, T1_hi, T1_lo); + + dh = ch; + dl = cl; + + ch = bh; + cl = bl; + + bh = ah; + bl = al; + + ah = sum64_hi(T1_hi, T1_lo, T2_hi, T2_lo); + al = sum64_lo(T1_hi, T1_lo, T2_hi, T2_lo); + } + + sum64(this.h, 0, ah, al); + sum64(this.h, 2, bh, bl); + sum64(this.h, 4, ch, cl); + sum64(this.h, 6, dh, dl); + sum64(this.h, 8, eh, el); + sum64(this.h, 10, fh, fl); + sum64(this.h, 12, gh, gl); + sum64(this.h, 14, hh, hl); +}; + +SHA512.prototype._digest = function digest(enc) { + if (enc === 'hex') + return utils.toHex32(this.h, 'big'); + else + return utils.split32(this.h, 'big'); +}; + +function ch64_hi(xh, xl, yh, yl, zh) { + var r = (xh & yh) ^ ((~xh) & zh); + if (r < 0) + r += 0x100000000; + return r; +} + +function ch64_lo(xh, xl, yh, yl, zh, zl) { + var r = (xl & yl) ^ ((~xl) & zl); + if (r < 0) + r += 0x100000000; + return r; +} + +function maj64_hi(xh, xl, yh, yl, zh) { + var r = (xh & yh) ^ (xh & zh) ^ (yh & zh); + if (r < 0) + r += 0x100000000; + return r; +} + +function maj64_lo(xh, xl, yh, yl, zh, zl) { + var r = (xl & yl) ^ (xl & zl) ^ (yl & zl); + if (r < 0) + r += 0x100000000; + return r; +} + +function s0_512_hi(xh, xl) { + var c0_hi = rotr64_hi(xh, xl, 28); + var c1_hi = rotr64_hi(xl, xh, 2); // 34 + var c2_hi = rotr64_hi(xl, xh, 7); // 39 + + var r = c0_hi ^ c1_hi ^ c2_hi; + if (r < 0) + r += 0x100000000; + return r; +} + +function s0_512_lo(xh, xl) { + var c0_lo = rotr64_lo(xh, xl, 28); + var c1_lo = rotr64_lo(xl, xh, 2); // 34 + var c2_lo = rotr64_lo(xl, xh, 7); // 39 + + var r = c0_lo ^ c1_lo ^ c2_lo; + if (r < 0) + r += 0x100000000; + return r; +} + +function s1_512_hi(xh, xl) { + var c0_hi = rotr64_hi(xh, xl, 14); + var c1_hi = rotr64_hi(xh, xl, 18); + var c2_hi = rotr64_hi(xl, xh, 9); // 41 + + var r = c0_hi ^ c1_hi ^ c2_hi; + if (r < 0) + r += 0x100000000; + return r; +} + +function s1_512_lo(xh, xl) { + var c0_lo = rotr64_lo(xh, xl, 14); + var c1_lo = rotr64_lo(xh, xl, 18); + var c2_lo = rotr64_lo(xl, xh, 9); // 41 + + var r = c0_lo ^ c1_lo ^ c2_lo; + if (r < 0) + r += 0x100000000; + return r; +} + +function g0_512_hi(xh, xl) { + var c0_hi = rotr64_hi(xh, xl, 1); + var c1_hi = rotr64_hi(xh, xl, 8); + var c2_hi = shr64_hi(xh, xl, 7); + + var r = c0_hi ^ c1_hi ^ c2_hi; + if (r < 0) + r += 0x100000000; + return r; +} + +function g0_512_lo(xh, xl) { + var c0_lo = rotr64_lo(xh, xl, 1); + var c1_lo = rotr64_lo(xh, xl, 8); + var c2_lo = shr64_lo(xh, xl, 7); + + var r = c0_lo ^ c1_lo ^ c2_lo; + if (r < 0) + r += 0x100000000; + return r; +} + +function g1_512_hi(xh, xl) { + var c0_hi = rotr64_hi(xh, xl, 19); + var c1_hi = rotr64_hi(xl, xh, 29); // 61 + var c2_hi = shr64_hi(xh, xl, 6); + + var r = c0_hi ^ c1_hi ^ c2_hi; + if (r < 0) + r += 0x100000000; + return r; +} + +function g1_512_lo(xh, xl) { + var c0_lo = rotr64_lo(xh, xl, 19); + var c1_lo = rotr64_lo(xl, xh, 29); // 61 + var c2_lo = shr64_lo(xh, xl, 6); + + var r = c0_lo ^ c1_lo ^ c2_lo; + if (r < 0) + r += 0x100000000; + return r; +} + +},{"../common":119,"../utils":129,"minimalistic-assert":136}],128:[function(require,module,exports){ +'use strict'; + +var utils = require('../utils'); +var rotr32 = utils.rotr32; + +function ft_1(s, x, y, z) { + if (s === 0) + return ch32(x, y, z); + if (s === 1 || s === 3) + return p32(x, y, z); + if (s === 2) + return maj32(x, y, z); +} +exports.ft_1 = ft_1; + +function ch32(x, y, z) { + return (x & y) ^ ((~x) & z); +} +exports.ch32 = ch32; + +function maj32(x, y, z) { + return (x & y) ^ (x & z) ^ (y & z); +} +exports.maj32 = maj32; + +function p32(x, y, z) { + return x ^ y ^ z; +} +exports.p32 = p32; + +function s0_256(x) { + return rotr32(x, 2) ^ rotr32(x, 13) ^ rotr32(x, 22); +} +exports.s0_256 = s0_256; + +function s1_256(x) { + return rotr32(x, 6) ^ rotr32(x, 11) ^ rotr32(x, 25); +} +exports.s1_256 = s1_256; + +function g0_256(x) { + return rotr32(x, 7) ^ rotr32(x, 18) ^ (x >>> 3); +} +exports.g0_256 = g0_256; + +function g1_256(x) { + return rotr32(x, 17) ^ rotr32(x, 19) ^ (x >>> 10); +} +exports.g1_256 = g1_256; + +},{"../utils":129}],129:[function(require,module,exports){ +'use strict'; + +var assert = require('minimalistic-assert'); +var inherits = require('inherits'); + +exports.inherits = inherits; + +function isSurrogatePair(msg, i) { + if ((msg.charCodeAt(i) & 0xFC00) !== 0xD800) { + return false; + } + if (i < 0 || i + 1 >= msg.length) { + return false; + } + return (msg.charCodeAt(i + 1) & 0xFC00) === 0xDC00; +} + +function toArray(msg, enc) { + if (Array.isArray(msg)) + return msg.slice(); + if (!msg) + return []; + var res = []; + if (typeof msg === 'string') { + if (!enc) { + // Inspired by stringToUtf8ByteArray() in closure-library by Google + // https://github.com/google/closure-library/blob/8598d87242af59aac233270742c8984e2b2bdbe0/closure/goog/crypt/crypt.js#L117-L143 + // Apache License 2.0 + // https://github.com/google/closure-library/blob/master/LICENSE + var p = 0; + for (var i = 0; i < msg.length; i++) { + var c = msg.charCodeAt(i); + if (c < 128) { + res[p++] = c; + } else if (c < 2048) { + res[p++] = (c >> 6) | 192; + res[p++] = (c & 63) | 128; + } else if (isSurrogatePair(msg, i)) { + c = 0x10000 + ((c & 0x03FF) << 10) + (msg.charCodeAt(++i) & 0x03FF); + res[p++] = (c >> 18) | 240; + res[p++] = ((c >> 12) & 63) | 128; + res[p++] = ((c >> 6) & 63) | 128; + res[p++] = (c & 63) | 128; + } else { + res[p++] = (c >> 12) | 224; + res[p++] = ((c >> 6) & 63) | 128; + res[p++] = (c & 63) | 128; + } + } + } else if (enc === 'hex') { + msg = msg.replace(/[^a-z0-9]+/ig, ''); + if (msg.length % 2 !== 0) + msg = '0' + msg; + for (i = 0; i < msg.length; i += 2) + res.push(parseInt(msg[i] + msg[i + 1], 16)); + } + } else { + for (i = 0; i < msg.length; i++) + res[i] = msg[i] | 0; + } + return res; +} +exports.toArray = toArray; + +function toHex(msg) { + var res = ''; + for (var i = 0; i < msg.length; i++) + res += zero2(msg[i].toString(16)); + return res; +} +exports.toHex = toHex; + +function htonl(w) { + var res = (w >>> 24) | + ((w >>> 8) & 0xff00) | + ((w << 8) & 0xff0000) | + ((w & 0xff) << 24); + return res >>> 0; +} +exports.htonl = htonl; + +function toHex32(msg, endian) { + var res = ''; + for (var i = 0; i < msg.length; i++) { + var w = msg[i]; + if (endian === 'little') + w = htonl(w); + res += zero8(w.toString(16)); + } + return res; +} +exports.toHex32 = toHex32; + +function zero2(word) { + if (word.length === 1) + return '0' + word; + else + return word; +} +exports.zero2 = zero2; + +function zero8(word) { + if (word.length === 7) + return '0' + word; + else if (word.length === 6) + return '00' + word; + else if (word.length === 5) + return '000' + word; + else if (word.length === 4) + return '0000' + word; + else if (word.length === 3) + return '00000' + word; + else if (word.length === 2) + return '000000' + word; + else if (word.length === 1) + return '0000000' + word; + else + return word; +} +exports.zero8 = zero8; + +function join32(msg, start, end, endian) { + var len = end - start; + assert(len % 4 === 0); + var res = new Array(len / 4); + for (var i = 0, k = start; i < res.length; i++, k += 4) { + var w; + if (endian === 'big') + w = (msg[k] << 24) | (msg[k + 1] << 16) | (msg[k + 2] << 8) | msg[k + 3]; + else + w = (msg[k + 3] << 24) | (msg[k + 2] << 16) | (msg[k + 1] << 8) | msg[k]; + res[i] = w >>> 0; + } + return res; +} +exports.join32 = join32; + +function split32(msg, endian) { + var res = new Array(msg.length * 4); + for (var i = 0, k = 0; i < msg.length; i++, k += 4) { + var m = msg[i]; + if (endian === 'big') { + res[k] = m >>> 24; + res[k + 1] = (m >>> 16) & 0xff; + res[k + 2] = (m >>> 8) & 0xff; + res[k + 3] = m & 0xff; + } else { + res[k + 3] = m >>> 24; + res[k + 2] = (m >>> 16) & 0xff; + res[k + 1] = (m >>> 8) & 0xff; + res[k] = m & 0xff; + } + } + return res; +} +exports.split32 = split32; + +function rotr32(w, b) { + return (w >>> b) | (w << (32 - b)); +} +exports.rotr32 = rotr32; + +function rotl32(w, b) { + return (w << b) | (w >>> (32 - b)); +} +exports.rotl32 = rotl32; + +function sum32(a, b) { + return (a + b) >>> 0; +} +exports.sum32 = sum32; + +function sum32_3(a, b, c) { + return (a + b + c) >>> 0; +} +exports.sum32_3 = sum32_3; + +function sum32_4(a, b, c, d) { + return (a + b + c + d) >>> 0; +} +exports.sum32_4 = sum32_4; + +function sum32_5(a, b, c, d, e) { + return (a + b + c + d + e) >>> 0; +} +exports.sum32_5 = sum32_5; + +function sum64(buf, pos, ah, al) { + var bh = buf[pos]; + var bl = buf[pos + 1]; + + var lo = (al + bl) >>> 0; + var hi = (lo < al ? 1 : 0) + ah + bh; + buf[pos] = hi >>> 0; + buf[pos + 1] = lo; +} +exports.sum64 = sum64; + +function sum64_hi(ah, al, bh, bl) { + var lo = (al + bl) >>> 0; + var hi = (lo < al ? 1 : 0) + ah + bh; + return hi >>> 0; +} +exports.sum64_hi = sum64_hi; + +function sum64_lo(ah, al, bh, bl) { + var lo = al + bl; + return lo >>> 0; +} +exports.sum64_lo = sum64_lo; + +function sum64_4_hi(ah, al, bh, bl, ch, cl, dh, dl) { + var carry = 0; + var lo = al; + lo = (lo + bl) >>> 0; + carry += lo < al ? 1 : 0; + lo = (lo + cl) >>> 0; + carry += lo < cl ? 1 : 0; + lo = (lo + dl) >>> 0; + carry += lo < dl ? 1 : 0; + + var hi = ah + bh + ch + dh + carry; + return hi >>> 0; +} +exports.sum64_4_hi = sum64_4_hi; + +function sum64_4_lo(ah, al, bh, bl, ch, cl, dh, dl) { + var lo = al + bl + cl + dl; + return lo >>> 0; +} +exports.sum64_4_lo = sum64_4_lo; + +function sum64_5_hi(ah, al, bh, bl, ch, cl, dh, dl, eh, el) { + var carry = 0; + var lo = al; + lo = (lo + bl) >>> 0; + carry += lo < al ? 1 : 0; + lo = (lo + cl) >>> 0; + carry += lo < cl ? 1 : 0; + lo = (lo + dl) >>> 0; + carry += lo < dl ? 1 : 0; + lo = (lo + el) >>> 0; + carry += lo < el ? 1 : 0; + + var hi = ah + bh + ch + dh + eh + carry; + return hi >>> 0; +} +exports.sum64_5_hi = sum64_5_hi; + +function sum64_5_lo(ah, al, bh, bl, ch, cl, dh, dl, eh, el) { + var lo = al + bl + cl + dl + el; + + return lo >>> 0; +} +exports.sum64_5_lo = sum64_5_lo; + +function rotr64_hi(ah, al, num) { + var r = (al << (32 - num)) | (ah >>> num); + return r >>> 0; +} +exports.rotr64_hi = rotr64_hi; + +function rotr64_lo(ah, al, num) { + var r = (ah << (32 - num)) | (al >>> num); + return r >>> 0; +} +exports.rotr64_lo = rotr64_lo; + +function shr64_hi(ah, al, num) { + return ah >>> num; +} +exports.shr64_hi = shr64_hi; + +function shr64_lo(ah, al, num) { + var r = (ah << (32 - num)) | (al >>> num); + return r >>> 0; +} +exports.shr64_lo = shr64_lo; + +},{"inherits":132,"minimalistic-assert":136}],130:[function(require,module,exports){ +'use strict'; + +var hash = require('hash.js'); +var utils = require('minimalistic-crypto-utils'); +var assert = require('minimalistic-assert'); + +function HmacDRBG(options) { + if (!(this instanceof HmacDRBG)) + return new HmacDRBG(options); + this.hash = options.hash; + this.predResist = !!options.predResist; + + this.outLen = this.hash.outSize; + this.minEntropy = options.minEntropy || this.hash.hmacStrength; + + this._reseed = null; + this.reseedInterval = null; + this.K = null; + this.V = null; + + var entropy = utils.toArray(options.entropy, options.entropyEnc || 'hex'); + var nonce = utils.toArray(options.nonce, options.nonceEnc || 'hex'); + var pers = utils.toArray(options.pers, options.persEnc || 'hex'); + assert(entropy.length >= (this.minEntropy / 8), + 'Not enough entropy. Minimum is: ' + this.minEntropy + ' bits'); + this._init(entropy, nonce, pers); +} +module.exports = HmacDRBG; + +HmacDRBG.prototype._init = function init(entropy, nonce, pers) { + var seed = entropy.concat(nonce).concat(pers); + + this.K = new Array(this.outLen / 8); + this.V = new Array(this.outLen / 8); + for (var i = 0; i < this.V.length; i++) { + this.K[i] = 0x00; + this.V[i] = 0x01; + } + + this._update(seed); + this._reseed = 1; + this.reseedInterval = 0x1000000000000; // 2^48 +}; + +HmacDRBG.prototype._hmac = function hmac() { + return new hash.hmac(this.hash, this.K); +}; + +HmacDRBG.prototype._update = function update(seed) { + var kmac = this._hmac() + .update(this.V) + .update([ 0x00 ]); + if (seed) + kmac = kmac.update(seed); + this.K = kmac.digest(); + this.V = this._hmac().update(this.V).digest(); + if (!seed) + return; + + this.K = this._hmac() + .update(this.V) + .update([ 0x01 ]) + .update(seed) + .digest(); + this.V = this._hmac().update(this.V).digest(); +}; + +HmacDRBG.prototype.reseed = function reseed(entropy, entropyEnc, add, addEnc) { + // Optional entropy enc + if (typeof entropyEnc !== 'string') { + addEnc = add; + add = entropyEnc; + entropyEnc = null; + } + + entropy = utils.toArray(entropy, entropyEnc); + add = utils.toArray(add, addEnc); + + assert(entropy.length >= (this.minEntropy / 8), + 'Not enough entropy. Minimum is: ' + this.minEntropy + ' bits'); + + this._update(entropy.concat(add || [])); + this._reseed = 1; +}; + +HmacDRBG.prototype.generate = function generate(len, enc, add, addEnc) { + if (this._reseed > this.reseedInterval) + throw new Error('Reseed is required'); + + // Optional encoding + if (typeof enc !== 'string') { + addEnc = add; + add = enc; + enc = null; + } + + // Optional additional data + if (add) { + add = utils.toArray(add, addEnc || 'hex'); + this._update(add); + } + + var temp = []; + while (temp.length < len) { + this.V = this._hmac().update(this.V).digest(); + temp = temp.concat(this.V); + } + + var res = temp.slice(0, len); + this._update(add); + this._reseed++; + return utils.encode(res, enc); +}; + +},{"hash.js":118,"minimalistic-assert":136,"minimalistic-crypto-utils":137}],131:[function(require,module,exports){ +/*! ieee754. BSD-3-Clause License. Feross Aboukhadijeh */ +exports.read = function (buffer, offset, isLE, mLen, nBytes) { + var e, m + var eLen = (nBytes * 8) - mLen - 1 + var eMax = (1 << eLen) - 1 + var eBias = eMax >> 1 + var nBits = -7 + var i = isLE ? (nBytes - 1) : 0 + var d = isLE ? -1 : 1 + var s = buffer[offset + i] + + i += d + + e = s & ((1 << (-nBits)) - 1) + s >>= (-nBits) + nBits += eLen + for (; nBits > 0; e = (e * 256) + buffer[offset + i], i += d, nBits -= 8) {} + + m = e & ((1 << (-nBits)) - 1) + e >>= (-nBits) + nBits += mLen + for (; nBits > 0; m = (m * 256) + buffer[offset + i], i += d, nBits -= 8) {} + + if (e === 0) { + e = 1 - eBias + } else if (e === eMax) { + return m ? NaN : ((s ? -1 : 1) * Infinity) + } else { + m = m + Math.pow(2, mLen) + e = e - eBias + } + return (s ? -1 : 1) * m * Math.pow(2, e - mLen) +} + +exports.write = function (buffer, value, offset, isLE, mLen, nBytes) { + var e, m, c + var eLen = (nBytes * 8) - mLen - 1 + var eMax = (1 << eLen) - 1 + var eBias = eMax >> 1 + var rt = (mLen === 23 ? Math.pow(2, -24) - Math.pow(2, -77) : 0) + var i = isLE ? 0 : (nBytes - 1) + var d = isLE ? 1 : -1 + var s = value < 0 || (value === 0 && 1 / value < 0) ? 1 : 0 + + value = Math.abs(value) + + if (isNaN(value) || value === Infinity) { + m = isNaN(value) ? 1 : 0 + e = eMax + } else { + e = Math.floor(Math.log(value) / Math.LN2) + if (value * (c = Math.pow(2, -e)) < 1) { + e-- + c *= 2 + } + if (e + eBias >= 1) { + value += rt / c + } else { + value += rt * Math.pow(2, 1 - eBias) + } + if (value * c >= 2) { + e++ + c /= 2 + } + + if (e + eBias >= eMax) { + m = 0 + e = eMax + } else if (e + eBias >= 1) { + m = ((value * c) - 1) * Math.pow(2, mLen) + e = e + eBias + } else { + m = value * Math.pow(2, eBias - 1) * Math.pow(2, mLen) + e = 0 + } + } + + for (; mLen >= 8; buffer[offset + i] = m & 0xff, i += d, m /= 256, mLen -= 8) {} + + e = (e << mLen) | m + eLen += mLen + for (; eLen > 0; buffer[offset + i] = e & 0xff, i += d, e /= 256, eLen -= 8) {} + + buffer[offset + i - d] |= s * 128 +} + +},{}],132:[function(require,module,exports){ +if (typeof Object.create === 'function') { + // implementation from standard node.js 'util' module + module.exports = function inherits(ctor, superCtor) { + if (superCtor) { + ctor.super_ = superCtor + ctor.prototype = Object.create(superCtor.prototype, { + constructor: { + value: ctor, + enumerable: false, + writable: true, + configurable: true + } + }) + } + }; +} else { + // old school shim for old browsers + module.exports = function inherits(ctor, superCtor) { + if (superCtor) { + ctor.super_ = superCtor + var TempCtor = function () {} + TempCtor.prototype = superCtor.prototype + ctor.prototype = new TempCtor() + ctor.prototype.constructor = ctor + } + } +} + +},{}],133:[function(require,module,exports){ +'use strict' +var inherits = require('inherits') +var HashBase = require('hash-base') +var Buffer = require('safe-buffer').Buffer + +var ARRAY16 = new Array(16) + +function MD5 () { + HashBase.call(this, 64) + + // state + this._a = 0x67452301 + this._b = 0xefcdab89 + this._c = 0x98badcfe + this._d = 0x10325476 +} + +inherits(MD5, HashBase) + +MD5.prototype._update = function () { + var M = ARRAY16 + for (var i = 0; i < 16; ++i) M[i] = this._block.readInt32LE(i * 4) + + var a = this._a + var b = this._b + var c = this._c + var d = this._d + + a = fnF(a, b, c, d, M[0], 0xd76aa478, 7) + d = fnF(d, a, b, c, M[1], 0xe8c7b756, 12) + c = fnF(c, d, a, b, M[2], 0x242070db, 17) + b = fnF(b, c, d, a, M[3], 0xc1bdceee, 22) + a = fnF(a, b, c, d, M[4], 0xf57c0faf, 7) + d = fnF(d, a, b, c, M[5], 0x4787c62a, 12) + c = fnF(c, d, a, b, M[6], 0xa8304613, 17) + b = fnF(b, c, d, a, M[7], 0xfd469501, 22) + a = fnF(a, b, c, d, M[8], 0x698098d8, 7) + d = fnF(d, a, b, c, M[9], 0x8b44f7af, 12) + c = fnF(c, d, a, b, M[10], 0xffff5bb1, 17) + b = fnF(b, c, d, a, M[11], 0x895cd7be, 22) + a = fnF(a, b, c, d, M[12], 0x6b901122, 7) + d = fnF(d, a, b, c, M[13], 0xfd987193, 12) + c = fnF(c, d, a, b, M[14], 0xa679438e, 17) + b = fnF(b, c, d, a, M[15], 0x49b40821, 22) + + a = fnG(a, b, c, d, M[1], 0xf61e2562, 5) + d = fnG(d, a, b, c, M[6], 0xc040b340, 9) + c = fnG(c, d, a, b, M[11], 0x265e5a51, 14) + b = fnG(b, c, d, a, M[0], 0xe9b6c7aa, 20) + a = fnG(a, b, c, d, M[5], 0xd62f105d, 5) + d = fnG(d, a, b, c, M[10], 0x02441453, 9) + c = fnG(c, d, a, b, M[15], 0xd8a1e681, 14) + b = fnG(b, c, d, a, M[4], 0xe7d3fbc8, 20) + a = fnG(a, b, c, d, M[9], 0x21e1cde6, 5) + d = fnG(d, a, b, c, M[14], 0xc33707d6, 9) + c = fnG(c, d, a, b, M[3], 0xf4d50d87, 14) + b = fnG(b, c, d, a, M[8], 0x455a14ed, 20) + a = fnG(a, b, c, d, M[13], 0xa9e3e905, 5) + d = fnG(d, a, b, c, M[2], 0xfcefa3f8, 9) + c = fnG(c, d, a, b, M[7], 0x676f02d9, 14) + b = fnG(b, c, d, a, M[12], 0x8d2a4c8a, 20) + + a = fnH(a, b, c, d, M[5], 0xfffa3942, 4) + d = fnH(d, a, b, c, M[8], 0x8771f681, 11) + c = fnH(c, d, a, b, M[11], 0x6d9d6122, 16) + b = fnH(b, c, d, a, M[14], 0xfde5380c, 23) + a = fnH(a, b, c, d, M[1], 0xa4beea44, 4) + d = fnH(d, a, b, c, M[4], 0x4bdecfa9, 11) + c = fnH(c, d, a, b, M[7], 0xf6bb4b60, 16) + b = fnH(b, c, d, a, M[10], 0xbebfbc70, 23) + a = fnH(a, b, c, d, M[13], 0x289b7ec6, 4) + d = fnH(d, a, b, c, M[0], 0xeaa127fa, 11) + c = fnH(c, d, a, b, M[3], 0xd4ef3085, 16) + b = fnH(b, c, d, a, M[6], 0x04881d05, 23) + a = fnH(a, b, c, d, M[9], 0xd9d4d039, 4) + d = fnH(d, a, b, c, M[12], 0xe6db99e5, 11) + c = fnH(c, d, a, b, M[15], 0x1fa27cf8, 16) + b = fnH(b, c, d, a, M[2], 0xc4ac5665, 23) + + a = fnI(a, b, c, d, M[0], 0xf4292244, 6) + d = fnI(d, a, b, c, M[7], 0x432aff97, 10) + c = fnI(c, d, a, b, M[14], 0xab9423a7, 15) + b = fnI(b, c, d, a, M[5], 0xfc93a039, 21) + a = fnI(a, b, c, d, M[12], 0x655b59c3, 6) + d = fnI(d, a, b, c, M[3], 0x8f0ccc92, 10) + c = fnI(c, d, a, b, M[10], 0xffeff47d, 15) + b = fnI(b, c, d, a, M[1], 0x85845dd1, 21) + a = fnI(a, b, c, d, M[8], 0x6fa87e4f, 6) + d = fnI(d, a, b, c, M[15], 0xfe2ce6e0, 10) + c = fnI(c, d, a, b, M[6], 0xa3014314, 15) + b = fnI(b, c, d, a, M[13], 0x4e0811a1, 21) + a = fnI(a, b, c, d, M[4], 0xf7537e82, 6) + d = fnI(d, a, b, c, M[11], 0xbd3af235, 10) + c = fnI(c, d, a, b, M[2], 0x2ad7d2bb, 15) + b = fnI(b, c, d, a, M[9], 0xeb86d391, 21) + + this._a = (this._a + a) | 0 + this._b = (this._b + b) | 0 + this._c = (this._c + c) | 0 + this._d = (this._d + d) | 0 +} + +MD5.prototype._digest = function () { + // create padding and handle blocks + this._block[this._blockOffset++] = 0x80 + if (this._blockOffset > 56) { + this._block.fill(0, this._blockOffset, 64) + this._update() + this._blockOffset = 0 + } + + this._block.fill(0, this._blockOffset, 56) + this._block.writeUInt32LE(this._length[0], 56) + this._block.writeUInt32LE(this._length[1], 60) + this._update() + + // produce result + var buffer = Buffer.allocUnsafe(16) + buffer.writeInt32LE(this._a, 0) + buffer.writeInt32LE(this._b, 4) + buffer.writeInt32LE(this._c, 8) + buffer.writeInt32LE(this._d, 12) + return buffer +} + +function rotl (x, n) { + return (x << n) | (x >>> (32 - n)) +} + +function fnF (a, b, c, d, m, k, s) { + return (rotl((a + ((b & c) | ((~b) & d)) + m + k) | 0, s) + b) | 0 +} + +function fnG (a, b, c, d, m, k, s) { + return (rotl((a + ((b & d) | (c & (~d))) + m + k) | 0, s) + b) | 0 +} + +function fnH (a, b, c, d, m, k, s) { + return (rotl((a + (b ^ c ^ d) + m + k) | 0, s) + b) | 0 +} + +function fnI (a, b, c, d, m, k, s) { + return (rotl((a + ((c ^ (b | (~d)))) + m + k) | 0, s) + b) | 0 +} + +module.exports = MD5 + +},{"hash-base":102,"inherits":132,"safe-buffer":160}],134:[function(require,module,exports){ +var bn = require('bn.js'); +var brorand = require('brorand'); + +function MillerRabin(rand) { + this.rand = rand || new brorand.Rand(); +} +module.exports = MillerRabin; + +MillerRabin.create = function create(rand) { + return new MillerRabin(rand); +}; + +MillerRabin.prototype._randbelow = function _randbelow(n) { + var len = n.bitLength(); + var min_bytes = Math.ceil(len / 8); + + // Generage random bytes until a number less than n is found. + // This ensures that 0..n-1 have an equal probability of being selected. + do + var a = new bn(this.rand.generate(min_bytes)); + while (a.cmp(n) >= 0); + + return a; +}; + +MillerRabin.prototype._randrange = function _randrange(start, stop) { + // Generate a random number greater than or equal to start and less than stop. + var size = stop.sub(start); + return start.add(this._randbelow(size)); +}; + +MillerRabin.prototype.test = function test(n, k, cb) { + var len = n.bitLength(); + var red = bn.mont(n); + var rone = new bn(1).toRed(red); + + if (!k) + k = Math.max(1, (len / 48) | 0); + + // Find d and s, (n - 1) = (2 ^ s) * d; + var n1 = n.subn(1); + for (var s = 0; !n1.testn(s); s++) {} + var d = n.shrn(s); + + var rn1 = n1.toRed(red); + + var prime = true; + for (; k > 0; k--) { + var a = this._randrange(new bn(2), n1); + if (cb) + cb(a); + + var x = a.toRed(red).redPow(d); + if (x.cmp(rone) === 0 || x.cmp(rn1) === 0) + continue; + + for (var i = 1; i < s; i++) { + x = x.redSqr(); + + if (x.cmp(rone) === 0) + return false; + if (x.cmp(rn1) === 0) + break; + } + + if (i === s) + return false; + } + + return prime; +}; + +MillerRabin.prototype.getDivisor = function getDivisor(n, k) { + var len = n.bitLength(); + var red = bn.mont(n); + var rone = new bn(1).toRed(red); + + if (!k) + k = Math.max(1, (len / 48) | 0); + + // Find d and s, (n - 1) = (2 ^ s) * d; + var n1 = n.subn(1); + for (var s = 0; !n1.testn(s); s++) {} + var d = n.shrn(s); + + var rn1 = n1.toRed(red); + + for (; k > 0; k--) { + var a = this._randrange(new bn(2), n1); + + var g = n.gcd(a); + if (g.cmpn(1) !== 0) + return g; + + var x = a.toRed(red).redPow(d); + if (x.cmp(rone) === 0 || x.cmp(rn1) === 0) + continue; + + for (var i = 1; i < s; i++) { + x = x.redSqr(); + + if (x.cmp(rone) === 0) + return x.fromRed().subn(1).gcd(n); + if (x.cmp(rn1) === 0) + break; + } + + if (i === s) { + x = x.redSqr(); + return x.fromRed().subn(1).gcd(n); + } + } + + return false; +}; + +},{"bn.js":135,"brorand":18}],135:[function(require,module,exports){ +arguments[4][15][0].apply(exports,arguments) +},{"buffer":19,"dup":15}],136:[function(require,module,exports){ +module.exports = assert; + +function assert(val, msg) { + if (!val) + throw new Error(msg || 'Assertion failed'); +} + +assert.equal = function assertEqual(l, r, msg) { + if (l != r) + throw new Error(msg || ('Assertion failed: ' + l + ' != ' + r)); +}; + +},{}],137:[function(require,module,exports){ +'use strict'; + +var utils = exports; + +function toArray(msg, enc) { + if (Array.isArray(msg)) + return msg.slice(); + if (!msg) + return []; + var res = []; + if (typeof msg !== 'string') { + for (var i = 0; i < msg.length; i++) + res[i] = msg[i] | 0; + return res; + } + if (enc === 'hex') { + msg = msg.replace(/[^a-z0-9]+/ig, ''); + if (msg.length % 2 !== 0) + msg = '0' + msg; + for (var i = 0; i < msg.length; i += 2) + res.push(parseInt(msg[i] + msg[i + 1], 16)); + } else { + for (var i = 0; i < msg.length; i++) { + var c = msg.charCodeAt(i); + var hi = c >> 8; + var lo = c & 0xff; + if (hi) + res.push(hi, lo); + else + res.push(lo); + } + } + return res; +} +utils.toArray = toArray; + +function zero2(word) { + if (word.length === 1) + return '0' + word; + else + return word; +} +utils.zero2 = zero2; + +function toHex(msg) { + var res = ''; + for (var i = 0; i < msg.length; i++) + res += zero2(msg[i].toString(16)); + return res; +} +utils.toHex = toHex; + +utils.encode = function encode(arr, enc) { + if (enc === 'hex') + return toHex(arr); + else + return arr; +}; + +},{}],138:[function(require,module,exports){ +module.exports={"2.16.840.1.101.3.4.1.1": "aes-128-ecb", +"2.16.840.1.101.3.4.1.2": "aes-128-cbc", +"2.16.840.1.101.3.4.1.3": "aes-128-ofb", +"2.16.840.1.101.3.4.1.4": "aes-128-cfb", +"2.16.840.1.101.3.4.1.21": "aes-192-ecb", +"2.16.840.1.101.3.4.1.22": "aes-192-cbc", +"2.16.840.1.101.3.4.1.23": "aes-192-ofb", +"2.16.840.1.101.3.4.1.24": "aes-192-cfb", +"2.16.840.1.101.3.4.1.41": "aes-256-ecb", +"2.16.840.1.101.3.4.1.42": "aes-256-cbc", +"2.16.840.1.101.3.4.1.43": "aes-256-ofb", +"2.16.840.1.101.3.4.1.44": "aes-256-cfb" +} +},{}],139:[function(require,module,exports){ +// from https://github.com/indutny/self-signed/blob/gh-pages/lib/asn1.js +// Fedor, you are amazing. +'use strict' + +var asn1 = require('asn1.js') + +exports.certificate = require('./certificate') + +var RSAPrivateKey = asn1.define('RSAPrivateKey', function () { + this.seq().obj( + this.key('version').int(), + this.key('modulus').int(), + this.key('publicExponent').int(), + this.key('privateExponent').int(), + this.key('prime1').int(), + this.key('prime2').int(), + this.key('exponent1').int(), + this.key('exponent2').int(), + this.key('coefficient').int() + ) +}) +exports.RSAPrivateKey = RSAPrivateKey + +var RSAPublicKey = asn1.define('RSAPublicKey', function () { + this.seq().obj( + this.key('modulus').int(), + this.key('publicExponent').int() + ) +}) +exports.RSAPublicKey = RSAPublicKey + +var PublicKey = asn1.define('SubjectPublicKeyInfo', function () { + this.seq().obj( + this.key('algorithm').use(AlgorithmIdentifier), + this.key('subjectPublicKey').bitstr() + ) +}) +exports.PublicKey = PublicKey + +var AlgorithmIdentifier = asn1.define('AlgorithmIdentifier', function () { + this.seq().obj( + this.key('algorithm').objid(), + this.key('none').null_().optional(), + this.key('curve').objid().optional(), + this.key('params').seq().obj( + this.key('p').int(), + this.key('q').int(), + this.key('g').int() + ).optional() + ) +}) + +var PrivateKeyInfo = asn1.define('PrivateKeyInfo', function () { + this.seq().obj( + this.key('version').int(), + this.key('algorithm').use(AlgorithmIdentifier), + this.key('subjectPrivateKey').octstr() + ) +}) +exports.PrivateKey = PrivateKeyInfo +var EncryptedPrivateKeyInfo = asn1.define('EncryptedPrivateKeyInfo', function () { + this.seq().obj( + this.key('algorithm').seq().obj( + this.key('id').objid(), + this.key('decrypt').seq().obj( + this.key('kde').seq().obj( + this.key('id').objid(), + this.key('kdeparams').seq().obj( + this.key('salt').octstr(), + this.key('iters').int() + ) + ), + this.key('cipher').seq().obj( + this.key('algo').objid(), + this.key('iv').octstr() + ) + ) + ), + this.key('subjectPrivateKey').octstr() + ) +}) + +exports.EncryptedPrivateKey = EncryptedPrivateKeyInfo + +var DSAPrivateKey = asn1.define('DSAPrivateKey', function () { + this.seq().obj( + this.key('version').int(), + this.key('p').int(), + this.key('q').int(), + this.key('g').int(), + this.key('pub_key').int(), + this.key('priv_key').int() + ) +}) +exports.DSAPrivateKey = DSAPrivateKey + +exports.DSAparam = asn1.define('DSAparam', function () { + this.int() +}) + +var ECPrivateKey = asn1.define('ECPrivateKey', function () { + this.seq().obj( + this.key('version').int(), + this.key('privateKey').octstr(), + this.key('parameters').optional().explicit(0).use(ECParameters), + this.key('publicKey').optional().explicit(1).bitstr() + ) +}) +exports.ECPrivateKey = ECPrivateKey + +var ECParameters = asn1.define('ECParameters', function () { + this.choice({ + namedCurve: this.objid() + }) +}) + +exports.signature = asn1.define('signature', function () { + this.seq().obj( + this.key('r').int(), + this.key('s').int() + ) +}) + +},{"./certificate":140,"asn1.js":1}],140:[function(require,module,exports){ +// from https://github.com/Rantanen/node-dtls/blob/25a7dc861bda38cfeac93a723500eea4f0ac2e86/Certificate.js +// thanks to @Rantanen + +'use strict' + +var asn = require('asn1.js') + +var Time = asn.define('Time', function () { + this.choice({ + utcTime: this.utctime(), + generalTime: this.gentime() + }) +}) + +var AttributeTypeValue = asn.define('AttributeTypeValue', function () { + this.seq().obj( + this.key('type').objid(), + this.key('value').any() + ) +}) + +var AlgorithmIdentifier = asn.define('AlgorithmIdentifier', function () { + this.seq().obj( + this.key('algorithm').objid(), + this.key('parameters').optional(), + this.key('curve').objid().optional() + ) +}) + +var SubjectPublicKeyInfo = asn.define('SubjectPublicKeyInfo', function () { + this.seq().obj( + this.key('algorithm').use(AlgorithmIdentifier), + this.key('subjectPublicKey').bitstr() + ) +}) + +var RelativeDistinguishedName = asn.define('RelativeDistinguishedName', function () { + this.setof(AttributeTypeValue) +}) + +var RDNSequence = asn.define('RDNSequence', function () { + this.seqof(RelativeDistinguishedName) +}) + +var Name = asn.define('Name', function () { + this.choice({ + rdnSequence: this.use(RDNSequence) + }) +}) + +var Validity = asn.define('Validity', function () { + this.seq().obj( + this.key('notBefore').use(Time), + this.key('notAfter').use(Time) + ) +}) + +var Extension = asn.define('Extension', function () { + this.seq().obj( + this.key('extnID').objid(), + this.key('critical').bool().def(false), + this.key('extnValue').octstr() + ) +}) + +var TBSCertificate = asn.define('TBSCertificate', function () { + this.seq().obj( + this.key('version').explicit(0).int().optional(), + this.key('serialNumber').int(), + this.key('signature').use(AlgorithmIdentifier), + this.key('issuer').use(Name), + this.key('validity').use(Validity), + this.key('subject').use(Name), + this.key('subjectPublicKeyInfo').use(SubjectPublicKeyInfo), + this.key('issuerUniqueID').implicit(1).bitstr().optional(), + this.key('subjectUniqueID').implicit(2).bitstr().optional(), + this.key('extensions').explicit(3).seqof(Extension).optional() + ) +}) + +var X509Certificate = asn.define('X509Certificate', function () { + this.seq().obj( + this.key('tbsCertificate').use(TBSCertificate), + this.key('signatureAlgorithm').use(AlgorithmIdentifier), + this.key('signatureValue').bitstr() + ) +}) + +module.exports = X509Certificate + +},{"asn1.js":1}],141:[function(require,module,exports){ +// adapted from https://github.com/apatil/pemstrip +var findProc = /Proc-Type: 4,ENCRYPTED[\n\r]+DEK-Info: AES-((?:128)|(?:192)|(?:256))-CBC,([0-9A-H]+)[\n\r]+([0-9A-z\n\r+/=]+)[\n\r]+/m +var startRegex = /^-----BEGIN ((?:.*? KEY)|CERTIFICATE)-----/m +var fullRegex = /^-----BEGIN ((?:.*? KEY)|CERTIFICATE)-----([0-9A-z\n\r+/=]+)-----END \1-----$/m +var evp = require('evp_bytestokey') +var ciphers = require('browserify-aes') +var Buffer = require('safe-buffer').Buffer +module.exports = function (okey, password) { + var key = okey.toString() + var match = key.match(findProc) + var decrypted + if (!match) { + var match2 = key.match(fullRegex) + decrypted = Buffer.from(match2[2].replace(/[\r\n]/g, ''), 'base64') + } else { + var suite = 'aes' + match[1] + var iv = Buffer.from(match[2], 'hex') + var cipherText = Buffer.from(match[3].replace(/[\r\n]/g, ''), 'base64') + var cipherKey = evp(password, iv.slice(0, 8), parseInt(match[1], 10)).key + var out = [] + var cipher = ciphers.createDecipheriv(suite, cipherKey, iv) + out.push(cipher.update(cipherText)) + out.push(cipher.final()) + decrypted = Buffer.concat(out) + } + var tag = key.match(startRegex)[1] + return { + tag: tag, + data: decrypted + } +} + +},{"browserify-aes":22,"evp_bytestokey":101,"safe-buffer":160}],142:[function(require,module,exports){ +var asn1 = require('./asn1') +var aesid = require('./aesid.json') +var fixProc = require('./fixProc') +var ciphers = require('browserify-aes') +var compat = require('pbkdf2') +var Buffer = require('safe-buffer').Buffer +module.exports = parseKeys + +function parseKeys (buffer) { + var password + if (typeof buffer === 'object' && !Buffer.isBuffer(buffer)) { + password = buffer.passphrase + buffer = buffer.key + } + if (typeof buffer === 'string') { + buffer = Buffer.from(buffer) + } + + var stripped = fixProc(buffer, password) + + var type = stripped.tag + var data = stripped.data + var subtype, ndata + switch (type) { + case 'CERTIFICATE': + ndata = asn1.certificate.decode(data, 'der').tbsCertificate.subjectPublicKeyInfo + // falls through + case 'PUBLIC KEY': + if (!ndata) { + ndata = asn1.PublicKey.decode(data, 'der') + } + subtype = ndata.algorithm.algorithm.join('.') + switch (subtype) { + case '1.2.840.113549.1.1.1': + return asn1.RSAPublicKey.decode(ndata.subjectPublicKey.data, 'der') + case '1.2.840.10045.2.1': + ndata.subjectPrivateKey = ndata.subjectPublicKey + return { + type: 'ec', + data: ndata + } + case '1.2.840.10040.4.1': + ndata.algorithm.params.pub_key = asn1.DSAparam.decode(ndata.subjectPublicKey.data, 'der') + return { + type: 'dsa', + data: ndata.algorithm.params + } + default: throw new Error('unknown key id ' + subtype) + } + // throw new Error('unknown key type ' + type) + case 'ENCRYPTED PRIVATE KEY': + data = asn1.EncryptedPrivateKey.decode(data, 'der') + data = decrypt(data, password) + // falls through + case 'PRIVATE KEY': + ndata = asn1.PrivateKey.decode(data, 'der') + subtype = ndata.algorithm.algorithm.join('.') + switch (subtype) { + case '1.2.840.113549.1.1.1': + return asn1.RSAPrivateKey.decode(ndata.subjectPrivateKey, 'der') + case '1.2.840.10045.2.1': + return { + curve: ndata.algorithm.curve, + privateKey: asn1.ECPrivateKey.decode(ndata.subjectPrivateKey, 'der').privateKey + } + case '1.2.840.10040.4.1': + ndata.algorithm.params.priv_key = asn1.DSAparam.decode(ndata.subjectPrivateKey, 'der') + return { + type: 'dsa', + params: ndata.algorithm.params + } + default: throw new Error('unknown key id ' + subtype) + } + // throw new Error('unknown key type ' + type) + case 'RSA PUBLIC KEY': + return asn1.RSAPublicKey.decode(data, 'der') + case 'RSA PRIVATE KEY': + return asn1.RSAPrivateKey.decode(data, 'der') + case 'DSA PRIVATE KEY': + return { + type: 'dsa', + params: asn1.DSAPrivateKey.decode(data, 'der') + } + case 'EC PRIVATE KEY': + data = asn1.ECPrivateKey.decode(data, 'der') + return { + curve: data.parameters.value, + privateKey: data.privateKey + } + default: throw new Error('unknown key type ' + type) + } +} +parseKeys.signature = asn1.signature +function decrypt (data, password) { + var salt = data.algorithm.decrypt.kde.kdeparams.salt + var iters = parseInt(data.algorithm.decrypt.kde.kdeparams.iters.toString(), 10) + var algo = aesid[data.algorithm.decrypt.cipher.algo.join('.')] + var iv = data.algorithm.decrypt.cipher.iv + var cipherText = data.subjectPrivateKey + var keylen = parseInt(algo.split('-')[1], 10) / 8 + var key = compat.pbkdf2Sync(password, salt, iters, keylen, 'sha1') + var cipher = ciphers.createDecipheriv(algo, key, iv) + var out = [] + out.push(cipher.update(cipherText)) + out.push(cipher.final()) + return Buffer.concat(out) +} + +},{"./aesid.json":138,"./asn1":139,"./fixProc":141,"browserify-aes":22,"pbkdf2":143,"safe-buffer":160}],143:[function(require,module,exports){ +exports.pbkdf2 = require('./lib/async') +exports.pbkdf2Sync = require('./lib/sync') + +},{"./lib/async":144,"./lib/sync":147}],144:[function(require,module,exports){ +(function (global){(function (){ +var Buffer = require('safe-buffer').Buffer + +var checkParameters = require('./precondition') +var defaultEncoding = require('./default-encoding') +var sync = require('./sync') +var toBuffer = require('./to-buffer') + +var ZERO_BUF +var subtle = global.crypto && global.crypto.subtle +var toBrowser = { + sha: 'SHA-1', + 'sha-1': 'SHA-1', + sha1: 'SHA-1', + sha256: 'SHA-256', + 'sha-256': 'SHA-256', + sha384: 'SHA-384', + 'sha-384': 'SHA-384', + 'sha-512': 'SHA-512', + sha512: 'SHA-512' +} +var checks = [] +function checkNative (algo) { + if (global.process && !global.process.browser) { + return Promise.resolve(false) + } + if (!subtle || !subtle.importKey || !subtle.deriveBits) { + return Promise.resolve(false) + } + if (checks[algo] !== undefined) { + return checks[algo] + } + ZERO_BUF = ZERO_BUF || Buffer.alloc(8) + var prom = browserPbkdf2(ZERO_BUF, ZERO_BUF, 10, 128, algo) + .then(function () { + return true + }).catch(function () { + return false + }) + checks[algo] = prom + return prom +} +var nextTick +function getNextTick () { + if (nextTick) { + return nextTick + } + if (global.process && global.process.nextTick) { + nextTick = global.process.nextTick + } else if (global.queueMicrotask) { + nextTick = global.queueMicrotask + } else if (global.setImmediate) { + nextTick = global.setImmediate + } else { + nextTick = global.setTimeout + } + return nextTick +} +function browserPbkdf2 (password, salt, iterations, length, algo) { + return subtle.importKey( + 'raw', password, { name: 'PBKDF2' }, false, ['deriveBits'] + ).then(function (key) { + return subtle.deriveBits({ + name: 'PBKDF2', + salt: salt, + iterations: iterations, + hash: { + name: algo + } + }, key, length << 3) + }).then(function (res) { + return Buffer.from(res) + }) +} + +function resolvePromise (promise, callback) { + promise.then(function (out) { + getNextTick()(function () { + callback(null, out) + }) + }, function (e) { + getNextTick()(function () { + callback(e) + }) + }) +} +module.exports = function (password, salt, iterations, keylen, digest, callback) { + if (typeof digest === 'function') { + callback = digest + digest = undefined + } + + digest = digest || 'sha1' + var algo = toBrowser[digest.toLowerCase()] + + if (!algo || typeof global.Promise !== 'function') { + getNextTick()(function () { + var out + try { + out = sync(password, salt, iterations, keylen, digest) + } catch (e) { + return callback(e) + } + callback(null, out) + }) + return + } + + checkParameters(iterations, keylen) + password = toBuffer(password, defaultEncoding, 'Password') + salt = toBuffer(salt, defaultEncoding, 'Salt') + if (typeof callback !== 'function') throw new Error('No callback provided to pbkdf2') + + resolvePromise(checkNative(algo).then(function (resp) { + if (resp) return browserPbkdf2(password, salt, iterations, keylen, algo) + + return sync(password, salt, iterations, keylen, digest) + }), callback) +} + +}).call(this)}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) +},{"./default-encoding":145,"./precondition":146,"./sync":147,"./to-buffer":148,"safe-buffer":160}],145:[function(require,module,exports){ +(function (process,global){(function (){ +var defaultEncoding +/* istanbul ignore next */ +if (global.process && global.process.browser) { + defaultEncoding = 'utf-8' +} else if (global.process && global.process.version) { + var pVersionMajor = parseInt(process.version.split('.')[0].slice(1), 10) + + defaultEncoding = pVersionMajor >= 6 ? 'utf-8' : 'binary' +} else { + defaultEncoding = 'utf-8' +} +module.exports = defaultEncoding + +}).call(this)}).call(this,require('_process'),typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) +},{"_process":149}],146:[function(require,module,exports){ +var MAX_ALLOC = Math.pow(2, 30) - 1 // default in iojs + +module.exports = function (iterations, keylen) { + if (typeof iterations !== 'number') { + throw new TypeError('Iterations not a number') + } + + if (iterations < 0) { + throw new TypeError('Bad iterations') + } + + if (typeof keylen !== 'number') { + throw new TypeError('Key length not a number') + } + + if (keylen < 0 || keylen > MAX_ALLOC || keylen !== keylen) { /* eslint no-self-compare: 0 */ + throw new TypeError('Bad key length') + } +} + +},{}],147:[function(require,module,exports){ +var md5 = require('create-hash/md5') +var RIPEMD160 = require('ripemd160') +var sha = require('sha.js') +var Buffer = require('safe-buffer').Buffer + +var checkParameters = require('./precondition') +var defaultEncoding = require('./default-encoding') +var toBuffer = require('./to-buffer') + +var ZEROS = Buffer.alloc(128) +var sizes = { + md5: 16, + sha1: 20, + sha224: 28, + sha256: 32, + sha384: 48, + sha512: 64, + rmd160: 20, + ripemd160: 20 +} + +function Hmac (alg, key, saltLen) { + var hash = getDigest(alg) + var blocksize = (alg === 'sha512' || alg === 'sha384') ? 128 : 64 + + if (key.length > blocksize) { + key = hash(key) + } else if (key.length < blocksize) { + key = Buffer.concat([key, ZEROS], blocksize) + } + + var ipad = Buffer.allocUnsafe(blocksize + sizes[alg]) + var opad = Buffer.allocUnsafe(blocksize + sizes[alg]) + for (var i = 0; i < blocksize; i++) { + ipad[i] = key[i] ^ 0x36 + opad[i] = key[i] ^ 0x5C + } + + var ipad1 = Buffer.allocUnsafe(blocksize + saltLen + 4) + ipad.copy(ipad1, 0, 0, blocksize) + this.ipad1 = ipad1 + this.ipad2 = ipad + this.opad = opad + this.alg = alg + this.blocksize = blocksize + this.hash = hash + this.size = sizes[alg] +} + +Hmac.prototype.run = function (data, ipad) { + data.copy(ipad, this.blocksize) + var h = this.hash(ipad) + h.copy(this.opad, this.blocksize) + return this.hash(this.opad) +} + +function getDigest (alg) { + function shaFunc (data) { + return sha(alg).update(data).digest() + } + function rmd160Func (data) { + return new RIPEMD160().update(data).digest() + } + + if (alg === 'rmd160' || alg === 'ripemd160') return rmd160Func + if (alg === 'md5') return md5 + return shaFunc +} + +function pbkdf2 (password, salt, iterations, keylen, digest) { + checkParameters(iterations, keylen) + password = toBuffer(password, defaultEncoding, 'Password') + salt = toBuffer(salt, defaultEncoding, 'Salt') + + digest = digest || 'sha1' + + var hmac = new Hmac(digest, password, salt.length) + + var DK = Buffer.allocUnsafe(keylen) + var block1 = Buffer.allocUnsafe(salt.length + 4) + salt.copy(block1, 0, 0, salt.length) + + var destPos = 0 + var hLen = sizes[digest] + var l = Math.ceil(keylen / hLen) + + for (var i = 1; i <= l; i++) { + block1.writeUInt32BE(i, salt.length) + + var T = hmac.run(block1, hmac.ipad1) + var U = T + + for (var j = 1; j < iterations; j++) { + U = hmac.run(U, hmac.ipad2) + for (var k = 0; k < hLen; k++) T[k] ^= U[k] + } + + T.copy(DK, destPos) + destPos += hLen + } + + return DK +} + +module.exports = pbkdf2 + +},{"./default-encoding":145,"./precondition":146,"./to-buffer":148,"create-hash/md5":68,"ripemd160":159,"safe-buffer":160,"sha.js":163}],148:[function(require,module,exports){ +var Buffer = require('safe-buffer').Buffer + +module.exports = function (thing, encoding, name) { + if (Buffer.isBuffer(thing)) { + return thing + } else if (typeof thing === 'string') { + return Buffer.from(thing, encoding) + } else if (ArrayBuffer.isView(thing)) { + return Buffer.from(thing.buffer) + } else { + throw new TypeError(name + ' must be a string, a Buffer, a typed array or a DataView') + } +} + +},{"safe-buffer":160}],149:[function(require,module,exports){ +// shim for using process in browser +var process = module.exports = {}; + +// cached from whatever global is present so that test runners that stub it +// don't break things. But we need to wrap it in a try catch in case it is +// wrapped in strict mode code which doesn't define any globals. It's inside a +// function because try/catches deoptimize in certain engines. + +var cachedSetTimeout; +var cachedClearTimeout; + +function defaultSetTimout() { + throw new Error('setTimeout has not been defined'); +} +function defaultClearTimeout () { + throw new Error('clearTimeout has not been defined'); +} +(function () { + try { + if (typeof setTimeout === 'function') { + cachedSetTimeout = setTimeout; + } else { + cachedSetTimeout = defaultSetTimout; + } + } catch (e) { + cachedSetTimeout = defaultSetTimout; + } + try { + if (typeof clearTimeout === 'function') { + cachedClearTimeout = clearTimeout; + } else { + cachedClearTimeout = defaultClearTimeout; + } + } catch (e) { + cachedClearTimeout = defaultClearTimeout; + } +} ()) +function runTimeout(fun) { + if (cachedSetTimeout === setTimeout) { + //normal enviroments in sane situations + return setTimeout(fun, 0); + } + // if setTimeout wasn't available but was latter defined + if ((cachedSetTimeout === defaultSetTimout || !cachedSetTimeout) && setTimeout) { + cachedSetTimeout = setTimeout; + return setTimeout(fun, 0); + } + try { + // when when somebody has screwed with setTimeout but no I.E. maddness + return cachedSetTimeout(fun, 0); + } catch(e){ + try { + // When we are in I.E. but the script has been evaled so I.E. doesn't trust the global object when called normally + return cachedSetTimeout.call(null, fun, 0); + } catch(e){ + // same as above but when it's a version of I.E. that must have the global object for 'this', hopfully our context correct otherwise it will throw a global error + return cachedSetTimeout.call(this, fun, 0); + } + } + + +} +function runClearTimeout(marker) { + if (cachedClearTimeout === clearTimeout) { + //normal enviroments in sane situations + return clearTimeout(marker); + } + // if clearTimeout wasn't available but was latter defined + if ((cachedClearTimeout === defaultClearTimeout || !cachedClearTimeout) && clearTimeout) { + cachedClearTimeout = clearTimeout; + return clearTimeout(marker); + } + try { + // when when somebody has screwed with setTimeout but no I.E. maddness + return cachedClearTimeout(marker); + } catch (e){ + try { + // When we are in I.E. but the script has been evaled so I.E. doesn't trust the global object when called normally + return cachedClearTimeout.call(null, marker); + } catch (e){ + // same as above but when it's a version of I.E. that must have the global object for 'this', hopfully our context correct otherwise it will throw a global error. + // Some versions of I.E. have different rules for clearTimeout vs setTimeout + return cachedClearTimeout.call(this, marker); + } + } + + + +} +var queue = []; +var draining = false; +var currentQueue; +var queueIndex = -1; + +function cleanUpNextTick() { + if (!draining || !currentQueue) { + return; + } + draining = false; + if (currentQueue.length) { + queue = currentQueue.concat(queue); + } else { + queueIndex = -1; + } + if (queue.length) { + drainQueue(); + } +} + +function drainQueue() { + if (draining) { + return; + } + var timeout = runTimeout(cleanUpNextTick); + draining = true; + + var len = queue.length; + while(len) { + currentQueue = queue; + queue = []; + while (++queueIndex < len) { + if (currentQueue) { + currentQueue[queueIndex].run(); + } + } + queueIndex = -1; + len = queue.length; + } + currentQueue = null; + draining = false; + runClearTimeout(timeout); +} + +process.nextTick = function (fun) { + var args = new Array(arguments.length - 1); + if (arguments.length > 1) { + for (var i = 1; i < arguments.length; i++) { + args[i - 1] = arguments[i]; + } + } + queue.push(new Item(fun, args)); + if (queue.length === 1 && !draining) { + runTimeout(drainQueue); + } +}; + +// v8 likes predictible objects +function Item(fun, array) { + this.fun = fun; + this.array = array; +} +Item.prototype.run = function () { + this.fun.apply(null, this.array); +}; +process.title = 'browser'; +process.browser = true; +process.env = {}; +process.argv = []; +process.version = ''; // empty string to avoid regexp issues +process.versions = {}; + +function noop() {} + +process.on = noop; +process.addListener = noop; +process.once = noop; +process.off = noop; +process.removeListener = noop; +process.removeAllListeners = noop; +process.emit = noop; +process.prependListener = noop; +process.prependOnceListener = noop; + +process.listeners = function (name) { return [] } + +process.binding = function (name) { + throw new Error('process.binding is not supported'); +}; + +process.cwd = function () { return '/' }; +process.chdir = function (dir) { + throw new Error('process.chdir is not supported'); +}; +process.umask = function() { return 0; }; + +},{}],150:[function(require,module,exports){ +exports.publicEncrypt = require('./publicEncrypt') +exports.privateDecrypt = require('./privateDecrypt') + +exports.privateEncrypt = function privateEncrypt (key, buf) { + return exports.publicEncrypt(key, buf, true) +} + +exports.publicDecrypt = function publicDecrypt (key, buf) { + return exports.privateDecrypt(key, buf, true) +} + +},{"./privateDecrypt":153,"./publicEncrypt":154}],151:[function(require,module,exports){ +var createHash = require('create-hash') +var Buffer = require('safe-buffer').Buffer + +module.exports = function (seed, len) { + var t = Buffer.alloc(0) + var i = 0 + var c + while (t.length < len) { + c = i2ops(i++) + t = Buffer.concat([t, createHash('sha1').update(seed).update(c).digest()]) + } + return t.slice(0, len) +} + +function i2ops (c) { + var out = Buffer.allocUnsafe(4) + out.writeUInt32BE(c, 0) + return out +} + +},{"create-hash":67,"safe-buffer":160}],152:[function(require,module,exports){ +arguments[4][15][0].apply(exports,arguments) +},{"buffer":19,"dup":15}],153:[function(require,module,exports){ +var parseKeys = require('parse-asn1') +var mgf = require('./mgf') +var xor = require('./xor') +var BN = require('bn.js') +var crt = require('browserify-rsa') +var createHash = require('create-hash') +var withPublic = require('./withPublic') +var Buffer = require('safe-buffer').Buffer + +module.exports = function privateDecrypt (privateKey, enc, reverse) { + var padding + if (privateKey.padding) { + padding = privateKey.padding + } else if (reverse) { + padding = 1 + } else { + padding = 4 + } + + var key = parseKeys(privateKey) + var k = key.modulus.byteLength() + if (enc.length > k || new BN(enc).cmp(key.modulus) >= 0) { + throw new Error('decryption error') + } + var msg + if (reverse) { + msg = withPublic(new BN(enc), key) + } else { + msg = crt(enc, key) + } + var zBuffer = Buffer.alloc(k - msg.length) + msg = Buffer.concat([zBuffer, msg], k) + if (padding === 4) { + return oaep(key, msg) + } else if (padding === 1) { + return pkcs1(key, msg, reverse) + } else if (padding === 3) { + return msg + } else { + throw new Error('unknown padding') + } +} + +function oaep (key, msg) { + var k = key.modulus.byteLength() + var iHash = createHash('sha1').update(Buffer.alloc(0)).digest() + var hLen = iHash.length + if (msg[0] !== 0) { + throw new Error('decryption error') + } + var maskedSeed = msg.slice(1, hLen + 1) + var maskedDb = msg.slice(hLen + 1) + var seed = xor(maskedSeed, mgf(maskedDb, hLen)) + var db = xor(maskedDb, mgf(seed, k - hLen - 1)) + if (compare(iHash, db.slice(0, hLen))) { + throw new Error('decryption error') + } + var i = hLen + while (db[i] === 0) { + i++ + } + if (db[i++] !== 1) { + throw new Error('decryption error') + } + return db.slice(i) +} + +function pkcs1 (key, msg, reverse) { + var p1 = msg.slice(0, 2) + var i = 2 + var status = 0 + while (msg[i++] !== 0) { + if (i >= msg.length) { + status++ + break + } + } + var ps = msg.slice(2, i - 1) + + if ((p1.toString('hex') !== '0002' && !reverse) || (p1.toString('hex') !== '0001' && reverse)) { + status++ + } + if (ps.length < 8) { + status++ + } + if (status) { + throw new Error('decryption error') + } + return msg.slice(i) +} +function compare (a, b) { + a = Buffer.from(a) + b = Buffer.from(b) + var dif = 0 + var len = a.length + if (a.length !== b.length) { + dif++ + len = Math.min(a.length, b.length) + } + var i = -1 + while (++i < len) { + dif += (a[i] ^ b[i]) + } + return dif +} + +},{"./mgf":151,"./withPublic":155,"./xor":156,"bn.js":152,"browserify-rsa":40,"create-hash":67,"parse-asn1":142,"safe-buffer":160}],154:[function(require,module,exports){ +var parseKeys = require('parse-asn1') +var randomBytes = require('randombytes') +var createHash = require('create-hash') +var mgf = require('./mgf') +var xor = require('./xor') +var BN = require('bn.js') +var withPublic = require('./withPublic') +var crt = require('browserify-rsa') +var Buffer = require('safe-buffer').Buffer + +module.exports = function publicEncrypt (publicKey, msg, reverse) { + var padding + if (publicKey.padding) { + padding = publicKey.padding + } else if (reverse) { + padding = 1 + } else { + padding = 4 + } + var key = parseKeys(publicKey) + var paddedMsg + if (padding === 4) { + paddedMsg = oaep(key, msg) + } else if (padding === 1) { + paddedMsg = pkcs1(key, msg, reverse) + } else if (padding === 3) { + paddedMsg = new BN(msg) + if (paddedMsg.cmp(key.modulus) >= 0) { + throw new Error('data too long for modulus') + } + } else { + throw new Error('unknown padding') + } + if (reverse) { + return crt(paddedMsg, key) + } else { + return withPublic(paddedMsg, key) + } +} + +function oaep (key, msg) { + var k = key.modulus.byteLength() + var mLen = msg.length + var iHash = createHash('sha1').update(Buffer.alloc(0)).digest() + var hLen = iHash.length + var hLen2 = 2 * hLen + if (mLen > k - hLen2 - 2) { + throw new Error('message too long') + } + var ps = Buffer.alloc(k - mLen - hLen2 - 2) + var dblen = k - hLen - 1 + var seed = randomBytes(hLen) + var maskedDb = xor(Buffer.concat([iHash, ps, Buffer.alloc(1, 1), msg], dblen), mgf(seed, dblen)) + var maskedSeed = xor(seed, mgf(maskedDb, hLen)) + return new BN(Buffer.concat([Buffer.alloc(1), maskedSeed, maskedDb], k)) +} +function pkcs1 (key, msg, reverse) { + var mLen = msg.length + var k = key.modulus.byteLength() + if (mLen > k - 11) { + throw new Error('message too long') + } + var ps + if (reverse) { + ps = Buffer.alloc(k - mLen - 3, 0xff) + } else { + ps = nonZero(k - mLen - 3) + } + return new BN(Buffer.concat([Buffer.from([0, reverse ? 1 : 2]), ps, Buffer.alloc(1), msg], k)) +} +function nonZero (len) { + var out = Buffer.allocUnsafe(len) + var i = 0 + var cache = randomBytes(len * 2) + var cur = 0 + var num + while (i < len) { + if (cur === cache.length) { + cache = randomBytes(len * 2) + cur = 0 + } + num = cache[cur++] + if (num) { + out[i++] = num + } + } + return out +} + +},{"./mgf":151,"./withPublic":155,"./xor":156,"bn.js":152,"browserify-rsa":40,"create-hash":67,"parse-asn1":142,"randombytes":157,"safe-buffer":160}],155:[function(require,module,exports){ +var BN = require('bn.js') +var Buffer = require('safe-buffer').Buffer + +function withPublic (paddedMsg, key) { + return Buffer.from(paddedMsg + .toRed(BN.mont(key.modulus)) + .redPow(new BN(key.publicExponent)) + .fromRed() + .toArray()) +} + +module.exports = withPublic + +},{"bn.js":152,"safe-buffer":160}],156:[function(require,module,exports){ +module.exports = function xor (a, b) { + var len = a.length + var i = -1 + while (++i < len) { + a[i] ^= b[i] + } + return a +} + +},{}],157:[function(require,module,exports){ +(function (process,global){(function (){ +'use strict' + +// limit of Crypto.getRandomValues() +// https://developer.mozilla.org/en-US/docs/Web/API/Crypto/getRandomValues +var MAX_BYTES = 65536 + +// Node supports requesting up to this number of bytes +// https://github.com/nodejs/node/blob/master/lib/internal/crypto/random.js#L48 +var MAX_UINT32 = 4294967295 + +function oldBrowser () { + throw new Error('Secure random number generation is not supported by this browser.\nUse Chrome, Firefox or Internet Explorer 11') +} + +var Buffer = require('safe-buffer').Buffer +var crypto = global.crypto || global.msCrypto + +if (crypto && crypto.getRandomValues) { + module.exports = randomBytes +} else { + module.exports = oldBrowser +} + +function randomBytes (size, cb) { + // phantomjs needs to throw + if (size > MAX_UINT32) throw new RangeError('requested too many random bytes') + + var bytes = Buffer.allocUnsafe(size) + + if (size > 0) { // getRandomValues fails on IE if size == 0 + if (size > MAX_BYTES) { // this is the max bytes crypto.getRandomValues + // can do at once see https://developer.mozilla.org/en-US/docs/Web/API/window.crypto.getRandomValues + for (var generated = 0; generated < size; generated += MAX_BYTES) { + // buffer.slice automatically checks if the end is past the end of + // the buffer so we don't have to here + crypto.getRandomValues(bytes.slice(generated, generated + MAX_BYTES)) + } + } else { + crypto.getRandomValues(bytes) + } + } + + if (typeof cb === 'function') { + return process.nextTick(function () { + cb(null, bytes) + }) + } + + return bytes +} + +}).call(this)}).call(this,require('_process'),typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) +},{"_process":149,"safe-buffer":160}],158:[function(require,module,exports){ +(function (process,global){(function (){ +'use strict' + +function oldBrowser () { + throw new Error('secure random number generation not supported by this browser\nuse chrome, FireFox or Internet Explorer 11') +} +var safeBuffer = require('safe-buffer') +var randombytes = require('randombytes') +var Buffer = safeBuffer.Buffer +var kBufferMaxLength = safeBuffer.kMaxLength +var crypto = global.crypto || global.msCrypto +var kMaxUint32 = Math.pow(2, 32) - 1 +function assertOffset (offset, length) { + if (typeof offset !== 'number' || offset !== offset) { // eslint-disable-line no-self-compare + throw new TypeError('offset must be a number') + } + + if (offset > kMaxUint32 || offset < 0) { + throw new TypeError('offset must be a uint32') + } + + if (offset > kBufferMaxLength || offset > length) { + throw new RangeError('offset out of range') + } +} + +function assertSize (size, offset, length) { + if (typeof size !== 'number' || size !== size) { // eslint-disable-line no-self-compare + throw new TypeError('size must be a number') + } + + if (size > kMaxUint32 || size < 0) { + throw new TypeError('size must be a uint32') + } + + if (size + offset > length || size > kBufferMaxLength) { + throw new RangeError('buffer too small') + } +} +if ((crypto && crypto.getRandomValues) || !process.browser) { + exports.randomFill = randomFill + exports.randomFillSync = randomFillSync +} else { + exports.randomFill = oldBrowser + exports.randomFillSync = oldBrowser +} +function randomFill (buf, offset, size, cb) { + if (!Buffer.isBuffer(buf) && !(buf instanceof global.Uint8Array)) { + throw new TypeError('"buf" argument must be a Buffer or Uint8Array') + } + + if (typeof offset === 'function') { + cb = offset + offset = 0 + size = buf.length + } else if (typeof size === 'function') { + cb = size + size = buf.length - offset + } else if (typeof cb !== 'function') { + throw new TypeError('"cb" argument must be a function') + } + assertOffset(offset, buf.length) + assertSize(size, offset, buf.length) + return actualFill(buf, offset, size, cb) +} + +function actualFill (buf, offset, size, cb) { + if (process.browser) { + var ourBuf = buf.buffer + var uint = new Uint8Array(ourBuf, offset, size) + crypto.getRandomValues(uint) + if (cb) { + process.nextTick(function () { + cb(null, buf) + }) + return + } + return buf + } + if (cb) { + randombytes(size, function (err, bytes) { + if (err) { + return cb(err) + } + bytes.copy(buf, offset) + cb(null, buf) + }) + return + } + var bytes = randombytes(size) + bytes.copy(buf, offset) + return buf +} +function randomFillSync (buf, offset, size) { + if (typeof offset === 'undefined') { + offset = 0 + } + if (!Buffer.isBuffer(buf) && !(buf instanceof global.Uint8Array)) { + throw new TypeError('"buf" argument must be a Buffer or Uint8Array') + } + + assertOffset(offset, buf.length) + + if (size === undefined) size = buf.length - offset + + assertSize(size, offset, buf.length) + + return actualFill(buf, offset, size) +} + +}).call(this)}).call(this,require('_process'),typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) +},{"_process":149,"randombytes":157,"safe-buffer":160}],159:[function(require,module,exports){ +'use strict' +var Buffer = require('buffer').Buffer +var inherits = require('inherits') +var HashBase = require('hash-base') + +var ARRAY16 = new Array(16) + +var zl = [ + 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 zr = [ + 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 sl = [ + 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 sr = [ + 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 +] + +var hl = [0x00000000, 0x5a827999, 0x6ed9eba1, 0x8f1bbcdc, 0xa953fd4e] +var hr = [0x50a28be6, 0x5c4dd124, 0x6d703ef3, 0x7a6d76e9, 0x00000000] + +function RIPEMD160 () { + HashBase.call(this, 64) + + // state + this._a = 0x67452301 + this._b = 0xefcdab89 + this._c = 0x98badcfe + this._d = 0x10325476 + this._e = 0xc3d2e1f0 +} + +inherits(RIPEMD160, HashBase) + +RIPEMD160.prototype._update = function () { + var words = ARRAY16 + for (var j = 0; j < 16; ++j) words[j] = this._block.readInt32LE(j * 4) + + var al = this._a | 0 + var bl = this._b | 0 + var cl = this._c | 0 + var dl = this._d | 0 + var el = this._e | 0 + + var ar = this._a | 0 + var br = this._b | 0 + var cr = this._c | 0 + var dr = this._d | 0 + var er = this._e | 0 + + // computation + for (var i = 0; i < 80; i += 1) { + var tl + var tr + if (i < 16) { + tl = fn1(al, bl, cl, dl, el, words[zl[i]], hl[0], sl[i]) + tr = fn5(ar, br, cr, dr, er, words[zr[i]], hr[0], sr[i]) + } else if (i < 32) { + tl = fn2(al, bl, cl, dl, el, words[zl[i]], hl[1], sl[i]) + tr = fn4(ar, br, cr, dr, er, words[zr[i]], hr[1], sr[i]) + } else if (i < 48) { + tl = fn3(al, bl, cl, dl, el, words[zl[i]], hl[2], sl[i]) + tr = fn3(ar, br, cr, dr, er, words[zr[i]], hr[2], sr[i]) + } else if (i < 64) { + tl = fn4(al, bl, cl, dl, el, words[zl[i]], hl[3], sl[i]) + tr = fn2(ar, br, cr, dr, er, words[zr[i]], hr[3], sr[i]) + } else { // if (i<80) { + tl = fn5(al, bl, cl, dl, el, words[zl[i]], hl[4], sl[i]) + tr = fn1(ar, br, cr, dr, er, words[zr[i]], hr[4], sr[i]) + } + + al = el + el = dl + dl = rotl(cl, 10) + cl = bl + bl = tl + + ar = er + er = dr + dr = rotl(cr, 10) + cr = br + br = tr + } + + // update state + var t = (this._b + cl + dr) | 0 + this._b = (this._c + dl + er) | 0 + this._c = (this._d + el + ar) | 0 + this._d = (this._e + al + br) | 0 + this._e = (this._a + bl + cr) | 0 + this._a = t +} + +RIPEMD160.prototype._digest = function () { + // create padding and handle blocks + this._block[this._blockOffset++] = 0x80 + if (this._blockOffset > 56) { + this._block.fill(0, this._blockOffset, 64) + this._update() + this._blockOffset = 0 + } + + this._block.fill(0, this._blockOffset, 56) + this._block.writeUInt32LE(this._length[0], 56) + this._block.writeUInt32LE(this._length[1], 60) + this._update() + + // produce result + var buffer = Buffer.alloc ? Buffer.alloc(20) : new Buffer(20) + buffer.writeInt32LE(this._a, 0) + buffer.writeInt32LE(this._b, 4) + buffer.writeInt32LE(this._c, 8) + buffer.writeInt32LE(this._d, 12) + buffer.writeInt32LE(this._e, 16) + return buffer +} + +function rotl (x, n) { + return (x << n) | (x >>> (32 - n)) +} + +function fn1 (a, b, c, d, e, m, k, s) { + return (rotl((a + (b ^ c ^ d) + m + k) | 0, s) + e) | 0 +} + +function fn2 (a, b, c, d, e, m, k, s) { + return (rotl((a + ((b & c) | ((~b) & d)) + m + k) | 0, s) + e) | 0 +} + +function fn3 (a, b, c, d, e, m, k, s) { + return (rotl((a + ((b | (~c)) ^ d) + m + k) | 0, s) + e) | 0 +} + +function fn4 (a, b, c, d, e, m, k, s) { + return (rotl((a + ((b & d) | (c & (~d))) + m + k) | 0, s) + e) | 0 +} + +function fn5 (a, b, c, d, e, m, k, s) { + return (rotl((a + (b ^ (c | (~d))) + m + k) | 0, s) + e) | 0 +} + +module.exports = RIPEMD160 + +},{"buffer":63,"hash-base":102,"inherits":132}],160:[function(require,module,exports){ +/*! safe-buffer. MIT License. Feross Aboukhadijeh */ +/* eslint-disable node/no-deprecated-api */ +var buffer = require('buffer') +var Buffer = buffer.Buffer + +// alternative to using Object.keys for old browsers +function copyProps (src, dst) { + for (var key in src) { + dst[key] = src[key] + } +} +if (Buffer.from && Buffer.alloc && Buffer.allocUnsafe && Buffer.allocUnsafeSlow) { + module.exports = buffer +} else { + // Copy properties from require('buffer') + copyProps(buffer, exports) + exports.Buffer = SafeBuffer +} + +function SafeBuffer (arg, encodingOrOffset, length) { + return Buffer(arg, encodingOrOffset, length) +} + +SafeBuffer.prototype = Object.create(Buffer.prototype) + +// Copy static methods from Buffer +copyProps(Buffer, SafeBuffer) + +SafeBuffer.from = function (arg, encodingOrOffset, length) { + if (typeof arg === 'number') { + throw new TypeError('Argument must not be a number') + } + return Buffer(arg, encodingOrOffset, length) +} + +SafeBuffer.alloc = function (size, fill, encoding) { + if (typeof size !== 'number') { + throw new TypeError('Argument must be a number') + } + var buf = Buffer(size) + if (fill !== undefined) { + if (typeof encoding === 'string') { + buf.fill(fill, encoding) + } else { + buf.fill(fill) + } + } else { + buf.fill(0) + } + return buf +} + +SafeBuffer.allocUnsafe = function (size) { + if (typeof size !== 'number') { + throw new TypeError('Argument must be a number') + } + return Buffer(size) +} + +SafeBuffer.allocUnsafeSlow = function (size) { + if (typeof size !== 'number') { + throw new TypeError('Argument must be a number') + } + return buffer.SlowBuffer(size) +} + +},{"buffer":63}],161:[function(require,module,exports){ +(function (process){(function (){ +/* eslint-disable node/no-deprecated-api */ + +'use strict' + +var buffer = require('buffer') +var Buffer = buffer.Buffer + +var safer = {} + +var key + +for (key in buffer) { + if (!buffer.hasOwnProperty(key)) continue + if (key === 'SlowBuffer' || key === 'Buffer') continue + safer[key] = buffer[key] +} + +var Safer = safer.Buffer = {} +for (key in Buffer) { + if (!Buffer.hasOwnProperty(key)) continue + if (key === 'allocUnsafe' || key === 'allocUnsafeSlow') continue + Safer[key] = Buffer[key] +} + +safer.Buffer.prototype = Buffer.prototype + +if (!Safer.from || Safer.from === Uint8Array.from) { + Safer.from = function (value, encodingOrOffset, length) { + if (typeof value === 'number') { + throw new TypeError('The "value" argument must not be of type number. Received type ' + typeof value) + } + if (value && typeof value.length === 'undefined') { + throw new TypeError('The first argument must be one of type string, Buffer, ArrayBuffer, Array, or Array-like Object. Received type ' + typeof value) + } + return Buffer(value, encodingOrOffset, length) + } +} + +if (!Safer.alloc) { + Safer.alloc = function (size, fill, encoding) { + if (typeof size !== 'number') { + throw new TypeError('The "size" argument must be of type number. Received type ' + typeof size) + } + if (size < 0 || size >= 2 * (1 << 30)) { + throw new RangeError('The value "' + size + '" is invalid for option "size"') + } + var buf = Buffer(size) + if (!fill || fill.length === 0) { + buf.fill(0) + } else if (typeof encoding === 'string') { + buf.fill(fill, encoding) + } else { + buf.fill(fill) + } + return buf + } +} + +if (!safer.kStringMaxLength) { + try { + safer.kStringMaxLength = process.binding('buffer').kStringMaxLength + } catch (e) { + // we can't determine kStringMaxLength in environments where process.binding + // is unsupported, so let's not set it + } +} + +if (!safer.constants) { + safer.constants = { + MAX_LENGTH: safer.kMaxLength + } + if (safer.kStringMaxLength) { + safer.constants.MAX_STRING_LENGTH = safer.kStringMaxLength + } +} + +module.exports = safer + +}).call(this)}).call(this,require('_process')) +},{"_process":149,"buffer":63}],162:[function(require,module,exports){ +var Buffer = require('safe-buffer').Buffer + +// prototype class for hash functions +function Hash (blockSize, finalSize) { + this._block = Buffer.alloc(blockSize) + this._finalSize = finalSize + this._blockSize = blockSize + this._len = 0 +} + +Hash.prototype.update = function (data, enc) { + if (typeof data === 'string') { + enc = enc || 'utf8' + data = Buffer.from(data, enc) + } + + var block = this._block + var blockSize = this._blockSize + var length = data.length + var accum = this._len + + for (var offset = 0; offset < length;) { + var assigned = accum % blockSize + var remainder = Math.min(length - offset, blockSize - assigned) + + for (var i = 0; i < remainder; i++) { + block[assigned + i] = data[offset + i] + } + + accum += remainder + offset += remainder + + if ((accum % blockSize) === 0) { + this._update(block) + } + } + + this._len += length + return this +} + +Hash.prototype.digest = function (enc) { + var rem = this._len % this._blockSize + + this._block[rem] = 0x80 + + // zero (rem + 1) trailing bits, where (rem + 1) is the smallest + // non-negative solution to the equation (length + 1 + (rem + 1)) === finalSize mod blockSize + this._block.fill(0, rem + 1) + + if (rem >= this._finalSize) { + this._update(this._block) + this._block.fill(0) + } + + var bits = this._len * 8 + + // uint32 + if (bits <= 0xffffffff) { + this._block.writeUInt32BE(bits, this._blockSize - 4) + + // uint64 + } else { + var lowBits = (bits & 0xffffffff) >>> 0 + var highBits = (bits - lowBits) / 0x100000000 + + this._block.writeUInt32BE(highBits, this._blockSize - 8) + this._block.writeUInt32BE(lowBits, this._blockSize - 4) + } + + this._update(this._block) + var hash = this._hash() + + return enc ? hash.toString(enc) : hash +} + +Hash.prototype._update = function () { + throw new Error('_update must be implemented by subclass') +} + +module.exports = Hash + +},{"safe-buffer":160}],163:[function(require,module,exports){ +var exports = module.exports = function SHA (algorithm) { + algorithm = algorithm.toLowerCase() + + var Algorithm = exports[algorithm] + if (!Algorithm) throw new Error(algorithm + ' is not supported (we accept pull requests)') + + return new Algorithm() +} + +exports.sha = require('./sha') +exports.sha1 = require('./sha1') +exports.sha224 = require('./sha224') +exports.sha256 = require('./sha256') +exports.sha384 = require('./sha384') +exports.sha512 = require('./sha512') + +},{"./sha":164,"./sha1":165,"./sha224":166,"./sha256":167,"./sha384":168,"./sha512":169}],164:[function(require,module,exports){ +/* + * A JavaScript implementation of the Secure Hash Algorithm, SHA-0, as defined + * in FIPS PUB 180-1 + * This source code is derived from sha1.js of the same repository. + * The difference between SHA-0 and SHA-1 is just a bitwise rotate left + * operation was added. + */ + +var inherits = require('inherits') +var Hash = require('./hash') +var Buffer = require('safe-buffer').Buffer + +var K = [ + 0x5a827999, 0x6ed9eba1, 0x8f1bbcdc | 0, 0xca62c1d6 | 0 +] + +var W = new Array(80) + +function Sha () { + this.init() + this._w = W + + Hash.call(this, 64, 56) +} + +inherits(Sha, Hash) + +Sha.prototype.init = function () { + this._a = 0x67452301 + this._b = 0xefcdab89 + this._c = 0x98badcfe + this._d = 0x10325476 + this._e = 0xc3d2e1f0 + + return this +} + +function rotl5 (num) { + return (num << 5) | (num >>> 27) +} + +function rotl30 (num) { + return (num << 30) | (num >>> 2) +} + +function ft (s, b, c, d) { + if (s === 0) return (b & c) | ((~b) & d) + if (s === 2) return (b & c) | (b & d) | (c & d) + return b ^ c ^ d +} + +Sha.prototype._update = function (M) { + var W = this._w + + var a = this._a | 0 + var b = this._b | 0 + var c = this._c | 0 + var d = this._d | 0 + var e = this._e | 0 + + for (var i = 0; i < 16; ++i) W[i] = M.readInt32BE(i * 4) + for (; i < 80; ++i) W[i] = W[i - 3] ^ W[i - 8] ^ W[i - 14] ^ W[i - 16] + + for (var j = 0; j < 80; ++j) { + var s = ~~(j / 20) + var t = (rotl5(a) + ft(s, b, c, d) + e + W[j] + K[s]) | 0 + + e = d + d = c + c = rotl30(b) + b = a + a = t + } + + this._a = (a + this._a) | 0 + this._b = (b + this._b) | 0 + this._c = (c + this._c) | 0 + this._d = (d + this._d) | 0 + this._e = (e + this._e) | 0 +} + +Sha.prototype._hash = function () { + var H = Buffer.allocUnsafe(20) + + H.writeInt32BE(this._a | 0, 0) + H.writeInt32BE(this._b | 0, 4) + H.writeInt32BE(this._c | 0, 8) + H.writeInt32BE(this._d | 0, 12) + H.writeInt32BE(this._e | 0, 16) + + return H +} + +module.exports = Sha + +},{"./hash":162,"inherits":132,"safe-buffer":160}],165:[function(require,module,exports){ +/* + * A JavaScript implementation of the Secure Hash Algorithm, SHA-1, as defined + * in FIPS PUB 180-1 + * Version 2.1a Copyright Paul Johnston 2000 - 2002. + * Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet + * Distributed under the BSD License + * See http://pajhome.org.uk/crypt/md5 for details. + */ + +var inherits = require('inherits') +var Hash = require('./hash') +var Buffer = require('safe-buffer').Buffer + +var K = [ + 0x5a827999, 0x6ed9eba1, 0x8f1bbcdc | 0, 0xca62c1d6 | 0 +] + +var W = new Array(80) + +function Sha1 () { + this.init() + this._w = W + + Hash.call(this, 64, 56) +} + +inherits(Sha1, Hash) + +Sha1.prototype.init = function () { + this._a = 0x67452301 + this._b = 0xefcdab89 + this._c = 0x98badcfe + this._d = 0x10325476 + this._e = 0xc3d2e1f0 + + return this +} + +function rotl1 (num) { + return (num << 1) | (num >>> 31) +} + +function rotl5 (num) { + return (num << 5) | (num >>> 27) +} + +function rotl30 (num) { + return (num << 30) | (num >>> 2) +} + +function ft (s, b, c, d) { + if (s === 0) return (b & c) | ((~b) & d) + if (s === 2) return (b & c) | (b & d) | (c & d) + return b ^ c ^ d +} + +Sha1.prototype._update = function (M) { + var W = this._w + + var a = this._a | 0 + var b = this._b | 0 + var c = this._c | 0 + var d = this._d | 0 + var e = this._e | 0 + + for (var i = 0; i < 16; ++i) W[i] = M.readInt32BE(i * 4) + for (; i < 80; ++i) W[i] = rotl1(W[i - 3] ^ W[i - 8] ^ W[i - 14] ^ W[i - 16]) + + for (var j = 0; j < 80; ++j) { + var s = ~~(j / 20) + var t = (rotl5(a) + ft(s, b, c, d) + e + W[j] + K[s]) | 0 + + e = d + d = c + c = rotl30(b) + b = a + a = t + } + + this._a = (a + this._a) | 0 + this._b = (b + this._b) | 0 + this._c = (c + this._c) | 0 + this._d = (d + this._d) | 0 + this._e = (e + this._e) | 0 +} + +Sha1.prototype._hash = function () { + var H = Buffer.allocUnsafe(20) + + H.writeInt32BE(this._a | 0, 0) + H.writeInt32BE(this._b | 0, 4) + H.writeInt32BE(this._c | 0, 8) + H.writeInt32BE(this._d | 0, 12) + H.writeInt32BE(this._e | 0, 16) + + return H +} + +module.exports = Sha1 + +},{"./hash":162,"inherits":132,"safe-buffer":160}],166:[function(require,module,exports){ +/** + * A JavaScript implementation of the Secure Hash Algorithm, SHA-256, as defined + * in FIPS 180-2 + * Version 2.2-beta Copyright Angel Marin, Paul Johnston 2000 - 2009. + * Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet + * + */ + +var inherits = require('inherits') +var Sha256 = require('./sha256') +var Hash = require('./hash') +var Buffer = require('safe-buffer').Buffer + +var W = new Array(64) + +function Sha224 () { + this.init() + + this._w = W // new Array(64) + + Hash.call(this, 64, 56) +} + +inherits(Sha224, Sha256) + +Sha224.prototype.init = function () { + this._a = 0xc1059ed8 + this._b = 0x367cd507 + this._c = 0x3070dd17 + this._d = 0xf70e5939 + this._e = 0xffc00b31 + this._f = 0x68581511 + this._g = 0x64f98fa7 + this._h = 0xbefa4fa4 + + return this +} + +Sha224.prototype._hash = function () { + var H = Buffer.allocUnsafe(28) + + H.writeInt32BE(this._a, 0) + H.writeInt32BE(this._b, 4) + H.writeInt32BE(this._c, 8) + H.writeInt32BE(this._d, 12) + H.writeInt32BE(this._e, 16) + H.writeInt32BE(this._f, 20) + H.writeInt32BE(this._g, 24) + + return H +} + +module.exports = Sha224 + +},{"./hash":162,"./sha256":167,"inherits":132,"safe-buffer":160}],167:[function(require,module,exports){ +/** + * A JavaScript implementation of the Secure Hash Algorithm, SHA-256, as defined + * in FIPS 180-2 + * Version 2.2-beta Copyright Angel Marin, Paul Johnston 2000 - 2009. + * Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet + * + */ + +var inherits = require('inherits') +var Hash = require('./hash') +var Buffer = require('safe-buffer').Buffer + +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 +] + +var W = new Array(64) + +function Sha256 () { + this.init() + + this._w = W // new Array(64) + + Hash.call(this, 64, 56) +} + +inherits(Sha256, Hash) + +Sha256.prototype.init = function () { + this._a = 0x6a09e667 + this._b = 0xbb67ae85 + this._c = 0x3c6ef372 + this._d = 0xa54ff53a + this._e = 0x510e527f + this._f = 0x9b05688c + this._g = 0x1f83d9ab + this._h = 0x5be0cd19 + + return this +} + +function ch (x, y, z) { + return z ^ (x & (y ^ z)) +} + +function maj (x, y, z) { + return (x & y) | (z & (x | y)) +} + +function sigma0 (x) { + return (x >>> 2 | x << 30) ^ (x >>> 13 | x << 19) ^ (x >>> 22 | x << 10) +} + +function sigma1 (x) { + return (x >>> 6 | x << 26) ^ (x >>> 11 | x << 21) ^ (x >>> 25 | x << 7) +} + +function gamma0 (x) { + return (x >>> 7 | x << 25) ^ (x >>> 18 | x << 14) ^ (x >>> 3) +} + +function gamma1 (x) { + return (x >>> 17 | x << 15) ^ (x >>> 19 | x << 13) ^ (x >>> 10) +} + +Sha256.prototype._update = function (M) { + var W = this._w + + var a = this._a | 0 + var b = this._b | 0 + var c = this._c | 0 + var d = this._d | 0 + var e = this._e | 0 + var f = this._f | 0 + var g = this._g | 0 + var h = this._h | 0 + + for (var i = 0; i < 16; ++i) W[i] = M.readInt32BE(i * 4) + for (; i < 64; ++i) W[i] = (gamma1(W[i - 2]) + W[i - 7] + gamma0(W[i - 15]) + W[i - 16]) | 0 + + for (var j = 0; j < 64; ++j) { + var T1 = (h + sigma1(e) + ch(e, f, g) + K[j] + W[j]) | 0 + var T2 = (sigma0(a) + maj(a, b, c)) | 0 + + h = g + g = f + f = e + e = (d + T1) | 0 + d = c + c = b + b = a + a = (T1 + T2) | 0 + } + + this._a = (a + this._a) | 0 + this._b = (b + this._b) | 0 + this._c = (c + this._c) | 0 + this._d = (d + this._d) | 0 + this._e = (e + this._e) | 0 + this._f = (f + this._f) | 0 + this._g = (g + this._g) | 0 + this._h = (h + this._h) | 0 +} + +Sha256.prototype._hash = function () { + var H = Buffer.allocUnsafe(32) + + H.writeInt32BE(this._a, 0) + H.writeInt32BE(this._b, 4) + H.writeInt32BE(this._c, 8) + H.writeInt32BE(this._d, 12) + H.writeInt32BE(this._e, 16) + H.writeInt32BE(this._f, 20) + H.writeInt32BE(this._g, 24) + H.writeInt32BE(this._h, 28) + + return H +} + +module.exports = Sha256 + +},{"./hash":162,"inherits":132,"safe-buffer":160}],168:[function(require,module,exports){ +var inherits = require('inherits') +var SHA512 = require('./sha512') +var Hash = require('./hash') +var Buffer = require('safe-buffer').Buffer + +var W = new Array(160) + +function Sha384 () { + this.init() + this._w = W + + Hash.call(this, 128, 112) +} + +inherits(Sha384, SHA512) + +Sha384.prototype.init = function () { + this._ah = 0xcbbb9d5d + this._bh = 0x629a292a + this._ch = 0x9159015a + this._dh = 0x152fecd8 + this._eh = 0x67332667 + this._fh = 0x8eb44a87 + this._gh = 0xdb0c2e0d + this._hh = 0x47b5481d + + this._al = 0xc1059ed8 + this._bl = 0x367cd507 + this._cl = 0x3070dd17 + this._dl = 0xf70e5939 + this._el = 0xffc00b31 + this._fl = 0x68581511 + this._gl = 0x64f98fa7 + this._hl = 0xbefa4fa4 + + return this +} + +Sha384.prototype._hash = function () { + var H = Buffer.allocUnsafe(48) + + function writeInt64BE (h, l, offset) { + H.writeInt32BE(h, offset) + H.writeInt32BE(l, offset + 4) + } + + writeInt64BE(this._ah, this._al, 0) + writeInt64BE(this._bh, this._bl, 8) + writeInt64BE(this._ch, this._cl, 16) + writeInt64BE(this._dh, this._dl, 24) + writeInt64BE(this._eh, this._el, 32) + writeInt64BE(this._fh, this._fl, 40) + + return H +} + +module.exports = Sha384 + +},{"./hash":162,"./sha512":169,"inherits":132,"safe-buffer":160}],169:[function(require,module,exports){ +var inherits = require('inherits') +var Hash = require('./hash') +var Buffer = require('safe-buffer').Buffer + +var K = [ + 0x428a2f98, 0xd728ae22, 0x71374491, 0x23ef65cd, + 0xb5c0fbcf, 0xec4d3b2f, 0xe9b5dba5, 0x8189dbbc, + 0x3956c25b, 0xf348b538, 0x59f111f1, 0xb605d019, + 0x923f82a4, 0xaf194f9b, 0xab1c5ed5, 0xda6d8118, + 0xd807aa98, 0xa3030242, 0x12835b01, 0x45706fbe, + 0x243185be, 0x4ee4b28c, 0x550c7dc3, 0xd5ffb4e2, + 0x72be5d74, 0xf27b896f, 0x80deb1fe, 0x3b1696b1, + 0x9bdc06a7, 0x25c71235, 0xc19bf174, 0xcf692694, + 0xe49b69c1, 0x9ef14ad2, 0xefbe4786, 0x384f25e3, + 0x0fc19dc6, 0x8b8cd5b5, 0x240ca1cc, 0x77ac9c65, + 0x2de92c6f, 0x592b0275, 0x4a7484aa, 0x6ea6e483, + 0x5cb0a9dc, 0xbd41fbd4, 0x76f988da, 0x831153b5, + 0x983e5152, 0xee66dfab, 0xa831c66d, 0x2db43210, + 0xb00327c8, 0x98fb213f, 0xbf597fc7, 0xbeef0ee4, + 0xc6e00bf3, 0x3da88fc2, 0xd5a79147, 0x930aa725, + 0x06ca6351, 0xe003826f, 0x14292967, 0x0a0e6e70, + 0x27b70a85, 0x46d22ffc, 0x2e1b2138, 0x5c26c926, + 0x4d2c6dfc, 0x5ac42aed, 0x53380d13, 0x9d95b3df, + 0x650a7354, 0x8baf63de, 0x766a0abb, 0x3c77b2a8, + 0x81c2c92e, 0x47edaee6, 0x92722c85, 0x1482353b, + 0xa2bfe8a1, 0x4cf10364, 0xa81a664b, 0xbc423001, + 0xc24b8b70, 0xd0f89791, 0xc76c51a3, 0x0654be30, + 0xd192e819, 0xd6ef5218, 0xd6990624, 0x5565a910, + 0xf40e3585, 0x5771202a, 0x106aa070, 0x32bbd1b8, + 0x19a4c116, 0xb8d2d0c8, 0x1e376c08, 0x5141ab53, + 0x2748774c, 0xdf8eeb99, 0x34b0bcb5, 0xe19b48a8, + 0x391c0cb3, 0xc5c95a63, 0x4ed8aa4a, 0xe3418acb, + 0x5b9cca4f, 0x7763e373, 0x682e6ff3, 0xd6b2b8a3, + 0x748f82ee, 0x5defb2fc, 0x78a5636f, 0x43172f60, + 0x84c87814, 0xa1f0ab72, 0x8cc70208, 0x1a6439ec, + 0x90befffa, 0x23631e28, 0xa4506ceb, 0xde82bde9, + 0xbef9a3f7, 0xb2c67915, 0xc67178f2, 0xe372532b, + 0xca273ece, 0xea26619c, 0xd186b8c7, 0x21c0c207, + 0xeada7dd6, 0xcde0eb1e, 0xf57d4f7f, 0xee6ed178, + 0x06f067aa, 0x72176fba, 0x0a637dc5, 0xa2c898a6, + 0x113f9804, 0xbef90dae, 0x1b710b35, 0x131c471b, + 0x28db77f5, 0x23047d84, 0x32caab7b, 0x40c72493, + 0x3c9ebe0a, 0x15c9bebc, 0x431d67c4, 0x9c100d4c, + 0x4cc5d4be, 0xcb3e42b6, 0x597f299c, 0xfc657e2a, + 0x5fcb6fab, 0x3ad6faec, 0x6c44198c, 0x4a475817 +] + +var W = new Array(160) + +function Sha512 () { + this.init() + this._w = W + + Hash.call(this, 128, 112) +} + +inherits(Sha512, Hash) + +Sha512.prototype.init = function () { + this._ah = 0x6a09e667 + this._bh = 0xbb67ae85 + this._ch = 0x3c6ef372 + this._dh = 0xa54ff53a + this._eh = 0x510e527f + this._fh = 0x9b05688c + this._gh = 0x1f83d9ab + this._hh = 0x5be0cd19 + + this._al = 0xf3bcc908 + this._bl = 0x84caa73b + this._cl = 0xfe94f82b + this._dl = 0x5f1d36f1 + this._el = 0xade682d1 + this._fl = 0x2b3e6c1f + this._gl = 0xfb41bd6b + this._hl = 0x137e2179 + + return this +} + +function Ch (x, y, z) { + return z ^ (x & (y ^ z)) +} + +function maj (x, y, z) { + return (x & y) | (z & (x | y)) +} + +function sigma0 (x, xl) { + return (x >>> 28 | xl << 4) ^ (xl >>> 2 | x << 30) ^ (xl >>> 7 | x << 25) +} + +function sigma1 (x, xl) { + return (x >>> 14 | xl << 18) ^ (x >>> 18 | xl << 14) ^ (xl >>> 9 | x << 23) +} + +function Gamma0 (x, xl) { + return (x >>> 1 | xl << 31) ^ (x >>> 8 | xl << 24) ^ (x >>> 7) +} + +function Gamma0l (x, xl) { + return (x >>> 1 | xl << 31) ^ (x >>> 8 | xl << 24) ^ (x >>> 7 | xl << 25) +} + +function Gamma1 (x, xl) { + return (x >>> 19 | xl << 13) ^ (xl >>> 29 | x << 3) ^ (x >>> 6) +} + +function Gamma1l (x, xl) { + return (x >>> 19 | xl << 13) ^ (xl >>> 29 | x << 3) ^ (x >>> 6 | xl << 26) +} + +function getCarry (a, b) { + return (a >>> 0) < (b >>> 0) ? 1 : 0 +} + +Sha512.prototype._update = function (M) { + var W = this._w + + var ah = this._ah | 0 + var bh = this._bh | 0 + var ch = this._ch | 0 + var dh = this._dh | 0 + var eh = this._eh | 0 + var fh = this._fh | 0 + var gh = this._gh | 0 + var hh = this._hh | 0 + + var al = this._al | 0 + var bl = this._bl | 0 + var cl = this._cl | 0 + var dl = this._dl | 0 + var el = this._el | 0 + var fl = this._fl | 0 + var gl = this._gl | 0 + var hl = this._hl | 0 + + for (var i = 0; i < 32; i += 2) { + W[i] = M.readInt32BE(i * 4) + W[i + 1] = M.readInt32BE(i * 4 + 4) + } + for (; i < 160; i += 2) { + var xh = W[i - 15 * 2] + var xl = W[i - 15 * 2 + 1] + var gamma0 = Gamma0(xh, xl) + var gamma0l = Gamma0l(xl, xh) + + xh = W[i - 2 * 2] + xl = W[i - 2 * 2 + 1] + var gamma1 = Gamma1(xh, xl) + var gamma1l = Gamma1l(xl, xh) + + // W[i] = gamma0 + W[i - 7] + gamma1 + W[i - 16] + var Wi7h = W[i - 7 * 2] + var Wi7l = W[i - 7 * 2 + 1] + + var Wi16h = W[i - 16 * 2] + var Wi16l = W[i - 16 * 2 + 1] + + var Wil = (gamma0l + Wi7l) | 0 + var Wih = (gamma0 + Wi7h + getCarry(Wil, gamma0l)) | 0 + Wil = (Wil + gamma1l) | 0 + Wih = (Wih + gamma1 + getCarry(Wil, gamma1l)) | 0 + Wil = (Wil + Wi16l) | 0 + Wih = (Wih + Wi16h + getCarry(Wil, Wi16l)) | 0 + + W[i] = Wih + W[i + 1] = Wil + } + + for (var j = 0; j < 160; j += 2) { + Wih = W[j] + Wil = W[j + 1] + + var majh = maj(ah, bh, ch) + var majl = maj(al, bl, cl) + + var sigma0h = sigma0(ah, al) + var sigma0l = sigma0(al, ah) + var sigma1h = sigma1(eh, el) + var sigma1l = sigma1(el, eh) + + // t1 = h + sigma1 + ch + K[j] + W[j] + var Kih = K[j] + var Kil = K[j + 1] + + var chh = Ch(eh, fh, gh) + var chl = Ch(el, fl, gl) + + var t1l = (hl + sigma1l) | 0 + var t1h = (hh + sigma1h + getCarry(t1l, hl)) | 0 + t1l = (t1l + chl) | 0 + t1h = (t1h + chh + getCarry(t1l, chl)) | 0 + t1l = (t1l + Kil) | 0 + t1h = (t1h + Kih + getCarry(t1l, Kil)) | 0 + t1l = (t1l + Wil) | 0 + t1h = (t1h + Wih + getCarry(t1l, Wil)) | 0 + + // t2 = sigma0 + maj + var t2l = (sigma0l + majl) | 0 + var t2h = (sigma0h + majh + getCarry(t2l, sigma0l)) | 0 + + hh = gh + hl = gl + gh = fh + gl = fl + fh = eh + fl = el + el = (dl + t1l) | 0 + eh = (dh + t1h + getCarry(el, dl)) | 0 + dh = ch + dl = cl + ch = bh + cl = bl + bh = ah + bl = al + al = (t1l + t2l) | 0 + ah = (t1h + t2h + getCarry(al, t1l)) | 0 + } + + this._al = (this._al + al) | 0 + this._bl = (this._bl + bl) | 0 + this._cl = (this._cl + cl) | 0 + this._dl = (this._dl + dl) | 0 + this._el = (this._el + el) | 0 + this._fl = (this._fl + fl) | 0 + this._gl = (this._gl + gl) | 0 + this._hl = (this._hl + hl) | 0 + + this._ah = (this._ah + ah + getCarry(this._al, al)) | 0 + this._bh = (this._bh + bh + getCarry(this._bl, bl)) | 0 + this._ch = (this._ch + ch + getCarry(this._cl, cl)) | 0 + this._dh = (this._dh + dh + getCarry(this._dl, dl)) | 0 + this._eh = (this._eh + eh + getCarry(this._el, el)) | 0 + this._fh = (this._fh + fh + getCarry(this._fl, fl)) | 0 + this._gh = (this._gh + gh + getCarry(this._gl, gl)) | 0 + this._hh = (this._hh + hh + getCarry(this._hl, hl)) | 0 +} + +Sha512.prototype._hash = function () { + var H = Buffer.allocUnsafe(64) + + function writeInt64BE (h, l, offset) { + H.writeInt32BE(h, offset) + H.writeInt32BE(l, offset + 4) + } + + writeInt64BE(this._ah, this._al, 0) + writeInt64BE(this._bh, this._bl, 8) + writeInt64BE(this._ch, this._cl, 16) + writeInt64BE(this._dh, this._dl, 24) + writeInt64BE(this._eh, this._el, 32) + writeInt64BE(this._fh, this._fl, 40) + writeInt64BE(this._gh, this._gl, 48) + writeInt64BE(this._hh, this._hl, 56) + + return H +} + +module.exports = Sha512 + +},{"./hash":162,"inherits":132,"safe-buffer":160}],170:[function(require,module,exports){ +// Copyright Joyent, Inc. and other Node contributors. +// +// 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. + +module.exports = Stream; + +var EE = require('events').EventEmitter; +var inherits = require('inherits'); + +inherits(Stream, EE); +Stream.Readable = require('readable-stream/lib/_stream_readable.js'); +Stream.Writable = require('readable-stream/lib/_stream_writable.js'); +Stream.Duplex = require('readable-stream/lib/_stream_duplex.js'); +Stream.Transform = require('readable-stream/lib/_stream_transform.js'); +Stream.PassThrough = require('readable-stream/lib/_stream_passthrough.js'); +Stream.finished = require('readable-stream/lib/internal/streams/end-of-stream.js') +Stream.pipeline = require('readable-stream/lib/internal/streams/pipeline.js') + +// Backwards-compat with node 0.4.x +Stream.Stream = Stream; + + + +// old-style streams. Note that the pipe method (the only relevant +// part of this class) is overridden in the Readable class. + +function Stream() { + EE.call(this); +} + +Stream.prototype.pipe = function(dest, options) { + var source = this; + + function ondata(chunk) { + if (dest.writable) { + if (false === dest.write(chunk) && source.pause) { + source.pause(); + } + } + } + + source.on('data', ondata); + + function ondrain() { + if (source.readable && source.resume) { + source.resume(); + } + } + + dest.on('drain', ondrain); + + // If the 'end' option is not supplied, dest.end() will be called when + // source gets the 'end' or 'close' events. Only dest.end() once. + if (!dest._isStdio && (!options || options.end !== false)) { + source.on('end', onend); + source.on('close', onclose); + } + + var didOnEnd = false; + function onend() { + if (didOnEnd) return; + didOnEnd = true; + + dest.end(); + } + + + function onclose() { + if (didOnEnd) return; + didOnEnd = true; + + if (typeof dest.destroy === 'function') dest.destroy(); + } + + // don't leave dangling pipes when there are errors. + function onerror(er) { + cleanup(); + if (EE.listenerCount(this, 'error') === 0) { + throw er; // Unhandled stream error in pipe. + } + } + + source.on('error', onerror); + dest.on('error', onerror); + + // remove all the event listeners that were added. + function cleanup() { + source.removeListener('data', ondata); + dest.removeListener('drain', ondrain); + + source.removeListener('end', onend); + source.removeListener('close', onclose); + + source.removeListener('error', onerror); + dest.removeListener('error', onerror); + + source.removeListener('end', cleanup); + source.removeListener('close', cleanup); + + dest.removeListener('close', cleanup); + } + + source.on('end', cleanup); + source.on('close', cleanup); + + dest.on('close', cleanup); + + dest.emit('pipe', source); + + // Allow for unix-like usage: A.pipe(B).pipe(C) + return dest; +}; + +},{"events":100,"inherits":132,"readable-stream/lib/_stream_duplex.js":172,"readable-stream/lib/_stream_passthrough.js":173,"readable-stream/lib/_stream_readable.js":174,"readable-stream/lib/_stream_transform.js":175,"readable-stream/lib/_stream_writable.js":176,"readable-stream/lib/internal/streams/end-of-stream.js":180,"readable-stream/lib/internal/streams/pipeline.js":182}],171:[function(require,module,exports){ +arguments[4][47][0].apply(exports,arguments) +},{"dup":47}],172:[function(require,module,exports){ +arguments[4][48][0].apply(exports,arguments) +},{"./_stream_readable":174,"./_stream_writable":176,"_process":149,"dup":48,"inherits":132}],173:[function(require,module,exports){ +arguments[4][49][0].apply(exports,arguments) +},{"./_stream_transform":175,"dup":49,"inherits":132}],174:[function(require,module,exports){ +arguments[4][50][0].apply(exports,arguments) +},{"../errors":171,"./_stream_duplex":172,"./internal/streams/async_iterator":177,"./internal/streams/buffer_list":178,"./internal/streams/destroy":179,"./internal/streams/from":181,"./internal/streams/state":183,"./internal/streams/stream":184,"_process":149,"buffer":63,"dup":50,"events":100,"inherits":132,"string_decoder/":185,"util":19}],175:[function(require,module,exports){ +arguments[4][51][0].apply(exports,arguments) +},{"../errors":171,"./_stream_duplex":172,"dup":51,"inherits":132}],176:[function(require,module,exports){ +arguments[4][52][0].apply(exports,arguments) +},{"../errors":171,"./_stream_duplex":172,"./internal/streams/destroy":179,"./internal/streams/state":183,"./internal/streams/stream":184,"_process":149,"buffer":63,"dup":52,"inherits":132,"util-deprecate":186}],177:[function(require,module,exports){ +arguments[4][53][0].apply(exports,arguments) +},{"./end-of-stream":180,"_process":149,"dup":53}],178:[function(require,module,exports){ +arguments[4][54][0].apply(exports,arguments) +},{"buffer":63,"dup":54,"util":19}],179:[function(require,module,exports){ +arguments[4][55][0].apply(exports,arguments) +},{"_process":149,"dup":55}],180:[function(require,module,exports){ +arguments[4][56][0].apply(exports,arguments) +},{"../../../errors":171,"dup":56}],181:[function(require,module,exports){ +arguments[4][57][0].apply(exports,arguments) +},{"dup":57}],182:[function(require,module,exports){ +arguments[4][58][0].apply(exports,arguments) +},{"../../../errors":171,"./end-of-stream":180,"dup":58}],183:[function(require,module,exports){ +arguments[4][59][0].apply(exports,arguments) +},{"../../../errors":171,"dup":59}],184:[function(require,module,exports){ +arguments[4][60][0].apply(exports,arguments) +},{"dup":60,"events":100}],185:[function(require,module,exports){ +// Copyright Joyent, Inc. and other Node contributors. +// +// 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. + +'use strict'; + +/**/ + +var Buffer = require('safe-buffer').Buffer; +/**/ + +var isEncoding = Buffer.isEncoding || function (encoding) { + encoding = '' + encoding; + switch (encoding && encoding.toLowerCase()) { + case 'hex':case 'utf8':case 'utf-8':case 'ascii':case 'binary':case 'base64':case 'ucs2':case 'ucs-2':case 'utf16le':case 'utf-16le':case 'raw': + return true; + default: + return false; + } +}; + +function _normalizeEncoding(enc) { + if (!enc) return 'utf8'; + var retried; + while (true) { + switch (enc) { + case 'utf8': + case 'utf-8': + return 'utf8'; + case 'ucs2': + case 'ucs-2': + case 'utf16le': + case 'utf-16le': + return 'utf16le'; + case 'latin1': + case 'binary': + return 'latin1'; + case 'base64': + case 'ascii': + case 'hex': + return enc; + default: + if (retried) return; // undefined + enc = ('' + enc).toLowerCase(); + retried = true; + } + } +}; + +// Do not cache `Buffer.isEncoding` when checking encoding names as some +// modules monkey-patch it to support additional encodings +function normalizeEncoding(enc) { + var nenc = _normalizeEncoding(enc); + if (typeof nenc !== 'string' && (Buffer.isEncoding === isEncoding || !isEncoding(enc))) throw new Error('Unknown encoding: ' + enc); + return nenc || enc; +} + +// StringDecoder provides an interface for efficiently splitting a series of +// buffers into a series of JS strings without breaking apart multi-byte +// characters. +exports.StringDecoder = StringDecoder; +function StringDecoder(encoding) { + this.encoding = normalizeEncoding(encoding); + var nb; + switch (this.encoding) { + case 'utf16le': + this.text = utf16Text; + this.end = utf16End; + nb = 4; + break; + case 'utf8': + this.fillLast = utf8FillLast; + nb = 4; + break; + case 'base64': + this.text = base64Text; + this.end = base64End; + nb = 3; + break; + default: + this.write = simpleWrite; + this.end = simpleEnd; + return; + } + this.lastNeed = 0; + this.lastTotal = 0; + this.lastChar = Buffer.allocUnsafe(nb); +} + +StringDecoder.prototype.write = function (buf) { + if (buf.length === 0) return ''; + var r; + var i; + if (this.lastNeed) { + r = this.fillLast(buf); + if (r === undefined) return ''; + i = this.lastNeed; + this.lastNeed = 0; + } else { + i = 0; + } + if (i < buf.length) return r ? r + this.text(buf, i) : this.text(buf, i); + return r || ''; +}; + +StringDecoder.prototype.end = utf8End; + +// Returns only complete characters in a Buffer +StringDecoder.prototype.text = utf8Text; + +// Attempts to complete a partial non-UTF-8 character using bytes from a Buffer +StringDecoder.prototype.fillLast = function (buf) { + if (this.lastNeed <= buf.length) { + buf.copy(this.lastChar, this.lastTotal - this.lastNeed, 0, this.lastNeed); + return this.lastChar.toString(this.encoding, 0, this.lastTotal); + } + buf.copy(this.lastChar, this.lastTotal - this.lastNeed, 0, buf.length); + this.lastNeed -= buf.length; +}; + +// Checks the type of a UTF-8 byte, whether it's ASCII, a leading byte, or a +// continuation byte. If an invalid byte is detected, -2 is returned. +function utf8CheckByte(byte) { + if (byte <= 0x7F) return 0;else if (byte >> 5 === 0x06) return 2;else if (byte >> 4 === 0x0E) return 3;else if (byte >> 3 === 0x1E) return 4; + return byte >> 6 === 0x02 ? -1 : -2; +} + +// Checks at most 3 bytes at the end of a Buffer in order to detect an +// incomplete multi-byte UTF-8 character. The total number of bytes (2, 3, or 4) +// needed to complete the UTF-8 character (if applicable) are returned. +function utf8CheckIncomplete(self, buf, i) { + var j = buf.length - 1; + if (j < i) return 0; + var nb = utf8CheckByte(buf[j]); + if (nb >= 0) { + if (nb > 0) self.lastNeed = nb - 1; + return nb; + } + if (--j < i || nb === -2) return 0; + nb = utf8CheckByte(buf[j]); + if (nb >= 0) { + if (nb > 0) self.lastNeed = nb - 2; + return nb; + } + if (--j < i || nb === -2) return 0; + nb = utf8CheckByte(buf[j]); + if (nb >= 0) { + if (nb > 0) { + if (nb === 2) nb = 0;else self.lastNeed = nb - 3; + } + return nb; + } + return 0; +} + +// Validates as many continuation bytes for a multi-byte UTF-8 character as +// needed or are available. If we see a non-continuation byte where we expect +// one, we "replace" the validated continuation bytes we've seen so far with +// a single UTF-8 replacement character ('\ufffd'), to match v8's UTF-8 decoding +// behavior. The continuation byte check is included three times in the case +// where all of the continuation bytes for a character exist in the same buffer. +// It is also done this way as a slight performance increase instead of using a +// loop. +function utf8CheckExtraBytes(self, buf, p) { + if ((buf[0] & 0xC0) !== 0x80) { + self.lastNeed = 0; + return '\ufffd'; + } + if (self.lastNeed > 1 && buf.length > 1) { + if ((buf[1] & 0xC0) !== 0x80) { + self.lastNeed = 1; + return '\ufffd'; + } + if (self.lastNeed > 2 && buf.length > 2) { + if ((buf[2] & 0xC0) !== 0x80) { + self.lastNeed = 2; + return '\ufffd'; + } + } + } +} + +// Attempts to complete a multi-byte UTF-8 character using bytes from a Buffer. +function utf8FillLast(buf) { + var p = this.lastTotal - this.lastNeed; + var r = utf8CheckExtraBytes(this, buf, p); + if (r !== undefined) return r; + if (this.lastNeed <= buf.length) { + buf.copy(this.lastChar, p, 0, this.lastNeed); + return this.lastChar.toString(this.encoding, 0, this.lastTotal); + } + buf.copy(this.lastChar, p, 0, buf.length); + this.lastNeed -= buf.length; +} + +// Returns all complete UTF-8 characters in a Buffer. If the Buffer ended on a +// partial character, the character's bytes are buffered until the required +// number of bytes are available. +function utf8Text(buf, i) { + var total = utf8CheckIncomplete(this, buf, i); + if (!this.lastNeed) return buf.toString('utf8', i); + this.lastTotal = total; + var end = buf.length - (total - this.lastNeed); + buf.copy(this.lastChar, 0, end); + return buf.toString('utf8', i, end); +} + +// For UTF-8, a replacement character is added when ending on a partial +// character. +function utf8End(buf) { + var r = buf && buf.length ? this.write(buf) : ''; + if (this.lastNeed) return r + '\ufffd'; + return r; +} + +// UTF-16LE typically needs two bytes per character, but even if we have an even +// number of bytes available, we need to check if we end on a leading/high +// surrogate. In that case, we need to wait for the next two bytes in order to +// decode the last character properly. +function utf16Text(buf, i) { + if ((buf.length - i) % 2 === 0) { + var r = buf.toString('utf16le', i); + if (r) { + var c = r.charCodeAt(r.length - 1); + if (c >= 0xD800 && c <= 0xDBFF) { + this.lastNeed = 2; + this.lastTotal = 4; + this.lastChar[0] = buf[buf.length - 2]; + this.lastChar[1] = buf[buf.length - 1]; + return r.slice(0, -1); + } + } + return r; + } + this.lastNeed = 1; + this.lastTotal = 2; + this.lastChar[0] = buf[buf.length - 1]; + return buf.toString('utf16le', i, buf.length - 1); +} + +// For UTF-16LE we do not explicitly append special replacement characters if we +// end on a partial character, we simply let v8 handle that. +function utf16End(buf) { + var r = buf && buf.length ? this.write(buf) : ''; + if (this.lastNeed) { + var end = this.lastTotal - this.lastNeed; + return r + this.lastChar.toString('utf16le', 0, end); + } + return r; +} + +function base64Text(buf, i) { + var n = (buf.length - i) % 3; + if (n === 0) return buf.toString('base64', i); + this.lastNeed = 3 - n; + this.lastTotal = 3; + if (n === 1) { + this.lastChar[0] = buf[buf.length - 1]; + } else { + this.lastChar[0] = buf[buf.length - 2]; + this.lastChar[1] = buf[buf.length - 1]; + } + return buf.toString('base64', i, buf.length - n); +} + +function base64End(buf) { + var r = buf && buf.length ? this.write(buf) : ''; + if (this.lastNeed) return r + this.lastChar.toString('base64', 0, 3 - this.lastNeed); + return r; +} + +// Pass bytes on through for single-byte encodings (e.g. ascii, latin1, hex) +function simpleWrite(buf) { + return buf.toString(this.encoding); +} + +function simpleEnd(buf) { + return buf && buf.length ? this.write(buf) : ''; +} +},{"safe-buffer":160}],186:[function(require,module,exports){ +(function (global){(function (){ + +/** + * Module exports. + */ + +module.exports = deprecate; + +/** + * Mark that a method should not be used. + * Returns a modified function which warns once by default. + * + * If `localStorage.noDeprecation = true` is set, then it is a no-op. + * + * If `localStorage.throwDeprecation = true` is set, then deprecated functions + * will throw an Error when invoked. + * + * If `localStorage.traceDeprecation = true` is set, then deprecated functions + * will invoke `console.trace()` instead of `console.error()`. + * + * @param {Function} fn - the function to deprecate + * @param {String} msg - the string to print to the console when `fn` is invoked + * @returns {Function} a new "deprecated" version of `fn` + * @api public + */ + +function deprecate (fn, msg) { + if (config('noDeprecation')) { + return fn; + } + + var warned = false; + function deprecated() { + if (!warned) { + if (config('throwDeprecation')) { + throw new Error(msg); + } else if (config('traceDeprecation')) { + console.trace(msg); + } else { + console.warn(msg); + } + warned = true; + } + return fn.apply(this, arguments); + } + + return deprecated; +} + +/** + * Checks `localStorage` for boolean values for the given `name`. + * + * @param {String} name + * @returns {Boolean} + * @api private + */ + +function config (name) { + // accessing global.localStorage can trigger a DOMException in sandboxed iframes + try { + if (!global.localStorage) return false; + } catch (_) { + return false; + } + var val = global.localStorage[name]; + if (null == val) return false; + return String(val).toLowerCase() === 'true'; +} + +}).call(this)}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) +},{}],187:[function(require,module,exports){ +const ModSet = require('./modset.js') +const ModPoint = require('./modpoint.js') + +class ModCurve { + constructor(a, b, n, p, g, preprocessing = {}) { + this.a = a + this.b = b + this.n = n + this.p = p + this.g = g + this.modSet = new ModSet(p) + this.postProcessings = preprocessing + } + + add(p1, p2) { + if (p1 === p2) { + return this.double(p1) + } + const ys = this.modSet.subtract(p2.y, p1.y) + const xs = this.modSet.subtract(p2.x, p1.x) + const s = this.modSet.divide(ys, xs) + const x3 = this.modSet.subtract(this.modSet.subtract(this.modSet.multiply(s,s),p1.x),p2.x) + const y3 = this.modSet.subtract(this.modSet.multiply(s, this.modSet.subtract(p1.x, x3)),p1.y) + const p3 = new ModPoint(this.modSet.mod(x3), this.modSet.mod(y3)) + return p3 + } + subtract(a, b) { + b = new ModPoint(b.x, this.modSet.multiply(b.y, -1n)) + const c = this.add(a, b) + return c + } + double(p) { + const sn = p.x ** 2n * 3n + this.a + const sd = 2n * p.y + const s = this.modSet.divide(sn,sd) + const x3 = this.modSet.mod((s ** 2n - p.x * 2n)) + const y3 = this.modSet.mod(s * (p.x - x3) - p.y) + const p3 = new ModPoint(x3, y3) + return p3 + } + multiply(p, s) { + let p_ = p + + if (s === 1n) { + return p_ + } + + let binaryS = s.toString(2) + const binarySLength = binaryS.length - 1 + + this.postProcessings[p] = this.postProcessings[p] || {} + const postProcessings = this.postProcessings[p] + const addings = [] + let n = p + for (var i = binarySLength; i >= 0; i --) { + const char = binaryS[i] + if (char === '1') { + addings.push(n) + } + const nStr = n.x.toString() + n = (postProcessings[nStr] || (postProcessings[nStr] = this.double(n))) + } + + p_ = addings[0] + addings.shift() + while (addings[0]) { + p_ = this.add(p_, addings[0]) + addings.shift() + } + + return p_ + } + xToY(x, parity) { + const y2 = this.modSet.add(this.modSet.power(x, 3n), this.b) + const y = this.modSet.squareRoots(y2) + if (parity === true) { + return y[1] + } + else if (parity === false) { + return y[0] + } + return y + } + verify(point) { + const verificationPoint = this.modSet.subtract( + this.modSet.add(this.modSet.power(point.x, 3n), this.b), + this.modSet.power(point.y, 2n) + ) + return verificationPoint === 0n + } + // inverse(p) { + // // a^p^n−2 + // return this.multiply(this.multiply(p, this.p), this.n.minus(2)) + // } +} +module.exports = ModCurve +},{"./modpoint.js":189,"./modset.js":190}],188:[function(require,module,exports){ +module.exports = { + ModSet: require('./modset.js'), + ModPoint: require('./modpoint.js'), + Curve: require('./curve.js'), +} +},{"./curve.js":187,"./modpoint.js":189,"./modset.js":190}],189:[function(require,module,exports){ +class ModPoint { + constructor(x, y) { + this.x = x + this.y = y + } + static fromJSON(object) { + return new ModPoint(BigInt('0x'+object.x), BigInt('0x'+object.y)) + } + static fromString(string) { + return ModPoint.fromJSON(JSON.parse(string)) + } + static fromSec1(sec1, curve) { + const mode = sec1.substr(0, 2) + const x = BigInt('0x'+sec1.substr(2, 64)) + let y = BigInt('0x'+(sec1.substr(66, 130) || 0)) + + const compressed = (mode === '03' || mode === '02') + if (compressed) { + if (!curve) { + throw 'no curve provided to recover y point with' + } + y = curve.xToY(x, mode === '03') + } + + const point = new ModPoint(x, y) + if ( + (mode === '04' && sec1.length !== 130) || + (compressed && sec1.length !== 66) || + (mode !== '04' && mode !== '03' && mode !== '02') + ) { + throw 'invalid address' + (mode === '03' || mode === '02') ? ' compressed addresses not yet supported' : '' + } + return point + } + get sec1Compressed() { + return this._sec1Compressed || (this._sec1Compressed = + `${ + this.y % 2n === 1n ? '03' : '02' + }${ + this.x.toString(16).padStart(64, '0') + }` + ) + } + get sec1Uncompressed() { + return this._sec1Uncompressed || (this._sec1Uncompressed = + `04${ + this.x.toString(16).padStart(64, '0') + }${ + this.y.toString(16).padStart(64, '0') + }` + ) + } + toJSON() { + return { x: this.x.toString(16), y: this.y.toString(16) } + } + toString() { + return JSON.stringify(this.toJSON()) + } +} +module.exports = ModPoint +},{}],190:[function(require,module,exports){ +const crypto = require('crypto') + +class ModSet { + constructor(p) { + this.p = p + } + random() { + return this.mod(BigInt('0x'+crypto.randomBytes(64).toString('hex'))) + } + mod(n) { + return (n % this.p + this.p) % this.p + } + add(a, b) { + return this.mod(a + b) + } + subtract(a, b) { + return this.mod(a - b) + } + multiply(a, b) { + return this.mod(a * b) + } + divide(c, a) { + const ap = this.power(a, this.p - 2n) + return this.mod(this.multiply(c, ap)) + } + squareRoots(k) { + this.p1 = this.p1 || (this.p - 1n) / 2n + if (this.power(k, this.p1) !== 1n) { + throw 'no integer square root' + } + this.p2 = this.p2 || (this.p + 1n) / 4n + const root = this.power(k, this.p2) + const negativeRoot = this.p - root + + return [root, negativeRoot] + } + power(a, b) { + let x = 1n + while (b > 0n) { + if (a === 0n) { + return 0n + } + if (b % 2n === 1n) { + x = this.multiply(x, a) + } + b = b / 2n + a = this.multiply(a, a) + } + + return x + } +} + +module.exports = ModSet +},{"crypto":71}]},{},[188])(188) +}); diff --git a/core/third-party/sodium.js b/core/third-party/sodium.js new file mode 100644 index 0000000..6a24db4 --- /dev/null +++ b/core/third-party/sodium.js @@ -0,0 +1,6428 @@ +(function(root) { + +function expose_libsodium(exports) { + "use strict"; + var Module = exports; + var Module; + if (typeof Module === 'undefined') { + Module = {}; + } + var root = Module; + if (typeof root['sodium'] !== 'object') { + if (typeof global === 'object') { + root = global; + } else if (typeof window === 'object') { + root = window; + } + } + if (typeof root['sodium'] === 'object' && typeof root['sodium']['totalMemory'] === 'number') { + Module['TOTAL_MEMORY'] = root['sodium']['totalMemory']; + } + var _Module = Module; + Module.ready = new Promise(function(resolve, reject) { + var Module = _Module; + Module.onAbort = reject; + Module.print = function(what) { + typeof(console) !== 'undefined' && console.log(what); + } + Module.printErr = function(what) { + typeof(console) !== 'undefined' && console.warn(what); + } + Module.onRuntimeInitialized = function() { + try { + /* Test arbitrary wasm function */ + Module._crypto_secretbox_keybytes(); + resolve(); + } catch (err) { + reject(err); + } + }; + Module.useBackupModule = function() { + return new Promise(function(resolve, reject) { + var Module = {}; + Module.onAbort = reject; + + Module.onRuntimeInitialized = function() { + Object.keys(_Module).forEach(function(k) { + if (k !== 'getRandomValue') { + delete _Module[k]; + } + }); + Object.keys(Module).forEach(function(k) { + _Module[k] = Module[k]; + }); + resolve(); + }; + + var Module=typeof Module!=="undefined"?Module:{};var moduleOverrides={};var key;for(key in Module){if(Module.hasOwnProperty(key)){moduleOverrides[key]=Module[key]}}var arguments_=[];var thisProgram="./this.program";var quit_=function(status,toThrow){throw toThrow};var ENVIRONMENT_IS_WEB=false;var ENVIRONMENT_IS_WORKER=false;var ENVIRONMENT_IS_NODE=false;var ENVIRONMENT_IS_SHELL=false;ENVIRONMENT_IS_WEB=typeof window==="object";ENVIRONMENT_IS_WORKER=typeof importScripts==="function";ENVIRONMENT_IS_NODE=typeof process==="object"&&typeof process.versions==="object"&&typeof process.versions.node==="string";ENVIRONMENT_IS_SHELL=!ENVIRONMENT_IS_WEB&&!ENVIRONMENT_IS_NODE&&!ENVIRONMENT_IS_WORKER;var scriptDirectory="";function locateFile(path){if(Module["locateFile"]){return Module["locateFile"](path,scriptDirectory)}return scriptDirectory+path}var read_,readAsync,readBinary,setWindowTitle;var nodeFS;var nodePath;if(ENVIRONMENT_IS_NODE){if(ENVIRONMENT_IS_WORKER){scriptDirectory=require("path").dirname(scriptDirectory)+"/"}else{scriptDirectory=__dirname+"/"}read_=function shell_read(filename,binary){var ret=tryParseAsDataURI(filename);if(ret){return binary?ret:ret.toString()}if(!nodeFS)nodeFS=require("fs");if(!nodePath)nodePath=require("path");filename=nodePath["normalize"](filename);return nodeFS["readFileSync"](filename,binary?null:"utf8")};readBinary=function readBinary(filename){var ret=read_(filename,true);if(!ret.buffer){ret=new Uint8Array(ret)}assert(ret.buffer);return ret};if(process["argv"].length>1){thisProgram=process["argv"][1].replace(/\\/g,"/")}arguments_=process["argv"].slice(2);if(typeof module!=="undefined"){module["exports"]=Module}quit_=function(status){process["exit"](status)};Module["inspect"]=function(){return"[Emscripten Module object]"}}else if(ENVIRONMENT_IS_SHELL){if(typeof read!="undefined"){read_=function shell_read(f){var data=tryParseAsDataURI(f);if(data){return intArrayToString(data)}return read(f)}}readBinary=function readBinary(f){var data;data=tryParseAsDataURI(f);if(data){return data}if(typeof readbuffer==="function"){return new Uint8Array(readbuffer(f))}data=read(f,"binary");assert(typeof data==="object");return data};if(typeof scriptArgs!="undefined"){arguments_=scriptArgs}else if(typeof arguments!="undefined"){arguments_=arguments}if(typeof quit==="function"){quit_=function(status){quit(status)}}if(typeof print!=="undefined"){if(typeof console==="undefined")console={};console.log=print;console.warn=console.error=typeof printErr!=="undefined"?printErr:print}}else if(ENVIRONMENT_IS_WEB||ENVIRONMENT_IS_WORKER){if(ENVIRONMENT_IS_WORKER){scriptDirectory=self.location.href}else if(typeof document!=="undefined"&&document.currentScript){scriptDirectory=document.currentScript.src}if(scriptDirectory.indexOf("blob:")!==0){scriptDirectory=scriptDirectory.substr(0,scriptDirectory.lastIndexOf("/")+1)}else{scriptDirectory=""}{read_=function(url){try{var xhr=new XMLHttpRequest;xhr.open("GET",url,false);xhr.send(null);return xhr.responseText}catch(err){var data=tryParseAsDataURI(url);if(data){return intArrayToString(data)}throw err}};if(ENVIRONMENT_IS_WORKER){readBinary=function(url){try{var xhr=new XMLHttpRequest;xhr.open("GET",url,false);xhr.responseType="arraybuffer";xhr.send(null);return new Uint8Array(xhr.response)}catch(err){var data=tryParseAsDataURI(url);if(data){return data}throw err}}}readAsync=function(url,onload,onerror){var xhr=new XMLHttpRequest;xhr.open("GET",url,true);xhr.responseType="arraybuffer";xhr.onload=function(){if(xhr.status==200||xhr.status==0&&xhr.response){onload(xhr.response);return}var data=tryParseAsDataURI(url);if(data){onload(data.buffer);return}onerror()};xhr.onerror=onerror;xhr.send(null)}}setWindowTitle=function(title){document.title=title}}else{}var out=Module["print"]||console.log.bind(console);var err=Module["printErr"]||console.warn.bind(console);for(key in moduleOverrides){if(moduleOverrides.hasOwnProperty(key)){Module[key]=moduleOverrides[key]}}moduleOverrides=null;if(Module["arguments"])arguments_=Module["arguments"];if(Module["thisProgram"])thisProgram=Module["thisProgram"];if(Module["quit"])quit_=Module["quit"];var wasmBinary;if(Module["wasmBinary"])wasmBinary=Module["wasmBinary"];var noExitRuntime=Module["noExitRuntime"]||true;var WebAssembly={Memory:function(opts){this.buffer=new ArrayBuffer(opts["initial"]*65536)},Module:function(binary){},Instance:function(module,info){this.exports=( +// EMSCRIPTEN_START_ASM +function instantiate(ha){function e(f){f.grow=function(b){var a=this.length;this.length=this.length+b;return a};f.set=function(c,d){this[c]=d};f.get=function(c){return this[c]};return f}var g;var h=new Uint8Array(123);for(var c=25;c>=0;--c){h[48+c]=52+c;h[65+c]=c;h[97+c]=26+c}h[43]=62;h[47]=63;function n(o,p,q){var i,j,c=0,k=p,l=q.length,m=p+(l*3>>2)-(q[l-2]=="=")-(q[l-1]=="=");for(;c>4;if(k>2;if(k>2]=y[M|0]|y[M+1|0]<<8|(y[M+2|0]<<16|y[M+3|0]<<24);x[O+4>>2]=aa;S=S+1|0;if((S|0)!=16){continue}break}B=za(P,a,64);b=B;M=x[b>>2];S=x[b+4>>2];c=M;aa=x[b+32>>2];P=x[b+128>>2];M=aa+P|0;W=x[b+36>>2];b=W+x[b+132>>2]|0;b=M>>>0

>>0?b+1|0:b;P=M;M=c+M|0;b=b+S|0;b=M>>>0

>>0?b+1|0:b;S=M;M=a- -64|0;P=b;K=ia(S^(y[M|0]|y[M+1|0]<<8|(y[M+2|0]<<16|y[M+3|0]<<24))^-1377402159,b^(y[M+4|0]|y[M+5|0]<<8|(y[M+6|0]<<16|y[M+7|0]<<24))^1359893119,32);b=Y;M=b;b=b+1779033703|0;O=K-205731576|0;b=O>>>0<4089235720?b+1|0:b;c=aa^O;aa=b;w=ia(c,W^b,24);b=Y;z=b;R=M;pa=x[B+140>>2];g=pa;c=K;b=b+P|0;K=w+S|0;b=K>>>0>>0?b+1|0:b;M=x[B+136>>2];S=M+K|0;b=b+g|0;e=S;q=K>>>0>e>>>0?b+1|0:b;c=ia(c^e,q^R,16);S=O+c|0;G=Y;b=aa+G|0;o=S;P=O>>>0>o>>>0?b+1|0:b;g=ia(o^w,P^z,63);h=Y;O=x[B+12>>2];w=x[B+144>>2];aa=x[B+40>>2];W=aa;S=w+W|0;Q=x[B+148>>2];R=x[B+44>>2];b=Q+R|0;b=S>>>0>>0?b+1|0:b;W=S;S=S+x[B+8>>2]|0;b=b+O|0;b=S>>>0>>0?b+1|0:b;K=ia(S^(y[a+72|0]|y[a+73|0]<<8|(y[a+74|0]<<16|y[a+75|0]<<24))^725511199,(y[a+76|0]|y[a+77|0]<<8|(y[a+78|0]<<16|y[a+79|0]<<24))^b^-1694144372,32);O=K-2067093701|0;d=O^aa;aa=Y;z=aa-((K>>>0<2067093701)+1150833018|0)|0;R=ia(d,R^z,24);i=x[B+156>>2];d=R;W=Y;b=b+W|0;R=R+S|0;b=R>>>0>>0?b+1|0:b;S=R+x[B+152>>2]|0;b=b+i|0;n=S;r=R>>>0>n>>>0?b+1|0:b;ja=ia(n^K,r^aa,16);S=O+ja|0;t=Y;b=z+t|0;ma=S;O=O>>>0>S>>>0?b+1|0:b;K=ia(d^S,O^W,63);z=Y;aa=x[B+20>>2];C=x[B+160>>2];R=x[B+48>>2];S=C+R|0;da=x[B+164>>2];j=x[B+52>>2];b=da+j|0;b=S>>>0>>0?b+1|0:b;W=S;S=S+x[B+16>>2]|0;b=b+aa|0;ga=S;S=S>>>0>>0?b+1|0:b;k=ia(ga^(y[a+80|0]|y[a+81|0]<<8|(y[a+82|0]<<16|y[a+83|0]<<24))^-79577749,S^(y[a+84|0]|y[a+85|0]<<8|(y[a+86|0]<<16|y[a+87|0]<<24))^528734635,32);b=Y;aa=b;b=b+1013904242|0;W=k-23791573|0;b=W>>>0<4271175723?b+1|0:b;d=R^W;R=b;b=ia(d,j^b,24);i=aa;qa=x[B+172>>2];J=qa;d=b;f=k;k=b;ga=b+ga|0;j=Y;b=j+S|0;b=k>>>0>ga>>>0?b+1|0:b;aa=x[B+168>>2];k=ga;S=aa+k|0;b=b+J|0;p=S;J=k>>>0>p>>>0?b+1|0:b;X=ia(f^p,J^i,16);S=W+X|0;F=Y;b=R+F|0;s=S;R=s>>>0>>0?b+1|0:b;j=ia(d^s,R^j,63);i=Y;k=x[B+28>>2];S=x[B+176>>2];ga=x[B+56>>2];m=ga;W=S+m|0;na=x[B+180>>2];l=x[B+60>>2];b=na+l|0;b=m>>>0>W>>>0?b+1|0:b;m=W;W=m+x[B+24>>2]|0;b=b+k|0;A=W;b=m>>>0>A>>>0?b+1|0:b;D=ia(A^(y[a+88|0]|y[a+89|0]<<8|(y[a+90|0]<<16|y[a+91|0]<<24))^327033209,b^(y[a+92|0]|y[a+93|0]<<8|(y[a+94|0]<<16|y[a+95|0]<<24))^1541459225,32);k=D;d=k+1595750129|0;f=d^ga;W=Y;ga=W-((k>>>0<2699217167)+1521486533|0)|0;k=ia(f,l^ga,24);l=ga;u=W;ga=x[B+188>>2];E=ga;f=k;H=d;m=Y;b=m+b|0;A=k+A|0;b=A>>>0>>0?b+1|0:b;W=x[B+184>>2];k=W+A|0;b=b+E|0;T=k;d=u;u=k>>>0>>0?b+1|0:b;d=ia(k^D,d^u,16);k=H+d|0;b=l;l=Y;b=b+l|0;b=k>>>0>>0?b+1|0:b;A=k;D=m;m=b;f=ia(f^k,D^b,63);k=Y;D=z;N=x[B+196>>2];E=N;H=K;L=s;b=z+q|0;e=e+K|0;b=e>>>0>>0?b+1|0:b;Z=x[B+192>>2];z=e;K=Z+e|0;b=b+E|0;e=K;K=z>>>0>e>>>0?b+1|0:b;s=ia(e^d,K^l,32);q=s;z=L+q|0;b=R;R=Y;b=b+R|0;b=z>>>0>>0?b+1|0:b;q=b;b=ia(H^z,b^D,24);la=x[B+204>>2];E=la;H=b;d=s;l=e;e=b;s=l+b|0;l=Y;b=l+K|0;b=e>>>0>s>>>0?b+1|0:b;D=x[B+200>>2];e=s;K=D+e|0;b=b+E|0;ba=K;e=e>>>0>K>>>0?b+1|0:b;ka=ia(d^K,e^R,16);R=z+ka|0;s=Y;b=q+s|0;d=R;q=l;l=z>>>0>d>>>0?b+1|0:b;E=ia(H^d,q^l,63);q=Y;R=i;ha=x[B+212>>2];H=ha;L=j;I=c;b=i+r|0;z=j+n|0;b=z>>>0>>0?b+1|0:b;K=x[B+208>>2];j=z;z=K+j|0;b=b+H|0;c=z;j=j>>>0>c>>>0?b+1|0:b;n=ia(I^c,j^G,32);i=A+n|0;z=Y;b=m+z|0;b=i>>>0>>0?b+1|0:b;R=ia(L^i,b^R,24);G=b;r=z;U=x[B+220>>2];H=U;L=R;I=i;i=Y;b=i+j|0;m=c+R|0;b=m>>>0>>0?b+1|0:b;z=x[B+216>>2];j=m;R=z+j|0;b=b+H|0;m=R;A=j>>>0>m>>>0?b+1|0:b;r=ia(m^n,A^r,16);j=r;R=I+j|0;c=Y;b=c+G|0;fa=R;j=j>>>0>R>>>0?b+1|0:b;H=ia(L^R,j^i,63);i=Y;G=k;ra=x[B+228>>2];n=ra;L=f;b=k+J|0;f=f+p|0;b=f>>>0

>>0?b+1|0:b;R=x[B+224>>2];k=R+f|0;b=b+n|0;J=k;k=k>>>0>>0?b+1|0:b;f=ia(J^ja,k^t,32);p=o+f|0;t=Y;b=t+P|0;b=p>>>0>>0?b+1|0:b;o=p;P=ia(L^p,b^G,24);p=b;L=x[B+236>>2];n=P;G=Y;b=G+k|0;J=J+P|0;b=J>>>0

>>0?b+1|0:b;$=x[B+232>>2];k=J;P=$+k|0;b=b+L|0;J=P;P=t;t=k>>>0>J>>>0?b+1|0:b;ea=ia(J^f,P^t,16);k=ea;P=k+o|0;b=p;p=Y;b=b+p|0;f=P;o=k>>>0>f>>>0?b+1|0:b;k=ia(n^f,o^G,63);G=Y;n=h;ja=x[B+244>>2];I=ja;_=g;ca=ma;b=h+u|0;ma=g+T|0;b=ma>>>0>>0?b+1|0:b;P=x[B+240>>2];h=ma;g=P+h|0;b=b+I|0;b=g>>>0>>0?b+1|0:b;h=b;X=ia(g^X,b^F,32);u=X;F=ca+u|0;b=O;O=Y;b=b+O|0;T=F;b=u>>>0>F>>>0?b+1|0:b;n=ia(_^F,b^n,24);ca=Y;_=ca;F=b;u=O;ma=x[B+252>>2];oa=n;b=h+ca|0;n=g+n|0;b=n>>>0>>0?b+1|0:b;O=x[B+248>>2];h=n;g=O+h|0;b=b+ma|0;n=g;I=u;u=g>>>0>>0?b+1|0:b;I=ia(g^X,I^u,16);h=I;g=h+T|0;b=F;F=Y;b=b+F|0;ca=g;g=g>>>0>>0?b+1|0:b;X=ia(oa^ca,g^_,63);b=Y;_=b;h=b;oa=r;r=P;T=r+ba|0;b=e+ja|0;b=r>>>0>T>>>0?b+1|0:b;e=T;r=e+X|0;b=b+h|0;h=r;r=e>>>0>h>>>0?b+1|0:b;T=ia(oa^h,r^c,32);c=f+T|0;e=Y;b=o+e|0;b=c>>>0>>0?b+1|0:b;f=b;X=ia(X^c,_^b,24);ba=X;b=Y;_=b;o=b;sa=X;b=r+ha|0;X=h+K|0;b=X>>>0>>0?b+1|0:b;r=X;h=ba+r|0;b=b+o|0;ba=h;o=e;e=h>>>0>>0?b+1|0:b;oa=ia(h^T,o^e,16);h=c+oa|0;o=Y;b=f+o|0;b=h>>>0>>0?b+1|0:b;c=h;f=b;X=ia(sa^c,b^_,63);r=Y;T=E;h=q;b=da+h|0;E=C+E|0;b=E>>>0>>0?b+1|0:b;q=m+E|0;b=b+A|0;b=q>>>0>>0?b+1|0:b;C=b;A=ia(q^ea,b^p,32);m=A;p=m+ca|0;b=g;g=Y;b=b+g|0;b=p>>>0>>0?b+1|0:b;m=h;h=b;E=ia(T^p,m^b,24);b=Y;da=b;m=b;T=A;b=C+N|0;A=q+Z|0;b=A>>>0>>0?b+1|0:b;C=A;q=C+E|0;b=b+m|0;b=q>>>0>>0?b+1|0:b;C=q;m=b;ea=ia(T^q,b^g,16);g=p+ea|0;A=Y;b=h+A|0;ca=g;h=g>>>0

>>0?b+1|0:b;E=ia(g^E,h^da,63);g=Y;q=i;b=i+la|0;p=D+H|0;b=p>>>0>>0?b+1|0:b;i=p+J|0;b=b+t|0;D=i;i=i>>>0>>0?b+1|0:b;F=ia(D^I,i^F,32);p=d+F|0;t=Y;b=l+t|0;b=d>>>0>p>>>0?b+1|0:b;d=q;q=b;l=ia(p^H,d^b,24);d=l;b=Y;H=b;J=b;T=F;F=O;l=F+D|0;b=i+ma|0;b=l>>>0>>0?b+1|0:b;i=d+l|0;b=b+J|0;I=i;F=t;t=i>>>0>>0?b+1|0:b;_=ia(T^i,F^t,16);i=p+_|0;J=Y;b=q+J|0;D=i;i=i>>>0

>>0?b+1|0:b;H=ia(D^d,i^H,63);q=Y;d=k;p=G;b=p+L|0;F=k+$|0;b=F>>>0>>0?b+1|0:b;k=n+F|0;b=b+u|0;F=k;k=k>>>0>>0?b+1|0:b;l=ia(F^ka,k^s,32);G=l+fa|0;b=j;j=Y;b=b+j|0;b=G>>>0>>0?b+1|0:b;u=G;s=ia(d^u,b^p,24);d=s;G=Y;n=G;p=b;T=u;u=l;b=F;F=S;l=b+F|0;b=k+na|0;b=l>>>0>>0?b+1|0:b;k=l+d|0;b=b+G|0;b=k>>>0>>0?b+1|0:b;F=k;l=b;u=ia(u^k,b^j,16);k=u;j=T+k|0;G=Y;b=G+p|0;d=j;k=d>>>0>>0?b+1|0:b;T=ia(s^d,k^n,63);j=Y;p=g;s=D;n=u;u=M;D=u+ba|0;b=e+pa|0;b=u>>>0>D>>>0?b+1|0:b;u=D+E|0;b=b+g|0;g=u;e=G;G=g>>>0>>0?b+1|0:b;D=ia(n^g,e^G,32);e=D;u=s+e|0;b=i;i=Y;b=b+i|0;b=e>>>0>u>>>0?b+1|0:b;e=u;s=ia(e^E,b^p,24);n=s;p=Y;E=p;u=b;ba=D;b=G+ra|0;D=g+R|0;b=D>>>0>>0?b+1|0:b;G=D;g=G+s|0;b=b+p|0;p=g;D=g>>>0>>0?b+1|0:b;ka=ia(ba^g,D^i,16);i=ka;g=i+e|0;b=u;u=Y;b=b+u|0;e=g;s=g>>>0>>0?b+1|0:b;da=ia(g^n,s^E,63);i=Y;fa=x[B+132>>2];n=fa;E=d;g=q;b=m+g|0;G=C+H|0;b=G>>>0>>0?b+1|0:b;d=x[B+128>>2];q=d+G|0;b=b+n|0;b=q>>>0>>0?b+1|0:b;G=b;m=ia(q^oa,b^o,32);C=E+m|0;b=k;k=Y;b=b+k|0;b=C>>>0>>0?b+1|0:b;o=C;n=ia(C^H,b^g,24);E=n;g=Y;H=g;C=b;ba=m;b=G+Q|0;m=w+q|0;b=m>>>0>>0?b+1|0:b;G=m;q=m+n|0;b=b+g|0;m=q;g=k;k=m>>>0>>0?b+1|0:b;g=ia(ba^m,g^k,16);q=g+o|0;b=C;C=Y;b=b+C|0;o=q;n=q>>>0>>0?b+1|0:b;la=ia(q^E,n^H,63);q=Y;G=j;b=t+U|0;H=z+I|0;b=H>>>0>>0?b+1|0:b;E=H;t=E+T|0;b=b+j|0;b=t>>>0>>0?b+1|0:b;E=t;j=b;H=ia(t^ea,b^A,32);A=c+H|0;t=Y;b=f+t|0;b=c>>>0>A>>>0?b+1|0:b;c=A;f=ia(c^T,b^G,24);T=f;G=Y;ba=G;A=b;I=c;c=W;f=c+E|0;b=j+ga|0;b=c>>>0>f>>>0?b+1|0:b;c=f;j=T+c|0;b=b+G|0;b=c>>>0>j>>>0?b+1|0:b;c=j;f=t;t=b;ea=ia(c^H,f^b,16);f=ea;G=I+f|0;j=Y;b=j+A|0;A=G;b=f>>>0>A>>>0?b+1|0:b;T=ia(A^T,b^ba,63);G=Y;E=b;H=g;I=X;g=aa;X=g+X|0;f=r;b=qa+f|0;b=g>>>0>X>>>0?b+1|0:b;g=F+X|0;b=b+l|0;r=g;l=J;J=g>>>0>>0?b+1|0:b;l=ia(g^_,l^J,32);F=l+ca|0;g=Y;b=g+h|0;ba=F;b=F>>>0>>0?b+1|0:b;f=ia(I^F,b^f,24);ca=Y;_=ca;h=b;F=g;X=x[B+156>>2];ca=f;I=l;b=J+_|0;l=f+r|0;b=l>>>0>>0?b+1|0:b;g=x[B+152>>2];r=g+l|0;b=b+X|0;b=r>>>0>>0?b+1|0:b;J=r;f=F;F=b;I=ia(I^r,f^b,16);l=I;r=l+ba|0;b=h;h=Y;b=b+h|0;b=l>>>0>r>>>0?b+1|0:b;l=r;f=b;ba=ia(ca^l,b^_,63);b=Y;ca=b;r=b;_=A;b=D+U|0;A=p+z|0;b=A>>>0

>>0?b+1|0:b;p=A+ba|0;b=b+r|0;r=p;D=C;C=p>>>0>>0?b+1|0:b;H=ia(p^H,D^C,32);D=H;A=_+D|0;p=Y;b=p+E|0;b=A>>>0>>0?b+1|0:b;D=b;ba=ia(ba^A,ca^b,24);ca=ba;b=Y;_=b;E=b;oa=H;b=C+N|0;H=r+Z|0;b=H>>>0>>0?b+1|0:b;C=H;r=C+ba|0;b=b+E|0;b=r>>>0>>0?b+1|0:b;C=r;E=p;p=b;ba=ia(oa^r,E^b,16);r=A+ba|0;E=Y;b=D+E|0;b=r>>>0>>0?b+1|0:b;A=r;D=b;Z=ia(r^ca,b^_,63);r=Y;H=i;_=da;b=i+ra|0;da=R+da|0;i=m+da|0;b=k+(R>>>0>da>>>0?b+1|0:b)|0;N=i;k=j;j=i>>>0>>0?b+1|0:b;da=ia(i^ea,k^j,32);k=l+da|0;i=Y;b=f+i|0;b=k>>>0>>0?b+1|0:b;m=b;f=ia(_^k,b^H,24);H=f;b=Y;ea=b;l=b;b=j+fa|0;f=d+N|0;b=f>>>0>>0?b+1|0:b;d=f;j=H+d|0;b=b+l|0;N=j;l=j>>>0>>0?b+1|0:b;da=ia(j^da,l^i,16);j=k+da|0;d=Y;b=m+d|0;fa=j;k=j>>>0>>0?b+1|0:b;f=ia(j^H,k^ea,63);j=Y;i=q;b=qa+i|0;m=aa;H=m+la|0;q=c+H|0;b=t+(m>>>0>H>>>0?b+1|0:b)|0;b=c>>>0>q>>>0?b+1|0:b;c=q;m=h;h=b;H=ia(c^I,m^b,32);t=e+H|0;q=Y;b=s+q|0;b=e>>>0>t>>>0?b+1|0:b;e=i;i=b;e=ia(t^la,e^b,24);b=Y;la=b;m=b;_=e;e=w;s=e+c|0;b=h+Q|0;b=e>>>0>s>>>0?b+1|0:b;e=s;h=_+e|0;b=b+m|0;ea=h;m=h>>>0>>0?b+1|0:b;I=ia(h^H,m^q,16);h=t+I|0;e=Y;b=i+e|0;H=h;q=h>>>0>>0?b+1|0:b;s=ia(_^h,q^la,63);h=Y;i=G;b=ma+i|0;t=O;c=t+T|0;G=J+c|0;b=F+(c>>>0>>0?b+1|0:b)|0;b=G>>>0>>0?b+1|0:b;t=b;c=ia(G^ka,b^u,32);F=o+c|0;J=Y;b=n+J|0;b=o>>>0>F>>>0?b+1|0:b;u=i;i=b;o=ia(F^T,u^b,24);n=o;b=Y;T=b;u=b;_=c;b=t+L|0;c=G+$|0;b=c>>>0>>0?b+1|0:b;G=c+n|0;b=b+u|0;u=G;n=J;J=c>>>0>u>>>0?b+1|0:b;c=ia(_^u,n^J,16);G=F+c|0;t=Y;b=i+t|0;n=G;G=n>>>0>>0?b+1|0:b;o=ia(o^n,G^T,63);i=Y;F=j;T=f;_=c;b=p+ha|0;c=C+K|0;b=c>>>0>>0?b+1|0:b;p=c;C=c+f|0;b=b+j|0;c=C;j=p>>>0>c>>>0?b+1|0:b;f=ia(_^c,j^t,32);t=f+H|0;b=q;q=Y;b=b+q|0;b=t>>>0>>0?b+1|0:b;C=b;F=ia(T^t,b^F,24);H=F;b=Y;T=b;p=b;F=P;c=F+c|0;b=j+ja|0;b=c>>>0>>0?b+1|0:b;j=H+c|0;b=b+p|0;la=j;p=j>>>0>>0?b+1|0:b;ka=ia(j^f,p^q,16);j=t+ka|0;F=Y;b=C+F|0;ca=j;j=j>>>0>>0?b+1|0:b;H=ia(ca^H,j^T,63);q=Y;t=h;f=s;b=l+X|0;s=g+N|0;b=s>>>0>>0?b+1|0:b;l=s;C=f+l|0;b=b+h|0;b=l>>>0>C>>>0?b+1|0:b;l=C;h=b;s=ia(l^ba,b^E,32);c=s;C=c+n|0;b=G;G=Y;b=b+G|0;b=c>>>0>C>>>0?b+1|0:b;c=C;f=ia(f^c,b^t,24);n=f;t=Y;C=b;E=c;c=s;b=l;l=S;s=b+l|0;b=h+na|0;b=l>>>0>s>>>0?b+1|0:b;l=s;h=l+f|0;b=b+t|0;b=h>>>0>>0?b+1|0:b;l=h;s=b;c=ia(c^h,b^G,16);h=E+c|0;f=Y;b=f+C|0;ba=h;h=h>>>0>>0?b+1|0:b;G=ia(ba^n,h^t,63);t=Y;C=i;E=o;o=W;n=o+ea|0;b=m+ga|0;b=n>>>0>>0?b+1|0:b;m=E+n|0;b=b+i|0;b=m>>>0>>0?b+1|0:b;o=m;i=b;n=ia(m^da,b^d,32);d=A+n|0;m=Y;b=D+m|0;D=d;b=d>>>0>>0?b+1|0:b;d=ia(E^d,b^C,24);E=d;C=Y;N=C;A=b;T=D;D=M;d=D+o|0;b=i+pa|0;b=d>>>0>>0?b+1|0:b;i=E+d|0;b=b+C|0;b=i>>>0>>0?b+1|0:b;D=i;d=m;m=b;ea=ia(i^n,d^b,16);C=ea;i=T+C|0;b=A;A=Y;b=b+A|0;b=i>>>0>>0?b+1|0:b;E=ia(i^E,b^N,63);C=Y;N=x[B+204>>2];o=i;n=b;d=r;b=J+d|0;i=u+Z|0;b=i>>>0>>0?b+1|0:b;T=x[B+200>>2];r=i;i=T+i|0;b=b+N|0;b=i>>>0>>0?b+1|0:b;r=b;u=ia(i^I,b^e,32);e=u;J=e+fa|0;b=k;k=Y;b=b+k|0;b=e>>>0>J>>>0?b+1|0:b;e=J;d=ia(e^Z,b^d,24);fa=Y;I=fa;J=b;Z=x[B+164>>2];_=e;fa=u;b=r+I|0;u=i+d|0;b=u>>>0>>0?b+1|0:b;da=x[B+160>>2];r=u;i=da+r|0;b=b+Z|0;u=i;e=i>>>0>>0?b+1|0:b;fa=ia(fa^i,e^k,16);k=fa;i=_+k|0;b=J;J=Y;b=b+J|0;_=i;i=i>>>0>>0?b+1|0:b;d=ia(d^_,i^I,63);b=Y;I=b;k=b;oa=c;r=W;c=r+la|0;b=p+ga|0;b=c>>>0>>0?b+1|0:b;r=c+d|0;b=b+k|0;k=r;r=c>>>0>k>>>0?b+1|0:b;f=ia(oa^k,r^f,32);c=o+f|0;p=Y;b=p+n|0;b=c>>>0>>0?b+1|0:b;o=c;n=ia(d^c,b^I,24);d=Y;I=d;c=b;la=o;oa=f;b=r+N|0;f=k+T|0;b=f>>>0>>0?b+1|0:b;k=f+n|0;b=b+d|0;o=k;d=p;p=k>>>0>>0?b+1|0:b;oa=ia(oa^k,d^p,16);r=oa;k=la+r|0;d=Y;b=d+c|0;sa=k;k=k>>>0>>0?b+1|0:b;la=ia(sa^n,k^I,63);r=Y;c=q;b=X+c|0;f=g+H|0;b=f>>>0>>0?b+1|0:b;g=f+l|0;b=b+s|0;s=g;g=g>>>0>>0?b+1|0:b;f=ia(s^ea,g^A,32);q=f+_|0;b=i;i=Y;b=b+i|0;b=f>>>0>q>>>0?b+1|0:b;l=b;c=ia(q^H,b^c,24);n=c;b=Y;H=b;A=b;b=s;s=M;c=b+s|0;b=g+pa|0;b=c>>>0>>0?b+1|0:b;g=n+c|0;b=b+A|0;X=g;A=g>>>0>>0?b+1|0:b;ea=ia(g^f,A^i,16);g=q+ea|0;s=Y;b=l+s|0;I=g;i=g>>>0>>0?b+1|0:b;c=ia(g^n,i^H,63);g=Y;f=G;q=t;b=q+L|0;l=G+$|0;b=l>>>0>>0?b+1|0:b;G=l+D|0;b=b+m|0;b=G>>>0>>0?b+1|0:b;t=b;m=ia(G^fa,b^J,32);l=m;J=l+ca|0;b=j;j=Y;b=b+j|0;b=l>>>0>J>>>0?b+1|0:b;l=J;D=ia(f^l,b^q,24);f=D;q=Y;n=q;J=b;H=l;L=m;b=t+ra|0;m=G+R|0;b=m>>>0>>0?b+1|0:b;t=m;G=m+f|0;b=b+q|0;m=G;l=t>>>0>m>>>0?b+1|0:b;fa=ia(L^m,l^j,16);q=fa;j=H+q|0;b=J;J=Y;b=b+J|0;f=j;q=f>>>0>>0?b+1|0:b;n=ia(D^f,q^n,63);j=Y;G=C;b=C+U|0;D=z+E|0;b=D>>>0>>0?b+1|0:b;t=u+D|0;b=b+e|0;b=t>>>0>>0?b+1|0:b;u=t;t=b;D=ia(u^ka,b^F,32);F=D;C=F+ba|0;b=h;h=Y;b=b+h|0;b=C>>>0>>0?b+1|0:b;e=G;G=b;e=ia(C^E,e^b,24);E=e;b=Y;H=b;F=b;L=D;b=u;u=P;D=b+u|0;b=t+ja|0;b=u>>>0>D>>>0?b+1|0:b;u=D;t=u+e|0;b=b+F|0;F=t;u=t>>>0>>0?b+1|0:b;e=ia(L^t,u^h,16);h=C+e|0;t=Y;b=G+t|0;b=h>>>0>>0?b+1|0:b;C=h;D=b;E=ia(h^E,b^H,63);h=Y;G=g;H=c;L=e;e=w;c=e+o|0;b=p+Q|0;b=c>>>0>>0?b+1|0:b;p=H+c|0;b=b+g|0;b=c>>>0>p>>>0?b+1|0:b;g=b;e=ia(L^p,b^t,32);c=e;t=c+f|0;b=q;q=Y;b=b+q|0;b=c>>>0>t>>>0?b+1|0:b;c=t;f=ia(H^c,b^G,24);o=f;G=Y;t=b;H=e;b=p;p=S;e=b+p|0;b=g+na|0;b=e>>>0

>>0?b+1|0:b;g=e+f|0;b=b+G|0;b=g>>>0>>0?b+1|0:b;p=g;e=b;ka=ia(H^g,b^q,16);q=ka;g=q+c|0;c=Y;b=c+t|0;f=g;t=g^o;o=g>>>0>>0?b+1|0:b;L=ia(t,o^G,63);G=Y;g=j;q=aa;t=q+X|0;b=A+qa|0;b=q>>>0>t>>>0?b+1|0:b;q=t+n|0;b=b+g|0;A=q;j=q>>>0>>0?b+1|0:b;d=ia(q^oa,j^d,32);t=C+d|0;q=Y;b=D+q|0;b=t>>>0>>0?b+1|0:b;C=t;D=ia(t^n,b^g,24);n=D;g=Y;H=g;t=b;X=C;C=K;A=C+A|0;b=j+ha|0;b=C>>>0>A>>>0?b+1|0:b;C=A;j=A+n|0;b=b+g|0;A=j;D=j>>>0>>0?b+1|0:b;j=ia(j^d,D^q,16);g=X+j|0;C=Y;b=C+t|0;ca=g;q=g>>>0>>0?b+1|0:b;$=ia(g^n,q^H,63);t=Y;g=h;H=E;b=l+Z|0;d=m+da|0;b=d>>>0>>0?b+1|0:b;m=d+E|0;b=b+g|0;h=m;m=d>>>0>h>>>0?b+1|0:b;n=ia(h^ea,m^s,32);s=n;l=s+sa|0;b=k;k=Y;b=b+k|0;E=l;b=l>>>0>>0?b+1|0:b;d=ia(H^l,b^g,24);g=Y;l=g;s=b;X=x[B+132>>2];H=d;b=m+g|0;d=h+d|0;b=d>>>0>>0?b+1|0:b;g=x[B+128>>2];h=g+d|0;b=b+X|0;b=h>>>0>>0?b+1|0:b;m=h;d=b;ea=ia(h^n,b^k,16);k=ea;h=k+E|0;b=s;s=Y;b=b+s|0;b=h>>>0>>0?b+1|0:b;ba=ia(H^h,b^l,63);k=Y;n=h;E=b;H=j;j=O;h=j+la|0;l=r;b=ma+l|0;b=h>>>0>>0?b+1|0:b;j=h+F|0;b=b+u|0;h=j;r=h>>>0>>0?b+1|0:b;F=ia(h^fa,r^J,32);u=F;J=u+I|0;j=Y;b=j+i|0;b=u>>>0>J>>>0?b+1|0:b;u=J;l=ia(u^la,b^l,24);I=Y;_=I;i=b;J=j;la=x[B+196>>2];fa=F;b=r+I|0;F=h+l|0;b=F>>>0>>0?b+1|0:b;j=x[B+192>>2];r=F;h=j+r|0;b=b+la|0;F=h;I=J;J=h>>>0>>0?b+1|0:b;fa=ia(fa^h,I^J,16);r=fa;h=r+u|0;b=i;i=Y;b=b+i|0;I=h;h=h>>>0>>0?b+1|0:b;l=ia(l^I,h^_,63);b=Y;_=b;r=b;b=e+N|0;u=p+T|0;b=u>>>0

>>0?b+1|0:b;p=u+l|0;b=b+r|0;b=p>>>0>>0?b+1|0:b;u=p;r=b;e=ia(p^H,b^C,32);p=n+e|0;C=Y;b=C+E|0;b=p>>>0>>0?b+1|0:b;n=p;E=ia(l^p,b^_,24);p=Y;N=p;l=b;H=e;b=r+X|0;e=g+u|0;b=e>>>0>>0?b+1|0:b;r=e+E|0;b=b+p|0;T=r;p=r>>>0>>0?b+1|0:b;_=ia(H^r,p^C,16);C=_;r=C+n|0;b=l;l=Y;b=b+l|0;u=r;e=r>>>0>>0?b+1|0:b;N=ia(r^E,e^N,63);C=Y;r=G;b=qa+r|0;n=aa;E=n+L|0;G=A+E|0;b=D+(n>>>0>E>>>0?b+1|0:b)|0;b=G>>>0>>0?b+1|0:b;A=b;n=ia(G^ea,b^s,32);s=n;D=s+I|0;b=h;h=Y;b=b+h|0;b=s>>>0>D>>>0?b+1|0:b;s=r;r=b;E=ia(D^L,s^b,24);b=Y;L=b;s=b;H=n;b=A+ga|0;n=G+W|0;b=n>>>0>>0?b+1|0:b;A=n;G=A+E|0;b=b+s|0;b=G>>>0>>0?b+1|0:b;A=G;s=b;ea=ia(H^A,b^h,16);h=D+ea|0;n=Y;b=r+n|0;I=h;G=h>>>0>>0?b+1|0:b;E=ia(h^E,G^L,63);h=Y;r=t;b=t+Q|0;H=w+$|0;t=m+H|0;b=d+(w>>>0>H>>>0?b+1|0:b)|0;b=m>>>0>t>>>0?b+1|0:b;d=i;i=b;H=ia(t^fa,d^b,32);D=f+H|0;m=Y;b=o+m|0;b=f>>>0>D>>>0?b+1|0:b;d=r;r=b;f=ia(D^$,d^b,24);o=f;b=Y;d=b;b=i+Z|0;f=t+da|0;b=f>>>0>>0?b+1|0:b;i=o+f|0;b=b+d|0;Z=i;t=i>>>0>>0?b+1|0:b;da=ia(i^H,t^m,16);i=D+da|0;m=Y;b=r+m|0;$=i;r=i>>>0>>0?b+1|0:b;f=ia(i^o,r^d,63);i=Y;D=k;b=k+ha|0;d=K;o=d+ba|0;k=F+o|0;b=J+(d>>>0>o>>>0?b+1|0:b)|0;d=k;k=d>>>0>>0?b+1|0:b;c=ia(d^ka,k^c,32);J=c+ca|0;b=q;q=Y;b=b+q|0;o=J;b=c>>>0>o>>>0?b+1|0:b;D=ia(o^ba,b^D,24);H=D;J=Y;L=J;F=b;D=O;d=D+d|0;b=k+ma|0;b=d>>>0>>0?b+1|0:b;k=H+d|0;b=b+J|0;J=k;D=k>>>0>>0?b+1|0:b;c=ia(k^c,D^q,16);k=c+o|0;b=F;F=Y;b=b+F|0;ba=k;q=k>>>0>>0?b+1|0:b;H=ia(k^H,q^L,63);k=Y;d=h;L=E;fa=c;c=P;o=c+T|0;b=p+ja|0;b=c>>>0>o>>>0?b+1|0:b;c=o;p=c+E|0;b=b+d|0;b=c>>>0>p>>>0?b+1|0:b;c=p;h=b;o=ia(fa^c,b^F,32);F=o;p=F+$|0;b=r;r=Y;b=b+r|0;E=p;b=p>>>0>>0?b+1|0:b;d=ia(L^p,b^d,24);L=d;p=Y;$=p;F=b;d=M;c=d+c|0;b=h+pa|0;b=c>>>0>>0?b+1|0:b;h=L+c|0;b=b+p|0;ka=h;d=r;r=h>>>0>>0?b+1|0:b;fa=ia(h^o,d^r,16);d=fa;h=d+E|0;p=Y;b=p+F|0;F=h;d=h>>>0>>0?b+1|0:b;L=ia(h^L,d^$,63);h=Y;c=i;E=f;b=s+U|0;f=z+A|0;b=f>>>0>>0?b+1|0:b;s=f;A=E+f|0;b=b+c|0;f=A;i=f>>>0>>0?b+1|0:b;o=ia(f^_,i^l,32);A=o;l=A+ba|0;b=q;q=Y;b=b+q|0;b=l>>>0>>0?b+1|0:b;A=b;c=ia(E^l,b^c,24);E=c;b=Y;$=b;s=b;c=R;f=c+f|0;b=i+ra|0;b=c>>>0>f>>>0?b+1|0:b;c=f;i=E+c|0;b=b+s|0;s=i;c=i>>>0>>0?b+1|0:b;q=ia(i^o,c^q,16);i=l+q|0;f=Y;b=A+f|0;b=i>>>0>>0?b+1|0:b;l=i;A=b;$=ia(i^E,b^$,63);i=Y;o=k;T=H;E=S;H=E+Z|0;b=t+na|0;b=E>>>0>H>>>0?b+1|0:b;E=H;t=T+E|0;b=b+k|0;b=t>>>0>>0?b+1|0:b;E=t;k=b;H=ia(t^ea,b^n,32);n=u+H|0;t=Y;b=e+t|0;b=n>>>0>>0?b+1|0:b;u=n;e=b;n=ia(T^u,b^o,24);Z=n;b=Y;T=b;o=b;b=k+la|0;E=j+E|0;b=E>>>0>>0?b+1|0:b;n=E;k=Z+n|0;b=b+o|0;o=k;E=t;t=k>>>0>>0?b+1|0:b;ba=ia(k^H,E^t,16);k=u+ba|0;n=Y;b=e+n|0;b=k>>>0>>0?b+1|0:b;u=k;Z=ia(k^Z,b^T,63);k=Y;ea=x[B+156>>2];T=ea;E=b;_=N;e=C;b=D+e|0;N=J+N|0;b=N>>>0>>0?b+1|0:b;H=x[B+152>>2];J=N;C=H+J|0;b=b+T|0;b=C>>>0>>0?b+1|0:b;J=b;D=ia(C^da,b^m,32);m=D+I|0;b=G;G=Y;b=b+G|0;b=m>>>0>>0?b+1|0:b;N=m;e=ia(_^m,b^e,24);T=e;da=Y;I=da;m=b;ca=x[B+236>>2];_=ca;ca=N;N=D;b=J+I|0;e=e+C|0;b=e>>>0>>0?b+1|0:b;D=x[B+232>>2];C=D+e|0;b=b+_|0;b=C>>>0>>0?b+1|0:b;e=G;G=b;da=ia(N^C,e^b,16);N=da;e=ca+N|0;J=Y;b=J+m|0;m=e;e=e>>>0>>0?b+1|0:b;T=ia(m^T,e^I,63);b=Y;I=b;N=b;ca=q;b=r+Q|0;q=w+ka|0;b=q>>>0>>0?b+1|0:b;w=q+T|0;b=b+N|0;N=w;w=w>>>0>>0?b+1|0:b;f=ia(ca^N,w^f,32);r=u+f|0;q=Y;b=q+E|0;E=r;b=r>>>0>>0?b+1|0:b;Q=ia(T^r,I^b,24);r=Y;ka=r;u=b;T=E;I=f;f=R;E=f+N|0;b=w+ra|0;b=f>>>0>E>>>0?b+1|0:b;f=E;w=f+Q|0;b=b+r|0;r=w;f=f>>>0>r>>>0?b+1|0:b;I=ia(I^r,f^q,16);q=I;w=T+q|0;b=u;u=Y;b=b+u|0;E=w;N=w>>>0>>0?b+1|0:b;T=ia(w^Q,N^ka,63);q=Y;w=h;ca=L;b=h+na|0;L=S+L|0;h=s+L|0;b=c+(S>>>0>L>>>0?b+1|0:b)|0;Q=h;h=h>>>0>>0?b+1|0:b;n=ia(Q^ba,h^n,32);c=m+n|0;s=Y;b=e+s|0;b=c>>>0>>0?b+1|0:b;m=c;e=w;w=b;c=ia(ca^c,e^b,24);L=c;b=Y;ba=b;e=b;ca=c;ka=n;c=K;n=c+Q|0;b=h+ha|0;b=c>>>0>n>>>0?b+1|0:b;c=n;h=L+c|0;b=b+e|0;L=h;e=h>>>0>>0?b+1|0:b;ka=ia(ka^h,e^s,16);h=m+ka|0;s=Y;b=w+s|0;b=h>>>0>>0?b+1|0:b;m=h;c=b;n=ia(ca^h,b^ba,63);h=Y;w=i;b=i+X|0;Q=g+$|0;b=Q>>>0>>0?b+1|0:b;g=o+Q|0;b=b+t|0;b=g>>>0>>0?b+1|0:b;o=g;g=b;Q=ia(o^da,b^J,32);t=F+Q|0;i=Y;b=d+i|0;b=t>>>0>>0?b+1|0:b;d=w;w=b;F=ia(t^$,d^b,24);d=F;b=Y;$=b;J=b;b=g+U|0;F=z+o|0;b=F>>>0>>0?b+1|0:b;g=F;z=d+g|0;b=b+J|0;o=z;F=i;i=g>>>0>z>>>0?b+1|0:b;Q=ia(z^Q,F^i,16);z=t+Q|0;J=Y;b=w+J|0;U=z;g=z>>>0>>0?b+1|0:b;F=ia(z^d,g^$,63);w=Y;z=k;b=k+la|0;t=j+Z|0;b=t>>>0>>0?b+1|0:b;j=t+C|0;b=b+G|0;b=j>>>0>>0?b+1|0:b;C=j;j=b;p=ia(C^fa,b^p,32);G=l+p|0;k=Y;b=A+k|0;b=l>>>0>G>>>0?b+1|0:b;d=z;z=b;l=ia(G^Z,d^b,24);A=l;b=Y;d=b;b=j+ea|0;C=C+H|0;b=C>>>0>>0?b+1|0:b;j=C+l|0;b=b+d|0;t=j;l=k;k=j>>>0>>0?b+1|0:b;p=ia(j^p,l^k,16);j=G+p|0;C=Y;b=z+C|0;l=j;j=j>>>0>>0?b+1|0:b;d=ia(l^A,j^d,63);z=Y;G=h;A=x[B+164>>2];H=p;b=h+f|0;p=r+n|0;b=p>>>0>>0?b+1|0:b;r=p;h=p+x[B+160>>2]|0;b=b+A|0;p=h;h=h>>>0>>0?b+1|0:b;A=ia(H^p,h^C,32);C=A;r=C+U|0;b=g;g=Y;b=b+g|0;b=r>>>0>>0?b+1|0:b;f=G;G=b;f=ia(r^n,f^b,24);b=Y;H=b;C=b;b=h+_|0;p=p+D|0;b=p>>>0>>0?b+1|0:b;h=p+f|0;b=b+C|0;U=h;h=h>>>0

>>0?b+1|0:b;$=ia(U^A,h^g,16);g=r+$|0;C=Y;b=G+C|0;G=g;r=g>>>0>>0?b+1|0:b;n=ia(g^f,r^H,63);g=Y;p=w;f=F;D=l;F=W;l=F+L|0;b=e+ga|0;b=l>>>0>>0?b+1|0:b;F=f+l|0;b=b+p|0;A=F;w=l>>>0>A>>>0?b+1|0:b;u=ia(A^I,w^u,32);l=u;F=D+l|0;b=j;j=Y;b=b+j|0;b=l>>>0>F>>>0?b+1|0:b;e=p;p=b;D=ia(f^F,e^b,24);e=D;b=Y;f=b;D=u;u=aa;A=u+A|0;b=w+qa|0;b=u>>>0>A>>>0?b+1|0:b;w=A+e|0;b=b+f|0;l=w;u=l>>>0>>0?b+1|0:b;A=ia(D^l,u^j,16);w=F+A|0;D=Y;b=p+D|0;p=w;F=p>>>0>>0?b+1|0:b;H=ia(p^e,F^f,63);w=Y;j=z;L=d;e=O;d=e+o|0;b=i+ma|0;b=e>>>0>d>>>0?b+1|0:b;e=d;i=L+d|0;b=b+j|0;d=i;z=d>>>0>>0?b+1|0:b;f=ia(d^ka,z^s,32);e=E+f|0;i=Y;b=N+i|0;b=e>>>0>>0?b+1|0:b;s=j;j=b;o=ia(L^e,s^b,24);b=Y;N=b;s=b;E=f;b=d;d=P;f=b+d|0;b=z+ja|0;b=d>>>0>f>>>0?b+1|0:b;d=f;z=d+o|0;b=b+s|0;b=d>>>0>z>>>0?b+1|0:b;s=b;L=ia(E^z,b^i,16);i=e+L|0;d=Y;b=j+d|0;b=i>>>0>>0?b+1|0:b;E=ia(i^o,b^N,63);j=Y;f=b;e=q;b=pa+e|0;o=M;N=o+T|0;q=t+N|0;b=k+(o>>>0>N>>>0?b+1|0:b)|0;o=q;k=q>>>0>>0?b+1|0:b;N=ia(q^Q,k^J,32);t=m+N|0;q=Y;b=c+q|0;b=m>>>0>t>>>0?b+1|0:b;J=b;b=ia(t^T,b^e,24);c=Y;Z=x[B+204>>2];Q=b;m=b;e=b+o|0;b=c+k|0;b=e>>>0>>0?b+1|0:b;k=e+x[B+200>>2]|0;b=b+Z|0;b=k>>>0>>0?b+1|0:b;e=q;q=b;Z=ia(k^N,e^b,16);e=t+Z|0;m=Y;b=J+m|0;b=e>>>0>>0?b+1|0:b;t=e;J=b;c=ia(Q^e,b^c,63);b=Y;e=b;o=i;Q=A;i=R;A=i+U|0;b=h+ra|0;b=i>>>0>A>>>0?b+1|0:b;i=A;h=i+c|0;b=b+e|0;N=h;h=h>>>0>>0?b+1|0:b;Q=ia(Q^N,h^D,32);D=Q;A=o+D|0;i=Y;b=i+f|0;b=A>>>0>>0?b+1|0:b;D=b;c=ia(c^A,e^b,24);b=Y;o=b;e=b;I=c;c=aa;f=c+N|0;b=h+qa|0;b=c>>>0>f>>>0?b+1|0:b;c=f;h=I+c|0;b=b+e|0;e=h;c=e>>>0>>0?b+1|0:b;Q=ia(e^Q,c^i,16);h=A+Q|0;f=Y;b=D+f|0;b=h>>>0>>0?b+1|0:b;A=h;D=b;h=ia(I^h,b^o,63);i=Y;o=g;I=n;b=g+pa|0;n=M;N=I+n|0;g=l+N|0;b=u+(n>>>0>N>>>0?b+1|0:b)|0;n=g;g=g>>>0>>0?b+1|0:b;d=ia(n^L,g^d,32);u=t+d|0;l=Y;b=J+l|0;b=t>>>0>u>>>0?b+1|0:b;t=u;J=b;o=ia(I^t,b^o,24);N=o;b=Y;U=b;u=b;I=o;L=d;d=O;o=d+n|0;b=g+ma|0;b=d>>>0>o>>>0?b+1|0:b;d=o;g=N+d|0;b=b+u|0;N=g;u=l;l=g>>>0>>0?b+1|0:b;L=ia(L^g,u^l,16);g=t+L|0;u=Y;b=J+u|0;b=g>>>0>>0?b+1|0:b;t=g;J=b;n=ia(I^g,b^U,63);g=Y;I=H;d=w;b=ja+d|0;o=P;H=o+H|0;w=z+H|0;b=s+(o>>>0>H>>>0?b+1|0:b)|0;s=w;w=z>>>0>s>>>0?b+1|0:b;o=ia(s^Z,w^m,32);m=G+o|0;z=Y;b=r+z|0;b=m>>>0>>0?b+1|0:b;G=m;r=b;b=ia(I^m,b^d,24);U=x[B+236>>2];I=b;d=s;s=b;d=d+b|0;m=Y;b=m+w|0;b=d>>>0>>0?b+1|0:b;w=d+x[B+232>>2]|0;b=b+U|0;b=w>>>0>>0?b+1|0:b;s=w;d=b;U=ia(s^o,b^z,16);w=G+U|0;o=Y;b=r+o|0;H=w;z=w>>>0>>0?b+1|0:b;m=ia(I^w,z^m,63);w=Y;G=j;Z=x[B+164>>2];I=E;b=j+q|0;r=k+E|0;b=r>>>0>>0?b+1|0:b;k=r;j=k+x[B+160>>2]|0;b=b+Z|0;E=j;j=j>>>0>>0?b+1|0:b;C=ia(E^$,j^C,32);q=p+C|0;k=Y;b=F+k|0;b=p>>>0>q>>>0?b+1|0:b;F=G;G=b;p=ia(I^q,F^b,24);F=p;b=Y;$=b;r=b;I=C;C=K;p=C+E|0;b=j+ha|0;b=p>>>0>>0?b+1|0:b;j=F+p|0;b=b+r|0;Z=j;r=k;k=j>>>0

>>0?b+1|0:b;p=ia(I^j,r^k,16);j=q+p|0;r=Y;b=G+r|0;b=j>>>0>>0?b+1|0:b;q=j;G=b;E=ia(j^F,b^$,63);j=Y;C=g;F=x[B+132>>2];I=p;b=g+c|0;p=e+n|0;b=p>>>0>>0?b+1|0:b;g=p+x[B+128>>2]|0;b=b+F|0;F=g;g=g>>>0

>>0?b+1|0:b;e=ia(I^F,g^r,32);r=e+H|0;b=z;z=Y;b=b+z|0;b=e>>>0>r>>>0?b+1|0:b;c=C;C=b;c=ia(r^n,c^b,24);b=Y;H=b;p=b;n=e;b=F;F=W;e=b+F|0;b=g+ga|0;b=e>>>0>>0?b+1|0:b;g=e+c|0;b=b+p|0;$=g;p=g>>>0>>0?b+1|0:b;X=ia(n^g,p^z,16);z=r+X|0;F=Y;b=C+F|0;b=z>>>0>>0?b+1|0:b;r=z;C=b;n=ia(r^c,b^H,63);z=Y;g=w;H=m;m=S;e=m+N|0;b=l+na|0;b=e>>>0>>0?b+1|0:b;l=e;m=H+e|0;b=b+g|0;e=m;w=l>>>0>e>>>0?b+1|0:b;c=ia(e^Q,w^f,32);l=q+c|0;m=Y;b=G+m|0;b=l>>>0>>0?b+1|0:b;q=l;f=g;g=b;b=ia(H^l,f^b,24);H=x[B+156>>2];f=b;l=b;e=b+e|0;G=Y;b=G+w|0;b=e>>>0>>0?b+1|0:b;w=e+x[B+152>>2]|0;b=b+H|0;b=e>>>0>w>>>0?b+1|0:b;l=w;e=m;m=b;N=ia(l^c,e^b,16);w=q+N|0;e=Y;b=g+e|0;b=w>>>0>>0?b+1|0:b;q=w;c=G;G=b;H=ia(f^q,c^b,63);g=Y;w=j;f=x[B+204>>2];b=j+d|0;c=s+E|0;b=c>>>0>>0?b+1|0:b;j=c+x[B+200>>2]|0;b=b+f|0;b=j>>>0>>0?b+1|0:b;c=u;u=b;c=ia(j^L,c^b,32);d=A+c|0;s=Y;b=D+s|0;b=d>>>0>>0?b+1|0:b;A=d;f=w;w=b;d=ia(d^E,f^b,24);b=Y;f=b;E=x[B+148>>2];L=d;b=b+u|0;d=j+d|0;b=d>>>0>>0?b+1|0:b;j=d+x[B+144>>2]|0;b=b+E|0;b=j>>>0>>0?b+1|0:b;u=j;d=s;s=b;Q=ia(j^c,d^b,16);j=A+Q|0;d=Y;b=w+d|0;b=j>>>0>>0?b+1|0:b;A=j;D=b;E=ia(L^j,f^b,63);j=Y;w=i;f=x[B+196>>2];L=h;b=i+k|0;c=h+Z|0;b=c>>>0>>0?b+1|0:b;i=c;h=c+x[B+192>>2]|0;b=b+f|0;c=h;h=c>>>0>>0?b+1|0:b;f=ia(c^U,h^o,32);k=t+f|0;i=Y;b=J+i|0;b=k>>>0>>0?b+1|0:b;w=ia(L^k,b^w,24);t=b;U=x[B+220>>2];L=U;o=w;I=k;k=Y;b=k+h|0;c=c+w|0;b=c>>>0>>0?b+1|0:b;J=x[B+216>>2];h=c;w=J+c|0;b=b+L|0;c=w;w=c^f;f=h>>>0>c>>>0?b+1|0:b;L=ia(w,f^i,16);h=L;w=I+h|0;b=t;t=Y;b=b+t|0;b=h>>>0>w>>>0?b+1|0:b;h=k;k=b;b=ia(o^w,h^b,63);T=x[B+236>>2];I=b;i=b;o=b+$|0;h=Y;b=h+p|0;b=i>>>0>o>>>0?b+1|0:b;p=o;i=p+x[B+232>>2]|0;b=b+T|0;o=i;i=i>>>0

>>0?b+1|0:b;N=ia(o^N,i^e,32);e=A+N|0;p=Y;b=D+p|0;b=e>>>0>>0?b+1|0:b;A=e;D=h;h=b;b=ia(I^e,D^b,24);I=N;e=b;o=b+o|0;D=Y;b=D+i|0;i=o+J|0;b=U+(e>>>0>o>>>0?b+1|0:b)|0;N=i;o=p;p=i>>>0>>0?b+1|0:b;U=ia(I^i,o^p,16);i=A+U|0;J=Y;b=h+J|0;b=i>>>0>>0?b+1|0:b;A=i;h=D;D=b;h=ia(e^i,h^b,63);i=Y;I=n;e=z;b=ga+e|0;o=W;n=o+n|0;z=l+n|0;b=m+(n>>>0>>0?b+1|0:b)|0;o=z;z=l>>>0>z>>>0?b+1|0:b;d=ia(o^Q,z^d,32);l=w+d|0;m=Y;b=k+m|0;b=l>>>0>>0?b+1|0:b;w=l;k=b;e=ia(I^l,b^e,24);n=e;b=Y;Q=b;l=b;I=d;e=P;d=e+o|0;b=z+ja|0;b=e>>>0>d>>>0?b+1|0:b;e=d;z=n+e|0;b=b+l|0;$=z;d=m;m=e>>>0>z>>>0?b+1|0:b;Z=ia(I^z,d^m,16);z=w+Z|0;l=Y;b=k+l|0;k=z;e=k>>>0>>0?b+1|0:b;o=ia(k^n,e^Q,63);w=Y;z=g;b=g+ra|0;d=R;n=d+H|0;g=u+n|0;b=s+(d>>>0>n>>>0?b+1|0:b)|0;s=g;g=g>>>0>>0?b+1|0:b;d=ia(s^L,g^t,32);u=r+d|0;t=Y;b=C+t|0;b=r>>>0>u>>>0?b+1|0:b;r=u;u=z;z=b;u=ia(r^H,u^b,24);n=u;b=Y;H=b;C=b;u=M;s=u+s|0;b=g+pa|0;b=u>>>0>s>>>0?b+1|0:b;g=n+s|0;b=b+C|0;C=g;u=t;t=g>>>0>>0?b+1|0:b;Q=ia(g^d,u^t,16);g=r+Q|0;u=Y;b=z+u|0;b=g>>>0>>0?b+1|0:b;r=g;s=b;n=ia(g^n,b^H,63);z=Y;H=x[B+156>>2];g=j;b=f+g|0;d=c+E|0;b=d>>>0>>0?b+1|0:b;j=d+x[B+152>>2]|0;b=b+H|0;b=j>>>0>>0?b+1|0:b;c=F;F=b;f=ia(j^X,c^b,32);c=q+f|0;d=Y;b=G+d|0;b=c>>>0>>0?b+1|0:b;q=c;G=g;g=b;c=ia(c^E,G^b,24);b=Y;E=b;H=x[B+204>>2];I=c;b=F+b|0;c=c+j|0;b=c>>>0>>0?b+1|0:b;j=c+x[B+200>>2]|0;b=b+H|0;L=j;F=j>>>0>>0?b+1|0:b;c=ia(j^f,F^d,16);d=q+c|0;j=Y;b=g+j|0;b=d>>>0>>0?b+1|0:b;q=d;G=b;E=ia(I^d,E^b,63);g=Y;d=w;H=c;c=aa;f=c+N|0;b=p+qa|0;b=c>>>0>f>>>0?b+1|0:b;c=f;p=c+o|0;b=b+d|0;w=p;f=j;j=c>>>0>p>>>0?b+1|0:b;f=ia(H^p,f^j,32);c=r+f|0;p=Y;b=s+p|0;b=c>>>0>>0?b+1|0:b;r=c;s=b;c=ia(c^o,b^d,24);b=Y;d=b;H=x[B+132>>2];o=c;b=j+b|0;c=c+w|0;b=c>>>0>>0?b+1|0:b;w=c+x[B+128>>2]|0;b=b+H|0;N=w;j=p;p=c>>>0>w>>>0?b+1|0:b;X=ia(w^f,j^p,16);w=r+X|0;c=Y;b=s+c|0;b=w>>>0>>0?b+1|0:b;r=w;s=b;H=ia(o^r,b^d,63);w=Y;j=z;d=O;f=d+$|0;b=m+ma|0;b=d>>>0>f>>>0?b+1|0:b;d=f;m=d+n|0;b=b+j|0;b=d>>>0>m>>>0?b+1|0:b;d=m;z=b;f=ia(d^U,b^J,32);m=q+f|0;J=Y;b=G+J|0;b=q>>>0>m>>>0?b+1|0:b;q=m;o=j;j=b;b=ia(m^n,o^b,24);n=x[B+164>>2];o=b;m=b;d=b+d|0;G=Y;b=G+z|0;b=d>>>0>>0?b+1|0:b;z=d+x[B+160>>2]|0;b=b+n|0;b=z>>>0>>0?b+1|0:b;m=z;d=J;J=b;d=ia(m^f,d^b,16);z=q+d|0;f=Y;b=j+f|0;b=z>>>0>>0?b+1|0:b;q=z;j=G;G=b;z=ia(o^q,j^b,63);j=Y;o=g;U=x[B+196>>2];I=E;b=g+t|0;n=C+E|0;b=n>>>0>>0?b+1|0:b;t=n;g=t+x[B+192>>2]|0;b=b+U|0;n=g;g=g>>>0>>0?b+1|0:b;E=ia(n^Z,g^l,32);C=A+E|0;t=Y;b=D+t|0;b=C>>>0>>0?b+1|0:b;l=b;D=ia(I^C,b^o,24);b=Y;U=b;A=b;I=D;D=S;o=D+n|0;b=g+na|0;b=o>>>0>>0?b+1|0:b;D=o;g=I+D|0;b=b+A|0;$=g;o=t;t=g>>>0>>0?b+1|0:b;Z=ia(g^E,o^t,16);g=C+Z|0;A=Y;b=l+A|0;b=g>>>0>>0?b+1|0:b;C=g;o=ia(I^g,b^U,63);g=Y;l=i;E=x[B+148>>2];D=b;I=h;b=i+F|0;n=h+L|0;b=n>>>0>>0?b+1|0:b;i=n;h=i+x[B+144>>2]|0;b=b+E|0;n=h;h=h>>>0>>0?b+1|0:b;u=ia(n^Q,h^u,32);F=k+u|0;i=Y;b=e+i|0;b=k>>>0>F>>>0?b+1|0:b;k=F;F=b;e=ia(I^k,b^l,24);E=e;b=Y;Q=b;l=b;L=u;u=K;e=u+n|0;b=h+ha|0;b=e>>>0>>0?b+1|0:b;h=E+e|0;b=b+l|0;l=h;u=h>>>0>>0?b+1|0:b;U=ia(L^h,u^i,16);h=k+U|0;i=Y;b=F+i|0;b=h>>>0>>0?b+1|0:b;k=h;F=b;e=ia(h^E,b^Q,63);b=Y;n=b;h=b;E=C;Q=d;C=S;d=C+N|0;b=p+na|0;b=d>>>0>>0?b+1|0:b;p=d;C=d+e|0;b=b+h|0;d=C;h=p>>>0>d>>>0?b+1|0:b;f=ia(Q^d,h^f,32);p=E+f|0;C=Y;b=C+D|0;b=p>>>0>>0?b+1|0:b;D=b;n=ia(e^p,n^b,24);b=Y;N=b;e=b;E=f;b=d;d=O;f=b+d|0;b=h+ma|0;b=d>>>0>f>>>0?b+1|0:b;d=f;h=d+n|0;b=b+e|0;Q=h;e=C;C=h>>>0>>0?b+1|0:b;L=ia(E^h,e^C,16);h=p+L|0;e=Y;b=D+e|0;b=h>>>0

>>0?b+1|0:b;p=h;D=b;E=ia(h^n,b^N,63);h=Y;d=w;b=ja+d|0;f=P;n=f+H|0;w=m+n|0;b=J+(f>>>0>n>>>0?b+1|0:b)|0;f=w;w=f>>>0>>0?b+1|0:b;A=ia(f^Z,w^A,32);m=k+A|0;J=Y;b=F+J|0;b=k>>>0>m>>>0?b+1|0:b;k=m;F=b;b=ia(k^H,b^d,24);H=x[B+204>>2];n=b;N=A;A=b;d=b+f|0;m=Y;b=m+w|0;b=d>>>0>>0?b+1|0:b;w=d+x[B+200>>2]|0;b=b+H|0;H=w;f=J;J=w>>>0>>0?b+1|0:b;N=ia(N^w,f^J,16);w=k+N|0;A=Y;b=F+A|0;F=w;d=m;m=k>>>0>w>>>0?b+1|0:b;f=ia(n^w,d^m,63);w=Y;k=j;n=x[B+220>>2];I=z;b=j+t|0;d=z+$|0;b=d>>>0>>0?b+1|0:b;z=d+x[B+216>>2]|0;b=b+n|0;t=z;z=d>>>0>t>>>0?b+1|0:b;d=ia(t^U,z^i,32);i=r+d|0;j=Y;b=s+j|0;b=i>>>0>>0?b+1|0:b;s=k;k=b;b=ia(I^i,s^b,24);U=x[B+156>>2];n=b;s=t;t=b;s=s+b|0;r=Y;b=r+z|0;b=t>>>0>s>>>0?b+1|0:b;t=s;z=t+x[B+152>>2]|0;b=b+U|0;U=z;t=z>>>0>>0?b+1|0:b;$=ia(z^d,t^j,16);z=i+$|0;s=Y;b=k+s|0;k=z;d=r;r=i>>>0>k>>>0?b+1|0:b;j=ia(n^k,d^r,63);i=Y;z=g;n=x[B+132>>2];b=g+u|0;d=l+o|0;b=d>>>0>>0?b+1|0:b;g=d+x[B+128>>2]|0;b=b+n|0;b=g>>>0>>0?b+1|0:b;l=b;c=ia(g^X,b^c,32);d=q+c|0;u=Y;b=G+u|0;b=d>>>0>>0?b+1|0:b;q=d;n=z;z=b;d=ia(d^o,n^b,24);b=Y;o=b;n=x[B+196>>2];I=d;b=l+b|0;d=g+d|0;b=d>>>0>>0?b+1|0:b;g=d+x[B+192>>2]|0;b=b+n|0;b=g>>>0>>0?b+1|0:b;l=g;d=u;u=b;c=ia(g^c,d^b,16);d=q+c|0;g=Y;b=z+g|0;b=d>>>0>>0?b+1|0:b;q=d;G=b;n=ia(I^d,o^b,63);z=Y;d=w;I=f;o=c;c=R;f=c+Q|0;b=C+ra|0;b=c>>>0>f>>>0?b+1|0:b;c=f;C=I+c|0;b=b+d|0;w=C;f=g;g=c>>>0>C>>>0?b+1|0:b;f=ia(o^C,f^g,32);c=k+f|0;C=Y;b=r+C|0;o=c;b=c>>>0>>0?b+1|0:b;c=ia(I^c,b^d,24);r=b;Z=x[B+148>>2];X=Z;Q=c;k=Y;b=g+k|0;c=c+w|0;b=c>>>0>>0?b+1|0:b;d=x[B+144>>2];w=d+c|0;b=b+X|0;X=w;w=c>>>0>w>>>0?b+1|0:b;T=ia(X^f,w^C,16);C=T;g=C+o|0;b=r;r=Y;b=b+r|0;b=g>>>0>>0?b+1|0:b;C=g;c=b;g=ia(Q^g,b^k,63);k=Y;f=i;Q=x[B+236>>2];I=j;b=f+J|0;o=j+H|0;b=o>>>0>>0?b+1|0:b;i=o;j=i+x[B+232>>2]|0;b=b+Q|0;o=j;j=i>>>0>j>>>0?b+1|0:b;e=ia(o^L,j^e,32);J=q+e|0;i=Y;b=G+i|0;b=q>>>0>J>>>0?b+1|0:b;q=J;G=b;f=ia(I^q,b^f,24);H=f;b=Y;Q=b;J=b;I=e;e=W;f=e+o|0;b=j+ga|0;b=e>>>0>f>>>0?b+1|0:b;e=f;j=H+e|0;b=b+J|0;L=j;J=j>>>0>>0?b+1|0:b;e=ia(I^j,J^i,16);j=q+e|0;f=Y;b=G+f|0;G=j;o=j>>>0>>0?b+1|0:b;H=ia(j^H,o^Q,63);j=Y;i=z;Q=n;q=M;n=q+U|0;b=t+pa|0;b=q>>>0>n>>>0?b+1|0:b;t=n;q=Q+t|0;b=b+i|0;z=q;q=q>>>0>>0?b+1|0:b;n=ia(z^N,q^A,32);A=p+n|0;t=Y;b=D+t|0;b=p>>>0>A>>>0?b+1|0:b;D=ia(Q^A,b^i,24);p=b;U=x[B+164>>2];Q=U;N=D;I=A;i=Y;b=q+i|0;D=z+D|0;b=D>>>0>>0?b+1|0:b;A=x[B+160>>2];q=D;z=A+q|0;b=b+Q|0;b=z>>>0>>0?b+1|0:b;D=t;t=b;da=ia(z^n,D^b,16);D=da;q=I+D|0;b=p;p=Y;b=b+p|0;b=q>>>0>>0?b+1|0:b;D=b;N=ia(N^q,b^i,63);i=Y;n=h;I=E;b=h+ha|0;E=K;Q=I+E|0;h=l+Q|0;b=u+(E>>>0>Q>>>0?b+1|0:b)|0;E=h;h=h>>>0>>0?b+1|0:b;s=ia(E^$,h^s,32);u=F+s|0;l=Y;b=m+l|0;b=u>>>0>>0?b+1|0:b;F=u;m=b;n=ia(I^F,b^n,24);Q=n;b=Y;$=b;u=b;I=s;s=aa;n=s+E|0;b=h+qa|0;b=n>>>0>>0?b+1|0:b;h=Q+n|0;b=b+u|0;u=h;s=l;l=h>>>0>>0?b+1|0:b;E=ia(I^h,s^l,16);h=F+E|0;s=Y;b=m+s|0;b=h>>>0>>0?b+1|0:b;F=h;m=b;n=ia(h^Q,b^$,63);b=Y;Q=b;h=b;I=e;b=w+ha|0;e=K+X|0;b=e>>>0>>0?b+1|0:b;w=e;K=e+n|0;b=b+h|0;e=K;w=w>>>0>e>>>0?b+1|0:b;f=ia(I^e,w^f,32);K=q+f|0;h=Y;b=D+h|0;ha=K;b=q>>>0>K>>>0?b+1|0:b;K=ia(n^K,Q^b,24);D=b;I=K;q=Y;b=q+w|0;e=e+K|0;b=e>>>0>>0?b+1|0:b;K=e+d|0;b=b+Z|0;n=K;e=d>>>0>n>>>0?b+1|0:b;Q=ia(n^f,e^h,16);w=Q;K=w+ha|0;b=D;D=Y;b=b+D|0;ha=K;w=w>>>0>K>>>0?b+1|0:b;h=ia(I^K,w^q,63);q=Y;K=k;f=x[B+196>>2];I=g;b=k+J|0;d=g+L|0;b=d>>>0>>0?b+1|0:b;k=d;g=d+x[B+192>>2]|0;b=b+f|0;d=g;g=d>>>0>>0?b+1|0:b;f=ia(d^da,g^p,32);p=F+f|0;k=Y;b=m+k|0;b=p>>>0>>0?b+1|0:b;m=K;K=b;b=ia(I^p,m^b,24);I=b;F=b;m=b+d|0;J=Y;b=J+g|0;g=m+A|0;b=U+(m>>>0>>0?b+1|0:b)|0;U=g;d=k;k=g>>>0>>0?b+1|0:b;L=ia(g^f,d^k,16);g=p+L|0;F=Y;b=K+F|0;b=g>>>0

>>0?b+1|0:b;p=g;d=J;J=b;d=ia(I^g,d^b,63);K=Y;g=j;b=ga+g|0;m=W;A=m+H|0;j=z+A|0;b=t+(m>>>0>A>>>0?b+1|0:b)|0;m=j;z=j>>>0>>0?b+1|0:b;A=ia(j^E,z^s,32);t=C+A|0;j=Y;b=c+j|0;b=t>>>0>>0?b+1|0:b;c=g;g=b;s=ia(t^H,c^b,24);c=s;b=Y;f=b;s=A;b=m;m=S;A=b+m|0;b=z+na|0;b=m>>>0>A>>>0?b+1|0:b;m=A;z=m+c|0;b=b+f|0;C=z;m=z>>>0>>0?b+1|0:b;E=ia(s^z,m^j,16);z=t+E|0;A=Y;b=g+A|0;H=z;z=z>>>0>>0?b+1|0:b;g=ia(H^c,z^f,63);j=Y;t=i;b=i+pa|0;s=M;c=s+N|0;i=u+c|0;b=l+(c>>>0>>0?b+1|0:b)|0;b=i>>>0>>0?b+1|0:b;u=i;i=b;s=ia(u^T,b^r,32);l=G+s|0;r=Y;b=o+r|0;b=l>>>0>>0?b+1|0:b;G=l;c=t;t=b;c=ia(l^N,c^b,24);b=Y;o=b;l=b;f=s;b=u;u=aa;s=b+u|0;b=i+qa|0;b=u>>>0>s>>>0?b+1|0:b;i=s+c|0;b=b+l|0;N=i;u=r;r=i>>>0>>0?b+1|0:b;s=ia(f^i,u^r,16);i=G+s|0;l=Y;b=t+l|0;b=i>>>0>>0?b+1|0:b;G=i;t=b;f=ia(i^c,b^o,63);i=Y;u=K;c=d;o=s;s=O;d=s+n|0;b=e+ma|0;b=d>>>0>>0?b+1|0:b;e=c+d|0;b=b+u|0;b=e>>>0>>0?b+1|0:b;s=e;K=b;d=ia(o^e,b^l,32);l=d+H|0;b=z;z=Y;b=b+z|0;b=d>>>0>l>>>0?b+1|0:b;e=u;u=b;b=ia(c^l,e^b,24);o=x[B+220>>2];c=b;H=d;e=s;s=b;d=e+b|0;e=Y;b=e+K|0;b=d>>>0>>0?b+1|0:b;K=d+x[B+216>>2]|0;b=b+o|0;n=K;s=d>>>0>n>>>0?b+1|0:b;H=ia(H^n,s^z,16);K=l+H|0;d=Y;b=u+d|0;b=l>>>0>K>>>0?b+1|0:b;l=K;u=b;K=ia(c^l,b^e,63);z=Y;e=j;o=x[B+204>>2];I=g;b=e+k|0;c=g+U|0;b=c>>>0>>0?b+1|0:b;j=c;g=c+x[B+200>>2]|0;b=b+o|0;c=g;g=c>>>0>>0?b+1|0:b;D=ia(c^Q,g^D,32);k=G+D|0;j=Y;b=t+j|0;b=k>>>0>>0?b+1|0:b;G=b;e=ia(I^k,b^e,24);o=e;b=Y;Q=b;t=b;I=D;D=P;e=D+c|0;b=g+ja|0;b=e>>>0>>0?b+1|0:b;g=o+e|0;b=b+t|0;U=g;t=g>>>0>>0?b+1|0:b;$=ia(I^g,t^j,16);g=k+$|0;D=Y;b=G+D|0;b=g>>>0>>0?b+1|0:b;k=g;G=b;g=ia(g^o,b^Q,63);j=Y;e=i;Q=x[B+156>>2];o=Q;I=f;b=e+m|0;f=f+C|0;b=f>>>0>>0?b+1|0:b;c=x[B+152>>2];C=f;i=c+f|0;b=b+o|0;f=i;i=f>>>0>>0?b+1|0:b;o=ia(f^L,i^F,32);C=o+ha|0;b=w;w=Y;b=b+w|0;b=C>>>0>>0?b+1|0:b;F=b;e=ia(I^C,b^e,24);ha=e;b=Y;L=b;m=b;I=e;e=R;f=e+f|0;b=i+ra|0;b=e>>>0>f>>>0?b+1|0:b;e=f;i=ha+e|0;b=b+m|0;ha=i;m=i>>>0>>0?b+1|0:b;Z=ia(i^o,m^w,16);w=C+Z|0;i=Y;b=F+i|0;b=w>>>0>>0?b+1|0:b;C=w;F=b;o=ia(I^w,b^L,63);w=Y;L=x[B+236>>2];I=h;e=q;b=e+r|0;f=h+N|0;b=f>>>0>>0?b+1|0:b;q=f;h=f+x[B+232>>2]|0;b=b+L|0;f=h;q=f>>>0>>0?b+1|0:b;A=ia(f^E,q^A,32);h=p+A|0;r=Y;b=J+r|0;E=h;b=h>>>0

>>0?b+1|0:b;h=ia(I^h,b^e,24);J=b;L=x[B+132>>2];N=h;I=E;E=A;p=Y;b=p+q|0;e=h+f|0;b=e>>>0>>0?b+1|0:b;A=x[B+128>>2];h=A+e|0;b=b+L|0;b=h>>>0>>0?b+1|0:b;q=h;e=r;r=b;E=ia(E^h,e^b,16);e=E;h=I+e|0;b=J;J=Y;b=b+J|0;b=h>>>0>>0?b+1|0:b;e=h;h=p;p=b;b=ia(N^e,h^b,63);N=b;f=b;n=b+n|0;h=Y;b=h+s|0;s=n+A|0;b=L+(f>>>0>n>>>0?b+1|0:b)|0;f=s;A=A>>>0>f>>>0?b+1|0:b;n=ia(f^$,A^D,32);s=C+n|0;D=Y;b=F+D|0;b=C>>>0>s>>>0?b+1|0:b;C=s;s=h;h=b;s=ia(N^C,s^b,24);N=s;b=Y;L=b;F=b;I=s;s=M;f=s+f|0;b=A+pa|0;b=f>>>0>>0?b+1|0:b;A=N+f|0;b=b+F|0;N=A;F=A>>>0>>0?b+1|0:b;$=ia(A^n,F^D,16);D=C+$|0;A=Y;b=h+A|0;b=C>>>0>D>>>0?b+1|0:b;C=D;D=b;n=ia(I^C,b^L,63);h=Y;s=z;L=x[B+148>>2];I=K;b=z+t|0;f=K+U|0;b=f>>>0>>0?b+1|0:b;z=f;K=f+x[B+144>>2]|0;b=b+L|0;f=K;K=z>>>0>f>>>0?b+1|0:b;U=ia(f^Z,K^i,32);i=e+U|0;z=Y;b=p+z|0;b=i>>>0>>0?b+1|0:b;t=b;b=ia(I^i,b^s,24);L=b;e=b;s=b+f|0;p=Y;b=p+K|0;K=c+s|0;b=Q+(e>>>0>s>>>0?b+1|0:b)|0;Q=K;e=c>>>0>K>>>0?b+1|0:b;U=ia(K^U,e^z,16);K=i+U|0;s=Y;b=t+s|0;t=K;c=p;p=i>>>0>t>>>0?b+1|0:b;z=ia(L^t,c^p,63);i=Y;K=j;f=x[B+164>>2];L=g;b=j+m|0;c=g+ha|0;b=c>>>0>>0?b+1|0:b;j=c;g=c+x[B+160>>2]|0;b=b+f|0;c=g;g=c>>>0>>0?b+1|0:b;f=ia(c^E,g^J,32);J=l+f|0;j=Y;b=u+j|0;b=l>>>0>J>>>0?b+1|0:b;u=K;K=b;l=ia(L^J,u^b,24);b=Y;E=b;m=b;I=l;l=aa;u=l+c|0;b=g+qa|0;b=l>>>0>u>>>0?b+1|0:b;l=u;g=I+l|0;b=b+m|0;ha=g;m=g>>>0>>0?b+1|0:b;L=ia(g^f,m^j,16);g=J+L|0;l=Y;b=K+l|0;b=g>>>0>>0?b+1|0:b;J=g;u=b;g=ia(I^g,b^E,63);j=Y;K=w;b=w+na|0;c=S;f=c+o|0;w=q+f|0;b=r+(c>>>0>f>>>0?b+1|0:b)|0;c=w;w=c>>>0>>0?b+1|0:b;d=ia(c^H,w^d,32);r=k+d|0;q=Y;b=G+q|0;b=k>>>0>r>>>0?b+1|0:b;k=r;f=K;K=b;r=ia(k^o,f^b,24);f=r;b=Y;o=b;E=d;r=W;d=r+c|0;b=w+ga|0;b=d>>>0>>0?b+1|0:b;w=f+d|0;b=b+o|0;G=w;c=q;q=w>>>0>>0?b+1|0:b;d=ia(E^w,c^q,16);w=k+d|0;r=Y;b=K+r|0;c=w;w=k>>>0>c>>>0?b+1|0:b;o=ia(c^f,w^o,63);K=Y;k=i;f=x[B+196>>2];E=z;H=d;b=i+F|0;d=z+N|0;b=d>>>0>>0?b+1|0:b;z=d+x[B+192>>2]|0;b=b+f|0;F=z;z=d>>>0>z>>>0?b+1|0:b;d=ia(H^F,z^r,32);r=J+d|0;i=Y;b=u+i|0;b=r>>>0>>0?b+1|0:b;f=k;k=b;b=ia(E^r,f^b,24);E=x[B+204>>2];f=b;u=F;F=b;u=u+b|0;J=Y;b=J+z|0;b=u>>>0>>0?b+1|0:b;z=u+x[B+200>>2]|0;b=b+E|0;H=z;F=z>>>0>>0?b+1|0:b;N=ia(z^d,F^i,16);z=r+N|0;u=Y;b=k+u|0;k=z;r=k>>>0>>0?b+1|0:b;z=ia(f^k,r^J,63);i=Y;J=j;Z=x[B+212>>2];f=Z;E=g;I=c;b=j+e|0;c=g+Q|0;b=c>>>0>>0?b+1|0:b;d=x[B+208>>2];g=d+c|0;b=b+f|0;e=g;g=g>>>0>>0?b+1|0:b;c=ia(e^$,g^A,32);j=I+c|0;b=w;w=Y;b=b+w|0;b=j>>>0>>0?b+1|0:b;f=J;J=b;b=ia(E^j,f^b,24);E=x[B+220>>2];I=b;f=c;c=e;e=b;c=c+b|0;A=Y;b=A+g|0;b=c>>>0>>0?b+1|0:b;g=c+x[B+216>>2]|0;b=b+E|0;Q=g;e=g>>>0>>0?b+1|0:b;c=ia(f^g,e^w,16);w=j+c|0;f=Y;b=J+f|0;J=w;g=A;A=j>>>0>w>>>0?b+1|0:b;w=ia(I^w,g^A,63);g=Y;j=K;I=o;o=R;E=o+ha|0;b=m+ra|0;b=o>>>0>E>>>0?b+1|0:b;o=E;m=I+o|0;b=b+j|0;K=m;m=m>>>0>>0?b+1|0:b;E=ia(K^U,m^s,32);o=C+E|0;s=Y;b=D+s|0;b=C>>>0>o>>>0?b+1|0:b;C=o;o=j;j=b;o=ia(I^C,o^b,24);b=Y;D=b;U=x[B+236>>2];I=o;b=m+b|0;o=o+K|0;b=o>>>0>>0?b+1|0:b;m=o;K=m+x[B+232>>2]|0;b=b+U|0;ha=K;m=m>>>0>K>>>0?b+1|0:b;U=ia(K^E,m^s,16);K=C+U|0;s=Y;b=j+s|0;j=K;C=C>>>0>j>>>0?b+1|0:b;E=ia(I^j,C^D,63);K=Y;D=h;I=n;b=h+ja|0;o=P;n=o+n|0;h=G+n|0;b=q+(n>>>0>>0?b+1|0:b)|0;o=h;h=h>>>0>>0?b+1|0:b;l=ia(o^L,h^l,32);G=t+l|0;q=Y;b=p+q|0;b=t>>>0>G>>>0?b+1|0:b;t=b;D=ia(I^G,b^D,24);n=D;b=Y;L=b;p=b;I=l;l=O;D=l+o|0;b=h+ma|0;b=l>>>0>D>>>0?b+1|0:b;l=D;h=n+l|0;b=b+p|0;p=h;o=q;q=h>>>0>>0?b+1|0:b;o=ia(I^h,o^q,16);h=G+o|0;l=Y;b=t+l|0;b=h>>>0>>0?b+1|0:b;G=h;t=b;D=ia(h^n,b^L,63);b=Y;n=b;h=b;L=c;b=F+ja|0;c=H+P|0;b=c>>>0

>>0?b+1|0:b;F=c;P=c+D|0;b=b+h|0;c=P;P=F>>>0>c>>>0?b+1|0:b;f=ia(L^c,P^f,32);F=j+f|0;h=Y;b=C+h|0;b=j>>>0>F>>>0?b+1|0:b;j=F;C=b;b=ia(D^j,n^b,24);H=b;n=f;D=b;c=b+c|0;F=Y;b=F+P|0;P=c+d|0;b=Z+(c>>>0>>0?b+1|0:b)|0;f=P;D=d>>>0>f>>>0?b+1|0:b;n=ia(n^f,D^h,16);P=j+n|0;d=Y;b=C+d|0;C=P;c=F;F=j>>>0>C>>>0?b+1|0:b;j=ia(H^C,c^F,63);h=Y;P=i;H=x[B+164>>2];L=z;b=i+e|0;c=z+Q|0;b=c>>>0>>0?b+1|0:b;i=c;z=c+x[B+160>>2]|0;b=b+H|0;c=z;z=i>>>0>c>>>0?b+1|0:b;s=ia(c^U,z^s,32);e=G+s|0;i=Y;b=t+i|0;b=e>>>0>>0?b+1|0:b;G=e;t=P;P=b;b=ia(L^e,t^b,24);Q=x[B+196>>2];L=b;H=s;e=b;s=b+c|0;t=Y;b=t+z|0;b=e>>>0>s>>>0?b+1|0:b;e=s;z=e+x[B+192>>2]|0;b=b+Q|0;c=z;s=i;i=e>>>0>c>>>0?b+1|0:b;H=ia(H^c,s^i,16);z=G+H|0;Q=Y;b=P+Q|0;b=z>>>0>>0?b+1|0:b;G=z;e=t;t=b;e=ia(L^z,e^b,63);P=Y;z=g;ja=x[B+204>>2];L=w;b=g+m|0;s=w+ha|0;b=s>>>0>>0?b+1|0:b;g=s;w=g+x[B+200>>2]|0;b=b+ja|0;s=w;w=g>>>0>w>>>0?b+1|0:b;l=ia(s^o,w^l,32);m=k+l|0;g=Y;b=r+g|0;b=k>>>0>m>>>0?b+1|0:b;k=m;m=z;z=b;m=ia(L^k,m^b,24);o=m;b=Y;ja=b;r=b;L=m;b=w+ma|0;m=s+O|0;b=m>>>0>>0?b+1|0:b;O=o+m|0;b=b+r|0;s=O;o=g;g=m>>>0>s>>>0?b+1|0:b;o=ia(s^l,o^g,16);O=k+o|0;r=Y;b=z+r|0;b=k>>>0>O>>>0?b+1|0:b;k=O;m=b;O=ia(L^k,b^ja,63);w=Y;ja=x[B+236>>2];z=K;b=q+z|0;l=p+E|0;b=l>>>0

>>0?b+1|0:b;q=l;K=l+x[B+232>>2]|0;b=b+ja|0;l=K;K=q>>>0>l>>>0?b+1|0:b;u=ia(l^N,K^u,32);p=J+u|0;q=Y;b=A+q|0;b=p>>>0>>0?b+1|0:b;A=z;z=b;A=ia(p^E,A^b,24);b=Y;N=b;J=b;b=K+na|0;l=l+S|0;b=l>>>0>>0?b+1|0:b;S=l+A|0;b=b+J|0;J=S;E=q;q=l>>>0>J>>>0?b+1|0:b;E=ia(J^u,E^q,16);S=p+E|0;na=Y;b=z+na|0;b=p>>>0>S>>>0?b+1|0:b;p=S;l=b;K=ia(A^p,b^N,63);z=Y;u=P;b=D+pa|0;A=f+M|0;b=A>>>0>>0?b+1|0:b;M=A+e|0;b=b+u|0;b=A>>>0>M>>>0?b+1|0:b;A=M;u=R+A|0;M=b;b=ra+b|0;b=u>>>0>>0?b+1|0:b;R=b;f=u;u=ia(A^E,M^na,32);M=k+u|0;A=Y;b=m+A|0;m=M;M=k>>>0>m>>>0?b+1|0:b;D=ia(m^e,M^P,24);k=D;P=f+k|0;e=Y;b=e+R|0;b=k>>>0>P>>>0?b+1|0:b;k=P;x[B>>2]=k;x[B+4>>2]=b;S=b;b=ia(k^u,b^A,16);P=Y;u=P;x[B+120>>2]=b;x[B+124>>2]=u;R=b;m=b+m|0;b=u+M|0;x[B+80>>2]=m;b=m>>>0>>0?b+1|0:b;x[B+84>>2]=b;ta=B,ua=ia(D^m,b^e,63),x[ta+40>>2]=ua;x[B+44>>2]=Y;M=w;m=x[B+132>>2];e=O;b=i+w|0;R=c+O|0;b=R>>>0>>0?b+1|0:b;O=R+x[B+128>>2]|0;b=b+m|0;b=O>>>0>>0?b+1|0:b;R=b;i=ia(O^n,b^d,32);w=p+i|0;m=Y;b=l+m|0;b=p>>>0>w>>>0?b+1|0:b;p=w;c=M;M=b;l=ia(e^p,c^b,24);w=l+O|0;u=Y;b=R+u|0;b=w>>>0>>0?b+1|0:b;R=x[B+144>>2];O=R+w|0;b=x[B+148>>2]+b|0;b=O>>>0>>0?b+1|0:b;x[B+8>>2]=O;x[B+12>>2]=b;b=ia(i^O,b^m,16);P=Y;w=P;x[B+96>>2]=b;x[B+100>>2]=w;O=b;R=b+p|0;b=w+M|0;M=R;x[B+88>>2]=M;b=O>>>0>M>>>0?b+1|0:b;x[B+92>>2]=b;ta=B,ua=ia(l^M,b^u,63),x[ta+48>>2]=ua;x[B+52>>2]=Y;R=x[B+220>>2];c=W;b=g+z|0;O=s+K|0;b=O>>>0>>0?b+1|0:b;P=O+x[B+216>>2]|0;b=b+R|0;b=P>>>0>>0?b+1|0:b;W=P;R=P;O=c+P|0;P=b;b=b+ga|0;b=O>>>0>>0?b+1|0:b;R=O;O=b;c=R;e=K;R=ia(H^W,P^Q,32);P=C+R|0;K=Y;b=F+K|0;w=P;P=C>>>0>w>>>0?b+1|0:b;z=ia(e^w,P^z,24);g=z;W=c+g|0;i=Y;b=i+O|0;O=W;x[B+16>>2]=O;b=g>>>0>O>>>0?b+1|0:b;x[B+20>>2]=b;b=ia(O^R,b^K,16);M=Y;x[B+104>>2]=b;x[B+108>>2]=M;O=b;W=b+w|0;b=P+M|0;P=W;x[B+64>>2]=P;b=O>>>0>P>>>0?b+1|0:b;x[B+68>>2]=b;ta=B,ua=ia(g^P,b^i,63),x[ta+56>>2]=ua;x[B+60>>2]=Y;b=h+qa|0;O=j+aa|0;b=O>>>0>>0?b+1|0:b;O=J+O|0;b=b+q|0;b=J>>>0>O>>>0?b+1|0:b;aa=b;K=ia(O^o,b^r,32);W=G+K|0;w=Y;b=t+w|0;b=G>>>0>W>>>0?b+1|0:b;M=b;z=ia(W^j,h^b,24);R=z+O|0;g=Y;b=aa+g|0;b=O>>>0>R>>>0?b+1|0:b;aa=x[B+152>>2];O=aa+R|0;b=x[B+156>>2]+b|0;b=O>>>0>>0?b+1|0:b;x[B+24>>2]=O;x[B+28>>2]=b;b=ia(K^O,b^w,16);x[B+112>>2]=b;aa=Y;x[B+116>>2]=aa;O=b+W|0;b=M+aa|0;M=O;x[B+72>>2]=M;b=M>>>0>>0?b+1|0:b;x[B+76>>2]=b;ta=B,ua=ia(z^M,b^g,63),x[ta+32>>2]=ua;x[B+36>>2]=Y;b=x[B+68>>2]^((y[a+4|0]|y[a+5|0]<<8|(y[a+6|0]<<16|y[a+7|0]<<24))^S);M=x[B+64>>2]^((y[a|0]|y[a+1|0]<<8|(y[a+2|0]<<16|y[a+3|0]<<24))^k);v[a|0]=M;v[a+1|0]=M>>>8;v[a+2|0]=M>>>16;v[a+3|0]=M>>>24;v[a+4|0]=b;v[a+5|0]=b>>>8;v[a+6|0]=b>>>16;v[a+7|0]=b>>>24;S=1;while(1){M=S<<3;b=M+a|0;M=B+M|0;P=M;O=x[M>>2]^(y[b|0]|y[b+1|0]<<8|(y[b+2|0]<<16|y[b+3|0]<<24));M=M- -64|0;aa=x[M>>2];M=x[M+4>>2]^(x[P+4>>2]^(y[b+4|0]|y[b+5|0]<<8|(y[b+6|0]<<16|y[b+7|0]<<24)));P=O^aa;v[b|0]=P;v[b+1|0]=P>>>8;v[b+2|0]=P>>>16;v[b+3|0]=P>>>24;v[b+4|0]=M;v[b+5|0]=M>>>8;v[b+6|0]=M>>>16;v[b+7|0]=M>>>24;S=S+1|0;if((S|0)!=8){continue}break}V=B+256|0}function pf(a,b,c,d,e,f,g){var h=0,i=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0,r=0,s=0,t=0,u=0,w=0,z=0,A=0,B=0,C=0,D=0,E=0,F=0,G=0,H=0,I=0,J=0,K=0,L=0,M=0,N=0,O=0,P=0,Q=0,R=0,S=0,T=0,U=0,W=0,X=0,Z=0,_=0,$=0,aa=0,ba=0,ca=0,da=0,ea=0,fa=0,ga=0,ha=0,ia=0,ja=0,ka=0,la=0,ma=0,na=0,pa=0,qa=0,ra=0,ta=0,ua=0,va=0,wa=0,xa=0,ya=0,za=0,Aa=0,Ba=0,Ca=0,Da=0,Ea=0,Fa=0,Ga=0,Ha=0,Ia=0,Ja=0,Ka=0,La=0,Ma=0,Oa=0,Pa=0,Qa=0,Ra=0,Sa=0,Ta=0,Ua=0,Va=0,Wa=0,Xa=0,Ya=0,Za=0,$a=0,ab=0,bb=0,cb=0,db=0,eb=0,fb=0,gb=0,hb=0,ib=0,jb=0,kb=0,lb=0,nb=0,ob=0,pb=0,qb=0,rb=0,sb=0;p=V-560|0;V=p;hd(p+352|0,g);Qb(p+288|0,f,32,0);Na(p+352|0,p+320|0,32,0);Na(p+352|0,c,d,e);_a(p+352|0,p+224|0);m=f;l=y[m+32|0]|y[m+33|0]<<8|(y[m+34|0]<<16|y[m+35|0]<<24);k=y[m+36|0]|y[m+37|0]<<8|(y[m+38|0]<<16|y[m+39|0]<<24);j=y[m+40|0]|y[m+41|0]<<8|(y[m+42|0]<<16|y[m+43|0]<<24);h=y[m+44|0]|y[m+45|0]<<8|(y[m+46|0]<<16|y[m+47|0]<<24);i=y[m+48|0]|y[m+49|0]<<8|(y[m+50|0]<<16|y[m+51|0]<<24);f=y[m+52|0]|y[m+53|0]<<8|(y[m+54|0]<<16|y[m+55|0]<<24);n=y[m+60|0]|y[m+61|0]<<8|(y[m+62|0]<<16|y[m+63|0]<<24);m=y[m+56|0]|y[m+57|0]<<8|(y[m+58|0]<<16|y[m+59|0]<<24);v[a+56|0]=m;v[a+57|0]=m>>>8;v[a+58|0]=m>>>16;v[a+59|0]=m>>>24;v[a+60|0]=n;v[a+61|0]=n>>>8;v[a+62|0]=n>>>16;v[a+63|0]=n>>>24;v[a+48|0]=i;v[a+49|0]=i>>>8;v[a+50|0]=i>>>16;v[a+51|0]=i>>>24;v[a+52|0]=f;v[a+53|0]=f>>>8;v[a+54|0]=f>>>16;v[a+55|0]=f>>>24;v[a+40|0]=j;v[a+41|0]=j>>>8;v[a+42|0]=j>>>16;v[a+43|0]=j>>>24;v[a+44|0]=h;v[a+45|0]=h>>>8;v[a+46|0]=h>>>16;v[a+47|0]=h>>>24;f=a+32|0;i=f;v[i|0]=l;v[i+1|0]=l>>>8;v[i+2|0]=l>>>16;v[i+3|0]=l>>>24;v[i+4|0]=k;v[i+5|0]=k>>>8;v[i+6|0]=k>>>16;v[i+7|0]=k>>>24;Eb(p+224|0);Yb(p,p+224|0);mb(a,p);hd(p+352|0,g);Na(p+352|0,a,64,0);Na(p+352|0,c,d,e);_a(p+352|0,p+160|0);Eb(p+160|0);v[p+288|0]=y[p+288|0]&248;v[p+319|0]=y[p+319|0]&63|64;a=p+160|0;Ja=sa(a);z=y[a+2|0]|y[a+3|0]<<8|(y[a+4|0]<<16|y[a+5|0]<<24);na=sa(a+5|0);ia=Y;t=y[a+7|0]|y[a+8|0]<<8|(y[a+9|0]<<16|y[a+10|0]<<24);A=y[a+10|0]|y[a+11|0]<<8|(y[a+12|0]<<16|y[a+13|0]<<24);ja=sa(a+13|0);q=Y;u=y[a+15|0]|y[a+16|0]<<8|(y[a+17|0]<<16|y[a+18|0]<<24);Pa=sa(a+18|0);B=Y;ka=sa(a+21|0);j=y[a+23|0]|y[a+24|0]<<8|(y[a+25|0]<<16|y[a+26|0]<<24);m=sa(a+26|0);g=Y;e=y[a+28|0]|y[a+29|0]<<8|(y[a+30|0]<<16|y[a+31|0]<<24);a=p+288|0;Fa=sa(a);w=y[a+2|0]|y[a+3|0]<<8|(y[a+4|0]<<16|y[a+5|0]<<24);Va=sa(a+5|0);o=Y;s=y[a+7|0]|y[a+8|0]<<8|(y[a+9|0]<<16|y[a+10|0]<<24);r=y[a+10|0]|y[a+11|0]<<8|(y[a+12|0]<<16|y[a+13|0]<<24);Wa=sa(a+13|0);n=Y;h=y[a+15|0]|y[a+16|0]<<8|(y[a+17|0]<<16|y[a+18|0]<<24);Qa=sa(a+18|0);i=Y;Ka=sa(a+21|0);d=y[a+23|0]|y[a+24|0]<<8|(y[a+25|0]<<16|y[a+26|0]<<24);l=sa(a+26|0);c=Y;a=y[a+28|0]|y[a+29|0]<<8|(y[a+30|0]<<16|y[a+31|0]<<24);la=p+224|0;ob=sa(la);k=la;pb=y[k+2|0]|y[k+3|0]<<8|(y[k+4|0]<<16|y[k+5|0]<<24);qb=sa(k+5|0);rb=Y;Ga=y[k+7|0]|y[k+8|0]<<8|(y[k+9|0]<<16|y[k+10|0]<<24);Da=y[k+10|0]|y[k+11|0]<<8|(y[k+12|0]<<16|y[k+13|0]<<24);La=sa(k+13|0);pa=Y;Ea=y[k+15|0]|y[k+16|0]<<8|(y[k+17|0]<<16|y[k+18|0]<<24);eb=sa(k+18|0);J=Y;H=sa(k+21|0);K=a>>>7|0;L=((g&3)<<30|m>>>2)&2097151;a=Fj(K,0,L,0);k=Y;g=a;M=((c&3)<<30|l>>>2)&2097151;N=e>>>7|0;a=Fj(M,0,N,0);e=g+a|0;c=Y+k|0;k=e;e=a>>>0>e>>>0?c+1|0:c;a=Fj(L,qa,M,ra);g=Y;O=d>>>5&2097151;c=Fj(O,0,N,0);d=c+a|0;a=Y+g|0;a=c>>>0>d>>>0?a+1|0:a;c=a;P=j>>>5&2097151;a=Fj(K,0,P,0);d=a+d|0;c=Y+c|0;j=d;c=a>>>0>d>>>0?c+1|0:c;E=c;a=d;c=c-((a>>>0<4293918720)-1|0)|0;F=a- -1048576|0;C=c;d=c>>21;c=(c&2097151)<<11|F>>>21;g=c+k|0;a=d+e|0;e=g;a=c>>>0>e>>>0?a+1|0:a;m=a;a=e;D=m-((a>>>0<4293918720)-1|0)|0;G=a- -1048576|0;a=Fj(K,0,N,0);Ha=a- -1048576|0;Ia=Y;c=Ia-((a>>>0<4293918720)-1|0)|0;l=D;d=l>>21;D=Ha&-2097152;g=a-D|0;fb=g+((l&2097151)<<11|G>>>21)|0;a=(Ia-((a>>>0>>0)+c|0)|0)+d|0;Ma=fb;a=g>>>0>Ma>>>0?a+1|0:a;Xa=a;k=Fj(Ma,a,-683901,-1);g=Y;a=c>>21;Ya=a;Ra=(c&2097151)<<11|Ha>>>21;a=Fj(Ra,a,136657,0);c=a+k|0;d=Y+g|0;D=c;k=a>>>0>c>>>0?d+1|0:d;Q=((n&1)<<31|Wa>>>1)&2097151;a=Fj(Q,0,L,qa);c=Y;d=a;R=r>>>4&2097151;a=Fj(R,0,N,0);d=d+a|0;c=Y+c|0;c=a>>>0>d>>>0?c+1|0:c;S=h>>>6&2097151;a=Fj(S,0,P,0);d=a+d|0;c=Y+c|0;c=a>>>0>d>>>0?c+1|0:c;a=0;ma=a;g=d;T=Ka&2097151;U=((B&7)<<29|Pa>>>3)&2097151;d=Fj(T,a,U,0);g=g+d|0;a=Y+c|0;a=d>>>0>g>>>0?a+1|0:a;W=((i&7)<<29|Qa>>>3)&2097151;X=ka&2097151;d=Fj(W,0,X,0);g=d+g|0;c=Y+a|0;c=d>>>0>g>>>0?c+1|0:c;Z=u>>>6&2097151;a=Fj(O,0,Z,0);g=a+g|0;d=Y+c|0;d=a>>>0>g>>>0?d+1|0:d;_=((q&1)<<31|ja>>>1)&2097151;c=Fj(M,ra,_,0);g=c+g|0;a=Y+d|0;d=g;c=c>>>0>d>>>0?a+1|0:a;$=A>>>4&2097151;a=Fj(K,0,$,0);d=a+d|0;c=Y+c|0;B=d;g=a>>>0>d>>>0?c+1|0:c;a=Fj(L,qa,R,0);c=Y;d=a;aa=s>>>7&2097151;a=Fj(aa,0,N,0);i=d+a|0;d=Y+c|0;d=a>>>0>i>>>0?d+1|0:d;c=Fj(P,0,Q,ta);i=c+i|0;a=Y+d|0;a=c>>>0>i>>>0?a+1|0:a;d=Fj(S,0,X,ua);i=d+i|0;c=Y+a|0;c=d>>>0>i>>>0?c+1|0:c;a=Fj(T,ma,Z,0);d=a+i|0;c=Y+c|0;c=a>>>0>d>>>0?c+1|0:c;a=d;d=Fj(U,va,W,wa);i=a+d|0;a=Y+c|0;a=d>>>0>i>>>0?a+1|0:a;c=Fj(O,0,_,xa);i=c+i|0;d=Y+a|0;d=c>>>0>i>>>0?d+1|0:d;c=Fj(M,ra,$,0);i=c+i|0;a=Y+d|0;d=i;c=c>>>0>d>>>0?a+1|0:a;ba=t>>>7&2097151;a=Fj(K,0,ba,0);d=a+d|0;c=Y+c|0;r=d;c=a>>>0>d>>>0?c+1|0:c;h=c;a=d;c=c-((a>>>0<4293918720)-1|0)|0;n=a- -1048576|0;i=c;d=c>>21;c=(c&2097151)<<11|n>>>21;s=c+B|0;a=d+g|0;a=c>>>0>s>>>0?a+1|0:a;g=s;d=g;s=d+D|0;c=a;a=a+k|0;a=d>>>0>s>>>0?a+1|0:a;d=s;k=c;c=g;k=k-((c>>>0<4293918720)-1|0)|0;q=c- -1048576|0;c=d;d=q&-2097152;u=c-d|0;g=k;B=a-(g+(c>>>0>>0)|0)|0;a=G&-2097152;c=m-((a>>>0>e>>>0)+l|0)|0;Sa=e-a|0;Za=c;a=Fj(Ra,Ya,-997805,-1);e=a+r|0;d=Y+h|0;d=a>>>0>e>>>0?d+1|0:d;a=e;e=Fj(Ma,Xa,136657,0);h=a+e|0;a=Y+d|0;c=Fj(Sa,c,-683901,-1);d=c+h|0;a=Y+(e>>>0>h>>>0?a+1|0:a)|0;a=c>>>0>d>>>0?a+1|0:a;c=n&-2097152;k=d-c|0;h=a-((c>>>0>d>>>0)+i|0)|0;a=Fj(L,qa,aa,0);d=Y;ca=((o&3)<<30|Va>>>2)&2097151;c=Fj(ca,0,N,0);e=c+a|0;a=Y+d|0;a=c>>>0>e>>>0?a+1|0:a;d=Fj(P,0,R,0);e=d+e|0;c=Y+a|0;c=d>>>0>e>>>0?c+1|0:c;a=Fj(Q,ta,X,ua);e=a+e|0;d=Y+c|0;d=a>>>0>e>>>0?d+1|0:d;c=Fj(S,0,U,va);e=c+e|0;a=Y+d|0;a=c>>>0>e>>>0?a+1|0:a;d=Fj(T,ma,_,xa);e=d+e|0;c=Y+a|0;c=d>>>0>e>>>0?c+1|0:c;d=Fj(W,wa,Z,0);e=d+e|0;a=Y+c|0;a=d>>>0>e>>>0?a+1|0:a;d=Fj(O,0,$,0);e=d+e|0;c=Y+a|0;c=d>>>0>e>>>0?c+1|0:c;a=Fj(M,ra,ba,0);e=a+e|0;d=Y+c|0;d=a>>>0>e>>>0?d+1|0:d;da=((ia&3)<<30|na>>>2)&2097151;c=Fj(K,0,da,0);e=c+e|0;a=Y+d|0;i=e;e=c>>>0>e>>>0?a+1|0:a;a=Fj(L,qa,ca,ya);c=Y;d=a;ea=w>>>5&2097151;a=Fj(ea,0,N,0);d=d+a|0;c=Y+c|0;c=a>>>0>d>>>0?c+1|0:c;a=Fj(P,0,aa,0);l=a+d|0;d=Y+c|0;d=a>>>0>l>>>0?d+1|0:d;c=Fj(R,0,X,ua);l=c+l|0;a=Y+d|0;a=c>>>0>l>>>0?a+1|0:a;c=Fj(Q,ta,U,va);d=c+l|0;a=Y+a|0;a=c>>>0>d>>>0?a+1|0:a;c=d;d=Fj(S,0,Z,0);l=c+d|0;c=Y+a|0;c=d>>>0>l>>>0?c+1|0:c;a=Fj(T,ma,$,0);d=a+l|0;c=Y+c|0;c=a>>>0>d>>>0?c+1|0:c;a=Fj(W,wa,_,xa);l=a+d|0;d=Y+c|0;d=a>>>0>l>>>0?d+1|0:d;c=Fj(O,0,ba,0);l=c+l|0;a=Y+d|0;a=c>>>0>l>>>0?a+1|0:a;c=Fj(M,ra,da,za);d=c+l|0;a=Y+a|0;a=c>>>0>d>>>0?a+1|0:a;c=a;fa=z>>>5&2097151;a=Fj(K,0,fa,0);d=a+d|0;c=Y+c|0;s=d;c=a>>>0>d>>>0?c+1|0:c;Va=c;a=d;d=c-((a>>>0<4293918720)-1|0)|0;fb=a- -1048576|0;Wa=d;a=d>>21;c=(d&2097151)<<11|fb>>>21;d=c+i|0;a=a+e|0;r=d;a=c>>>0>d>>>0?a+1|0:a;Qa=a;a=d;d=Qa-((a>>>0<4293918720)-1|0)|0;na=a- -1048576|0;Ka=d;a=d>>21;d=(d&2097151)<<11|na>>>21;e=d+k|0;c=a+h|0;n=e;c=d>>>0>e>>>0?c+1|0:c;Ia=c;a=e;d=c-((a>>>0<4293918720)-1|0)|0;ja=a- -1048576|0;D=d;a=d>>21;c=(d&2097151)<<11|ja>>>21;d=c+u|0;a=a+B|0;h=d;a=c>>>0>d>>>0?a+1|0:a;G=a;a=d;d=G-((a>>>0<4293918720)-1|0)|0;ka=a- -1048576|0;z=d;m=(d&2097151)<<11|ka>>>21;i=d>>21;a=Fj(L,qa,S,0);c=Y;d=a;a=Fj(N,0,Q,ta);d=d+a|0;c=Y+c|0;c=a>>>0>d>>>0?c+1|0:c;a=Fj(T,ma,X,ua);d=a+d|0;c=Y+c|0;c=a>>>0>d>>>0?c+1|0:c;a=d;d=Fj(P,0,W,wa);e=a+d|0;a=Y+c|0;a=d>>>0>e>>>0?a+1|0:a;c=Fj(O,0,U,va);e=c+e|0;d=Y+a|0;d=c>>>0>e>>>0?d+1|0:d;c=Fj(M,ra,Z,0);e=c+e|0;a=Y+d|0;a=c>>>0>e>>>0?a+1|0:a;d=Fj(K,0,_,xa);e=d+e|0;c=Y+a|0;c=d>>>0>e>>>0?c+1|0:c;d=Fj(Ra,Ya,-683901,-1);k=e+d|0;a=c;c=a+Y|0;c=d>>>0>k>>>0?c+1|0:c;d=k;k=a;a=e;k=k-((a>>>0<4293918720)-1|0)|0;w=a- -1048576|0;a=d;d=w&-2097152;l=a-d|0;e=k;d=c-(e+(a>>>0>>0)|0)|0;a=g>>21;c=(g&2097151)<<11|q>>>21;g=c+l|0;a=a+d|0;a=c>>>0>g>>>0?a+1|0:a;c=g;o=c- -1048576|0;l=a-((c>>>0<4293918720)-1|0)|0;g=l;d=o&-2097152;k=c-d|0;m=k+m|0;d=(a-((c>>>0>>0)+g|0)|0)+i|0;$a=m;d=k>>>0>m>>>0?d+1|0:d;ab=d;l=Fj(m,d,-683901,-1);k=Y;c=Fj(P,0,T,ma);a=Y;d=c;c=Fj(N,0,S,0);d=d+c|0;a=Y+a|0;a=c>>>0>d>>>0?a+1|0:a;c=d;d=Fj(L,qa,W,wa);i=c+d|0;c=Y+a|0;c=d>>>0>i>>>0?c+1|0:c;d=Fj(O,0,X,ua);i=d+i|0;a=Y+c|0;a=d>>>0>i>>>0?a+1|0:a;d=Fj(M,ra,U,va);i=d+i|0;c=Y+a|0;c=d>>>0>i>>>0?c+1|0:c;a=Fj(K,0,Z,0);i=a+i|0;d=Y+c|0;d=a>>>0>i>>>0?d+1|0:d;a=e>>21;c=(e&2097151)<<11|w>>>21;e=c+i|0;a=a+d|0;a=c>>>0>e>>>0?a+1|0:a;c=e;Aa=c- -1048576|0;i=a-((c>>>0<4293918720)-1|0)|0;t=i;d=Aa&-2097152;e=c-d|0;d=(a-((c>>>0>>0)+i|0)|0)+(g>>21)|0;a=(g&2097151)<<11|o>>>21;e=a+e|0;bb=e;d=a>>>0>e>>>0?d+1|0:d;cb=d;c=Fj(e,d,136657,0);d=c+l|0;a=Y+k|0;Pa=d;A=c>>>0>d>>>0?a+1|0:a;c=Fj(X,ua,ea,0);a=Y;d=c;ga=Fa&2097151;c=Fj(ga,0,P,0);d=d+c|0;a=Y+a|0;a=c>>>0>d>>>0?a+1|0:a;c=d;d=Fj(U,va,ca,ya);e=c+d|0;c=Y+a|0;c=d>>>0>e>>>0?c+1|0:c;a=Fj(Z,0,aa,0);e=a+e|0;d=Y+c|0;d=a>>>0>e>>>0?d+1|0:d;c=Fj(R,0,_,xa);e=c+e|0;a=Y+d|0;a=c>>>0>e>>>0?a+1|0:a;d=Fj(Q,ta,$,0);e=d+e|0;c=Y+a|0;c=d>>>0>e>>>0?c+1|0:c;d=Fj(S,0,ba,0);e=d+e|0;a=Y+c|0;a=d>>>0>e>>>0?a+1|0:a;d=Fj(T,ma,fa,0);e=d+e|0;c=Y+a|0;c=d>>>0>e>>>0?c+1|0:c;a=Fj(W,wa,da,za);e=a+e|0;d=Y+c|0;d=a>>>0>e>>>0?d+1|0:d;ha=Ja&2097151;c=Fj(O,0,ha,0);e=c+e|0;a=Y+d|0;a=c>>>0>e>>>0?a+1|0:a;d=(y[la+23|0]|y[la+24|0]<<8|(y[la+25|0]<<16|y[la+26|0]<<24))>>>5&2097151;e=d+e|0;g=e;e=d>>>0>e>>>0?a+1|0:a;a=Fj(U,va,ea,0);c=Y;d=a;a=Fj(X,ua,ga,Ba);d=d+a|0;c=Y+c|0;c=a>>>0>d>>>0?c+1|0:c;a=Fj(Z,0,ca,ya);i=a+d|0;d=Y+c|0;d=a>>>0>i>>>0?d+1|0:d;c=Fj(_,xa,aa,0);i=c+i|0;a=Y+d|0;a=c>>>0>i>>>0?a+1|0:a;c=Fj(R,0,$,0);d=c+i|0;a=Y+a|0;a=c>>>0>d>>>0?a+1|0:a;c=d;d=Fj(Q,ta,ba,0);i=c+d|0;c=Y+a|0;c=d>>>0>i>>>0?c+1|0:c;a=Fj(S,0,da,za);d=a+i|0;c=Y+c|0;c=a>>>0>d>>>0?c+1|0:c;a=Fj(ha,Ca,T,ma);i=a+d|0;d=Y+c|0;d=a>>>0>i>>>0?d+1|0:d;c=Fj(W,wa,fa,0);i=c+i|0;a=Y+d|0;a=c>>>0>i>>>0?a+1|0:a;c=H&2097151;d=c+i|0;i=d;a=c>>>0>d>>>0?a+1|0:a;q=a;a=d;d=q-((a>>>0<4293918720)-1|0)|0;ia=a- -1048576|0;u=d;a=(d&2097151)<<11|ia>>>21;g=a+g|0;d=(d>>>21|0)+e|0;d=a>>>0>g>>>0?d+1|0:d;o=d;a=F&-2097152;Fa=j-a|0;H=E-((a>>>0>j>>>0)+C|0)|0;c=Fj(L,qa,O,0);a=Y;d=c;c=Fj(N,0,T,ma);d=d+c|0;a=Y+a|0;a=c>>>0>d>>>0?a+1|0:a;c=d;d=Fj(M,ra,P,0);e=c+d|0;c=Y+a|0;c=d>>>0>e>>>0?c+1|0:c;a=Fj(K,0,X,ua);e=a+e|0;d=Y+c|0;d=a>>>0>e>>>0?d+1|0:d;k=e;a=Fj(N,0,W,wa);c=Y;e=a;a=Fj(L,qa,T,ma);e=e+a|0;c=Y+c|0;c=a>>>0>e>>>0?c+1|0:c;a=e;e=Fj(O,0,P,0);j=a+e|0;a=Y+c|0;a=e>>>0>j>>>0?a+1|0:a;c=Fj(M,ra,X,ua);e=c+j|0;a=Y+a|0;a=c>>>0>e>>>0?a+1|0:a;c=e;e=Fj(K,0,U,va);j=c+e|0;c=Y+a|0;c=e>>>0>j>>>0?c+1|0:c;e=j;m=c;a=e;j=c-((a>>>0<4293918720)-1|0)|0;E=a- -1048576|0;l=j;a=j>>21;j=(j&2097151)<<11|E>>>21;k=j+k|0;c=a+d|0;d=k;c=j>>>0>d>>>0?c+1|0:c;k=c;a=d;F=c-((a>>>0<4293918720)-1|0)|0;C=a- -1048576|0;j=F;a=j>>21;F=(j&2097151)<<11|C>>>21;Fa=F+Fa|0;c=a+H|0;Oa=Fa;c=F>>>0>Oa>>>0?c+1|0:c;db=c;H=Fj(Oa,c,470296,0);F=Y;c=C&-2097152;a=k-((c>>>0>d>>>0)+j|0)|0;Ta=d-c|0;Ha=a;c=Fj(Sa,Za,666643,0);j=c+H|0;d=Y+F|0;d=c>>>0>j>>>0?d+1|0:d;c=Fj(Ta,a,654183,0);j=c+j|0;a=Y+d|0;k=j;c=c>>>0>j>>>0?a+1|0:a;d=E&-2097152;a=e-d|0;j=m-((d>>>0>e>>>0)+l|0)|0;e=(t&2097151)<<11|Aa>>>21;l=e+a|0;d=(t>>21)+j|0;gb=l;d=e>>>0>l>>>0?d+1|0:d;Ja=d;hb=g- -1048576|0;j=o-((g>>>0<4293918720)-1|0)|0;e=j;a=Fj(l,d,-997805,-1);d=a+k|0;c=Y+c|0;c=a>>>0>d>>>0?c+1|0:c;g=d+g|0;a=c+o|0;a=d>>>0>g>>>0?a+1|0:a;d=g;c=hb&-2097152;H=d-c|0;F=a-((c>>>0>d>>>0)+e|0)|0;a=Fj(Ta,Ha,470296,0);c=Y;d=a;a=Fj(Oa,db,666643,0);g=d+a|0;d=Y+c|0;d=a>>>0>g>>>0?d+1|0:d;c=Fj(l,Ja,654183,0);g=c+g|0;a=Y+d|0;d=g+i|0;c=q+(c>>>0>g>>>0?a+1|0:a)|0;c=d>>>0>>0?c+1|0:c;a=ia&-2097152;o=d-a|0;j=c-((a>>>0>d>>>0)+u|0)|0;c=Fj(Z,0,ea,0);a=Y;d=c;c=Fj(U,va,ga,Ba);d=d+c|0;a=Y+a|0;a=c>>>0>d>>>0?a+1|0:a;c=Fj(_,xa,ca,ya);d=c+d|0;a=Y+a|0;a=c>>>0>d>>>0?a+1|0:a;c=d;d=Fj($,0,aa,0);g=c+d|0;c=Y+a|0;c=d>>>0>g>>>0?c+1|0:c;a=Fj(R,0,ba,0);g=a+g|0;d=Y+c|0;d=a>>>0>g>>>0?d+1|0:d;a=Fj(Q,ta,da,za);g=a+g|0;c=Y+d|0;c=a>>>0>g>>>0?c+1|0:c;d=Fj(S,0,fa,0);g=d+g|0;a=Y+c|0;a=d>>>0>g>>>0?a+1|0:a;c=Fj(ha,Ca,W,wa);d=c+g|0;a=Y+a|0;a=c>>>0>d>>>0?a+1|0:a;c=d;d=((J&7)<<29|eb>>>3)&2097151;g=c+d|0;i=g;g=d>>>0>g>>>0?a+1|0:a;a=Fj(_,xa,ea,0);c=Y;d=a;a=Fj(Z,0,ga,Ba);k=d+a|0;d=Y+c|0;d=a>>>0>k>>>0?d+1|0:d;c=Fj($,0,ca,ya);k=c+k|0;a=Y+d|0;a=c>>>0>k>>>0?a+1|0:a;d=Fj(aa,0,ba,0);k=d+k|0;c=Y+a|0;c=d>>>0>k>>>0?c+1|0:c;d=Fj(R,0,da,za);k=d+k|0;a=Y+c|0;a=d>>>0>k>>>0?a+1|0:a;d=Fj(Q,ta,fa,0);k=d+k|0;c=Y+a|0;c=d>>>0>k>>>0?c+1|0:c;a=Fj(ha,Ca,S,0);k=a+k|0;d=Y+c|0;c=k;a=a>>>0>c>>>0?d+1|0:d;c=Ea>>>6&2097151;d=k+c|0;E=d;a=c>>>0>d>>>0?a+1|0:a;m=a;a=d;d=m-((a>>>0<4293918720)-1|0)|0;C=a- -1048576|0;B=d;a=(d&2097151)<<11|C>>>21;i=a+i|0;d=(d>>>21|0)+g|0;g=i;d=a>>>0>g>>>0?d+1|0:d;l=d;a=g;d=d-((a>>>0<4293918720)-1|0)|0;t=a- -1048576|0;k=d;c=d>>>21|0;d=(d&2097151)<<11|t>>>21;i=d+o|0;a=c+j|0;q=i;a=d>>>0>i>>>0?a+1|0:a;j=a;a=i;d=j-((a>>>0<4293918720)-1|0)|0;u=a- -1048576|0;w=d;a=(d&2097151)<<11|u>>>21;i=a+H|0;d=(d>>21)+F|0;d=a>>>0>i>>>0?d+1|0:d;J=i+Pa|0;c=d;a=c+A|0;a=i>>>0>J>>>0?a+1|0:a;d=J;o=c;c=i;o=o-((c>>>0<4293918720)-1|0)|0;ib=c- -1048576|0;c=d;d=ib&-2097152;jb=c-d|0;i=o;I=a-(i+(c>>>0>>0)|0)|0;a=Fj(bb,cb,-997805,-1);d=a+q|0;c=Y+j|0;Aa=d;o=a>>>0>d>>>0?c+1|0:c;c=Fj(gb,Ja,470296,0);a=Y;d=c;c=Fj(Ta,Ha,666643,0);d=d+c|0;a=Y+a|0;a=c>>>0>d>>>0?a+1|0:a;c=d+g|0;a=a+l|0;a=c>>>0>>0?a+1|0:a;d=c;c=t&-2097152;t=d-c|0;A=a-((c>>>0>d>>>0)+k|0)|0;a=Fj(gb,Ja,666643,0);d=a+E|0;c=Y+m|0;q=d;j=a>>>0>d>>>0?c+1|0:c;c=Fj($,0,ea,0);a=Y;d=c;c=Fj(_,xa,ga,Ba);d=d+c|0;a=Y+a|0;a=c>>>0>d>>>0?a+1|0:a;c=Fj(ba,0,ca,ya);d=c+d|0;a=Y+a|0;a=c>>>0>d>>>0?a+1|0:a;c=d;d=Fj(aa,0,da,za);g=c+d|0;c=Y+a|0;c=d>>>0>g>>>0?c+1|0:c;a=Fj(R,0,fa,0);g=a+g|0;d=Y+c|0;d=a>>>0>g>>>0?d+1|0:d;a=Fj(ha,Ca,Q,ta);g=a+g|0;c=Y+d|0;c=a>>>0>g>>>0?c+1|0:c;d=((pa&1)<<31|La>>>1)&2097151;g=d+g|0;a=c;k=g;g=d>>>0>g>>>0?a+1|0:a;c=Fj(ba,0,ea,0);a=Y;d=c;c=Fj($,0,ga,Ba);d=d+c|0;a=Y+a|0;a=c>>>0>d>>>0?a+1|0:a;c=d;d=Fj(ca,ya,da,za);l=c+d|0;c=Y+a|0;c=d>>>0>l>>>0?c+1|0:c;a=Fj(aa,0,fa,0);d=a+l|0;c=Y+c|0;c=a>>>0>d>>>0?c+1|0:c;a=Fj(ha,Ca,R,0);l=a+d|0;d=Y+c|0;c=l;a=a>>>0>c>>>0?d+1|0:d;c=Da>>>4&2097151;d=l+c|0;m=d;a=c>>>0>d>>>0?a+1|0:a;ia=a;a=d;d=ia-((a>>>0<4293918720)-1|0)|0;eb=a- -1048576|0;Da=d;a=(d&2097151)<<11|eb>>>21;k=a+k|0;d=(d>>>21|0)+g|0;l=k;d=a>>>0>k>>>0?d+1|0:d;pa=d;a=k;d=d-((a>>>0<4293918720)-1|0)|0;Pa=a- -1048576|0;Ea=d;c=d>>>21|0;d=(d&2097151)<<11|Pa>>>21;g=d+q|0;a=c+j|0;c=g;d=d>>>0>c>>>0?a+1|0:a;a=C&-2097152;J=d-((a>>>0>c>>>0)+B|0)|0;k=c-a|0;a=k;d=J-((a>>>0<4293918720)-1|0)|0;Fa=a- -1048576|0;E=d;c=d>>21;a=(d&2097151)<<11|Fa>>>21;d=a+t|0;c=c+A|0;H=d;c=a>>>0>d>>>0?c+1|0:c;C=c;a=d;g=c-((a>>>0<4293918720)-1|0)|0;F=a- -1048576|0;t=g;a=ka&-2097152;d=G-((a>>>0>h>>>0)+z|0)|0;Ua=h-a|0;La=d;c=g>>21;g=(g&2097151)<<11|F>>>21;h=g+Aa|0;a=c+o|0;a=g>>>0>h>>>0?a+1|0:a;g=Fj($a,ab,136657,0);c=u&-2097152;j=g+(h-c|0)|0;c=Y+(a-((c>>>0>h>>>0)+w|0)|0)|0;c=g>>>0>j>>>0?c+1|0:c;d=Fj(Ua,d,-683901,-1);g=d+j|0;a=Y+c|0;j=g;a=d>>>0>g>>>0?a+1|0:a;A=a;a=g;d=A-((a>>>0<4293918720)-1|0)|0;ka=a- -1048576|0;q=d;c=d>>21;a=(d&2097151)<<11|ka>>>21;d=a+jb|0;c=c+I|0;h=d;c=a>>>0>d>>>0?c+1|0:c;u=c;a=d;d=c-((a>>>0<4293918720)-1|0)|0;G=a- -1048576|0;B=d;Aa=(d&2097151)<<11|G>>>21;w=d>>21;c=Fj(P,0,ea,0);a=Y;d=c;c=Fj(L,qa,ga,Ba);d=d+c|0;a=Y+a|0;a=c>>>0>d>>>0?a+1|0:a;c=Fj(X,ua,ca,ya);g=c+d|0;d=Y+a|0;d=c>>>0>g>>>0?d+1|0:d;a=Fj(U,va,aa,0);g=a+g|0;c=Y+d|0;c=a>>>0>g>>>0?c+1|0:c;d=Fj(R,0,Z,0);g=d+g|0;a=Y+c|0;a=d>>>0>g>>>0?a+1|0:a;d=Fj(Q,ta,_,xa);g=d+g|0;c=Y+a|0;c=d>>>0>g>>>0?c+1|0:c;d=Fj(S,0,$,0);g=d+g|0;a=Y+c|0;a=d>>>0>g>>>0?a+1|0:a;c=Fj(T,ma,da,za);g=c+g|0;d=Y+a|0;d=c>>>0>g>>>0?d+1|0:d;a=Fj(W,wa,ba,0);g=a+g|0;c=Y+d|0;c=a>>>0>g>>>0?c+1|0:c;d=Fj(O,0,fa,0);g=d+g|0;a=Y+c|0;a=d>>>0>g>>>0?a+1|0:a;d=Fj(ha,Ca,M,ra);g=d+g|0;c=Y+a|0;c=d>>>0>g>>>0?c+1|0:c;a=sa(la+26|0);d=Y;d=((d&3)<<30|a>>>2)&2097151;g=d+g|0;a=c;z=g;a=d>>>0>g>>>0?a+1|0:a;g=a;a=Fj(Sa,Za,470296,0);c=Y;d=a;a=Fj(Ma,Xa,666643,0);I=d+a|0;d=Y+c|0;d=a>>>0>I>>>0?d+1|0:d;a=Fj(Oa,db,654183,0);I=a+I|0;c=Y+d|0;c=a>>>0>I>>>0?c+1|0:c;a=Fj(Ta,Ha,-997805,-1);d=a+I|0;c=Y+c|0;c=a>>>0>d>>>0?c+1|0:c;a=d;d=Fj(gb,Ja,136657,0);I=a+d|0;a=Y+c|0;a=d>>>0>I>>>0?a+1|0:a;c=I;d=c+z|0;a=a+g|0;a=c>>>0>d>>>0?a+1|0:a;c=d;d=a;a=z;o=g-((a>>>0<4293918720)-1|0)|0;kb=a- -1048576|0;g=o;o=c;c=e>>>21|0;a=(e&2097151)<<11|hb>>>21;e=o+a|0;d=c+d|0;d=a>>>0>e>>>0?d+1|0:d;a=kb&-2097152;c=e-a|0;z=Fj(bb,cb,-683901,-1);I=c+z|0;e=d-((a>>>0>e>>>0)+g|0)|0;a=e+Y|0;a=z>>>0>I>>>0?a+1|0:a;z=I;d=a;a=c;o=e-((a>>>0<4293918720)-1|0)|0;lb=a- -1048576|0;e=o;c=i>>21;a=(i&2097151)<<11|ib>>>21;i=a+z|0;d=c+d|0;d=a>>>0>i>>>0?d+1|0:d;a=lb&-2097152;c=i-a|0;z=c;Aa=c+Aa|0;i=d-((a>>>0>i>>>0)+e|0)|0;a=i+w|0;d=Aa;nb=c- -1048576|0;o=i-((c>>>0<4293918720)-1|0)|0;i=o;c=d;d=nb&-2097152;sb=c-d|0;hb=(z>>>0>c>>>0?a+1|0:a)-((c>>>0>>0)+i|0)|0;a=G&-2097152;ib=h-a|0;jb=u-((a>>>0>h>>>0)+B|0)|0;a=ka&-2097152;I=j-a|0;Aa=A-((a>>>0>j>>>0)+q|0)|0;c=Fj(bb,cb,654183,0);d=c+H|0;a=Y+C|0;a=c>>>0>d>>>0?a+1|0:a;h=d;c=F&-2097152;d=Fj($a,ab,-997805,-1);j=(h-c|0)+d|0;c=Y+(a-((c>>>0>h>>>0)+t|0)|0)|0;c=d>>>0>j>>>0?c+1|0:c;d=Fj(Ua,La,136657,0);h=d+j|0;a=Y+c|0;ka=h;q=d>>>0>h>>>0?a+1|0:a;a=ja&-2097152;G=n-a|0;t=Ia-((a>>>0>n>>>0)+D|0)|0;a=Fj(Ma,Xa,-997805,-1);c=Y;d=a;a=Fj(Ra,Ya,654183,0);d=d+a|0;c=Y+c|0;c=a>>>0>d>>>0?c+1|0:c;a=Fj(Sa,Za,136657,0);d=a+d|0;c=Y+c|0;c=a>>>0>d>>>0?c+1|0:c;a=d;d=Fj(Oa,db,-683901,-1);h=a+d|0;a=Y+c|0;c=h+r|0;d=Qa+(d>>>0>h>>>0?a+1|0:a)|0;d=c>>>0>>0?d+1|0:d;a=na&-2097152;A=c-a|0;r=d-((a>>>0>c>>>0)+Ka|0)|0;a=Fj(Ma,Xa,654183,0);c=Y;d=a;a=Fj(Ra,Ya,470296,0);d=d+a|0;c=Y+c|0;c=a>>>0>d>>>0?c+1|0:c;a=d;d=Fj(Sa,Za,-997805,-1);h=a+d|0;a=Y+c|0;c=h+s|0;d=Va+(d>>>0>h>>>0?a+1|0:a)|0;a=Fj(Oa,db,136657,0);h=a+c|0;c=Y+(c>>>0>>0?d+1|0:d)|0;c=a>>>0>h>>>0?c+1|0:c;d=Fj(Ta,Ha,-683901,-1);h=d+h|0;a=Y+c|0;a=d>>>0>h>>>0?a+1|0:a;d=h;c=fb&-2097152;n=d-c|0;h=a-((c>>>0>d>>>0)+Wa|0)|0;c=Fj(L,qa,ea,0);a=Y;d=c;c=Fj(N,0,ga,Ba);d=d+c|0;a=Y+a|0;a=c>>>0>d>>>0?a+1|0:a;c=d;d=Fj(P,0,ca,ya);j=c+d|0;c=Y+a|0;c=d>>>0>j>>>0?c+1|0:c;d=Fj(X,ua,aa,0);j=d+j|0;a=Y+c|0;a=d>>>0>j>>>0?a+1|0:a;c=Fj(R,0,U,va);j=c+j|0;d=Y+a|0;d=c>>>0>j>>>0?d+1|0:d;a=Fj(Q,ta,Z,0);j=a+j|0;c=Y+d|0;c=a>>>0>j>>>0?c+1|0:c;d=Fj(S,0,_,xa);j=d+j|0;a=Y+c|0;a=d>>>0>j>>>0?a+1|0:a;d=Fj(T,ma,ba,0);j=d+j|0;c=Y+a|0;c=d>>>0>j>>>0?c+1|0:c;d=Fj(W,wa,$,0);j=d+j|0;a=Y+c|0;a=d>>>0>j>>>0?a+1|0:a;c=Fj(O,0,da,za);j=c+j|0;d=Y+a|0;d=c>>>0>j>>>0?d+1|0:d;a=Fj(ha,Ca,K,0);j=a+j|0;c=Y+d|0;c=a>>>0>j>>>0?c+1|0:c;d=Fj(M,ra,fa,0);j=d+j|0;a=Y+c|0;a=d>>>0>j>>>0?a+1|0:a;d=(y[la+28|0]|y[la+29|0]<<8|(y[la+30|0]<<16|y[la+31|0]<<24))>>>7|0;j=d+j|0;c=d>>>0>j>>>0?a+1|0:a;d=g>>>21|0;g=(g&2097151)<<11|kb>>>21;j=g+j|0;a=c+d|0;a=g>>>0>j>>>0?a+1|0:a;u=a;a=j;c=u-((a>>>0<4293918720)-1|0)|0;z=a- -1048576|0;B=c;d=c>>21;c=(c&2097151)<<11|z>>>21;g=c+n|0;a=d+h|0;h=g;a=c>>>0>g>>>0?a+1|0:a;w=a;a=g;c=w-((a>>>0<4293918720)-1|0)|0;C=a- -1048576|0;o=c;d=c>>21;c=(c&2097151)<<11|C>>>21;g=c+A|0;a=d+r|0;a=c>>>0>g>>>0?a+1|0:a;s=a;a=g;c=s-((a>>>0<4293918720)-1|0)|0;A=a- -1048576|0;r=c;d=c>>21;c=(c&2097151)<<11|A>>>21;n=c+G|0;a=d+t|0;na=n;a=c>>>0>n>>>0?a+1|0:a;D=a;a=Fj(n,a,-683901,-1);d=a+ka|0;c=Y+q|0;q=d;n=a>>>0>d>>>0?c+1|0:c;a=A&-2097152;r=s-((a>>>0>g>>>0)+r|0)|0;ja=g-a|0;G=r;c=Fj(bb,cb,470296,0)+k|0;a=J+Y|0;a=c>>>0>>0?a+1|0:a;g=c;d=Fa&-2097152;c=Fj($a,ab,654183,0);k=(g-d|0)+c|0;d=Y+(a-((d>>>0>g>>>0)+E|0)|0)|0;a=Fj(Ua,La,-997805,-1);g=a+k|0;c=Y+(c>>>0>k>>>0?d+1|0:d)|0;c=a>>>0>g>>>0?c+1|0:c;d=Fj(na,D,136657,0);g=d+g|0;a=Y+c|0;a=d>>>0>g>>>0?a+1|0:a;d=Fj(ja,r,-683901,-1);g=d+g|0;c=Y+a|0;c=d>>>0>g>>>0?c+1|0:c;s=c;a=g;d=c-((a>>>0<4293918720)-1|0)|0;t=a- -1048576|0;r=d;a=d>>21;c=(d&2097151)<<11|t>>>21;d=c+q|0;a=a+n|0;a=c>>>0>d>>>0?a+1|0:a;n=a;a=d;A=n-((a>>>0<4293918720)-1|0)|0;q=a- -1048576|0;k=A;a=k>>21;A=(k&2097151)<<11|q>>>21;E=A+I|0;c=a+Aa|0;F=E;A=A>>>0>E>>>0?c+1|0:c;a=q&-2097152;ka=d-a|0;Va=n-((a>>>0>d>>>0)+k|0)|0;a=t&-2097152;Ka=g-a|0;Ia=s-((a>>>0>g>>>0)+r|0)|0;a=Fj(bb,cb,666643,0);c=Pa&-2097152;g=a+(l-c|0)|0;d=Y+(pa-((c>>>0>l>>>0)+Ea|0)|0)|0;d=a>>>0>g>>>0?d+1|0:d;a=Fj($a,ab,470296,0);g=a+g|0;c=Y+d|0;c=a>>>0>g>>>0?c+1|0:c;d=Fj(Ua,La,654183,0);g=d+g|0;a=Y+c|0;r=g;g=d>>>0>g>>>0?a+1|0:a;a=C&-2097152;n=h-a|0;k=w-((a>>>0>h>>>0)+o|0)|0;c=Fj(Ma,Xa,470296,0);a=Y;d=c;c=Fj(Ra,Ya,666643,0);d=d+c|0;a=Y+a|0;a=c>>>0>d>>>0?a+1|0:a;c=d;d=Fj(Sa,Za,654183,0);h=c+d|0;c=Y+a|0;c=d>>>0>h>>>0?c+1|0:c;d=Fj(Oa,db,-997805,-1);h=d+h|0;a=Y+c|0;a=d>>>0>h>>>0?a+1|0:a;c=Fj(Ta,Ha,136657,0);h=c+h|0;d=Y+a|0;d=c>>>0>h>>>0?d+1|0:d;a=Fj(gb,Ja,-683901,-1);h=a+h|0;c=Y+d|0;d=h+j|0;a=u+(a>>>0>h>>>0?c+1|0:c)|0;a=d>>>0>>0?a+1|0:a;h=d;d=z&-2097152;c=h-d|0;d=a-((d>>>0>h>>>0)+B|0)|0;h=c;a=e>>21;c=(e&2097151)<<11|lb>>>21;e=h+c|0;a=a+d|0;l=e;a=c>>>0>e>>>0?a+1|0:a;w=a;a=e;d=w-((a>>>0<4293918720)-1|0)|0;Ea=a- -1048576|0;o=d;c=(d&2097151)<<11|Ea>>>21;e=c+n|0;d=(d>>21)+k|0;H=e;d=c>>>0>e>>>0?d+1|0:d;z=d;a=Fj(e,d,-683901,-1);d=a+r|0;c=Y+g|0;c=a>>>0>d>>>0?c+1|0:c;a=d;d=Fj(na,D,-997805,-1);e=a+d|0;a=Y+c|0;a=d>>>0>e>>>0?a+1|0:a;d=Fj(ja,G,136657,0);e=d+e|0;c=Y+a|0;B=e;e=d>>>0>e>>>0?c+1|0:c;c=Fj(da,za,ea,0);a=Y;d=c;c=Fj(ba,0,ga,Ba);d=d+c|0;a=Y+a|0;a=c>>>0>d>>>0?a+1|0:a;c=Fj(ca,ya,fa,0);g=c+d|0;d=Y+a|0;d=c>>>0>g>>>0?d+1|0:d;a=Fj(ha,Ca,aa,0);g=a+g|0;c=Y+d|0;d=g;a=a>>>0>d>>>0?c+1|0:c;c=Ga>>>7&2097151;d=c+d|0;j=d;d=c>>>0>d>>>0?a+1|0:a;a=Fj(ea,0,fa,0);c=Y;g=a;a=Fj(da,za,ga,Ba);g=g+a|0;c=Y+c|0;c=a>>>0>g>>>0?c+1|0:c;a=Fj(ha,Ca,ca,ya);g=a+g|0;c=Y+c|0;c=a>>>0>g>>>0?c+1|0:c;a=g;g=((rb&3)<<30|qb>>>2)&2097151;h=a+g|0;a=c;k=h;a=g>>>0>h>>>0?a+1|0:a;g=a;a=h;h=g-((a>>>0<4293918720)-1|0)|0;pa=a- -1048576|0;q=h;c=h>>>21|0;a=(h&2097151)<<11|pa>>>21;h=a+j|0;c=c+d|0;j=h;c=a>>>0>h>>>0?c+1|0:c;u=c;a=h;d=c-((a>>>0<4293918720)-1|0)|0;J=a- -1048576|0;s=d;c=d>>>21|0;d=m+((d&2097151)<<11|J>>>21)|0;a=c+ia|0;a=d>>>0>>0?a+1|0:a;h=d;c=eb&-2097152;d=Fj($a,ab,666643,0);m=(h-c|0)+d|0;c=Y+(a-((c>>>0>h>>>0)+Da|0)|0)|0;c=d>>>0>m>>>0?c+1|0:c;a=Fj(Ua,La,470296,0);d=a+m|0;c=Y+c|0;c=a>>>0>d>>>0?c+1|0:c;a=d;d=Fj(H,z,136657,0);h=a+d|0;a=Y+c|0;a=d>>>0>h>>>0?a+1|0:a;c=Fj(na,D,654183,0);d=c+h|0;a=Y+a|0;a=c>>>0>d>>>0?a+1|0:a;c=Fj(ja,G,-997805,-1);h=c+d|0;d=Y+a|0;E=h;d=c>>>0>h>>>0?d+1|0:d;r=d;a=h;d=d-((a>>>0<4293918720)-1|0)|0;C=a- -1048576|0;n=d;a=d>>21;d=(d&2097151)<<11|C>>>21;h=d+B|0;c=a+e|0;c=d>>>0>h>>>0?c+1|0:c;e=c;a=h;d=c-((a>>>0<4293918720)-1|0)|0;t=a- -1048576|0;m=d;c=(d&2097151)<<11|t>>>21;B=c+Ka|0;d=(d>>21)+Ia|0;Wa=B;B=c>>>0>B>>>0?d+1|0:d;d=i>>21;a=(i&2097151)<<11|nb>>>21;c=Ea&-2097152;i=a+(l-c|0)|0;c=d+(w-((c>>>0>l>>>0)+o|0)|0)|0;c=a>>>0>i>>>0?c+1|0:c;w=c;a=i;c=c-((a>>>0<4293918720)-1|0)|0;Ea=a- -1048576|0;o=c;d=c>>21;Da=d;Ga=(c&2097151)<<11|Ea>>>21;c=Fj(Ga,d,-683901,-1);d=c+h|0;a=Y+e|0;a=c>>>0>d>>>0?a+1|0:a;c=t&-2097152;Qa=d-c|0;Ka=a-((c>>>0>d>>>0)+m|0)|0;a=Fj(Ga,Da,136657,0);d=a+E|0;c=Y+r|0;c=a>>>0>d>>>0?c+1|0:c;a=C&-2097152;Ia=d-a|0;ia=c-((a>>>0>d>>>0)+n|0)|0;a=Fj(Ua,La,666643,0);c=J&-2097152;d=a+(j-c|0)|0;c=Y+(u-((c>>>0>j>>>0)+s|0)|0)|0;c=a>>>0>d>>>0?c+1|0:c;a=d;d=Fj(H,z,-997805,-1);e=a+d|0;a=Y+c|0;a=d>>>0>e>>>0?a+1|0:a;c=Fj(na,D,470296,0);e=c+e|0;d=Y+a|0;d=c>>>0>e>>>0?d+1|0:d;a=Fj(ja,G,654183,0);e=a+e|0;c=Y+d|0;u=e;l=a>>>0>e>>>0?c+1|0:c;h=g;c=Fj(ha,Ca,ea,0);a=Y;d=c;c=Fj(fa,0,ga,Ba);d=d+c|0;a=Y+a|0;a=c>>>0>d>>>0?a+1|0:a;c=d;d=pb>>>5&2097151;e=c+d|0;c=d>>>0>e>>>0?a+1|0:a;j=e;d=ob&2097151;e=Fj(ha,Ca,ga,Ba)+d|0;a=Y;g=e;a=d>>>0>e>>>0?a+1|0:a;s=a;a=e;e=s-((a>>>0<4293918720)-1|0)|0;J=a- -1048576|0;r=e;d=e>>>21|0;a=(e&2097151)<<11|J>>>21;e=a+j|0;c=c+d|0;c=a>>>0>e>>>0?c+1|0:c;n=c;a=e;c=c-((a>>>0<4293918720)-1|0)|0;E=a- -1048576|0;m=c;d=c>>>21|0;c=(c&2097151)<<11|E>>>21;j=c+k|0;a=d+h|0;a=c>>>0>j>>>0?a+1|0:a;d=Fj(H,z,654183,0);h=j;c=pa&-2097152;j=d+(h-c|0)|0;c=Y+(a-((q&16383)+(c>>>0>h>>>0)|0)|0)|0;a=Fj(na,D,666643,0);h=a+j|0;d=Y+(d>>>0>j>>>0?c+1|0:c)|0;d=a>>>0>h>>>0?d+1|0:d;c=Fj(ja,G,470296,0);h=c+h|0;a=Y+d|0;C=h;a=c>>>0>h>>>0?a+1|0:a;k=a;a=h;c=k-((a>>>0<4293918720)-1|0)|0;t=a- -1048576|0;j=c;d=c>>21;c=(c&2097151)<<11|t>>>21;h=c+u|0;a=d+l|0;q=h;a=c>>>0>h>>>0?a+1|0:a;c=a;a=h;l=c-((a>>>0<4293918720)-1|0)|0;u=a- -1048576|0;h=l;d=h>>21;l=(h&2097151)<<11|u>>>21;pa=l+Ia|0;a=d+ia|0;D=pa;l=l>>>0>D>>>0?a+1|0:a;a=Fj(Ga,Da,-997805,-1);d=a+q|0;c=Y+c|0;c=a>>>0>d>>>0?c+1|0:c;a=u&-2097152;ia=d-a|0;pa=c-((a>>>0>d>>>0)+h|0)|0;a=Fj(Ga,Da,654183,0);d=a+C|0;c=Y+k|0;c=a>>>0>d>>>0?c+1|0:c;a=t&-2097152;q=d-a|0;u=c-((a>>>0>d>>>0)+j|0)|0;c=Fj(H,z,470296,0);a=E&-2097152;d=c+(e-a|0)|0;a=Y+(n-((m&16383)+(a>>>0>e>>>0)|0)|0)|0;a=c>>>0>d>>>0?a+1|0:a;c=Fj(ja,G,666643,0);e=c+d|0;d=Y+a|0;d=c>>>0>e>>>0?d+1|0:d;h=e;a=Fj(H,z,666643,0);c=J&-2097152;e=a+(g-c|0)|0;c=Y+(s-((r&4095)+(c>>>0>g>>>0)|0)|0)|0;c=a>>>0>e>>>0?c+1|0:c;k=c;a=e;g=c-((a>>>0<4293918720)-1|0)|0;r=a- -1048576|0;j=g;a=g>>21;c=(g&2097151)<<11|r>>>21;g=c+h|0;d=a+d|0;n=g;d=c>>>0>g>>>0?d+1|0:d;h=d;a=g;d=d-((a>>>0<4293918720)-1|0)|0;m=a- -1048576|0;g=d;a=d>>21;d=(d&2097151)<<11|m>>>21;s=d+q|0;c=a+u|0;c=d>>>0>s>>>0?c+1|0:c;d=c;c=Fj(Ga,Da,470296,0);n=c+n|0;a=Y+h|0;a=c>>>0>n>>>0?a+1|0:a;h=m&-2097152;c=n-h|0;h=a-((h>>>0>n>>>0)+g|0)|0;m=c;a=Fj(Ga,Da,666643,0);c=r&-2097152;g=a+(e-c|0)|0;c=Y+(k-((c>>>0>e>>>0)+j|0)|0)|0;c=a>>>0>g>>>0?c+1|0:c;e=g;a=c>>21;c=(c&2097151)<<11|e>>>21;e=m+c|0;a=a+h|0;a=c>>>0>e>>>0?a+1|0:a;C=e;c=a>>21;a=(a&2097151)<<11|e>>>21;e=a+s|0;d=c+d|0;h=e;c=e;d=a>>>0>c>>>0?d+1|0:d;a=d>>21;d=(d&2097151)<<11|c>>>21;e=d+ia|0;c=a+pa|0;k=e;a=e;c=d>>>0>a>>>0?c+1|0:c;d=c>>21;c=(c&2097151)<<11|a>>>21;e=c+D|0;a=d+l|0;m=e;d=e;a=c>>>0>d>>>0?a+1|0:a;c=a>>21;a=(a&2097151)<<11|d>>>21;d=a+Qa|0;c=c+Ka|0;c=a>>>0>d>>>0?c+1|0:c;t=d;a=c>>21;c=(c&2097151)<<11|d>>>21;d=c+Wa|0;a=a+B|0;a=c>>>0>d>>>0?a+1|0:a;q=d;c=a>>21;a=(a&2097151)<<11|d>>>21;e=a+ka|0;d=c+Va|0;u=e;c=e;d=a>>>0>c>>>0?d+1|0:d;a=d>>21;d=(d&2097151)<<11|c>>>21;e=d+F|0;c=a+A|0;B=e;a=e;c=d>>>0>a>>>0?c+1|0:c;d=c>>21;c=(c&2097151)<<11|a>>>21;e=c+ib|0;a=d+jb|0;s=e;d=e;a=c>>>0>d>>>0?a+1|0:a;c=a>>21;a=(a&2097151)<<11|d>>>21;d=a+sb|0;c=c+hb|0;c=a>>>0>d>>>0?c+1|0:c;r=d;a=c>>21;e=(c&2097151)<<11|d>>>21;d=Ea&-2097152;c=i-d|0;e=e+c|0;d=(w-((d>>>0>i>>>0)+o|0)|0)+a|0;n=e;a=e;d=c>>>0>a>>>0?d+1|0:d;w=(d&2097151)<<11|a>>>21;c=d>>21;l=c;a=g&2097151;d=Fj(w,c,666643,0)+a|0;c=Y;j=d;c=a>>>0>d>>>0?c+1|0:c;e=c;v[f|0]=d;v[f+1|0]=(c&255)<<24|d>>>8;g=f;c=C&2097151;d=Fj(w,l,470296,0)+c|0;a=Y;a=c>>>0>d>>>0?a+1|0:a;o=d;d=e;c=d>>21;i=(d&2097151)<<11|j>>>21;o=o+i|0;d=a+c|0;d=i>>>0>o>>>0?d+1|0:d;i=o;v[g+4|0]=(d&2047)<<21|i>>>11;a=d;d=i;v[g+3|0]=(a&7)<<29|d>>>3;d=h&2097151;h=Fj(w,l,654183,0)+d|0;c=Y;c=d>>>0>h>>>0?c+1|0:c;d=h;h=(a&2097151)<<11|i>>>21;o=d+h|0;a=(a>>21)+c|0;a=h>>>0>o>>>0?a+1|0:a;h=o;c=a;v[g+6|0]=(a&63)<<26|h>>>6;g=0;d=((e&65535)<<16|j>>>16)&31;j=i&2097151;a=j;v[f+2|0]=d|a<<5;e=f;d=k&2097151;i=Fj(w,l,-997805,-1)+d|0;a=Y;a=d>>>0>i>>>0?a+1|0:a;d=a;a=c>>21;c=(c&2097151)<<11|h>>>21;i=c+i|0;d=a+d|0;k=i;d=c>>>0>i>>>0?d+1|0:d;v[e+9|0]=(d&511)<<23|i>>>9;a=d;d=i;v[e+8|0]=(a&1)<<31|d>>>1;i=0;h=h&2097151;d=h;v[e+5|0]=(g&524287)<<13|j>>>19|d<<2;d=m&2097151;g=Fj(w,l,136657,0)+d|0;c=Y;c=d>>>0>g>>>0?c+1|0:c;d=a>>21;a=(a&2097151)<<11|k>>>21;g=a+g|0;c=c+d|0;j=g;c=a>>>0>g>>>0?c+1|0:c;v[e+12|0]=(c&4095)<<20|g>>>12;d=c;a=c;c=g;v[e+11|0]=(a&15)<<28|c>>>4;g=0;m=k&2097151;c=m;v[e+7|0]=(i&16383)<<18|h>>>14|c<<7;c=t&2097151;i=Fj(w,l,-683901,-1)+c|0;a=Y;a=c>>>0>i>>>0?a+1|0:a;c=d>>21;d=(d&2097151)<<11|j>>>21;i=d+i|0;a=a+c|0;h=i;a=d>>>0>h>>>0?a+1|0:a;c=a;v[e+14|0]=(a&127)<<25|h>>>7;i=0;k=j&2097151;d=k;v[e+10|0]=(g&131071)<<15|m>>>17|d<<4;a=a>>21;c=(c&2097151)<<11|h>>>21;j=c+(q&2097151)|0;d=c>>>0>j>>>0?a+1|0:a;v[e+17|0]=(d&1023)<<22|j>>>10;a=d;d=j;v[e+16|0]=(a&3)<<30|d>>>2;l=h&2097151;d=l;v[e+13|0]=(i&1048575)<<12|k>>>20|d<<1;c=a;a=a>>21;d=(c&2097151)<<11|j>>>21;h=d+(u&2097151)|0;c=d>>>0>h>>>0?a+1|0:a;v[e+20|0]=(c&8191)<<19|h>>>13;a=c;c=h;v[e+19|0]=(a&31)<<27|c>>>5;k=j&2097151;c=k;v[e+15|0]=(g&32767)<<17|l>>>15|c<<6;c=a;a=a>>21;e=(c&2097151)<<11|h>>>21;l=e+(B&2097151)|0;c=e>>>0>l>>>0?a+1|0:a;v[f+21|0]=l;a=h;v[f+18|0]=(i&262143)<<14|k>>>18|a<<3;e=c;a=c;c=l;v[f+22|0]=(a&255)<<24|c>>>8;g=f;c=a>>21;a=(a&2097151)<<11|l>>>21;h=a+(s&2097151)|0;d=a>>>0>h>>>0?c+1|0:c;v[g+25|0]=(d&2047)<<21|h>>>11;a=d;d=h;v[g+24|0]=(a&7)<<29|d>>>3;d=g;g=(a&2097151)<<11|h>>>21;j=g+(r&2097151)|0;c=a>>21;i=j;c=g>>>0>i>>>0?c+1|0:c;a=c;v[d+27|0]=(a&63)<<26|i>>>6;g=0;j=h&2097151;c=j;v[d+23|0]=((e&65535)<<16|l>>>16)&31|c<<5;c=a;a=a>>21;c=(c&2097151)<<11|i>>>21;e=c+(n&2097151)|0;a=c>>>0>e>>>0?a+1|0:a;d=e;v[f+31|0]=(a&131071)<<15|d>>>17;v[f+30|0]=(a&511)<<23|d>>>9;v[f+29|0]=(a&1)<<31|d>>>1;a=0;i=i&2097151;h=i;v[f+26|0]=(g&524287)<<13|j>>>19|h<<2;v[f+28|0]=(a&16383)<<18|h>>>14|d<<7;oa(p+288|0,64);oa(p+224|0,64);if(b){x[b>>2]=64;x[b+4>>2]=0}V=p+560|0;return 0}function Ga(a,b,c){var d=0,e=0,f=0,g=0,h=0,i=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0,r=0,s=0,t=0,u=0,w=0,x=0,z=0,A=0,B=0,C=0,D=0,E=0,F=0,G=0,H=0,I=0,J=0,K=0,L=0,M=0,N=0,O=0,P=0,Q=0,R=0,S=0,T=0,U=0,V=0,W=0,X=0,Z=0,_=0,$=0,aa=0,ba=0,ca=0,da=0,ea=0,fa=0,ga=0,ha=0,ia=0,ja=0,ka=0,la=0,ma=0,na=0,oa=0,pa=0,qa=0,ra=0,ta=0,ua=0,va=0,wa=0,xa=0,ya=0,za=0,Aa=0,Ba=0,Ca=0,Da=0,Ea=0,Fa=0,Ga=0,Ha=0,Ia=0,Ja=0,Ka=0,La=0,Ma=0,Na=0,Oa=0,Pa=0,Qa=0,Ra=0,Sa=0,Ta=0,Ua=0,Va=0,Wa=0,Xa=0,Ya=0,Za=0,_a=0;u=sa(b);f=y[b+2|0]|y[b+3|0]<<8|(y[b+4|0]<<16|y[b+5|0]<<24);z=sa(b+5|0);k=Y;i=y[b+7|0]|y[b+8|0]<<8|(y[b+9|0]<<16|y[b+10|0]<<24);j=y[b+10|0]|y[b+11|0]<<8|(y[b+12|0]<<16|y[b+13|0]<<24);M=sa(b+13|0);h=Y;l=y[b+15|0]|y[b+16|0]<<8|(y[b+17|0]<<16|y[b+18|0]<<24);N=sa(b+18|0);r=Y;C=sa(b+21|0);e=y[b+23|0]|y[b+24|0]<<8|(y[b+25|0]<<16|y[b+26|0]<<24);H=sa(b+26|0);d=Y;g=y[b+28|0]|y[b+29|0]<<8|(y[b+30|0]<<16|y[b+31|0]<<24);I=sa(c);p=y[c+2|0]|y[c+3|0]<<8|(y[c+4|0]<<16|y[c+5|0]<<24);J=sa(c+5|0);m=Y;o=y[c+7|0]|y[c+8|0]<<8|(y[c+9|0]<<16|y[c+10|0]<<24);s=y[c+10|0]|y[c+11|0]<<8|(y[c+12|0]<<16|y[c+13|0]<<24);w=sa(c+13|0);t=Y;K=y[c+15|0]|y[c+16|0]<<8|(y[c+17|0]<<16|y[c+18|0]<<24);A=sa(c+18|0);D=Y;E=sa(c+21|0);q=y[c+23|0]|y[c+24|0]<<8|(y[c+25|0]<<16|y[c+26|0]<<24);x=sa(c+26|0);n=Y;O=(y[c+28|0]|y[c+29|0]<<8|(y[c+30|0]<<16|y[c+31|0]<<24))>>>7|0;b=d;P=((b&3)<<30|H>>>2)&2097151;b=Fj(O,0,P,0);d=Y;F=b;b=n;n=x;Q=((b&3)<<30|n>>>2)&2097151;n=0;R=g>>>7|0;c=Fj(Q,n,R,0);b=F+c|0;d=Y+d|0;d=b>>>0>>0?d+1|0:d;H=b;b=Fj(P,ma,Q,n);g=Y;S=q>>>5&2097151;q=Fj(S,0,R,0);c=q+b|0;b=Y+g|0;b=c>>>0>>0?b+1|0:b;T=e>>>5&2097151;e=Fj(O,0,T,0);c=e+c|0;b=Y+b|0;b=c>>>0>>0?b+1|0:b;e=c;x=b;b=b-((c>>>0<4293918720)-1|0)|0;g=c- -1048576|0;B=b;c=H;H=(b&2097151)<<11|g>>>21;q=c+H|0;b=(b>>21)+d|0;c=q;ya=c- -1048576|0;b=c>>>0>>0?b+1|0:b;d=b-((c>>>0<4293918720)-1|0)|0;F=d;q=b;b=ya&-2097152;H=q-((b>>>0>c>>>0)+d|0)|0;Ca=c-b|0;Ka=Fj(Ca,H,666643,0);La=Y;U=p>>>5&2097151;V=C&2097151;b=Fj(U,0,V,0);c=Y;W=I&2097151;p=Fj(W,0,T,0);b=p+b|0;d=Y+c|0;d=b>>>0

>>0?d+1|0:d;c=b;b=m;X=((b&3)<<30|J>>>2)&2097151;q=0;b=r;Z=((b&7)<<29|N>>>3)&2097151;r=Fj(X,q,Z,0);c=c+r|0;b=Y+d|0;b=c>>>0>>0?b+1|0:b;_=o>>>7&2097151;$=l>>>6&2097151;l=Fj(_,0,$,0);d=l+c|0;c=Y+b|0;c=d>>>0>>0?c+1|0:c;l=d;aa=s>>>4&2097151;b=h;ba=((b&1)<<31|M>>>1)&2097151;d=Fj(aa,0,ba,0);b=l+d|0;c=Y+c|0;c=b>>>0>>0?c+1|0:c;d=b;b=t;ca=((b&1)<<31|w>>>1)&2097151;s=0;da=j>>>4&2097151;j=Fj(ca,s,da,0);d=d+j|0;b=Y+c|0;ea=K>>>6&2097151;fa=i>>>7&2097151;i=Fj(ea,0,fa,0);c=i+d|0;d=Y+(d>>>0>>0?b+1|0:b)|0;d=c>>>0>>0?d+1|0:d;b=c;c=0;la=c;ga=E&2097151;ha=f>>>5&2097151;f=Fj(ga,c,ha,0);c=f+b|0;b=Y+d|0;d=c;c=c>>>0>>0?b+1|0:b;i=d;b=D;ia=((b&7)<<29|A>>>3)&2097151;t=0;b=k;ja=((b&3)<<30|z>>>2)&2097151;d=Fj(ia,t,ja,0);b=i+d|0;c=Y+c|0;c=b>>>0>>0?c+1|0:c;ka=u&2097151;f=Fj(S,0,ka,0);d=f+b|0;b=Y+c|0;l=d;i=d>>>0>>0?b+1|0:b;b=Fj(Z,na,U,0);c=Y;f=Fj(V,oa,W,pa);b=f+b|0;d=Y+c|0;d=b>>>0>>0?d+1|0:d;f=Fj($,0,X,q);b=f+b|0;c=Y+d|0;c=b>>>0>>0?c+1|0:c;d=Fj(_,0,ba,qa);b=d+b|0;c=Y+c|0;c=b>>>0>>0?c+1|0:c;f=Fj(aa,0,da,0);d=f+b|0;b=Y+c|0;b=d>>>0>>0?b+1|0:b;c=d;d=Fj(ca,s,fa,0);c=c+d|0;b=Y+b|0;b=c>>>0>>0?b+1|0:b;f=Fj(ja,ra,ea,0);c=f+c|0;d=Y+b|0;d=c>>>0>>0?d+1|0:d;f=Fj(ha,0,ia,t);b=f+c|0;c=Y+d|0;c=b>>>0>>0?c+1|0:c;d=Fj(ka,ta,ga,la);b=d+b|0;c=Y+c|0;f=b;c=b>>>0>>0?c+1|0:c;j=c;c=b;b=j-((b>>>0<4293918720)-1|0)|0;k=c- -1048576|0;h=b;c=l;l=(b&2097151)<<11|k>>>21;d=c+l|0;b=(b>>>21|0)+i|0;b=d>>>0>>0?b+1|0:b;c=d;i=c+Ka|0;d=b+La|0;d=i>>>0>>0?d+1|0:d;b=b-((c>>>0<4293918720)-1|0)|0;l=b;ua=c- -1048576|0;c=ua&-2097152;u=i-c|0;z=d-((c>>>0>i>>>0)+b|0)|0;b=g&-2097152;K=e-b|0;D=x-((b>>>0>e>>>0)+B|0)|0;b=Fj(P,ma,S,0);c=Y;e=Fj(R,0,ga,la);b=e+b|0;d=Y+c|0;d=b>>>0>>0?d+1|0:d;e=Fj(Q,n,T,0);c=e+b|0;b=Y+d|0;b=c>>>0>>0?b+1|0:b;d=Fj(O,0,V,oa);c=d+c|0;b=Y+b|0;m=c;g=c>>>0>>0?b+1|0:b;b=Fj(R,0,ia,t);c=Y;d=Fj(P,ma,ga,la);b=d+b|0;c=Y+c|0;c=b>>>0>>0?c+1|0:c;d=Fj(T,0,S,0);b=d+b|0;c=Y+c|0;c=b>>>0>>0?c+1|0:c;e=Fj(Q,n,V,oa);b=e+b|0;d=Y+c|0;d=b>>>0>>0?d+1|0:d;e=Fj(O,0,Z,na);c=e+b|0;b=Y+d|0;b=c>>>0>>0?b+1|0:b;e=c;r=b;b=b-((c>>>0<4293918720)-1|0)|0;i=c- -1048576|0;p=b;c=m;d=b>>21;m=(b&2097151)<<11|i>>>21;b=c+m|0;c=d+g|0;g=b;c=b>>>0>>0?c+1|0:c;m=c;c=b;b=m-((b>>>0<4293918720)-1|0)|0;c=c- -1048576|0;o=b;x=(b&2097151)<<11|c>>>21;K=x+K|0;b=(b>>21)+D|0;Da=K;b=x>>>0>K>>>0?b+1|0:b;K=b;d=c&-2097152;c=m-((d>>>0>g>>>0)+o|0)|0;Ea=g-d|0;D=c;g=Fj(Da,b,470296,0);d=g+u|0;b=Y+z|0;b=d>>>0>>0?b+1|0:b;g=Fj(Ea,c,654183,0);d=g+d|0;c=Y+b|0;o=d;m=d>>>0>>0?c+1|0:c;b=i&-2097152;i=e-b|0;p=r-((b>>>0>e>>>0)+p|0)|0;b=Fj(T,0,ga,la);d=Y;e=Fj(R,0,ea,0);c=e+b|0;b=Y+d|0;b=c>>>0>>0?b+1|0:b;e=Fj(P,ma,ia,t);d=e+c|0;c=Y+b|0;c=d>>>0>>0?c+1|0:c;b=d;d=Fj(V,oa,S,0);b=b+d|0;c=Y+c|0;c=b>>>0>>0?c+1|0:c;e=Fj(Q,n,Z,na);b=e+b|0;d=Y+c|0;d=b>>>0>>0?d+1|0:d;e=Fj(O,0,$,0);c=e+b|0;b=Y+d|0;x=c;g=c>>>0>>0?b+1|0:b;b=Fj(P,ma,ea,0);d=Y;e=Fj(R,0,ca,s);c=e+b|0;b=Y+d|0;b=c>>>0>>0?b+1|0:b;e=Fj(V,oa,ga,la);d=e+c|0;c=Y+b|0;c=d>>>0>>0?c+1|0:c;b=d;d=Fj(T,0,ia,t);b=b+d|0;c=Y+c|0;c=b>>>0>>0?c+1|0:c;e=Fj(Z,na,S,0);b=e+b|0;d=Y+c|0;d=b>>>0>>0?d+1|0:d;e=Fj(Q,n,$,0);c=e+b|0;b=Y+d|0;b=c>>>0>>0?b+1|0:b;d=Fj(O,0,ba,qa);c=d+c|0;b=Y+b|0;e=c;b=c>>>0>>0?b+1|0:b;r=b;b=c;c=r-((b>>>0<4293918720)-1|0)|0;u=b- -1048576|0;J=c;b=x;x=(c&2097151)<<11|u>>>21;d=b+x|0;c=(c>>21)+g|0;g=d;c=d>>>0>>0?c+1|0:c;w=c;b=d;c=c-((b>>>0<4293918720)-1|0)|0;z=b- -1048576|0;A=c;b=c>>21;d=(c&2097151)<<11|z>>>21;c=d+i|0;b=b+p|0;Ma=c;b=c>>>0>>0?b+1|0:b;x=b;d=Fj(c,b,-997805,-1);b=d+o|0;c=Y+m|0;o=b;m=b>>>0>>0?c+1|0:c;b=k&-2097152;i=f-b|0;j=j-((b>>>0>f>>>0)+h|0)|0;b=Fj($,0,U,0);c=Y;f=Fj(Z,na,W,pa);b=f+b|0;d=Y+c|0;d=b>>>0>>0?d+1|0:d;f=Fj(X,q,ba,qa);c=f+b|0;b=Y+d|0;b=c>>>0>>0?b+1|0:b;f=Fj(_,0,da,0);d=f+c|0;c=Y+b|0;c=d>>>0>>0?c+1|0:c;f=Fj(aa,0,fa,0);d=f+d|0;b=Y+c|0;b=d>>>0>>0?b+1|0:b;f=Fj(ca,s,ja,ra);d=f+d|0;c=Y+b|0;c=d>>>0>>0?c+1|0:c;f=Fj(ha,0,ea,0);b=f+d|0;d=Y+c|0;d=b>>>0>>0?d+1|0:d;f=Fj(ka,ta,ia,t);c=f+b|0;b=Y+d|0;h=c;k=c>>>0>>0?b+1|0:b;b=Fj(U,0,ba,qa);c=Y;d=Fj($,0,W,pa);b=d+b|0;c=Y+c|0;c=b>>>0>>0?c+1|0:c;f=Fj(X,q,da,0);d=f+b|0;b=Y+c|0;b=d>>>0>>0?b+1|0:b;f=Fj(_,0,fa,0);d=f+d|0;c=Y+b|0;c=d>>>0>>0?c+1|0:c;f=Fj(aa,0,ja,ra);b=f+d|0;d=Y+c|0;d=b>>>0>>0?d+1|0:d;f=Fj(ca,s,ha,0);c=f+b|0;b=Y+d|0;b=c>>>0>>0?b+1|0:b;f=Fj(ka,ta,ea,0);d=f+c|0;c=Y+b|0;c=d>>>0>>0?c+1|0:c;f=d;p=c;b=d;c=c-((b>>>0<4293918720)-1|0)|0;M=b- -1048576|0;E=c;b=h;h=(c&2097151)<<11|M>>>21;d=b+h|0;c=(c>>>21|0)+k|0;k=d;c=d>>>0>>0?c+1|0:c;Ka=c;b=d;c=c-((b>>>0<4293918720)-1|0)|0;N=b- -1048576|0;La=c;b=i;i=(c&2097151)<<11|N>>>21;d=b+i|0;c=(c>>>21|0)+j|0;c=d>>>0>>0?c+1|0:c;i=Fj(Da,K,666643,0);d=i+d|0;b=Y+c|0;b=d>>>0>>0?b+1|0:b;i=Fj(Ea,D,470296,0);d=i+d|0;c=Y+b|0;c=d>>>0>>0?c+1|0:c;i=Fj(Ma,x,654183,0);b=i+d|0;d=Y+c|0;d=b>>>0>>0?d+1|0:d;i=b;Sa=d;c=b;b=d-((b>>>0<4293918720)-1|0)|0;C=c- -1048576|0;Ua=b;c=b>>21;d=(b&2097151)<<11|C>>>21;b=d+o|0;c=c+m|0;j=b;c=b>>>0>>0?c+1|0:c;G=c;c=b;b=G-((b>>>0<4293918720)-1|0)|0;I=c- -1048576|0;wa=b;xa=(b&2097151)<<11|I>>>21;za=b>>21;b=Fj(T,0,U,0);c=Y;h=Fj(P,ma,W,pa);b=h+b|0;d=Y+c|0;d=b>>>0>>0?d+1|0:d;h=Fj(V,oa,X,q);c=h+b|0;b=Y+d|0;b=c>>>0>>0?b+1|0:b;h=Fj(Z,na,_,0);d=h+c|0;c=Y+b|0;c=d>>>0>>0?c+1|0:c;h=Fj($,0,aa,0);d=h+d|0;b=Y+c|0;b=d>>>0>>0?b+1|0:b;h=Fj(ba,qa,ca,s);d=h+d|0;c=Y+b|0;c=d>>>0>>0?c+1|0:c;h=Fj(da,0,ea,0);b=h+d|0;d=Y+c|0;d=b>>>0>>0?d+1|0:d;h=Fj(ja,ra,ga,la);c=h+b|0;b=Y+d|0;b=c>>>0>>0?b+1|0:b;h=Fj(fa,0,ia,t);d=h+c|0;c=Y+b|0;c=d>>>0>>0?c+1|0:c;h=Fj(S,0,ha,0);d=h+d|0;b=Y+c|0;b=d>>>0>>0?b+1|0:b;h=Fj(Q,n,ka,ta);d=h+d|0;c=Y+b|0;c=d>>>0>>0?c+1|0:c;h=d;o=c;Aa=Fj(Ca,H,470296,0);Ba=Y;b=Fj(O,0,R,0);Fa=b- -1048576|0;B=Y;c=B-((b>>>0<4293918720)-1|0)|0;m=c;d=Fa&-2097152;Na=b-d|0;c=B-((b>>>0>>0)+c|0)|0;b=F;d=b>>21;B=(b&2097151)<<11|ya>>>21;b=B+Na|0;c=c+d|0;Oa=b;c=b>>>0>>0?c+1|0:c;B=c;d=Fj(b,c,666643,0);b=d+Aa|0;c=Y+Ba|0;c=b>>>0>>0?c+1|0:c;F=b;d=b+h|0;b=c+o|0;b=d>>>0>>0?b+1|0:b;c=h;h=o-((c>>>0<4293918720)-1|0)|0;Xa=c- -1048576|0;o=h;c=l>>>21|0;l=(l&2097151)<<11|ua>>>21;d=l+d|0;b=b+c|0;b=d>>>0>>0?b+1|0:b;l=Fj(Da,K,654183,0);c=l+d|0;d=Y+b|0;d=c>>>0>>0?d+1|0:d;l=Fj(Ea,D,-997805,-1);b=l+c|0;c=Y+d|0;c=b>>>0>>0?c+1|0:c;F=Fj(Ma,x,136657,0);l=Xa&-2097152;d=F+(b-l|0)|0;b=Y+(c-((b>>>0>>0)+h|0)|0)|0;b=d>>>0>>0?b+1|0:b;L=d;h=d;d=d+xa|0;c=za;za=b;c=c+b|0;xa=d;va=d>>>0>>0?c+1|0:c;b=z&-2097152;Aa=g-b|0;Ba=w-((b>>>0>g>>>0)+A|0)|0;Ga=(m&2097151)<<11|Fa>>>21;c=m>>21;m=c;c=Fj(Ga,c,-683901,-1);b=c+e|0;d=Y+r|0;d=b>>>0>>0?d+1|0:d;c=u&-2097152;g=b-c|0;r=d-((b>>>0>>0)+J|0)|0;b=Fj(P,ma,ca,s);c=Y;d=Fj(R,0,aa,0);b=d+b|0;c=Y+c|0;c=b>>>0>>0?c+1|0:c;d=Fj(T,0,ea,0);b=d+b|0;c=Y+c|0;c=b>>>0>>0?c+1|0:c;e=Fj(Z,na,ga,la);b=e+b|0;d=Y+c|0;d=b>>>0>>0?d+1|0:d;e=Fj(V,oa,ia,t);c=e+b|0;b=Y+d|0;b=c>>>0>>0?b+1|0:b;d=Fj(S,0,$,0);c=d+c|0;b=Y+b|0;b=c>>>0>>0?b+1|0:b;e=Fj(Q,n,ba,qa);d=e+c|0;c=Y+b|0;c=d>>>0>>0?c+1|0:c;b=d;d=Fj(O,0,da,0);b=b+d|0;c=Y+c|0;u=b;e=b>>>0>>0?c+1|0:c;b=Fj(P,ma,aa,0);c=Y;h=Fj(R,0,_,0);b=h+b|0;d=Y+c|0;d=b>>>0>>0?d+1|0:d;h=Fj(T,0,ca,s);c=h+b|0;b=Y+d|0;b=c>>>0>>0?b+1|0:b;d=Fj(V,oa,ea,0);c=d+c|0;b=Y+b|0;b=c>>>0>>0?b+1|0:b;h=Fj($,0,ga,la);d=h+c|0;c=Y+b|0;c=d>>>0>>0?c+1|0:c;b=d;d=Fj(Z,na,ia,t);b=b+d|0;c=Y+c|0;c=b>>>0>>0?c+1|0:c;h=Fj(S,0,ba,qa);b=h+b|0;d=Y+c|0;d=b>>>0>>0?d+1|0:d;h=Fj(Q,n,da,0);c=h+b|0;b=Y+d|0;b=c>>>0>>0?b+1|0:b;d=Fj(O,0,fa,0);c=d+c|0;b=Y+b|0;h=c;b=c>>>0>>0?b+1|0:b;J=b;b=c;c=J-((b>>>0<4293918720)-1|0)|0;l=b- -1048576|0;w=c;b=u;u=(c&2097151)<<11|l>>>21;d=b+u|0;c=(c>>21)+e|0;e=d;c=d>>>0>>0?c+1|0:c;A=c;b=d;c=c-((b>>>0<4293918720)-1|0)|0;z=b- -1048576|0;ya=c;b=c>>21;d=(c&2097151)<<11|z>>>21;c=d+g|0;b=b+r|0;g=c;b=c>>>0>>0?b+1|0:b;ua=b;b=c;c=ua-((b>>>0<4293918720)-1|0)|0;F=b- -1048576|0;Fa=c;r=(c&2097151)<<11|F>>>21;d=r+Aa|0;c=(c>>21)+Ba|0;Pa=d;c=d>>>0>>0?c+1|0:c;u=c;Ya=L- -1048576|0;b=za-((L>>>0<4293918720)-1|0)|0;r=b;za=Fj(d,c,-683901,-1);c=za+xa|0;d=Y+va|0;d=c>>>0>>0?d+1|0:d;b=Ya&-2097152;d=d-(r+(b>>>0>c>>>0)|0)|0;b=c-b|0;Za=b- -1048576|0;c=d-((b>>>0<4293918720)-1|0)|0;za=c;L=Za&-2097152;Ha=b-L|0;Va=d-((b>>>0>>0)+c|0)|0;d=Fj(Pa,u,136657,0);c=I&-2097152;b=d+(j-c|0)|0;c=Y+(G-((c>>>0>j>>>0)+wa|0)|0)|0;Ba=b;G=b>>>0>>0?c+1|0:c;b=F&-2097152;Na=g-b|0;Ta=ua-((b>>>0>g>>>0)+Fa|0)|0;b=Fj(Oa,B,-683901,-1);c=Y;g=Fj(Ga,m,136657,0);b=g+b|0;d=Y+c|0;c=b+e|0;b=A+(b>>>0>>0?d+1|0:d)|0;b=c>>>0>>0?b+1|0:b;d=z&-2097152;z=c-d|0;A=b-((c>>>0>>0)+ya|0)|0;d=Fj(Ga,m,-997805,-1);c=d+h|0;b=Y+J|0;b=c>>>0>>0?b+1|0:b;e=Fj(Oa,B,136657,0);c=e+c|0;d=Y+b|0;d=c>>>0>>0?d+1|0:d;e=Fj(Ca,H,-683901,-1);c=e+c|0;b=Y+d|0;b=c>>>0>>0?b+1|0:b;d=l&-2097152;j=c-d|0;h=b-((c>>>0>>0)+w|0)|0;b=Fj(P,ma,_,0);c=Y;d=Fj(R,0,X,q);b=d+b|0;c=Y+c|0;c=b>>>0>>0?c+1|0:c;e=Fj(T,0,aa,0);b=e+b|0;d=Y+c|0;d=b>>>0>>0?d+1|0:d;e=Fj(V,oa,ca,s);c=e+b|0;b=Y+d|0;b=c>>>0>>0?b+1|0:b;d=Fj(Z,na,ea,0);c=d+c|0;b=Y+b|0;b=c>>>0>>0?b+1|0:b;e=Fj(ba,qa,ga,la);d=e+c|0;c=Y+b|0;c=d>>>0>>0?c+1|0:c;b=d;d=Fj($,0,ia,t);b=b+d|0;c=Y+c|0;c=b>>>0>>0?c+1|0:c;e=Fj(S,0,da,0);b=e+b|0;d=Y+c|0;d=b>>>0>>0?d+1|0:d;e=Fj(Q,n,fa,0);c=e+b|0;b=Y+d|0;b=c>>>0>>0?b+1|0:b;d=Fj(O,0,ja,ra);c=d+c|0;b=Y+b|0;l=c;g=c>>>0>>0?b+1|0:b;b=Fj(P,ma,X,q);c=Y;d=Fj(R,0,U,0);b=d+b|0;c=Y+c|0;c=b>>>0>>0?c+1|0:c;d=Fj(T,0,_,0);b=d+b|0;c=Y+c|0;c=b>>>0>>0?c+1|0:c;e=Fj(V,oa,aa,0);b=e+b|0;d=Y+c|0;d=b>>>0>>0?d+1|0:d;e=Fj(Z,na,ca,s);c=e+b|0;b=Y+d|0;b=c>>>0>>0?b+1|0:b;d=Fj($,0,ea,0);c=d+c|0;b=Y+b|0;b=c>>>0>>0?b+1|0:b;e=Fj(da,0,ga,la);d=e+c|0;c=Y+b|0;c=d>>>0>>0?c+1|0:c;b=d;d=Fj(ba,qa,ia,t);b=b+d|0;c=Y+c|0;c=b>>>0>>0?c+1|0:c;e=Fj(S,0,fa,0);b=e+b|0;d=Y+c|0;d=b>>>0>>0?d+1|0:d;e=Fj(Q,n,ja,ra);c=e+b|0;b=Y+d|0;b=c>>>0>>0?b+1|0:b;d=Fj(O,0,ha,0);c=d+c|0;b=Y+b|0;e=c;b=c>>>0>>0?b+1|0:b;wa=b;b=c;c=wa-((b>>>0<4293918720)-1|0)|0;I=b- -1048576|0;L=c;b=l;l=(c&2097151)<<11|I>>>21;d=b+l|0;c=(c>>21)+g|0;g=d;c=d>>>0>>0?c+1|0:c;va=c;b=d;c=c-((b>>>0<4293918720)-1|0)|0;F=b- -1048576|0;ya=c;b=c>>21;d=(c&2097151)<<11|F>>>21;c=d+j|0;b=b+h|0;j=c;b=c>>>0>>0?b+1|0:b;ua=b;b=c;c=ua-((b>>>0<4293918720)-1|0)|0;J=b- -1048576|0;Fa=c;h=(c&2097151)<<11|J>>>21;d=h+z|0;c=(c>>21)+A|0;c=d>>>0>>0?c+1|0:c;h=d;xa=c;b=d;c=c-((b>>>0<4293918720)-1|0)|0;w=b- -1048576|0;Aa=c;b=c>>21;d=(c&2097151)<<11|w>>>21;c=d+Na|0;b=b+Ta|0;Qa=c;b=c>>>0>>0?b+1|0:b;z=b;d=Fj(c,b,-683901,-1);b=d+Ba|0;c=Y+G|0;Ra=b;G=b>>>0>>0?c+1|0:c;b=C&-2097152;Ia=i-b|0;Wa=Sa-((b>>>0>i>>>0)+Ua|0)|0;d=Fj(Ea,D,666643,0);b=N&-2097152;c=d+(k-b|0)|0;b=Y+(Ka-((b>>>0>k>>>0)+La|0)|0)|0;b=c>>>0>>0?b+1|0:b;d=Fj(Ma,x,470296,0);c=d+c|0;b=Y+b|0;A=c;l=c>>>0>>0?b+1|0:b;i=f;b=Fj(U,0,da,0);c=Y;d=Fj(W,pa,ba,qa);b=d+b|0;c=Y+c|0;c=b>>>0>>0?c+1|0:c;d=Fj(X,q,fa,0);b=d+b|0;c=Y+c|0;c=b>>>0>>0?c+1|0:c;f=Fj(_,0,ja,ra);b=f+b|0;d=Y+c|0;d=b>>>0>>0?d+1|0:d;f=Fj(aa,0,ha,0);c=f+b|0;b=Y+d|0;b=c>>>0>>0?b+1|0:b;d=Fj(ca,s,ka,ta);c=d+c|0;b=Y+b|0;C=c;k=c>>>0>>0?b+1|0:b;b=Fj(U,0,fa,0);c=Y;d=Fj(W,pa,da,0);b=d+b|0;c=Y+c|0;c=b>>>0>>0?c+1|0:c;d=Fj(X,q,ja,ra);b=d+b|0;c=Y+c|0;c=b>>>0>>0?c+1|0:c;f=Fj(_,0,ha,0);b=f+b|0;d=Y+c|0;d=b>>>0>>0?d+1|0:d;f=Fj(aa,0,ka,ta);c=f+b|0;b=Y+d|0;b=c>>>0>>0?b+1|0:b;f=c;Ka=b;b=b-((c>>>0<4293918720)-1|0)|0;N=c- -1048576|0;La=b;c=C;d=b>>>21|0;C=(b&2097151)<<11|N>>>21;b=c+C|0;c=d+k|0;k=b;c=b>>>0>>0?c+1|0:c;Sa=c;c=b;b=Sa-((b>>>0<4293918720)-1|0)|0;C=c- -1048576|0;Ua=b;c=i;i=(b&2097151)<<11|C>>>21;c=c+i|0;b=(b>>>21|0)+p|0;b=c>>>0>>0?b+1|0:b;p=Fj(Ma,x,666643,0);i=M&-2097152;d=p+(c-i|0)|0;c=Y+(b-((c>>>0>>0)+E|0)|0)|0;i=d;c=d>>>0

>>0?c+1|0:c;Ba=c;b=d;c=c-((b>>>0<4293918720)-1|0)|0;M=b- -1048576|0;Na=c;b=c>>21;d=(c&2097151)<<11|M>>>21;c=d+A|0;b=b+l|0;l=c;b=c>>>0>>0?b+1|0:b;Ta=b;b=c;c=Ta-((b>>>0<4293918720)-1|0)|0;A=b- -1048576|0;_a=c;b=h;d=w&-2097152;h=xa-((b>>>0>>0)+Aa|0)|0;Ja=b-d|0;p=h;w=(c&2097151)<<11|A>>>21;d=w+Ia|0;c=(c>>21)+Wa|0;c=d>>>0>>0?c+1|0:c;w=Fj(Pa,u,-997805,-1);b=w+d|0;d=Y+c|0;d=b>>>0>>0?d+1|0:d;w=Fj(Qa,z,136657,0);c=w+b|0;b=Y+d|0;b=c>>>0>>0?b+1|0:b;d=Fj(Ja,h,-683901,-1);c=d+c|0;b=Y+b|0;b=c>>>0>>0?b+1|0:b;d=c;xa=b;b=b-((c>>>0<4293918720)-1|0)|0;w=c- -1048576|0;Aa=b;E=(b&2097151)<<11|w>>>21;h=E+Ra|0;b=(b>>21)+G|0;b=h>>>0>>0?b+1|0:b;G=b;c=h;b=b-((c>>>0<4293918720)-1|0)|0;E=c- -1048576|0;Ra=b;Ia=(b&2097151)<<11|E>>>21;Ha=Ia+Ha|0;b=(b>>21)+Va|0;Va=Ha;Ha=Ha>>>0>>0?b+1|0:b;b=E&-2097152;Ia=c-b|0;Ra=G-((b>>>0>c>>>0)+Ra|0)|0;b=w&-2097152;Wa=d-b|0;xa=xa-((b>>>0>d>>>0)+Aa|0)|0;d=Fj(Pa,u,654183,0);c=A&-2097152;b=d+(l-c|0)|0;c=Y+(Ta-((c>>>0>l>>>0)+_a|0)|0)|0;c=b>>>0>>0?c+1|0:c;h=Fj(Qa,z,-997805,-1);d=h+b|0;b=Y+c|0;b=d>>>0>>0?b+1|0:b;c=d;d=Fj(Ja,p,136657,0);c=c+d|0;b=Y+b|0;A=c;l=c>>>0>>0?b+1|0:b;b=J&-2097152;h=j-b|0;E=ua-((b>>>0>j>>>0)+Fa|0)|0;b=Fj(Oa,B,-997805,-1);c=Y;d=Fj(Ga,m,654183,0);b=d+b|0;c=Y+c|0;c=b>>>0>>0?c+1|0:c;j=Fj(Ca,H,136657,0);d=j+b|0;b=Y+c|0;b=d>>>0>>0?b+1|0:b;c=d;d=Fj(Da,K,-683901,-1);c=c+d|0;b=Y+b|0;b=c>>>0>>0?b+1|0:b;d=c+g|0;c=b+va|0;c=d>>>0>>0?c+1|0:c;b=d;d=F&-2097152;j=b-d|0;G=c-((b>>>0>>0)+ya|0)|0;b=Fj(Oa,B,654183,0);c=Y;d=Fj(Ga,m,470296,0);b=d+b|0;c=Y+c|0;c=b>>>0>>0?c+1|0:c;g=Fj(Ca,H,-997805,-1);d=g+b|0;b=Y+c|0;b=d>>>0>>0?b+1|0:b;d=d+e|0;c=b+wa|0;c=d>>>0>>0?c+1|0:c;e=Fj(Da,K,136657,0);d=e+d|0;b=Y+c|0;b=d>>>0>>0?b+1|0:b;e=Fj(Ea,D,-683901,-1);c=e+d|0;d=Y+b|0;d=c>>>0>>0?d+1|0:d;b=c;c=I&-2097152;g=b-c|0;J=d-((b>>>0>>0)+L|0)|0;b=Fj(P,ma,U,0);d=Y;e=Fj(R,0,W,pa);c=e+b|0;b=Y+d|0;b=c>>>0>>0?b+1|0:b;d=Fj(T,0,X,q);c=d+c|0;b=Y+b|0;b=c>>>0>>0?b+1|0:b;e=Fj(V,oa,_,0);c=e+c|0;d=Y+b|0;d=c>>>0>>0?d+1|0:d;e=Fj(Z,na,aa,0);b=e+c|0;c=Y+d|0;c=b>>>0>>0?c+1|0:c;d=Fj($,0,ca,s);b=d+b|0;c=Y+c|0;c=b>>>0>>0?c+1|0:c;e=Fj(ba,qa,ea,0);d=e+b|0;b=Y+c|0;b=d>>>0>>0?b+1|0:b;c=d;d=Fj(fa,0,ga,la);c=c+d|0;b=Y+b|0;b=c>>>0>>0?b+1|0:b;e=Fj(da,0,ia,t);c=e+c|0;d=Y+b|0;d=c>>>0>>0?d+1|0:d;e=Fj(S,0,ja,ra);b=e+c|0;c=Y+d|0;c=b>>>0>>0?c+1|0:c;d=Fj(Q,n,ha,0);b=d+b|0;c=Y+c|0;c=b>>>0>>0?c+1|0:c;e=Fj(O,0,ka,ta);d=e+b|0;b=Y+c|0;b=d>>>0>>0?b+1|0:b;e=(o&2097151)<<11|Xa>>>21;d=e+d|0;b=(o>>>21|0)+b|0;b=d>>>0>>0?b+1|0:b;e=d;I=b;c=d;b=b-((c>>>0<4293918720)-1|0)|0;o=c- -1048576|0;F=b;c=b>>21;d=(b&2097151)<<11|o>>>21;b=d+g|0;c=c+J|0;g=b;c=b>>>0>>0?c+1|0:c;J=c;c=b;b=J-((b>>>0<4293918720)-1|0)|0;n=c- -1048576|0;w=b;c=j;j=(b&2097151)<<11|n>>>21;d=c+j|0;b=(b>>21)+G|0;b=d>>>0>>0?b+1|0:b;s=b;c=d;b=b-((c>>>0<4293918720)-1|0)|0;j=c- -1048576|0;t=b;L=h;c=b>>21;h=(b&2097151)<<11|j>>>21;b=L+h|0;c=c+E|0;L=b;c=b>>>0>>0?c+1|0:c;h=c;G=A;A=Fj(b,c,-683901,-1);c=G+A|0;b=Y+l|0;G=c;A=c>>>0>>0?b+1|0:b;b=j&-2097152;j=s-((b>>>0>d>>>0)+t|0)|0;va=d-b|0;l=j;s=Fj(Pa,u,470296,0);c=M&-2097152;b=s+(i-c|0)|0;d=Y+(Ba-((c>>>0>i>>>0)+Na|0)|0)|0;d=b>>>0>>0?d+1|0:d;i=Fj(Qa,z,654183,0);b=i+b|0;c=Y+d|0;c=b>>>0>>0?c+1|0:c;i=Fj(Ja,p,-997805,-1);d=i+b|0;b=Y+c|0;b=d>>>0>>0?b+1|0:b;i=Fj(L,h,136657,0);d=i+d|0;c=Y+b|0;c=d>>>0>>0?c+1|0:c;i=Fj(va,j,-683901,-1);b=i+d|0;d=Y+c|0;d=b>>>0>>0?d+1|0:d;i=b;M=d;c=d-((b>>>0<4293918720)-1|0)|0;s=b- -1048576|0;E=c;j=(c&2097151)<<11|s>>>21;d=j+G|0;c=(c>>21)+A|0;c=d>>>0>>0?c+1|0:c;j=d;A=c;b=d;c=c-((b>>>0<4293918720)-1|0)|0;t=b- -1048576|0;G=c;b=c>>21;wa=(c&2097151)<<11|t>>>21;c=wa+Wa|0;d=b+xa|0;ya=c;wa=c>>>0>>0?d+1|0:d;b=t&-2097152;ua=j-b|0;A=A-((b>>>0>j>>>0)+G|0)|0;b=s&-2097152;G=i-b|0;E=M-((b>>>0>i>>>0)+E|0)|0;d=Fj(Pa,u,666643,0);c=C&-2097152;b=d+(k-c|0)|0;c=Y+(Sa-((c>>>0>k>>>0)+Ua|0)|0)|0;c=b>>>0>>0?c+1|0:c;k=Fj(Qa,z,470296,0);b=k+b|0;d=Y+c|0;d=b>>>0>>0?d+1|0:d;k=Fj(Ja,p,654183,0);b=k+b|0;c=Y+d|0;i=b;k=b>>>0>>0?c+1|0:c;b=n&-2097152;j=g-b|0;g=J-((b>>>0>g>>>0)+w|0)|0;b=Fj(Oa,B,470296,0);d=Y;m=Fj(Ga,m,666643,0);c=m+b|0;b=Y+d|0;b=c>>>0>>0?b+1|0:b;m=Fj(Ca,H,654183,0);c=m+c|0;d=Y+b|0;d=c>>>0>>0?d+1|0:d;m=Fj(Da,K,-997805,-1);b=m+c|0;c=Y+d|0;c=b>>>0>>0?c+1|0:c;d=Fj(Ea,D,136657,0);b=d+b|0;c=Y+c|0;c=b>>>0>>0?c+1|0:c;d=b+e|0;b=c+I|0;b=d>>>0>>0?b+1|0:b;c=d;d=Fj(Ma,x,-683901,-1);c=c+d|0;b=Y+b|0;b=c>>>0>>0?b+1|0:b;d=o&-2097152;e=c-d|0;c=b-((c>>>0>>0)+F|0)|0;b=e;e=(r&2097151)<<11|Ya>>>21;d=b+e|0;c=(r>>21)+c|0;c=d>>>0>>0?c+1|0:c;e=d;H=c;b=d;c=c-((b>>>0<4293918720)-1|0)|0;m=b- -1048576|0;K=c;b=j;j=(c&2097151)<<11|m>>>21;d=b+j|0;c=(c>>21)+g|0;C=d;c=d>>>0>>0?c+1|0:c;r=c;c=Fj(d,c,-683901,-1);b=c+i|0;d=Y+k|0;d=b>>>0>>0?d+1|0:d;g=Fj(L,h,-997805,-1);b=g+b|0;c=Y+d|0;c=b>>>0>>0?c+1|0:c;g=Fj(va,l,136657,0);d=g+b|0;b=Y+c|0;t=d;j=d>>>0>>0?b+1|0:b;b=Fj(U,0,ja,ra);d=Y;g=Fj(W,pa,fa,0);c=g+b|0;b=Y+d|0;b=c>>>0>>0?b+1|0:b;g=Fj(X,q,ha,0);d=g+c|0;c=Y+b|0;c=d>>>0>>0?c+1|0:c;g=Fj(_,0,ka,ta);b=g+d|0;d=Y+c|0;d=b>>>0>>0?d+1|0:d;k=b;b=Fj(U,0,ha,0);c=Y;g=Fj(W,pa,ja,ra);b=g+b|0;c=Y+c|0;c=b>>>0>>0?c+1|0:c;i=Fj(X,q,ka,ta);g=i+b|0;b=Y+c|0;b=g>>>0>>0?b+1|0:b;i=b;c=g;b=b-((c>>>0<4293918720)-1|0)|0;o=c- -1048576|0;D=b;x=k;c=b>>>21|0;k=(b&2097151)<<11|o>>>21;b=x+k|0;c=c+d|0;c=b>>>0>>0?c+1|0:c;k=b;x=c;c=b;b=x-((b>>>0<4293918720)-1|0)|0;n=c- -1048576|0;B=b;d=f+((b&2097151)<<11|n>>>21)|0;b=Ka+(b>>>21|0)|0;b=d>>>0>>0?b+1|0:b;q=Fj(Qa,z,666643,0);c=d;f=N&-2097152;d=q+(c-f|0)|0;c=Y+(b-((c>>>0>>0)+La|0)|0)|0;c=d>>>0>>0?c+1|0:c;b=d;d=Fj(Ja,p,470296,0);b=b+d|0;c=Y+c|0;c=b>>>0>>0?c+1|0:c;f=Fj(C,r,136657,0);d=f+b|0;b=Y+c|0;b=d>>>0>>0?b+1|0:b;f=Fj(L,h,654183,0);c=f+d|0;d=Y+b|0;d=c>>>0>>0?d+1|0:d;f=Fj(va,l,-997805,-1);c=f+c|0;b=Y+d|0;q=c;b=c>>>0>>0?b+1|0:b;u=b;b=b-((c>>>0<4293918720)-1|0)|0;s=c- -1048576|0;z=b;d=b>>21;f=(b&2097151)<<11|s>>>21;b=f+t|0;c=d+j|0;c=b>>>0>>0?c+1|0:c;f=b;j=c;c=b;b=j-((b>>>0<4293918720)-1|0)|0;t=c- -1048576|0;M=b;N=(b&2097151)<<11|t>>>21;c=N+G|0;b=(b>>21)+E|0;F=c;N=c>>>0>>0?b+1|0:b;d=j;b=m&-2097152;c=e-b|0;j=H-((b>>>0>e>>>0)+K|0)|0;e=c;c=za;b=c>>21;m=(c&2097151)<<11|Za>>>21;e=e+m|0;c=b+j|0;c=e>>>0>>0?c+1|0:c;H=c;b=e;c=c-((b>>>0<4293918720)-1|0)|0;m=b- -1048576|0;K=c;I=(c&2097151)<<11|m>>>21;b=c>>21;j=b;c=f;f=Fj(I,b,-683901,-1);c=c+f|0;b=Y+d|0;b=c>>>0>>0?b+1|0:b;d=t&-2097152;J=c-d|0;M=b-((c>>>0>>0)+M|0)|0;d=Fj(I,j,136657,0);b=d+q|0;c=Y+u|0;c=b>>>0>>0?c+1|0:c;d=s&-2097152;u=b-d|0;z=c-((b>>>0>>0)+z|0)|0;d=Fj(Ja,p,666643,0);c=n&-2097152;b=d+(k-c|0)|0;c=Y+(x-((c>>>0>k>>>0)+B|0)|0)|0;c=b>>>0>>0?c+1|0:c;f=Fj(C,r,-997805,-1);b=f+b|0;d=Y+c|0;d=b>>>0>>0?d+1|0:d;f=Fj(L,h,470296,0);c=f+b|0;b=Y+d|0;b=c>>>0>>0?b+1|0:b;f=Fj(va,l,654183,0);d=f+c|0;c=Y+b|0;B=d;p=d>>>0>>0?c+1|0:c;n=g;q=i;b=Fj(U,0,ka,ta);d=Y;f=Fj(W,pa,ha,0);c=f+b|0;b=Y+d|0;g=c;d=c>>>0>>0?b+1|0:b;f=Fj(W,pa,ka,ta);b=Y;w=b;c=f;b=b-((c>>>0<4293918720)-1|0)|0;k=c- -1048576|0;s=b;i=g;c=b>>>21|0;g=(b&2097151)<<11|k>>>21;b=i+g|0;d=c+d|0;d=b>>>0>>0?d+1|0:d;g=b;t=d;c=b;b=d-((b>>>0<4293918720)-1|0)|0;i=c- -1048576|0;x=b;c=n;n=(b&2097151)<<11|i>>>21;d=c+n|0;b=(b>>>21|0)+q|0;b=d>>>0>>0?b+1|0:b;n=Fj(C,r,654183,0);o=o&-2097152;c=n+(d-o|0)|0;d=Y+(b-((D&8191)+(d>>>0>>0)|0)|0)|0;h=Fj(L,h,666643,0);b=h+c|0;c=Y+(c>>>0>>0?d+1|0:d)|0;c=b>>>0>>0?c+1|0:c;h=Fj(va,l,470296,0);d=h+b|0;b=Y+c|0;b=d>>>0>>0?b+1|0:b;n=b;c=d;b=b-((c>>>0<4293918720)-1|0)|0;h=c- -1048576|0;q=b;c=b>>21;o=(b&2097151)<<11|h>>>21;b=o+B|0;c=c+p|0;c=b>>>0>>0?c+1|0:c;D=c;c=b;b=D-((b>>>0<4293918720)-1|0)|0;o=c- -1048576|0;B=b;E=(b&2097151)<<11|o>>>21;u=E+u|0;b=(b>>21)+z|0;z=u;u=u>>>0>>0?b+1|0:b;p=Fj(I,j,-997805,-1);c=c+p|0;b=Y+D|0;b=c>>>0

>>0?b+1|0:b;p=o&-2097152;D=c-p|0;B=b-((c>>>0

>>0)+B|0)|0;c=Fj(I,j,654183,0);b=c+d|0;d=Y+n|0;d=b>>>0>>0?d+1|0:d;c=h&-2097152;o=b-c|0;n=d-((b>>>0>>0)+q|0)|0;d=Fj(C,r,470296,0);c=i&-2097152;b=d+(g-c|0)|0;c=Y+(t-((x&8191)+(c>>>0>g>>>0)|0)|0)|0;c=b>>>0>>0?c+1|0:c;d=Fj(va,l,666643,0);b=d+b|0;c=Y+c|0;p=b;i=b>>>0>>0?c+1|0:c;g=Fj(C,r,666643,0);c=k&-2097152;b=g+(f-c|0)|0;d=Y+(w-((s&2047)+(c>>>0>f>>>0)|0)|0)|0;f=b;d=b>>>0>>0?d+1|0:d;h=d;c=d-((b>>>0<4293918720)-1|0)|0;g=b- -1048576|0;l=c;k=(c&2097151)<<11|g>>>21;d=k+p|0;c=(c>>21)+i|0;c=d>>>0>>0?c+1|0:c;k=d;r=c;b=d;c=c-((b>>>0<4293918720)-1|0)|0;i=b- -1048576|0;p=c;d=o;b=c>>21;o=(c&2097151)<<11|i>>>21;c=d+o|0;d=b+n|0;n=c;o=c>>>0>>0?d+1|0:d;d=Fj(I,j,470296,0);b=d+k|0;c=Y+r|0;c=b>>>0>>0?c+1|0:c;d=i&-2097152;k=b-d|0;i=c-((b>>>0>>0)+p|0)|0;c=g&-2097152;g=Fj(I,j,666643,0);b=(f-c|0)+g|0;d=Y+(h-((c>>>0>f>>>0)+l|0)|0)|0;d=b>>>0>>0?d+1|0:d;g=b;c=d>>21;f=(d&2097151)<<11|b>>>21;d=f+k|0;b=c+i|0;k=d;c=d;b=c>>>0>>0?b+1|0:b;d=b>>21;f=(b&2097151)<<11|c>>>21;b=f+n|0;c=d+o|0;l=b;d=b;c=b>>>0>>0?c+1|0:c;b=c>>21;d=(c&2097151)<<11|d>>>21;c=d+D|0;b=b+B|0;b=c>>>0>>0?b+1|0:b;r=c;d=c;c=b>>21;d=(b&2097151)<<11|d>>>21;b=d+z|0;c=c+u|0;c=b>>>0>>0?c+1|0:c;p=b;d=b;b=c>>21;f=(c&2097151)<<11|d>>>21;c=f+J|0;d=b+M|0;o=c;b=c;d=b>>>0>>0?d+1|0:d;c=d>>21;f=(d&2097151)<<11|b>>>21;d=f+F|0;b=c+N|0;n=d;c=d;b=c>>>0>>0?b+1|0:b;d=b>>21;f=(b&2097151)<<11|c>>>21;b=f+ua|0;c=d+A|0;q=b;d=b;c=b>>>0>>0?c+1|0:c;b=c>>21;d=(c&2097151)<<11|d>>>21;c=d+ya|0;b=b+wa|0;b=c>>>0>>0?b+1|0:b;s=c;d=c;c=b>>21;d=(b&2097151)<<11|d>>>21;b=d+Ia|0;c=c+Ra|0;c=b>>>0>>0?c+1|0:c;t=b;d=b;b=c>>21;f=(c&2097151)<<11|d>>>21;c=f+Va|0;d=b+Ha|0;D=c;b=c;d=b>>>0>>0?d+1|0:d;c=d>>21;b=(d&2097151)<<11|b>>>21;d=m&-2097152;f=e-d|0;b=b+f|0;c=(H-((d>>>0>e>>>0)+K|0)|0)+c|0;m=b;c=b>>>0>>0?c+1|0:c;h=(c&2097151)<<11|b>>>21;b=c>>21;f=b;c=g&2097151;b=Fj(h,b,666643,0)+c|0;d=Y;g=b;d=b>>>0>>0?d+1|0:d;e=d;v[a|0]=b;v[a+1|0]=(d&255)<<24|b>>>8;k=k&2097151;b=Fj(h,f,470296,0)+k|0;c=Y;c=b>>>0>>0?c+1|0:c;k=c;d=b;c=e;b=c>>21;j=(c&2097151)<<11|g>>>21;i=d+j|0;c=b+k|0;k=i;c=i>>>0>>0?c+1|0:c;d=i;v[a+4|0]=(c&2047)<<21|d>>>11;b=c;v[a+3|0]=(b&7)<<29|d>>>3;j=a;i=l&2097151;c=Fj(h,f,654183,0)+i|0;d=Y;d=c>>>0>>0?d+1|0:d;l=c;c=b;b=b>>21;i=(c&2097151)<<11|k>>>21;c=l+i|0;b=b+d|0;b=c>>>0>>0?b+1|0:b;i=c;d=b;v[j+6|0]=(b&63)<<26|c>>>6;j=0;l=k&2097151;b=l;v[a+2|0]=((e&65535)<<16|g>>>16)&31|b<<5;g=a;e=r&2097151;b=Fj(h,f,-997805,-1)+e|0;c=Y;c=b>>>0>>0?c+1|0:c;k=b;b=d>>21;e=(d&2097151)<<11|i>>>21;d=k+e|0;c=b+c|0;c=d>>>0>>0?c+1|0:c;e=d;v[g+9|0]=(c&511)<<23|d>>>9;d=c;b=c;c=e;v[g+8|0]=(b&1)<<31|c>>>1;k=0;r=i&2097151;b=r;c=b<<2;b=j;v[g+5|0]=c|((b&524287)<<13|l>>>19);i=g;g=p&2097151;c=Fj(h,f,136657,0)+g|0;b=Y;b=c>>>0>>0?b+1|0:b;j=(d&2097151)<<11|e>>>21;g=j+c|0;d=(d>>21)+b|0;d=g>>>0>>0?d+1|0:d;v[i+12|0]=(d&4095)<<20|g>>>12;c=d;b=c;d=g;v[i+11|0]=(b&15)<<28|d>>>4;i=0;j=e&2097151;b=j;d=b<<7;b=k;v[a+7|0]=d|((b&16383)<<18|r>>>14);k=a;e=o&2097151;d=Fj(h,f,-683901,-1)+e|0;b=Y;b=d>>>0>>0?b+1|0:b;f=(c&2097151)<<11|g>>>21;e=f+d|0;c=(c>>21)+b|0;c=e>>>0>>0?c+1|0:c;b=c;v[k+14|0]=(b&127)<<25|e>>>7;f=0;k=g&2097151;c=k;d=c<<4;c=i;v[a+10|0]=d|((c&131071)<<15|j>>>17);g=a;c=b;b=b>>21;j=(c&2097151)<<11|e>>>21;d=j+(n&2097151)|0;c=d>>>0>>0?b+1|0:b;v[g+17|0]=(c&1023)<<22|d>>>10;b=c;v[g+16|0]=(b&3)<<30|d>>>2;g=0;j=e&2097151;c=j;i=c<<1;c=f;v[a+13|0]=i|((c&1048575)<<12|k>>>20);c=b;b=b>>21;k=(c&2097151)<<11|d>>>21;c=k+(q&2097151)|0;f=c;b=c>>>0>>0?b+1|0:b;e=c;v[a+20|0]=(b&8191)<<19|c>>>13;c=b;v[a+19|0]=(b&31)<<27|e>>>5;k=0;h=d&2097151;b=h;d=b<<6;b=g;v[a+15|0]=d|((b&32767)<<17|j>>>15);d=c>>21;g=a;j=(c&2097151)<<11|e>>>21;e=j+(s&2097151)|0;i=e;v[g+21|0]=e;b=f;c=b<<3;b=k;v[g+18|0]=c|((b&262143)<<14|h>>>18);e=e>>>0>>0?d+1|0:d;v[g+22|0]=(e&255)<<24|i>>>8;b=e;d=b>>21;g=(b&2097151)<<11|i>>>21;b=g+(t&2097151)|0;c=d;d=b;c=b>>>0>>0?c+1|0:c;v[a+25|0]=(c&2047)<<21|b>>>11;b=c;v[a+24|0]=(b&7)<<29|d>>>3;g=a;b=b>>21;k=(c&2097151)<<11|d>>>21;c=k+(D&2097151)|0;f=c;b=c>>>0>>0?b+1|0:b;c=b;v[g+27|0]=(b&63)<<26|f>>>6;g=0;h=((e&65535)<<16|i>>>16)&31;i=d&2097151;b=i;v[a+23|0]=h|b<<5;e=a;j=(c&2097151)<<11|f>>>21;d=j+(m&2097151)|0;c=c>>21;c=d>>>0>>0?c+1|0:c;v[e+31|0]=(c&131071)<<15|d>>>17;b=c;v[e+30|0]=(b&511)<<23|d>>>9;v[e+29|0]=(b&1)<<31|d>>>1;e=0;f=f&2097151;c=f;b=c<<2;c=g;g=i;v[a+26|0]=b|((c&524287)<<13|g>>>19);v[a+28|0]=(e&16383)<<18|f>>>14|d<<7}function pc(a,b,c,d){var e=0,f=0,g=0,h=0,i=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0,r=0,s=0,t=0,u=0,v=0,w=0,z=0,A=0,B=0,C=0,D=0,E=0,F=0,G=0,H=0,I=0,J=0,K=0,L=0,M=0,N=0,O=0,P=0,Q=0,R=0,S=0,T=0,U=0,V=0;while(1){e=m<<3;k=e+c|0;e=b+e|0;C=y[e+4|0]|y[e+5|0]<<8|(y[e+6|0]<<16|y[e+7|0]<<24);o=y[e|0]|y[e+1|0]<<8|(y[e+2|0]<<16|y[e+3|0]<<24);j=o<<24|o<<8&16711680;e=C<<24|o>>>8;f=e&65280;e=C<<8|o>>>24;j=e&255|f|j;e=C;x[k>>2]=((e&255)<<24|o>>>8)&-16777216|((e&16777215)<<8|o>>>24)&16711680|(e>>>8&65280|e>>>24)|i;x[k+4>>2]=j;m=m+1|0;if((m|0)!=16){continue}break}b=za(d,a,64);while(1){A=P<<3;C=A+c|0;d=C;e=x[d>>2];d=x[d+4>>2];o=b;z=x[o+32>>2];n=x[o+36>>2];k=ia(z,n,14);j=Y;k=ia(z,n,18)^k;j=Y^j;k=ia(z,n,41)^k;e=k+e|0;d=(Y^j)+d|0;d=e>>>0>>0?d+1|0:d;k=e;e=o;g=x[e+48>>2];j=A+35088|0;m=x[j>>2];k=m+k|0;d=x[j+4>>2]+d|0;d=k>>>0>>0?d+1|0:d;h=x[e+40>>2];j=g^(h^g)&z;k=j+k|0;f=x[e+52>>2];v=x[e+44>>2];e=((f^v)&n^f)+d|0;e=j>>>0>k>>>0?e+1|0:e;j=x[o+56>>2];k=j+k|0;d=x[o+60>>2]+e|0;d=j>>>0>k>>>0?d+1|0:d;j=k;m=x[o+24>>2];k=j+m|0;e=x[o+28>>2]+d|0;i=k;e=i>>>0>>0?e+1|0:e;r=e;x[o+24>>2]=i;x[o+28>>2]=e;k=o;u=x[k>>2];m=x[k+4>>2];e=ia(u,m,28);o=Y;e=ia(u,m,34)^e;t=Y^o;o=j+(ia(u,m,39)^e)|0;e=d+(Y^t)|0;e=j>>>0>o>>>0?e+1|0:e;t=x[k+16>>2];s=x[k+8>>2];p=u&(t|s)|s&t;o=p+o|0;d=e;e=x[k+20>>2];j=x[k+12>>2];d=d+(m&(e|j)|e&j)|0;l=o;d=o>>>0

>>0?d+1|0:d;o=d;x[k+56>>2]=l;x[k+60>>2]=d;d=k;k=e;e=ia(i,r,14);p=Y;q=ia(i,r,18)^e;p=Y^p;B=t;t=(h^z)&i^h;g=t+g|0;e=((n^v)&r^v)+f|0;e=g>>>0>>0?e+1|0:e;f=ia(i,r,41)^q;g=f+g|0;e=(Y^p)+e|0;e=g>>>0>>0?e+1|0:e;f=A|8;I=f+c|0;t=I;p=x[t>>2];g=p+g|0;e=x[t+4>>2]+e|0;e=g>>>0

>>0?e+1|0:e;f=f+35088|0;t=x[f>>2];g=t+g|0;e=x[f+4>>2]+e|0;e=g>>>0>>0?e+1|0:e;p=g;f=g;g=B+f|0;q=k;k=e;e=q+e|0;e=g>>>0>>0?e+1|0:e;t=e;x[d+16>>2]=g;x[d+20>>2]=e;f=d;d=ia(l,o,28);e=Y;q=ia(l,o,34)^d;w=Y^e;d=p;p=(s|u)&l|s&u;d=d+p|0;e=((j|m)&o|j&m)+k|0;e=d>>>0

>>0?e+1|0:e;p=ia(l,o,39)^q;k=p+d|0;d=(Y^w)+e|0;q=k;d=k>>>0

>>0?d+1|0:d;k=d;x[f+48>>2]=q;x[f+52>>2]=d;p=f;d=ia(g,t,14);e=Y;f=ia(g,t,18)^d;w=Y^e;B=s;s=(i^z)&g^z;d=s+h|0;e=((n^r)&t^n)+v|0;e=d>>>0>>0?e+1|0:e;f=ia(g,t,41)^f;d=f+d|0;e=(Y^w)+e|0;e=d>>>0>>0?e+1|0:e;f=d;s=A|16;L=s+c|0;d=L;h=x[d>>2];f=f+h|0;d=x[d+4>>2]+e|0;d=f>>>0>>0?d+1|0:d;e=s+35088|0;s=x[e>>2];f=s+f|0;e=x[e+4>>2]+d|0;e=f>>>0>>0?e+1|0:e;h=f;f=B+f|0;d=e;e=e+j|0;e=f>>>0>>0?e+1|0:e;s=e;x[p+8>>2]=f;x[p+12>>2]=e;e=p;j=ia(q,k,28);p=Y;v=ia(q,k,34)^j;p=Y^p;j=h;h=(l|u)&q|l&u;j=j+h|0;d=((m|o)&k|m&o)+d|0;d=j>>>0>>0?d+1|0:d;h=ia(q,k,39)^v;j=h+j|0;d=(Y^p)+d|0;v=j;d=j>>>0>>0?d+1|0:d;j=d;x[e+40>>2]=v;x[e+44>>2]=d;h=e;d=ia(f,s,14);e=Y;p=ia(f,s,18)^d;w=Y^e;E=u;e=(r^(r^t)&s)+n|0;u=i^(g^i)&f;d=u+z|0;p=ia(f,s,41)^p;n=d+p|0;d=(Y^w)+(d>>>0>>0?e+1|0:e)|0;d=n>>>0

>>0?d+1|0:d;p=A|24;B=p+c|0;e=B;u=x[e>>2];n=u+n|0;e=x[e+4>>2]+d|0;e=n>>>0>>0?e+1|0:e;d=n;n=p+35088|0;p=x[n>>2];d=d+p|0;e=x[n+4>>2]+e|0;e=d>>>0

>>0?e+1|0:e;u=d;p=d;n=E+d|0;d=e+m|0;d=n>>>0

>>0?d+1|0:d;p=d;x[h>>2]=n;x[h+4>>2]=d;d=ia(v,j,28);m=Y;z=ia(v,j,34)^d;w=Y^m;m=(l|q)&v|l&q;d=m+u|0;e=((k|o)&j|k&o)+e|0;e=d>>>0>>0?e+1|0:e;u=ia(v,j,39)^z;m=u+d|0;d=(Y^w)+e|0;d=m>>>0>>0?d+1|0:d;u=m;m=d;x[h+32>>2]=u;x[h+36>>2]=d;d=h;e=ia(n,p,14);h=Y;z=ia(n,p,18)^e;w=Y^h;E=l;e=r+(t^(s^t)&p)|0;h=i+(g^(g^f)&n)|0;e=h>>>0>>0?e+1|0:e;r=ia(n,p,41)^z;i=r+h|0;e=(Y^w)+e|0;e=i>>>0>>0?e+1|0:e;r=A|32;J=r+c|0;h=J;l=x[h>>2];i=l+i|0;e=x[h+4>>2]+e|0;e=i>>>0>>0?e+1|0:e;r=r+35088|0;h=x[r>>2];i=h+i|0;e=x[r+4>>2]+e|0;e=i>>>0>>0?e+1|0:e;l=i;i=E+i|0;h=o;o=e;e=h+e|0;e=i>>>0>>0?e+1|0:e;r=e;x[d+56>>2]=i;x[d+60>>2]=e;h=d;d=ia(u,m,28);e=Y;z=ia(u,m,34)^d;w=Y^e;d=l;l=(q|v)&u|q&v;d=d+l|0;e=((j|k)&m|j&k)+o|0;e=d>>>0>>0?e+1|0:e;l=ia(u,m,39)^z;o=l+d|0;d=(Y^w)+e|0;z=o;d=l>>>0>o>>>0?d+1|0:d;o=d;x[h+24>>2]=z;x[h+28>>2]=d;d=ia(i,r,14);e=Y;l=ia(i,r,18)^d;w=Y^e;e=t+(s^(p^s)&r)|0;d=g+(f^(f^n)&i)|0;e=d>>>0>>0?e+1|0:e;g=ia(i,r,41)^l;d=g+d|0;e=(Y^w)+e|0;e=d>>>0>>0?e+1|0:e;g=d;t=A|40;D=t+c|0;d=D;l=x[d>>2];g=g+l|0;d=x[d+4>>2]+e|0;d=g>>>0>>0?d+1|0:d;e=t+35088|0;t=x[e>>2];g=t+g|0;e=x[e+4>>2]+d|0;e=g>>>0>>0?e+1|0:e;l=g;g=g+q|0;d=e;e=e+k|0;e=g>>>0>>0?e+1|0:e;t=e;x[h+48>>2]=g;x[h+52>>2]=e;e=h;k=ia(z,o,28);h=Y;q=ia(z,o,34)^k;h=Y^h;k=l;l=(v|u)&z|v&u;k=k+l|0;d=((j|m)&o|j&m)+d|0;d=k>>>0>>0?d+1|0:d;l=ia(z,o,39)^q;k=l+k|0;d=(Y^h)+d|0;q=k;d=k>>>0>>0?d+1|0:d;k=d;x[e+16>>2]=q;x[e+20>>2]=d;h=e;d=ia(g,t,14);e=Y;l=ia(g,t,18)^d;w=Y^e;e=s+(p^(p^r)&t)|0;d=f+(n^(i^n)&g)|0;e=d>>>0>>0?e+1|0:e;s=ia(g,t,41)^l;f=s+d|0;d=(Y^w)+e|0;d=f>>>0>>0?d+1|0:d;s=A|48;Q=s+c|0;e=Q;l=x[e>>2];f=l+f|0;e=x[e+4>>2]+d|0;e=f>>>0>>0?e+1|0:e;d=f;f=s+35088|0;s=x[f>>2];d=d+s|0;e=x[f+4>>2]+e|0;e=d>>>0>>0?e+1|0:e;l=d;f=d+v|0;d=e+j|0;d=f>>>0>>0?d+1|0:d;s=d;x[h+40>>2]=f;x[h+44>>2]=d;d=ia(q,k,28);j=Y;v=ia(q,k,34)^d;w=Y^j;j=(u|z)&q|u&z;d=j+l|0;e=((m|o)&k|m&o)+e|0;e=d>>>0>>0?e+1|0:e;l=ia(q,k,39)^v;j=l+d|0;d=(Y^w)+e|0;v=j;d=j>>>0>>0?d+1|0:d;j=d;x[h+8>>2]=v;x[h+12>>2]=d;d=h;e=ia(f,s,14);h=Y;l=ia(f,s,18)^e;w=Y^h;e=p+(r^(r^t)&s)|0;h=n+(i^(g^i)&f)|0;e=h>>>0>>0?e+1|0:e;p=ia(f,s,41)^l;n=p+h|0;e=(Y^w)+e|0;e=n>>>0

>>0?e+1|0:e;p=A|56;R=p+c|0;h=R;l=x[h>>2];n=l+n|0;e=x[h+4>>2]+e|0;e=n>>>0>>0?e+1|0:e;p=p+35088|0;h=x[p>>2];n=h+n|0;e=x[p+4>>2]+e|0;e=h>>>0>n>>>0?e+1|0:e;l=n;n=n+u|0;h=m;m=e;e=h+e|0;e=n>>>0>>0?e+1|0:e;p=e;x[d+32>>2]=n;x[d+36>>2]=e;h=d;d=ia(v,j,28);e=Y;u=ia(v,j,34)^d;w=Y^e;d=l;l=(q|z)&v|q&z;d=d+l|0;e=((k|o)&j|k&o)+m|0;e=d>>>0>>0?e+1|0:e;l=ia(v,j,39)^u;m=l+d|0;d=(Y^w)+e|0;u=m;d=m>>>0>>0?d+1|0:d;m=d;x[h>>2]=u;x[h+4>>2]=d;l=h;d=ia(n,p,14);e=Y;h=ia(n,p,18)^d;w=Y^e;e=r+(t^(s^t)&p)|0;d=i+(g^(g^f)&n)|0;e=d>>>0>>0?e+1|0:e;i=ia(n,p,41)^h;d=i+d|0;e=(Y^w)+e|0;e=d>>>0>>0?e+1|0:e;i=d;r=A|64;S=r+c|0;d=S;h=x[d>>2];i=i+h|0;d=x[d+4>>2]+e|0;d=i>>>0>>0?d+1|0:d;e=r+35088|0;r=x[e>>2];i=r+i|0;e=x[e+4>>2]+d|0;e=i>>>0>>0?e+1|0:e;r=i;h=i;i=i+z|0;d=e;e=e+o|0;e=i>>>0>>0?e+1|0:e;h=e;x[l+24>>2]=i;x[l+28>>2]=e;e=l;o=ia(u,m,28);l=Y;z=ia(u,m,34)^o;l=Y^l;o=r;r=(q|v)&u|q&v;o=o+r|0;d=((j|k)&m|j&k)+d|0;d=o>>>0>>0?d+1|0:d;r=ia(u,m,39)^z;o=r+o|0;d=(Y^l)+d|0;z=o;d=o>>>0>>0?d+1|0:d;o=d;x[e+56>>2]=z;x[e+60>>2]=d;r=e;d=ia(i,h,14);e=Y;l=ia(i,h,18)^d;w=Y^e;e=t+(s^(p^s)&h)|0;d=g+(f^(f^n)&i)|0;e=d>>>0>>0?e+1|0:e;t=ia(i,h,41)^l;g=t+d|0;d=(Y^w)+e|0;d=g>>>0>>0?d+1|0:d;t=A|72;F=t+c|0;e=F;l=x[e>>2];g=l+g|0;e=x[e+4>>2]+d|0;e=g>>>0>>0?e+1|0:e;d=g;g=t+35088|0;t=x[g>>2];d=d+t|0;e=x[g+4>>2]+e|0;e=d>>>0>>0?e+1|0:e;t=d;l=d;g=d+q|0;d=e+k|0;d=g>>>0>>0?d+1|0:d;l=d;x[r+16>>2]=g;x[r+20>>2]=d;d=ia(z,o,28);k=Y;q=ia(z,o,34)^d;w=Y^k;k=(v|u)&z|v&u;d=k+t|0;e=((j|m)&o|j&m)+e|0;e=d>>>0>>0?e+1|0:e;t=ia(z,o,39)^q;k=t+d|0;d=(Y^w)+e|0;w=k;d=k>>>0>>0?d+1|0:d;k=d;x[r+48>>2]=w;x[r+52>>2]=d;d=r;e=ia(g,l,14);r=Y;t=ia(g,l,18)^e;q=Y^r;e=s+(p^(h^p)&l)|0;r=f+(n^(i^n)&g)|0;e=r>>>0>>0?e+1|0:e;f=r;r=ia(g,l,41)^t;f=f+r|0;e=(Y^q)+e|0;e=f>>>0>>0?e+1|0:e;r=A|80;G=r+c|0;t=G;s=x[t>>2];f=s+f|0;e=x[t+4>>2]+e|0;e=f>>>0>>0?e+1|0:e;r=r+35088|0;t=x[r>>2];f=t+f|0;e=x[r+4>>2]+e|0;e=f>>>0>>0?e+1|0:e;r=f;f=f+v|0;q=j;j=e;e=q+e|0;e=f>>>0>>0?e+1|0:e;s=e;x[d+8>>2]=f;x[d+12>>2]=e;t=d;d=ia(w,k,28);e=Y;q=ia(w,k,34)^d;v=Y^e;d=r;r=(u|z)&w|u&z;d=d+r|0;e=((m|o)&k|m&o)+j|0;e=d>>>0>>0?e+1|0:e;r=ia(w,k,39)^q;j=r+d|0;d=(Y^v)+e|0;d=j>>>0>>0?d+1|0:d;r=d;x[t+40>>2]=j;x[t+44>>2]=d;d=ia(f,s,14);e=Y;q=ia(f,s,18)^d;v=Y^e;e=p+(h^(h^l)&s)|0;d=n+(i^(g^i)&f)|0;e=d>>>0>>0?e+1|0:e;n=ia(f,s,41)^q;d=n+d|0;e=(Y^v)+e|0;e=d>>>0>>0?e+1|0:e;n=d;p=A|88;E=p+c|0;d=E;q=x[d>>2];n=n+q|0;d=x[d+4>>2]+e|0;d=n>>>0>>0?d+1|0:d;e=p+35088|0;p=x[e>>2];n=p+n|0;e=x[e+4>>2]+d|0;e=n>>>0

>>0?e+1|0:e;q=n;p=n;n=n+u|0;d=e;e=e+m|0;e=n>>>0

>>0?e+1|0:e;p=e;x[t>>2]=n;x[t+4>>2]=e;e=t;m=ia(j,r,28);t=Y;v=ia(j,r,34)^m;t=Y^t;m=q;q=(w|z)&j|w&z;m=m+q|0;d=((k|o)&r|k&o)+d|0;d=m>>>0>>0?d+1|0:d;q=ia(j,r,39)^v;m=q+m|0;d=(Y^t)+d|0;d=m>>>0>>0?d+1|0:d;t=d;x[e+32>>2]=m;x[e+36>>2]=d;q=e;d=ia(n,p,14);e=Y;v=ia(n,p,18)^d;u=Y^e;e=h+(l^(l^s)&p)|0;d=i+(g^(g^f)&n)|0;e=d>>>0>>0?e+1|0:e;h=ia(n,p,41)^v;i=h+d|0;d=(Y^u)+e|0;d=i>>>0>>0?d+1|0:d;h=A|96;T=h+c|0;e=T;v=x[e>>2];i=v+i|0;e=x[e+4>>2]+d|0;e=i>>>0>>0?e+1|0:e;d=i;i=h+35088|0;h=x[i>>2];d=d+h|0;e=x[i+4>>2]+e|0;e=d>>>0>>0?e+1|0:e;u=d;h=d;i=d+z|0;d=e+o|0;v=i;d=i>>>0>>0?d+1|0:d;i=d;x[q+56>>2]=v;x[q+60>>2]=d;h=q;d=ia(m,t,28);o=Y;q=ia(m,t,34)^d;z=Y^o;o=(j|w)&m|j&w;d=o+u|0;e=((k|r)&t|k&r)+e|0;e=d>>>0>>0?e+1|0:e;q=ia(m,t,39)^q;o=q+d|0;d=(Y^z)+e|0;d=o>>>0>>0?d+1|0:d;q=o;o=d;x[h+24>>2]=q;x[h+28>>2]=d;d=h;e=ia(v,i,14);h=Y;u=ia(v,i,18)^e;z=Y^h;e=l+(s^(p^s)&i)|0;h=g+(f^(f^n)&v)|0;e=h>>>0>>0?e+1|0:e;g=h;h=ia(v,i,41)^u;g=g+h|0;e=(Y^z)+e|0;e=g>>>0>>0?e+1|0:e;h=A|104;U=h+c|0;l=U;u=x[l>>2];g=u+g|0;e=x[l+4>>2]+e|0;e=g>>>0>>0?e+1|0:e;h=h+35088|0;l=x[h>>2];g=l+g|0;e=x[h+4>>2]+e|0;e=g>>>0>>0?e+1|0:e;l=g;h=g;g=g+w|0;u=k;k=e;e=u+e|0;u=g;e=g>>>0>>0?e+1|0:e;g=e;x[d+48>>2]=u;x[d+52>>2]=e;h=d;d=ia(q,o,28);e=Y;z=ia(q,o,34)^d;w=Y^e;d=l;l=(j|m)&q|j&m;d=d+l|0;e=((r|t)&o|r&t)+k|0;e=d>>>0>>0?e+1|0:e;l=ia(q,o,39)^z;k=l+d|0;d=(Y^w)+e|0;d=k>>>0>>0?d+1|0:d;l=k;k=d;x[h+16>>2]=l;x[h+20>>2]=d;d=ia(u,g,14);e=Y;z=ia(u,g,18)^d;w=Y^e;e=s+(p^(i^p)&g)|0;d=f+(n^(n^v)&u)|0;e=d>>>0>>0?e+1|0:e;f=ia(u,g,41)^z;d=f+d|0;e=(Y^w)+e|0;e=d>>>0>>0?e+1|0:e;f=d;s=A|112;z=s+c|0;d=z;w=x[d>>2];f=f+w|0;d=x[d+4>>2]+e|0;d=f>>>0>>0?d+1|0:d;e=s+35088|0;s=x[e>>2];f=s+f|0;e=x[e+4>>2]+d|0;e=f>>>0>>0?e+1|0:e;w=f;f=j+f|0;d=e;e=r+e|0;s=f;e=f>>>0>>0?e+1|0:e;j=e;x[h+40>>2]=f;x[h+44>>2]=e;e=h;f=ia(l,k,28);r=Y;h=ia(l,k,34)^f;r=Y^r;f=w;w=(m|q)&l|m&q;f=f+w|0;d=((o|t)&k|o&t)+d|0;d=f>>>0>>0?d+1|0:d;h=ia(l,k,39)^h;f=h+f|0;d=(Y^r)+d|0;d=f>>>0>>0?d+1|0:d;h=f;f=d;x[e+8>>2]=h;x[e+12>>2]=d;d=ia(s,j,14);e=Y;w=ia(s,j,18)^d;K=Y^e;e=p+(i^(g^i)&j)|0;d=n+(v^(v^u)&s)|0;e=d>>>0>>0?e+1|0:e;i=ia(s,j,41)^w;j=i+d|0;d=(Y^K)+e|0;d=j>>>0>>0?d+1|0:d;g=A|120;i=g+c|0;e=i;n=x[e>>2];j=n+j|0;e=x[e+4>>2]+d|0;e=j>>>0>>0?e+1|0:e;d=j;j=g+35088|0;g=x[j>>2];d=d+g|0;e=x[j+4>>2]+e|0;e=d>>>0>>0?e+1|0:e;g=d;j=m+d|0;d=e+t|0;r=b;x[r+32>>2]=j;x[r+36>>2]=j>>>0>>0?d+1|0:d;d=ia(h,f,28);j=Y;m=ia(h,f,34)^d;n=Y^j;e=((k|o)&f|k&o)+e|0;d=g;g=(l|q)&h|l&q;d=d+g|0;k=ia(h,f,39)^m;o=d+k|0;d=(Y^n)+(d>>>0>>0?e+1|0:e)|0;j=r;x[j>>2]=o;x[j+4>>2]=k>>>0>o>>>0?d+1|0:d;if((P|0)==64){while(1){d=V<<3;c=d+a|0;e=b+d|0;o=x[e>>2];d=o+x[c>>2]|0;e=x[c+4>>2]+x[e+4>>2]|0;x[c>>2]=d;x[c+4>>2]=d>>>0>>0?e+1|0:e;V=V+1|0;if((V|0)!=8){continue}break}}else{P=P+16|0;j=(P<<3)+c|0;d=x[z+4>>2];r=d;e=d>>>6|0;K=x[z>>2];d=((d&63)<<26|K>>>6)^ia(K,d,19);e=Y^e;d=ia(K,r,61)^d;M=x[F>>2];o=M;d=d+o|0;v=x[F+4>>2];e=v+(Y^e)|0;e=d>>>0>>0?e+1|0:e;o=x[C>>2];d=o+d|0;e=x[C+4>>2]+e|0;g=d;d=d>>>0>>0?e+1|0:e;o=x[I+4>>2];k=o;e=k>>>7|0;m=x[I>>2];o=((k&127)<<25|m>>>7)^ia(m,k,1);e=Y^e;f=g;g=ia(m,k,8)^o;o=f+g|0;e=(Y^e)+d|0;F=o;e=g>>>0>o>>>0?e+1|0:e;o=e;x[j>>2]=F;x[j+4>>2]=e;j=C;d=m;N=x[G>>2];m=N;d=d+m|0;u=x[G+4>>2];e=u+k|0;e=d>>>0>>0?e+1|0:e;m=d;d=e;k=x[i+4>>2];t=k;e=k>>>6|0;G=x[i>>2];k=((k&63)<<26|G>>>6)^ia(G,k,19);i=Y^e;k=ia(G,t,61)^k;e=k+m|0;d=(Y^i)+d|0;m=e;e=e>>>0>>0?d+1|0:d;k=x[L+4>>2];i=k;d=i>>>7|0;g=x[L>>2];k=((i&127)<<25|g>>>7)^ia(g,i,1);f=Y^d;k=ia(g,i,8)^k;d=k+m|0;e=(Y^f)+e|0;H=d;e=d>>>0>>0?e+1|0:e;k=e;x[j+136>>2]=d;x[j+140>>2]=e;m=j;O=x[E>>2];j=O;e=j+g|0;z=x[E+4>>2];d=z+i|0;d=e>>>0>>0?d+1|0:d;j=d;d=ia(F,o,19);g=Y;h=e;i=d;e=o;d=e>>>6|0;f=i^((e&63)<<26|F>>>6)^ia(F,e,61);i=h+f|0;e=(Y^(d^g))+j|0;e=f>>>0>i>>>0?e+1|0:e;d=e;j=x[B+4>>2];g=j;e=g>>>7|0;f=x[B>>2];j=((g&127)<<25|f>>>7)^ia(f,g,1);e=Y^e;h=i;i=ia(f,g,8)^j;j=h+i|0;e=(Y^e)+d|0;s=j;e=j>>>0>>0?e+1|0:e;j=e;x[m+144>>2]=s;x[m+148>>2]=e;i=m;E=x[T>>2];m=E;e=m+f|0;w=x[T+4>>2];d=w+g|0;d=e>>>0>>0?d+1|0:d;m=d;d=ia(H,k,19);f=Y;h=e;g=d;e=k;d=e>>>6|0;n=g^((e&63)<<26|H>>>6)^ia(H,e,61);g=h+n|0;e=(Y^(d^f))+m|0;f=g;d=f>>>0>>0?e+1|0:e;m=x[J+4>>2];g=m;e=g>>>7|0;n=x[J>>2];m=((g&127)<<25|n>>>7)^ia(n,g,1);e=Y^e;h=f;f=ia(n,g,8)^m;m=h+f|0;e=(Y^e)+d|0;p=m;e=f>>>0>m>>>0?e+1|0:e;m=e;x[i+152>>2]=p;x[i+156>>2]=e;f=i;I=x[U>>2];i=I;e=i+n|0;L=x[U+4>>2];d=L+g|0;d=e>>>0>>0?d+1|0:d;i=d;d=ia(s,j,19);g=Y;l=e;h=d;e=j;d=e>>>6|0;n=h^((e&63)<<26|s>>>6)^ia(s,e,61);e=l+n|0;d=(Y^(d^g))+i|0;h=e;e=e>>>0>>0?d+1|0:d;i=x[D+4>>2];n=i;d=i>>>7|0;g=x[D>>2];i=((i&127)<<25|g>>>7)^ia(g,i,1);l=Y^d;i=ia(g,n,8)^i;d=i+h|0;e=(Y^l)+e|0;h=d;e=d>>>0>>0?e+1|0:e;i=e;x[f+160>>2]=d;x[f+164>>2]=e;d=n+r|0;e=g+K|0;d=e>>>0>>0?d+1|0:d;g=d;d=ia(p,m,19);l=Y;n=e;q=d;e=m;d=e>>>6|0;q=q^((e&63)<<26|p>>>6)^ia(p,e,61);n=n+q|0;e=(Y^(d^l))+g|0;e=n>>>0>>0?e+1|0:e;q=n;g=e;l=x[Q+4>>2];n=l;e=n>>>7|0;d=x[Q>>2];l=((n&127)<<25|d>>>7)^ia(d,n,1);e=Y^e;B=q;q=ia(d,n,8)^l;l=B+q|0;e=(Y^e)+g|0;e=l>>>0>>0?e+1|0:e;g=e;x[f+168>>2]=l;x[f+172>>2]=e;q=f;e=d;f=e+G|0;d=n+t|0;d=e>>>0>f>>>0?d+1|0:d;e=f;f=d;d=ia(h,i,19);A=Y;C=e;n=d;e=i;d=e>>>6|0;B=n^((e&63)<<26|h>>>6)^ia(h,e,61);n=C+B|0;e=(Y^(d^A))+f|0;A=n;d=n>>>0>>0?e+1|0:e;f=x[R+4>>2];B=f;e=f>>>7|0;n=x[R>>2];f=((f&127)<<25|n>>>7)^ia(n,f,1);J=Y^e;f=ia(n,B,8)^f;e=f+A|0;d=(Y^J)+d|0;J=e;d=e>>>0>>0?d+1|0:d;f=d;x[q+176>>2]=e;x[q+180>>2]=d;A=q;d=o+B|0;e=n+F|0;d=e>>>0>>0?d+1|0:d;n=d;d=ia(l,g,19);B=Y;C=e;q=d;e=g;d=e>>>6|0;D=q^((e&63)<<26|l>>>6)^ia(l,e,61);q=C+D|0;e=(Y^(d^B))+n|0;B=q;n=q>>>0>>0?e+1|0:e;q=x[S+4>>2];D=q;e=q>>>7|0;d=x[S>>2];q=((q&127)<<25|d>>>7)^ia(d,q,1);e=Y^e;C=B;B=ia(d,D,8)^q;q=C+B|0;e=(Y^e)+n|0;e=q>>>0>>0?e+1|0:e;n=e;x[A+184>>2]=q;x[A+188>>2]=e;B=A;e=d;A=e+H|0;d=k+D|0;d=e>>>0>A>>>0?d+1|0:d;e=A;k=d;d=ia(J,f,19);A=Y;D=e;C=d;e=f;d=e>>>6|0;H=C^((e&63)<<26|J>>>6)^ia(J,e,61);e=D+H|0;d=(Y^(d^A))+k|0;d=e>>>0>>0?d+1|0:d;k=d;d=ia(M,v,1);H=Y;C=e;A=d;e=v;d=e>>>7|0;D=A^((e&127)<<25|M>>>7)^ia(M,e,8);A=C+D|0;e=(Y^(d^H))+k|0;e=A>>>0>>0?e+1|0:e;k=e;x[B+192>>2]=A;x[B+196>>2]=e;d=j+v|0;e=s+M|0;d=e>>>0>>0?d+1|0:d;j=d;d=ia(q,n,19);s=Y;C=e;v=d;e=n;d=e>>>6|0;v=v^((e&63)<<26|q>>>6)^ia(q,e,61);e=C+v|0;d=(Y^(d^s))+j|0;d=e>>>0>>0?d+1|0:d;j=d;d=ia(N,u,1);v=Y;C=e;s=d;e=u;d=e>>>7|0;H=s^((e&127)<<25|N>>>7)^ia(N,e,8);s=C+H|0;e=(Y^(d^v))+j|0;v=s;e=s>>>0>>0?e+1|0:e;j=e;x[B+200>>2]=s;x[B+204>>2]=e;s=B;d=m+u|0;e=p+N|0;d=e>>>0

>>0?d+1|0:d;m=d;d=ia(A,k,19);p=Y;C=e;B=d;e=k;d=e>>>6|0;u=B^((e&63)<<26|A>>>6)^ia(A,e,61);e=C+u|0;d=(Y^(d^p))+m|0;d=e>>>0>>0?d+1|0:d;m=d;d=ia(O,z,1);u=Y;C=e;p=d;e=z;d=e>>>7|0;B=p^((e&127)<<25|O>>>7)^ia(O,e,8);p=C+B|0;e=(Y^(d^u))+m|0;e=p>>>0>>0?e+1|0:e;m=e;x[s+208>>2]=p;x[s+212>>2]=e;d=i+z|0;e=h+O|0;d=e>>>0>>0?d+1|0:d;i=d;d=ia(v,j,19);h=Y;u=e;B=d;e=j;d=e>>>6|0;j=B^((e&63)<<26|v>>>6)^ia(v,e,61);e=u+j|0;d=(Y^(d^h))+i|0;d=e>>>0>>0?d+1|0:d;j=d;d=ia(E,w,1);h=Y;B=e;i=d;e=w;d=e>>>7|0;v=i^((e&127)<<25|E>>>7)^ia(E,e,8);i=B+v|0;e=(Y^(d^h))+j|0;h=i;e=i>>>0>>0?e+1|0:e;j=e;x[s+216>>2]=i;x[s+220>>2]=e;i=s;d=g+w|0;e=l+E|0;d=e>>>0>>0?d+1|0:d;g=d;d=ia(p,m,19);s=Y;B=e;l=d;e=m;d=e>>>6|0;m=l^((e&63)<<26|p>>>6)^ia(p,e,61);e=B+m|0;d=(Y^(d^s))+g|0;d=e>>>0>>0?d+1|0:d;m=d;d=ia(I,L,1);s=Y;l=e;g=d;e=L;d=e>>>7|0;p=g^((e&127)<<25|I>>>7)^ia(I,e,8);g=l+p|0;e=(Y^(d^s))+m|0;s=g;e=g>>>0

>>0?e+1|0:e;m=e;x[i+224>>2]=g;x[i+228>>2]=e;d=f+L|0;e=J+I|0;d=e>>>0>>0?d+1|0:d;g=d;d=ia(h,j,19);f=Y;p=e;l=d;e=j;d=e>>>6|0;j=l^((e&63)<<26|h>>>6)^ia(h,e,61);e=p+j|0;d=(Y^(d^f))+g|0;d=e>>>0>>0?d+1|0:d;j=d;d=ia(K,r,1);f=Y;h=e;g=d;e=r;d=e>>>7|0;p=g^((e&127)<<25|K>>>7)^ia(K,e,8);g=h+p|0;e=(Y^(d^f))+j|0;f=g;e=f>>>0

>>0?e+1|0:e;j=e;x[i+232>>2]=f;x[i+236>>2]=e;e=i;d=n+r|0;i=q+K|0;d=i>>>0>>0?d+1|0:d;g=d;d=ia(s,m,19);n=Y;l=i;h=d;i=m;d=i>>>6|0;i=h^((i&63)<<26|s>>>6)^ia(s,i,61);m=l+i|0;d=(Y^(d^n))+g|0;g=m;m=i>>>0>g>>>0?d+1|0:d;d=ia(G,t,1);n=Y;i=e;h=d;e=t;d=e>>>7|0;r=h^((e&127)<<25|G>>>7)^ia(G,e,8);g=r+g|0;e=(Y^(d^n))+m|0;x[i+240>>2]=g;x[i+244>>2]=g>>>0>>0?e+1|0:e;d=k+t|0;e=A+G|0;d=e>>>0>>0?d+1|0:d;k=d;d=ia(f,j,19);m=Y;h=e;g=d;e=j;d=e>>>6|0;j=g^((e&63)<<26|f>>>6)^ia(f,e,61);e=h+j|0;d=(Y^(d^m))+k|0;d=e>>>0>>0?d+1|0:d;k=d;d=ia(F,o,1);j=Y;g=e;m=d;e=o;d=e>>>7|0;m=m^((e&127)<<25|F>>>7)^ia(F,e,8);o=g+m|0;e=(Y^(d^j))+k|0;x[i+248>>2]=o;x[i+252>>2]=m>>>0>o>>>0?e+1|0:e;continue}break}}function Eb(a){var b=0,c=0,d=0,e=0,f=0,g=0,h=0,i=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0,r=0,s=0,t=0,u=0,w=0,x=0,z=0,A=0,B=0,C=0,D=0,E=0,F=0,G=0,H=0,I=0,J=0,K=0,L=0,M=0,N=0,O=0,P=0,Q=0,R=0,S=0,T=0,U=0,V=0,W=0,X=0,Z=0,_=0,$=0,aa=0,ba=0,ca=0,da=0,ea=0,fa=0,ga=0,ha=0,ia=0;ea=sa(a);fa=y[a+2|0]|y[a+3|0]<<8|(y[a+4|0]<<16|y[a+5|0]<<24);ga=sa(a+5|0);ha=Y;X=y[a+7|0]|y[a+8|0]<<8|(y[a+9|0]<<16|y[a+10|0]<<24);Z=y[a+10|0]|y[a+11|0]<<8|(y[a+12|0]<<16|y[a+13|0]<<24);ia=sa(a+13|0);_=Y;p=y[a+15|0]|y[a+16|0]<<8|(y[a+17|0]<<16|y[a+18|0]<<24);F=sa(a+18|0);q=Y;k=sa(a+21|0);g=y[a+23|0]|y[a+24|0]<<8|(y[a+25|0]<<16|y[a+26|0]<<24);f=sa(a+26|0);c=Y;Q=y[a+28|0]|y[a+29|0]<<8|(y[a+30|0]<<16|y[a+31|0]<<24);z=y[a+31|0]|y[a+32|0]<<8|(y[a+33|0]<<16|y[a+34|0]<<24);D=sa(a+34|0);C=Y;r=y[a+36|0]|y[a+37|0]<<8|(y[a+38|0]<<16|y[a+39|0]<<24);G=sa(a+39|0);t=Y;i=sa(a+42|0);e=y[a+44|0]|y[a+45|0]<<8|(y[a+46|0]<<16|y[a+47|0]<<24);d=sa(a+47|0);h=Y;H=((h&3)<<30|d>>>2)&2097151;b=((c&3)<<30|f>>>2)&2097151;f=Fj(H,0,136657,0)+b|0;c=Y;c=b>>>0>f>>>0?c+1|0:c;I=(y[a+49|0]|y[a+50|0]<<8|(y[a+51|0]<<16|y[a+52|0]<<24))>>>7&2097151;d=Fj(I,0,-997805,-1);f=d+f|0;b=Y+c|0;b=d>>>0>f>>>0?b+1|0:b;J=(y[a+52|0]|y[a+53|0]<<8|(y[a+54|0]<<16|y[a+55|0]<<24))>>>4&2097151;c=Fj(J,0,654183,0);f=c+f|0;d=Y+b|0;d=c>>>0>f>>>0?d+1|0:d;b=f;c=sa(a+55|0);f=Y;K=((f&1)<<31|c>>>1)&2097151;c=Fj(K,0,470296,0);f=b+c|0;b=Y+d|0;b=c>>>0>f>>>0?b+1|0:b;L=(y[a+57|0]|y[a+58|0]<<8|(y[a+59|0]<<16|y[a+60|0]<<24))>>>6&2097151;d=Fj(L,0,666643,0);f=d+f|0;c=Y+b|0;c=d>>>0>f>>>0?c+1|0:c;m=c;d=c;j=e>>>5&2097151;M=(y[a+60|0]|y[a+61|0]<<8|(y[a+62|0]<<16|y[a+63|0]<<24))>>>3|0;c=i&2097151;e=Fj(M,0,-683901,-1)+c|0;b=Y;i=e;b=c>>>0>e>>>0?b+1|0:b;n=b;b=e;e=n-((b>>>0<4293918720)-1|0)|0;o=b- -1048576|0;w=e;b=e>>21;e=(e&2097151)<<11|o>>>21;j=e+j|0;R=j;c=e>>>0>j>>>0?b+1|0:b;B=c;b=Fj(j,c,-683901,-1);h=b+f|0;c=Y+d|0;E=h;l=b>>>0>h>>>0?c+1|0:c;d=g>>>5&2097151;h=Fj(H,U,-997805,-1)+d|0;b=Y;b=d>>>0>h>>>0?b+1|0:b;c=Fj(I,0,654183,0);h=c+h|0;d=Y+b|0;d=c>>>0>h>>>0?d+1|0:d;b=Fj(J,0,470296,0);h=b+h|0;c=Y+d|0;c=b>>>0>h>>>0?c+1|0:c;d=Fj(K,V,666643,0);h=d+h|0;b=Y+c|0;g=h;d=d>>>0>g>>>0?b+1|0:b;b=k&2097151;h=Fj(H,U,654183,0)+b|0;c=Y;c=b>>>0>h>>>0?c+1|0:c;b=h;h=Fj(I,0,470296,0);e=b+h|0;b=Y+c|0;b=e>>>0>>0?b+1|0:b;h=Fj(J,0,666643,0);e=h+e|0;c=Y+b|0;j=e;c=e>>>0>>0?c+1|0:c;e=c;b=j;h=c-((b>>>0<4293918720)-1|0)|0;N=b- -1048576|0;s=h;b=h>>>21|0;c=(h&2097151)<<11|N>>>21;h=c+g|0;d=b+d|0;g=h;d=c>>>0>g>>>0?d+1|0:d;k=d;b=g;u=d-((b>>>0<4293918720)-1|0)|0;x=b- -1048576|0;ca=f- -1048576|0;m=m-((f>>>0<4293918720)-1|0)|0;h=m;d=u;b=d>>21;f=(d&2097151)<<11|x>>>21;u=f+E|0;c=b+l|0;c=f>>>0>u>>>0?c+1|0:c;f=u;b=ca&-2097152;m=c-((b>>>0>f>>>0)+h|0)|0;b=f-b|0;da=b- -1048576|0;f=m-((b>>>0<4293918720)-1|0)|0;c=da&-2097152;$=b-c|0;aa=m-((b>>>0>>0)+f|0)|0;c=Fj(R,B,136657,0)+g|0;b=k+Y|0;b=c>>>0>>0?b+1|0:b;g=c;c=x&-2097152;O=g-c|0;E=b-((c>>>0>g>>>0)+d|0)|0;b=o&-2097152;m=i-b|0;l=n-((b>>>0>i>>>0)+w|0)|0;b=((t&7)<<29|G>>>3)&2097151;d=Fj(M,0,136657,0)+b|0;c=Y;c=b>>>0>d>>>0?c+1|0:c;b=d;d=Fj(L,0,-683901,-1);g=b+d|0;b=Y+c|0;i=g;g=d>>>0>g>>>0?b+1|0:b;b=Fj(K,V,-683901,-1);c=Y;d=b;b=r>>>6&2097151;d=d+b|0;c=b>>>0>d>>>0?c+1|0:c;b=Fj(M,0,-997805,-1);k=b+d|0;d=Y+c|0;d=b>>>0>k>>>0?d+1|0:d;c=Fj(L,0,136657,0);k=c+k|0;b=Y+d|0;b=c>>>0>k>>>0?b+1|0:b;o=b;b=k;c=o-((b>>>0<4293918720)-1|0)|0;G=b- -1048576|0;x=c;b=(c&2097151)<<11|G>>>21;i=b+i|0;c=(c>>21)+g|0;c=b>>>0>i>>>0?c+1|0:c;n=c;b=i;c=c-((b>>>0<4293918720)-1|0)|0;u=b- -1048576|0;w=c;d=c>>21;c=(c&2097151)<<11|u>>>21;g=c+m|0;b=d+l|0;S=g;b=c>>>0>g>>>0?b+1|0:b;A=b;c=Fj(g,b,-683901,-1);d=c+O|0;b=Y+E|0;ba=d;r=c>>>0>d>>>0?b+1|0:b;l=j;b=((q&7)<<29|F>>>3)&2097151;d=Fj(H,U,470296,0)+b|0;c=Y;c=b>>>0>d>>>0?c+1|0:c;b=Fj(I,0,666643,0);d=b+d|0;c=Y+c|0;m=d;d=b>>>0>d>>>0?c+1|0:c;g=p>>>6&2097151;j=Fj(H,U,666643,0)+g|0;b=Y;b=g>>>0>j>>>0?b+1|0:b;p=b;b=j;g=p-((b>>>0<4293918720)-1|0)|0;O=b- -1048576|0;q=g;c=g>>>21|0;b=(g&2097151)<<11|O>>>21;g=b+m|0;c=c+d|0;c=b>>>0>g>>>0?c+1|0:c;t=c;b=g;F=c-((b>>>0<4293918720)-1|0)|0;E=b- -1048576|0;b=u&-2097152;d=n-((b>>>0>i>>>0)+w|0)|0;P=i-b|0;T=d;m=F;i=(m&2097151)<<11|E>>>21;l=i+l|0;b=(m>>>21|0)+e|0;b=i>>>0>l>>>0?b+1|0:b;e=Fj(R,B,-997805,-1);i=l;c=N&-2097152;l=e+(i-c|0)|0;c=Y+(b-((s&8191)+(c>>>0>i>>>0)|0)|0)|0;c=e>>>0>l>>>0?c+1|0:c;b=Fj(S,A,136657,0);e=b+l|0;c=Y+c|0;c=b>>>0>e>>>0?c+1|0:c;d=Fj(P,d,-683901,-1);e=d+e|0;b=Y+c|0;b=d>>>0>e>>>0?b+1|0:b;n=b;b=e;d=n-((b>>>0<4293918720)-1|0)|0;u=b- -1048576|0;w=d;b=d>>21;d=(d&2097151)<<11|u>>>21;i=d+ba|0;c=b+r|0;c=d>>>0>i>>>0?c+1|0:c;d=i;l=c;b=d;r=c-((b>>>0<4293918720)-1|0)|0;s=b- -1048576|0;i=r;b=i>>21;c=(i&2097151)<<11|s>>>21;r=c+$|0;b=b+aa|0;$=r;r=c>>>0>r>>>0?b+1|0:b;b=s&-2097152;aa=d-b|0;ba=l-((b>>>0>d>>>0)+i|0)|0;b=u&-2097152;F=e-b|0;N=n-((b>>>0>e>>>0)+w|0)|0;b=Fj(R,B,654183,0);c=E&-2097152;e=b+(g-c|0)|0;d=Y+(t-((m&8191)+(c>>>0>g>>>0)|0)|0)|0;d=b>>>0>e>>>0?d+1|0:d;c=Fj(S,A,-997805,-1);e=c+e|0;b=Y+d|0;b=c>>>0>e>>>0?b+1|0:b;d=Fj(P,T,136657,0);e=d+e|0;c=Y+b|0;u=e;i=d>>>0>e>>>0?c+1|0:c;b=G&-2097152;s=k-b|0;t=o-((b>>>0>k>>>0)+x|0)|0;c=((C&1)<<31|D>>>1)&2097151;e=Fj(J,0,-683901,-1)+c|0;b=Y;b=c>>>0>e>>>0?b+1|0:b;c=Fj(K,V,136657,0);d=c+e|0;b=Y+b|0;b=c>>>0>d>>>0?b+1|0:b;c=d;d=Fj(M,0,654183,0);e=c+d|0;c=Y+b|0;c=d>>>0>e>>>0?c+1|0:c;b=Fj(L,0,-997805,-1);d=b+e|0;c=Y+c|0;k=d;e=b>>>0>d>>>0?c+1|0:c;b=Fj(I,0,-683901,-1);d=Y;c=b;b=z>>>4&2097151;c=c+b|0;d=b>>>0>c>>>0?d+1|0:d;b=c;c=Fj(J,0,136657,0);g=b+c|0;b=Y+d|0;b=c>>>0>g>>>0?b+1|0:b;d=Fj(K,V,-997805,-1);g=d+g|0;c=Y+b|0;c=d>>>0>g>>>0?c+1|0:c;d=Fj(M,0,470296,0);g=d+g|0;b=Y+c|0;b=d>>>0>g>>>0?b+1|0:b;d=Fj(L,0,654183,0);g=d+g|0;c=Y+b|0;c=d>>>0>g>>>0?c+1|0:c;n=c;b=g;d=c-((b>>>0<4293918720)-1|0)|0;x=b- -1048576|0;w=d;b=d>>21;c=(d&2097151)<<11|x>>>21;d=c+k|0;b=b+e|0;e=d;b=c>>>0>d>>>0?b+1|0:b;l=b;b=d;d=l-((b>>>0<4293918720)-1|0)|0;m=b- -1048576|0;k=d;b=d>>21;d=(d&2097151)<<11|m>>>21;o=d+s|0;c=b+t|0;W=o;c=d>>>0>o>>>0?c+1|0:c;z=c;b=Fj(o,c,-683901,-1);c=b+u|0;d=Y+i|0;t=c;i=b>>>0>c>>>0?d+1|0:d;b=m&-2097152;k=l-((b>>>0>e>>>0)+k|0)|0;D=e-b|0;C=k;b=Fj(R,B,470296,0);c=O&-2097152;d=b+(j-c|0)|0;c=Y+(p-((q&2047)+(c>>>0>j>>>0)|0)|0)|0;c=b>>>0>d>>>0?c+1|0:c;b=Fj(S,A,654183,0);d=b+d|0;c=Y+c|0;c=b>>>0>d>>>0?c+1|0:c;b=Fj(P,T,-997805,-1);e=b+d|0;d=Y+c|0;d=b>>>0>e>>>0?d+1|0:d;c=Fj(o,z,136657,0);e=c+e|0;b=Y+d|0;b=c>>>0>e>>>0?b+1|0:b;d=Fj(D,k,-683901,-1);e=d+e|0;c=Y+b|0;c=d>>>0>e>>>0?c+1|0:c;l=c;b=e;d=c-((b>>>0<4293918720)-1|0)|0;q=b- -1048576|0;k=d;b=d>>21;c=(d&2097151)<<11|q>>>21;d=c+t|0;b=b+i|0;b=c>>>0>d>>>0?b+1|0:b;i=b;b=d;t=i-((b>>>0<4293918720)-1|0)|0;m=b- -1048576|0;j=t;b=j>>21;t=(j&2097151)<<11|m>>>21;p=t+F|0;c=b+N|0;F=p;t=p>>>0>>0?c+1|0:c;b=m&-2097152;N=d-b|0;G=i-((b>>>0>d>>>0)+j|0)|0;b=q&-2097152;u=e-b|0;o=l-((b>>>0>e>>>0)+k|0)|0;c=((_&1)<<31|ia>>>1)&2097151;e=Fj(R,B,666643,0)+c|0;b=Y;b=c>>>0>e>>>0?b+1|0:b;d=Fj(S,A,470296,0);e=d+e|0;c=Y+b|0;c=d>>>0>e>>>0?c+1|0:c;d=Fj(P,T,654183,0);e=d+e|0;b=Y+c|0;b=d>>>0>e>>>0?b+1|0:b;c=Fj(W,z,-997805,-1);e=c+e|0;d=Y+b|0;d=c>>>0>e>>>0?d+1|0:d;b=Fj(D,C,136657,0);e=b+e|0;c=Y+d|0;k=e;j=b>>>0>e>>>0?c+1|0:c;b=x&-2097152;i=g-b|0;g=n-((b>>>0>g>>>0)+w|0)|0;b=Fj(H,U,-683901,-1);c=Y;d=b;b=Q>>>7&2097151;d=d+b|0;c=b>>>0>d>>>0?c+1|0:c;b=Fj(I,0,136657,0);e=b+d|0;d=Y+c|0;d=b>>>0>e>>>0?d+1|0:d;c=Fj(J,0,-997805,-1);e=c+e|0;b=Y+d|0;b=c>>>0>e>>>0?b+1|0:b;d=Fj(K,V,654183,0);e=d+e|0;c=Y+b|0;c=d>>>0>e>>>0?c+1|0:c;d=Fj(M,0,666643,0);e=d+e|0;b=Y+c|0;b=d>>>0>e>>>0?b+1|0:b;d=Fj(L,0,470296,0);e=d+e|0;c=Y+b|0;c=d>>>0>e>>>0?c+1|0:c;d=e;b=c;c=h>>21;h=(h&2097151)<<11|ca>>>21;e=h+d|0;d=b+c|0;d=e>>>0>>0?d+1|0:d;w=d;b=e;d=d-((b>>>0<4293918720)-1|0)|0;n=b- -1048576|0;l=d;c=d>>21;d=(d&2097151)<<11|n>>>21;h=d+i|0;b=c+g|0;B=h;b=d>>>0>h>>>0?b+1|0:b;s=b;b=Fj(h,b,-683901,-1);d=b+k|0;c=Y+j|0;j=d;h=b>>>0>d>>>0?c+1|0:c;b=Fj(S,A,666643,0);d=Y;c=b;b=Z>>>4&2097151;c=c+b|0;d=b>>>0>c>>>0?d+1|0:d;b=c;c=Fj(P,T,470296,0);g=b+c|0;b=Y+d|0;b=c>>>0>g>>>0?b+1|0:b;d=Fj(W,z,654183,0);g=d+g|0;c=Y+b|0;c=d>>>0>g>>>0?c+1|0:c;b=Fj(D,C,-997805,-1);d=b+g|0;c=Y+c|0;c=b>>>0>d>>>0?c+1|0:c;b=d;d=Fj(B,s,136657,0);g=b+d|0;b=Y+c|0;b=d>>>0>g>>>0?b+1|0:b;k=b;b=g;d=k-((b>>>0<4293918720)-1|0)|0;p=b- -1048576|0;i=d;c=d>>21;d=(d&2097151)<<11|p>>>21;j=d+j|0;b=c+h|0;h=j;b=d>>>0>h>>>0?b+1|0:b;d=b;b=h;m=d-((b>>>0<4293918720)-1|0)|0;q=b- -1048576|0;j=m;c=j>>21;m=(j&2097151)<<11|q>>>21;x=m+u|0;b=c+o|0;O=x;m=m>>>0>x>>>0?b+1|0:b;c=n&-2097152;b=e-c|0;e=w-((c>>>0>e>>>0)+l|0)|0;l=b;b=f>>21;c=(f&2097151)<<11|da>>>21;f=l+c|0;b=b+e|0;e=f;b=c>>>0>e>>>0?b+1|0:b;n=b;b=e;f=n-((b>>>0<4293918720)-1|0)|0;x=b- -1048576|0;w=f;b=f>>21;o=b;A=(f&2097151)<<11|x>>>21;b=Fj(A,b,-683901,-1);f=b+h|0;c=Y+d|0;c=b>>>0>f>>>0?c+1|0:c;d=f;b=q&-2097152;E=d-b|0;u=c-((b>>>0>d>>>0)+j|0)|0;c=Fj(A,o,136657,0)+g|0;b=k+Y|0;b=c>>>0>>0?b+1|0:b;d=c;c=p&-2097152;Q=d-c|0;p=b-((c>>>0>d>>>0)+i|0)|0;b=Fj(P,T,666643,0);c=Y;d=b;b=X>>>7&2097151;d=d+b|0;c=b>>>0>d>>>0?c+1|0:c;b=Fj(W,z,470296,0);f=b+d|0;d=Y+c|0;d=b>>>0>f>>>0?d+1|0:d;c=Fj(D,C,654183,0);f=c+f|0;b=Y+d|0;b=c>>>0>f>>>0?b+1|0:b;c=Fj(B,s,-997805,-1);d=c+f|0;b=Y+b|0;i=d;d=c>>>0>d>>>0?b+1|0:b;b=((ha&3)<<30|ga>>>2)&2097151;f=Fj(W,z,666643,0)+b|0;c=Y;c=b>>>0>f>>>0?c+1|0:c;b=Fj(D,C,470296,0);f=b+f|0;c=Y+c|0;c=b>>>0>f>>>0?c+1|0:c;b=f;f=Fj(B,s,654183,0);h=b+f|0;b=Y+c|0;b=f>>>0>h>>>0?b+1|0:b;f=h;j=b;b=f;h=j-((b>>>0<4293918720)-1|0)|0;q=b- -1048576|0;g=h;c=g>>21;h=(g&2097151)<<11|q>>>21;i=h+i|0;b=c+d|0;k=i;b=h>>>0>i>>>0?b+1|0:b;d=b;b=i;l=d-((b>>>0<4293918720)-1|0)|0;i=b- -1048576|0;h=l;c=h>>21;l=(h&2097151)<<11|i>>>21;z=l+Q|0;b=c+p|0;X=z;l=l>>>0>z>>>0?b+1|0:b;b=Fj(A,o,-997805,-1);c=b+k|0;d=Y+d|0;d=b>>>0>c>>>0?d+1|0:d;b=i&-2097152;Z=c-b|0;_=d-((b>>>0>c>>>0)+h|0)|0;b=Fj(A,o,654183,0)+f|0;c=j+Y|0;c=b>>>0>>0?c+1|0:c;d=b;b=q&-2097152;Q=d-b|0;z=c-((b>>>0>d>>>0)+g|0)|0;b=Fj(D,C,666643,0);d=Y;c=b;b=fa>>>5&2097151;c=c+b|0;d=b>>>0>c>>>0?d+1|0:d;b=c;c=Fj(B,s,470296,0);f=b+c|0;b=Y+d|0;g=f;d=c>>>0>f>>>0?b+1|0:b;c=ea&2097151;f=Fj(B,s,666643,0)+c|0;b=Y;h=f;b=c>>>0>f>>>0?b+1|0:b;k=b;b=f;f=k-((b>>>0<4293918720)-1|0)|0;p=b- -1048576|0;i=f;c=f>>21;b=(f&2097151)<<11|p>>>21;f=b+g|0;d=c+d|0;d=b>>>0>f>>>0?d+1|0:d;j=d;b=f;d=d-((b>>>0<4293918720)-1|0)|0;q=b- -1048576|0;g=d;c=d>>21;d=(d&2097151)<<11|q>>>21;s=d+Q|0;b=c+z|0;b=d>>>0>s>>>0?b+1|0:b;d=b;b=Fj(A,o,470296,0)+f|0;c=j+Y|0;c=b>>>0>>0?c+1|0:c;j=b;f=q&-2097152;b=b-f|0;g=c-((f>>>0>j>>>0)+g|0)|0;j=b;c=Fj(A,o,666643,0);b=p&-2097152;f=c+(h-b|0)|0;b=Y+(k-((b>>>0>h>>>0)+i|0)|0)|0;b=c>>>0>f>>>0?b+1|0:b;h=f;c=b>>21;b=(b&2097151)<<11|f>>>21;f=j+b|0;c=c+g|0;c=b>>>0>f>>>0?c+1|0:c;C=f;b=c>>21;c=(c&2097151)<<11|f>>>21;f=c+s|0;d=b+d|0;g=f;b=f;d=c>>>0>b>>>0?d+1|0:d;c=d>>21;d=(d&2097151)<<11|b>>>21;f=d+Z|0;b=c+_|0;i=f;c=f;b=d>>>0>c>>>0?b+1|0:b;d=b>>21;b=(b&2097151)<<11|c>>>21;f=b+X|0;c=d+l|0;l=f;d=f;c=b>>>0>d>>>0?c+1|0:c;b=c>>21;c=(c&2097151)<<11|d>>>21;d=c+E|0;b=b+u|0;b=c>>>0>d>>>0?b+1|0:b;s=d;c=b>>21;b=(b&2097151)<<11|d>>>21;d=b+O|0;c=c+m|0;c=b>>>0>d>>>0?c+1|0:c;o=d;b=c>>21;c=(c&2097151)<<11|d>>>21;f=c+N|0;d=b+G|0;p=f;b=f;d=c>>>0>b>>>0?d+1|0:d;c=d>>21;d=(d&2097151)<<11|b>>>21;f=d+F|0;b=c+t|0;q=f;c=f;b=d>>>0>c>>>0?b+1|0:b;d=b>>21;b=(b&2097151)<<11|c>>>21;f=b+aa|0;c=d+ba|0;t=f;d=f;c=b>>>0>d>>>0?c+1|0:c;b=c>>21;c=(c&2097151)<<11|d>>>21;d=c+$|0;b=b+r|0;b=c>>>0>d>>>0?b+1|0:b;m=d;c=b>>21;f=(b&2097151)<<11|d>>>21;d=x&-2097152;b=e-d|0;f=f+b|0;d=(n-((d>>>0>e>>>0)+w|0)|0)+c|0;w=f;c=f;d=b>>>0>c>>>0?d+1|0:d;r=(d&2097151)<<11|c>>>21;b=d>>21;k=b;c=h&2097151;d=Fj(r,b,666643,0)+c|0;b=Y;j=d;b=c>>>0>d>>>0?b+1|0:b;f=b;v[a|0]=d;v[a+1|0]=(b&255)<<24|d>>>8;b=C&2097151;d=Fj(r,k,470296,0)+b|0;c=Y;c=b>>>0>d>>>0?c+1|0:c;h=d;d=f;b=d>>21;e=(d&2097151)<<11|j>>>21;n=h+e|0;d=b+c|0;d=e>>>0>n>>>0?d+1|0:d;e=n;v[a+4|0]=(d&2047)<<21|e>>>11;c=d;b=c;d=e;v[a+3|0]=(b&7)<<29|d>>>3;d=g&2097151;g=Fj(r,k,654183,0)+d|0;b=Y;b=d>>>0>g>>>0?b+1|0:b;d=g;g=(c&2097151)<<11|e>>>21;n=d+g|0;c=(c>>21)+b|0;c=g>>>0>n>>>0?c+1|0:c;g=n;b=c;v[a+6|0]=(b&63)<<26|g>>>6;h=0;d=((f&65535)<<16|j>>>16)&31;j=e&2097151;c=j;v[a+2|0]=d|c<<5;d=i&2097151;e=Fj(r,k,-997805,-1)+d|0;c=Y;c=d>>>0>e>>>0?c+1|0:c;d=c;c=b>>21;b=(b&2097151)<<11|g>>>21;e=b+e|0;d=c+d|0;i=e;d=b>>>0>e>>>0?d+1|0:d;v[a+9|0]=(d&511)<<23|e>>>9;c=d;b=c;d=e;v[a+8|0]=(b&1)<<31|d>>>1;e=0;g=g&2097151;d=g;v[a+5|0]=(h&524287)<<13|j>>>19|d<<2;d=l&2097151;h=Fj(r,k,136657,0)+d|0;b=Y;b=d>>>0>h>>>0?b+1|0:b;d=c>>21;c=(c&2097151)<<11|i>>>21;h=c+h|0;b=b+d|0;j=h;b=c>>>0>h>>>0?b+1|0:b;c=h;v[a+12|0]=(b&4095)<<20|c>>>12;d=b;v[a+11|0]=(b&15)<<28|c>>>4;h=0;l=i&2097151;c=l;v[a+7|0]=(e&16383)<<18|g>>>14|c<<7;b=s&2097151;e=Fj(r,k,-683901,-1)+b|0;c=Y;c=b>>>0>e>>>0?c+1|0:c;b=d>>21;d=(d&2097151)<<11|j>>>21;e=d+e|0;c=b+c|0;g=e;c=d>>>0>e>>>0?c+1|0:c;b=c;v[a+14|0]=(b&127)<<25|e>>>7;e=0;i=j&2097151;d=i;v[a+10|0]=(h&131071)<<15|l>>>17|d<<4;c=b>>21;b=(b&2097151)<<11|g>>>21;j=b+(o&2097151)|0;d=b>>>0>j>>>0?c+1|0:c;v[a+17|0]=(d&1023)<<22|j>>>10;b=d;d=j;v[a+16|0]=(b&3)<<30|d>>>2;k=g&2097151;d=k;v[a+13|0]=(e&1048575)<<12|i>>>20|d<<1;d=(b&2097151)<<11|j>>>21;g=d+(p&2097151)|0;b=b>>21;b=d>>>0>g>>>0?b+1|0:b;c=g;v[a+20|0]=(b&8191)<<19|c>>>13;v[a+19|0]=(b&31)<<27|c>>>5;i=j&2097151;c=i;v[a+15|0]=(h&32767)<<17|k>>>15|c<<6;c=b>>21;f=(b&2097151)<<11|g>>>21;k=f+(q&2097151)|0;b=c;b=f>>>0>k>>>0?b+1|0:b;f=b;v[a+21|0]=k;b=g;v[a+18|0]=(e&262143)<<14|i>>>18|b<<3;b=f;v[a+22|0]=(b&255)<<24|k>>>8;c=a;d=b;b=b>>21;h=(d&2097151)<<11|k>>>21;g=h+(t&2097151)|0;d=g>>>0>>0?b+1|0:b;v[c+25|0]=(d&2047)<<21|g>>>11;b=d;d=g;v[c+24|0]=(b&7)<<29|d>>>3;d=c;h=(b&2097151)<<11|g>>>21;j=h+(m&2097151)|0;b=b>>21;e=j;b=h>>>0>e>>>0?b+1|0:b;c=b;v[d+27|0]=(b&63)<<26|e>>>6;h=0;j=g&2097151;b=j;v[d+23|0]=((f&65535)<<16|k>>>16)&31|b<<5;b=c;c=b>>21;b=(b&2097151)<<11|e>>>21;f=b+(w&2097151)|0;c=b>>>0>f>>>0?c+1|0:c;d=f;v[a+31|0]=(c&131071)<<15|d>>>17;b=c;v[a+30|0]=(b&511)<<23|d>>>9;v[a+29|0]=(b&1)<<31|d>>>1;c=0;e=e&2097151;v[a+26|0]=(h&524287)<<13|j>>>19|e<<2;v[a+28|0]=(c&16383)<<18|e>>>14|d<<7}function Ob(a,b,c,d,e,f,g,h,i,j,k,l){var m=0,n=0,o=0,p=0,q=0,r=0,s=0,t=0,u=0,w=0,z=0,B=0,C=0,E=0,F=0,G=0,H=0,I=0,J=0,K=0,L=0,M=0,N=0,O=0,P=0,Q=0,R=0,S=0,T=0,U=0,Z=0,_=0,$=0,aa=0,ba=0,ca=0,da=0,ea=0,fa=0,ga=0,ha=0,ja=0,la=0,ma=0,na=0,pa=0,qa=0,sa=0,ta=0,ua=0,va=0,wa=0,xa=0,ya=0,Aa=0,Ca=0,Da=0,Ea=0,Fa=0,Ga=0,Ha=0;o=V+-64|0;V=o;ja=Za(i);a:{if(!ja){c=-22;break a}x[o+32>>2]=0;x[o+36>>2]=0;x[o+24>>2]=0;x[o+28>>2]=0;x[o+20>>2]=g;x[o+16>>2]=f;x[o+12>>2]=e;x[o+8>>2]=d;x[o+4>>2]=i;x[o>>2]=ja;x[o+56>>2]=0;x[o+52>>2]=c;x[o+48>>2]=c;x[o+44>>2]=b;x[o+40>>2]=a;b=V-48|0;V=b;a=Dc(o);b:{if(a){break b}a=-26;if(l-1>>>0>1){break b}c=x[o+44>>2];a=x[o+48>>2];x[b>>2]=0;d=x[o+40>>2];x[b+28>>2]=a;x[b+12>>2]=-1;x[b+8>>2]=d;d=a<<3;d=c>>>0>>0?d:c;c=a<<2;a=(d>>>0)/(c>>>0)|0;x[b+20>>2]=a;x[b+24>>2]=a<<2;x[b+16>>2]=D(a,c);a=x[o+52>>2];x[b+36>>2]=l;x[b+32>>2]=a;c=V-80|0;V=c;a=-25;c:{if(!b|!o){break c}a=Za(x[b+20>>2]<<3);x[b+4>>2]=a;if(!a){a=-22;break c}d=V-16|0;V=d;a=-22;e=x[b+16>>2];d:{if(!b|!e){break d}f=e<<10;if(((f>>>0)/(e>>>0)|0)!=1024){break d}e=Za(12);x[b>>2]=e;if(!e){break d}x[e>>2]=0;x[e+4>>2]=0;e=Lf(d+12|0,f);x[9301]=e;e:{f:{if(e){x[d+12>>2]=0;break f}e=x[d+12>>2];if(e){break e}}Ka(x[b>>2]);x[b>>2]=0;break d}x[x[b>>2]>>2]=e;x[x[b>>2]+4>>2]=e;x[x[b>>2]+8>>2]=f;a=0}V=d+16|0;if(a){Qd(b,x[o+56>>2]);break c}d=x[b+36>>2];e=V;a=e-448&-64;V=a;if(!(!o|!c)){Ib(a- -64|0,0,0,64);ra(a+60|0,x[o+48>>2]);Ja(a- -64|0,a+60|0,4,0);ra(a+60|0,x[o+4>>2]);Ja(a- -64|0,a+60|0,4,0);ra(a+60|0,x[o+44>>2]);Ja(a- -64|0,a+60|0,4,0);ra(a+60|0,x[o+40>>2]);Ja(a- -64|0,a+60|0,4,0);ra(a+60|0,19);Ja(a- -64|0,a+60|0,4,0);ra(a+60|0,d);Ja(a- -64|0,a+60|0,4,0);ra(a+60|0,x[o+12>>2]);Ja(a- -64|0,a+60|0,4,0);d=x[o+8>>2];g:{if(!d){break g}Ja(a- -64|0,d,x[o+12>>2],0);if(!(v[o+56|0]&1)){break g}oa(x[o+8>>2],x[o+12>>2]);x[o+12>>2]=0}ra(a+60|0,x[o+20>>2]);Ja(a- -64|0,a+60|0,4,0);d=x[o+16>>2];if(d){Ja(a- -64|0,d,x[o+20>>2],0)}ra(a+60|0,x[o+28>>2]);Ja(a- -64|0,a+60|0,4,0);d=x[o+24>>2];h:{if(!d){break h}Ja(a- -64|0,d,x[o+28>>2],0);if(!(y[o+56|0]&2)){break h}oa(x[o+24>>2],x[o+28>>2]);x[o+28>>2]=0}ra(a+60|0,x[o+36>>2]);Ja(a- -64|0,a+60|0,4,0);d=x[o+32>>2];if(d){Ja(a- -64|0,d,x[o+36>>2],0)}Hb(a- -64|0,c,64)}V=e;oa(c- -64|0,8);a=0;d=V-1024|0;V=d;if(x[b+28>>2]){f=c+68|0;e=c- -64|0;while(1){ra(e,0);ra(f,a);Fc(d,1024,c,72);Pd(x[x[b>>2]+4>>2]+(D(x[b+24>>2],a)<<10)|0,d);ra(e,1);Fc(d,1024,c,72);Pd((x[x[b>>2]+4>>2]+(D(x[b+24>>2],a)<<10)|0)+1024|0,d);a=a+1|0;if(a>>>0>2]){continue}break}}oa(d,1024);V=d+1024|0;oa(c,72);a=0}V=c+80|0;if(a){break b}if(x[b+8>>2]){while(1){a=0;f=0;e=V-32|0;V=e;i:{if(!b|!x[b+28>>2]){break i}x[e+16>>2]=ta;while(1){v[e+24|0]=a;sa=0;d=0;if(!f){while(1){x[e+28>>2]=0;c=x[e+28>>2];x[e+8>>2]=x[e+24>>2];x[e+12>>2]=c;x[e+20>>2]=sa;c=x[e+20>>2];x[e>>2]=x[e+16>>2];x[e+4>>2]=c;d=0;j:{if(!b){break j}k:{l:{if(x[b+36>>2]!=2){break l}g=x[e>>2];if(!(y[e+8|0]<2?g:1)){break l}ua=x[b+4>>2];c=1;break k}ua=x[b+4>>2];f=ua;c=V-4096|0;V=c;$b(c+3072|0);$b(c+2048|0);m:{if(!b|!e){break m}x[c+2048>>2]=x[e>>2];x[c+2052>>2]=0;x[c+2056>>2]=x[e+4>>2];x[c+2060>>2]=0;x[c+2064>>2]=y[e+8|0];x[c+2068>>2]=0;x[c+2072>>2]=x[b+16>>2];x[c+2076>>2]=0;x[c+2080>>2]=x[b+8>>2];x[c+2084>>2]=0;x[c+2088>>2]=x[b+36>>2];x[c+2092>>2]=0;if(!x[b+20>>2]){break m}while(1){g=d&127;if(!g){P=x[c+2100>>2];m=P+1|0;n=P;P=x[c+2096>>2]+1|0;da=P>>>0<1?m:n;x[c+2096>>2]=P;x[c+2100>>2]=da;$b(c);$b(c+1024|0);Ec(c+3072|0,c+2048|0,c);Ec(c+3072|0,c,c+1024|0)}g=(c+1024|0)+(g<<3)|0;P=x[g+4>>2];da=f+(d<<3)|0;x[da>>2]=x[g>>2];x[da+4>>2]=P;d=d+1|0;if(d>>>0>2]){continue}break}}V=c+4096|0;g=x[e>>2];c=0}Fa=c;c=y[e+8|0];P=!(c|g)<<1;d=x[b+20>>2];if(P>>>0>=d>>>0){break j}f=x[b+24>>2];g=(D(f,x[e+4>>2])+P|0)+D(c,d)|0;d=g+((g>>>0)%(f>>>0)|0?-1:f-1|0)|0;while(1){da=((g>>>0)%(f>>>0)|0)==1?g-1|0:d;c=x[b+28>>2];n:{if(!Fa){d=x[b>>2];H=(P<<3)+ua|0;break n}d=x[b>>2];H=x[d+4>>2]+(da<<10)|0}I=x[H>>2];H=x[H+4>>2];x[e+12>>2]=P;c=(H>>>0)%(c>>>0)|0;H=x[e+4>>2];t=y[e+8|0]?c:H;d=x[d+4>>2];n=t;t=x[e>>2];c=t?c:n;f=d+(D(c,f)<<10)|0;c=(c|0)==(H|0);n=f;o:{if(!x[e>>2]){f=y[e+8|0];if(!f){f=x[e+12>>2]-1|0;m=0;break o}f=D(f,x[b+20>>2]);H=x[e+12>>2];if(c){f=(f+H|0)-1|0;m=0;break o}f=f-!H|0;m=0;break o}f=x[b+24>>2];H=x[b+20>>2];f=c?x[e+12>>2]+(f+(H^-1)|0)|0:(f-H|0)-!x[e+12>>2]|0;c=y[e+8|0];m=0;if((c|0)==3){break o}m=D(H,c+1|0)}H=f-1|0;c=m+H|0;Fj(I,0,I,0);Fj(f,0,Y,0);f=Y;Ej(c-f|0,(c>>>0>>0)-(c>>>0>>0)|0,x[b+24>>2]);Y=X;c=n+(W<<10)|0;H=d+(da<<10)|0;f=d+(g<<10)|0;p:{if(t){Ec(H,c,f);break p}I=0;d=V-2048|0;V=d;pb(d+1024|0,c);xb(d+1024|0,H);pb(d,d+1024|0);H=0;while(1){c=I<<7;t=(d+1024|0)+(c|64)|0;m=t;r=x[m>>2];u=(d+1024|0)+(c|96)|0;n=u;B=x[n>>2];n=x[n+4>>2];C=r;z=x[m+4>>2];m=c+(d+1024|0)|0;r=(d+1024|0)+(c|32)|0;E=x[r>>2];q=x[r+4>>2];p=ka(x[m>>2],x[m+4>>2],E,q);s=n;n=Y;B=ia(B^p,s^n,32);s=Y;z=ka(C,z,B,s);C=z^E;E=Y;q=ia(C,q^E,24);C=n;n=Y;_=ka(p,C,q,n);w=Y;ea=ia(_^B,w^s,16);$=Y;fa=ka(z,E,ea,$);aa=Y;n=ia(q^fa,aa^n,63);B=Y;q=(d+1024|0)+(c|104)|0;z=x[q>>2];K=x[q+4>>2];E=(d+1024|0)+(c|72)|0;p=E;G=x[p>>2];F=x[p+4>>2];p=(d+1024|0)+(c|8)|0;s=(d+1024|0)+(c|40)|0;J=x[s>>2];T=x[s+4>>2];C=ka(x[p>>2],x[p+4>>2],J,T);L=z^C;z=Y;K=ia(L,z^K,32);ca=Y;L=ka(G,F,K,ca);G=L^J;J=Y;T=ia(G,T^J,24);G=z;z=Y;ba=ka(C,G,T,z);ga=Y;na=ia(ba^K,ga^ca,16);va=Y;wa=ka(L,J,na,va);xa=Y;z=ia(T^wa,xa^z,63);K=Y;T=(d+1024|0)+(c|112)|0;J=T;L=x[J>>2];R=x[J+4>>2];J=(d+1024|0)+(c|80)|0;F=x[J>>2];Q=x[J+4>>2];C=(d+1024|0)+(c|16)|0;ca=(d+1024|0)+(c|48)|0;N=ca;U=x[N>>2];N=x[N+4>>2];G=ka(x[C>>2],x[C+4>>2],U,N);M=L^G;L=Y;R=ia(M,L^R,32);M=Y;O=ka(F,Q,R,M);F=O^U;U=Y;N=ia(F,N^U,24);F=L;L=Y;ya=ka(G,F,N,L);Aa=Y;Ca=ia(ya^R,Aa^M,16);Da=Y;Q=ka(O,U,Ca,Da);la=Y;L=ia(N^Q,la^L,63);R=Y;N=(d+1024|0)+(c|120)|0;M=x[N>>2];O=x[N+4>>2];U=(d+1024|0)+(c|88)|0;G=U;S=x[G>>2];pa=x[G+4>>2];G=(d+1024|0)+(c|24)|0;c=(d+1024|0)+(c|56)|0;Z=x[c>>2];F=x[c+4>>2];ha=ka(x[G>>2],x[G+4>>2],Z,F);ma=M^ha;M=Y;O=ia(ma,M^O,32);ma=Y;qa=ka(S,pa,O,ma);S=qa^Z;Z=Y;F=ia(S,F^Z,24);S=F;pa=Z;Z=M;M=Y;F=ka(ha,Z,F,M);Z=Y;ha=ia(F^O,Z^ma,16);ma=Y;qa=ka(qa,pa,ha,ma);Ea=Y;M=ia(S^qa,Ea^M,63);O=Y;S=Q;pa=la;_=ka(_,w,z,K);w=Y;Q=ia(ha^_,ma^w,32);la=Y;ha=ka(S,pa,Q,la);S=K;K=Y;z=ia(ha^z,S^K,24);S=_;_=Y;w=ka(S,w,z,_);x[m>>2]=w;S=m;m=Y;x[S+4>>2]=m;m=ia(w^Q,m^la,16);w=Y;x[N>>2]=m;x[N+4>>2]=w;m=ka(ha,K,m,w);x[J>>2]=m;K=Y;x[J+4>>2]=K;Ga=s,Ha=ia(m^z,K^_,63),x[Ga>>2]=Ha;x[s+4>>2]=Y;m=L;s=ka(ba,ga,L,R);z=Y;K=ia(ea^s,$^z,32);J=Y;L=ka(qa,Ea,K,J);w=R;R=Y;m=ia(m^L,w^R,24);w=s;s=Y;z=ka(w,z,m,s);x[p>>2]=z;w=p;p=Y;x[w+4>>2]=p;p=ia(z^K,p^J,16);z=Y;x[u>>2]=p;x[u+4>>2]=z;u=ka(L,R,p,z);x[U>>2]=u;p=Y;x[U+4>>2]=p;Ga=ca,Ha=ia(m^u,p^s,63),x[Ga>>2]=Ha;x[ca+4>>2]=Y;m=ka(ya,Aa,M,O);p=Y;s=ia(na^m,va^p,32);z=Y;K=ka(fa,aa,s,z);J=Y;u=ia(K^M,J^O,24);w=p;p=Y;m=ka(m,w,u,p);x[C>>2]=m;w=C;C=Y;x[w+4>>2]=C;m=ia(m^s,z^C,16);s=Y;x[q>>2]=m;x[q+4>>2]=s;m=ka(K,J,m,s);x[t>>2]=m;q=t;t=Y;x[q+4>>2]=t;Ga=c,Ha=ia(m^u,t^p,63),x[Ga>>2]=Ha;x[c+4>>2]=Y;c=n;t=ka(F,Z,n,B);u=Y;m=ia(Ca^t,Da^u,32);n=Y;q=ka(wa,xa,m,n);p=B;B=Y;c=ia(c^q,p^B,24);p=u;u=Y;t=ka(t,p,c,u);x[G>>2]=t;p=Y;x[G+4>>2]=p;t=ia(m^t,n^p,16);m=Y;x[T>>2]=t;x[T+4>>2]=m;t=ka(q,B,t,m);x[E>>2]=t;m=Y;x[E+4>>2]=m;Ga=r,Ha=ia(c^t,m^u,63),x[Ga>>2]=Ha;x[r+4>>2]=Y;I=I+1|0;if((I|0)!=8){continue}break}while(1){u=H<<4;c=u+(d+1024|0)|0;I=x[c+512>>2];t=x[c+772>>2];p=I;q=x[c+516>>2];s=x[c+768>>2];I=x[c+256>>2];m=x[c+260>>2];r=ka(x[c>>2],x[c+4>>2],I,m);n=t;t=Y;n=ia(s^r,n^t,32);B=Y;q=ka(p,q,n,B);p=q^I;I=Y;m=ia(p,m^I,24);C=I;I=Y;p=ka(r,t,m,I);s=Y;z=ia(p^n,s^B,16);K=Y;T=ka(q,C,z,K);J=Y;I=ia(m^T,J^I,63);t=Y;m=x[c+780>>2];C=x[c+520>>2];w=x[c+524>>2];E=x[c+776>>2];u=(d+1024|0)+(u|8)|0;r=u;q=x[r>>2];B=x[r+4>>2];r=x[c+264>>2];n=x[c+268>>2];B=ka(q,B,r,n);q=m;m=Y;q=ia(E^B,q^m,32);E=Y;C=ka(C,w,q,E);w=C^r;r=Y;n=ia(w,n^r,24);w=C;C=m;m=Y;C=ka(B,C,n,m);ca=Y;L=ia(C^q,ca^E,16);R=Y;N=ka(w,r,L,R);U=Y;m=ia(n^N,U^m,63);r=Y;n=x[c+900>>2];F=x[c+640>>2];Q=x[c+644>>2];G=x[c+896>>2];B=x[c+384>>2];q=x[c+388>>2];E=ka(x[c+128>>2],x[c+132>>2],B,q);w=n;n=Y;G=ia(G^E,w^n,32);M=Y;O=ka(F,Q,G,M);w=O^B;B=Y;q=ia(w,q^B,24);w=O;F=G;G=n;n=Y;G=ka(E,G,q,n);E=M;M=Y;O=ia(F^G,E^M,16);_=Y;w=ka(w,B,O,_);ea=Y;n=ia(q^w,ea^n,63);B=Y;q=x[c+908>>2];Q=x[c+648>>2];Z=x[c+652>>2];la=x[c+904>>2];E=x[c+392>>2];$=x[c+396>>2];fa=ka(x[c+136>>2],x[c+140>>2],E,$);F=q;q=Y;aa=ia(la^fa,F^q,32);ba=Y;ga=ka(Q,Z,aa,ba);F=ga^E;E=Y;$=ia(F,$^E,24);F=$;Q=q;q=Y;$=ka(fa,Q,$,q);fa=Y;aa=ia($^aa,fa^ba,16);ba=Y;ga=ka(ga,E,aa,ba);na=Y;q=ia(F^ga,na^q,63);E=Y;F=w;Q=ea;p=ka(p,s,m,r);s=Y;w=ia(aa^p,ba^s,32);ea=Y;aa=ka(F,Q,w,ea);ba=Y;m=ia(aa^m,ba^r,24);r=p;p=Y;r=ka(r,s,m,p);x[c>>2]=r;s=Y;x[c+4>>2]=s;r=ia(r^w,s^ea,16);s=Y;x[c+904>>2]=r;x[c+908>>2]=s;r=ka(aa,ba,r,s);x[c+640>>2]=r;s=Y;x[c+644>>2]=s;Ga=c,Ha=ia(m^r,p^s,63),x[Ga+264>>2]=Ha;x[c+268>>2]=Y;m=n;r=ka(C,ca,n,B);n=Y;p=ia(z^r,K^n,32);s=Y;z=ka(ga,na,p,s);C=B;B=Y;m=ia(m^z,C^B,24);C=r;r=Y;n=ka(C,n,m,r);x[u>>2]=n;C=u;u=Y;x[C+4>>2]=u;u=ia(n^p,u^s,16);n=Y;x[c+768>>2]=u;x[c+772>>2]=n;u=ka(z,B,u,n);x[c+648>>2]=u;n=Y;x[c+652>>2]=n;Ga=c,Ha=ia(m^u,n^r,63),x[Ga+384>>2]=Ha;x[c+388>>2]=Y;p=q;m=ka(G,M,q,E);r=Y;n=ia(L^m,R^r,32);B=Y;q=ka(T,J,n,B);s=E;E=Y;u=ia(p^q,s^E,24);p=r;r=Y;m=ka(m,p,u,r);x[c+128>>2]=m;p=Y;x[c+132>>2]=p;m=ia(m^n,p^B,16);n=Y;x[c+776>>2]=m;x[c+780>>2]=n;m=ka(q,E,m,n);x[c+512>>2]=m;n=Y;x[c+516>>2]=n;Ga=c,Ha=ia(m^u,n^r,63),x[Ga+392>>2]=Ha;x[c+396>>2]=Y;u=ka($,fa,I,t);m=Y;r=ia(O^u,_^m,32);n=Y;B=ka(N,U,r,n);q=Y;I=ia(B^I,q^t,24);p=u;u=Y;t=ka(p,m,I,u);x[c+136>>2]=t;m=Y;x[c+140>>2]=m;t=ia(r^t,m^n,16);m=Y;x[c+896>>2]=t;x[c+900>>2]=m;t=ka(B,q,t,m);x[c+520>>2]=t;m=Y;x[c+524>>2]=m;Ga=c,Ha=ia(t^I,m^u,63),x[Ga+256>>2]=Ha;x[c+260>>2]=Y;H=H+1|0;if((H|0)!=8){continue}break}pb(f,d);xb(f,d+1024|0);V=d+2048|0}P=P+1|0;if(P>>>0>=A[b+20>>2]){break j}g=g+1|0;d=da+1|0;f=x[b+24>>2];continue}}d=x[b+28>>2];sa=sa+1|0;if(d>>>0>sa>>>0){continue}break}}a=a+1|0;if((a|0)==4){break i}f=!d;continue}}V=e+32|0;ta=ta+1|0;if(ta>>>0>2]){continue}break}}a=V-2048|0;V=a;if(!(!o|!b)){pb(a+1024|0,(x[x[b>>2]+4>>2]+(x[b+24>>2]<<10)|0)-1024|0);if(A[b+28>>2]>=2){f=1;while(1){c=x[b+24>>2];xb(a+1024|0,(x[x[b>>2]+4>>2]+(D(c,f)+c<<10)|0)-1024|0);f=f+1|0;if(f>>>0>2]){continue}break}}c=a+1024|0;f=0;while(1){d=f<<3;e=d+a|0;d=c+d|0;Ba(e,x[d>>2],x[d+4>>2]);f=f+1|0;if((f|0)!=128){continue}break}Fc(x[o>>2],x[o+4>>2],a,1024);oa(a+1024|0,1024);oa(a,1024);Qd(b,x[o+56>>2])}V=a+2048|0;a=0}V=b+48|0;c=a;q:{if(c){oa(ja,i);break q}r:{if(!j|!k){break r}d=V-16|0;V=d;b=-31;s:{t:{u:{v:{w:{switch(l-1|0){case 1:if(k>>>0<13){break u}b=y[1417]|y[1418]<<8|(y[1419]<<16|y[1420]<<24);a=j;c=y[1413]|y[1414]<<8|(y[1415]<<16|y[1416]<<24);v[a|0]=c;v[a+1|0]=c>>>8;v[a+2|0]=c>>>16;v[a+3|0]=c>>>24;v[a+4|0]=b;v[a+5|0]=b>>>8;v[a+6|0]=b>>>16;v[a+7|0]=b>>>24;b=y[1422]|y[1423]<<8|(y[1424]<<16|y[1425]<<24);c=y[1418]|y[1419]<<8|(y[1420]<<16|y[1421]<<24);v[a+5|0]=c;v[a+6|0]=c>>>8;v[a+7|0]=c>>>16;v[a+8|0]=c>>>24;v[a+9|0]=b;v[a+10|0]=b>>>8;v[a+11|0]=b>>>16;v[a+12|0]=b>>>24;c=k-12|0;e=a+12|0;break v;case 0:break w;default:break t}}if(k>>>0<12){break u}b=y[1405]|y[1406]<<8|(y[1407]<<16|y[1408]<<24);a=j;c=y[1401]|y[1402]<<8|(y[1403]<<16|y[1404]<<24);v[a|0]=c;v[a+1|0]=c>>>8;v[a+2|0]=c>>>16;v[a+3|0]=c>>>24;v[a+4|0]=b;v[a+5|0]=b>>>8;v[a+6|0]=b>>>16;v[a+7|0]=b>>>24;b=y[1409]|y[1410]<<8|(y[1411]<<16|y[1412]<<24);v[a+8|0]=b;v[a+9|0]=b>>>8;v[a+10|0]=b>>>16;v[a+11|0]=b>>>24;c=k-11|0;e=a+11|0}b=Dc(o);if(b){break t}lc(d+5|0,19);a=Ta(d+5|0);if(a>>>0>=c>>>0){break u}b=za(e,d+5|0,a+1|0);c=c-a|0;if(c>>>0<4){break u}a=a+b|0;v[a|0]=36;v[a+1|0]=109;v[a+2|0]=61;v[a+3|0]=0;lc(d+5|0,x[o+44>>2]);c=c-3|0;b=Ta(d+5|0);if(c>>>0<=b>>>0){break u}a=za(a+3|0,d+5|0,b+1|0);c=c-b|0;if(c>>>0<4){break u}a=a+b|0;v[a|0]=44;v[a+1|0]=116;v[a+2|0]=61;v[a+3|0]=0;lc(d+5|0,x[o+40>>2]);c=c-3|0;b=Ta(d+5|0);if(c>>>0<=b>>>0){break u}a=za(a+3|0,d+5|0,b+1|0);c=c-b|0;if(c>>>0<4){break u}a=a+b|0;v[a|0]=44;v[a+1|0]=112;v[a+2|0]=61;v[a+3|0]=0;lc(d+5|0,x[o+48>>2]);c=c-3|0;b=Ta(d+5|0);if(c>>>0<=b>>>0){break u}a=za(a+3|0,d+5|0,b+1|0);c=c-b|0;if(c>>>0<2){break u}a=a+b|0;v[a|0]=36;v[a+1|0]=0;a=a+1|0;c=c-1|0;if(!od(a,c,x[o+16>>2],x[o+20>>2],3)){break u}b=-31;e=c;c=Ta(a);e=e-c|0;if(e>>>0<2){break t}a=a+c|0;v[a|0]=36;v[a+1|0]=0;a=od(a+1|0,e-1|0,x[o>>2],x[o+4>>2],3);V=d+16|0;b=a?0:-31;break s}b=-31}V=d+16|0}if(!b){break r}oa(ja,i);oa(j,k);c=-31;break q}if(h){za(h,ja,i)}oa(ja,i);c=0}Ka(ja)}V=o- -64|0;return c}function Za(a){a=a|0;var b=0,c=0,d=0,e=0,f=0,g=0,h=0,i=0,j=0,k=0,l=0,m=0,n=0,o=0;m=V-16|0;V=m;a:{b:{c:{d:{e:{f:{g:{h:{i:{j:{k:{l:{if(a>>>0<=244){f=x[9302];i=a>>>0<11?16:a+11&-8;c=i>>>3|0;b=f>>>c|0;if(b&3){d=c+((b^-1)&1)|0;b=d<<3;e=x[b+37256>>2];a=e+8|0;c=x[e+8>>2];b=b+37248|0;m:{if((c|0)==(b|0)){n=37208,o=Gj(-2,d)&f,x[n>>2]=o;break m}x[c+12>>2]=b;x[b+8>>2]=c}b=d<<3;x[e+4>>2]=b|3;b=b+e|0;x[b+4>>2]=x[b+4>>2]|1;break a}k=x[9304];if(k>>>0>=i>>>0){break l}if(b){a=2<>>12&16;c=a;b=b>>>a|0;a=b>>>5&8;c=c|a;b=b>>>a|0;a=b>>>2&4;c=c|a;b=b>>>a|0;a=b>>>1&2;c=c|a;b=b>>>a|0;a=b>>>1&1;c=(c|a)+(b>>>a|0)|0;a=c<<3;g=x[a+37256>>2];b=x[g+8>>2];a=a+37248|0;n:{if((b|0)==(a|0)){f=Gj(-2,c)&f;x[9302]=f;break n}x[b+12>>2]=a;x[a+8>>2]=b}a=g+8|0;x[g+4>>2]=i|3;d=g+i|0;b=c<<3;e=b-i|0;x[d+4>>2]=e|1;x[b+g>>2]=e;if(k){b=k>>>3|0;c=(b<<3)+37248|0;g=x[9307];b=1<>2]}x[c+8>>2]=g;x[b+12>>2]=g;x[g+12>>2]=c;x[g+8>>2]=b}x[9307]=d;x[9304]=e;break a}h=x[9303];if(!h){break l}b=(h&0-h)-1|0;a=b>>>12&16;c=a;b=b>>>a|0;a=b>>>5&8;c=c|a;b=b>>>a|0;a=b>>>2&4;c=c|a;b=b>>>a|0;a=b>>>1&2;c=c|a;b=b>>>a|0;a=b>>>1&1;b=x[((c|a)+(b>>>a|0)<<2)+37512>>2];d=(x[b+4>>2]&-8)-i|0;c=b;while(1){p:{a=x[c+16>>2];if(!a){a=x[c+20>>2];if(!a){break p}}c=(x[a+4>>2]&-8)-i|0;e=c>>>0>>0;d=e?c:d;b=e?a:b;c=a;continue}break}j=b+i|0;if(j>>>0<=b>>>0){break k}l=x[b+24>>2];e=x[b+12>>2];if((e|0)!=(b|0)){a=x[b+8>>2];x[a+12>>2]=e;x[e+8>>2]=a;break b}c=b+20|0;a=x[c>>2];if(!a){a=x[b+16>>2];if(!a){break j}c=b+16|0}while(1){g=c;e=a;c=a+20|0;a=x[c>>2];if(a){continue}c=e+16|0;a=x[e+16>>2];if(a){continue}break}x[g>>2]=0;break b}i=-1;if(a>>>0>4294967231){break l}a=a+11|0;i=a&-8;j=x[9303];if(!j){break l}d=0-i|0;f=0;q:{if(i>>>0<256){break q}f=31;if(i>>>0>16777215){break q}a=a>>>8|0;g=a+1048320>>>16&8;a=a<>>16&4;a=a<>>16&2;a=(a<>>15|0)-(b|(c|g))|0;f=(a<<1|i>>>a+21&1)+28|0}c=x[(f<<2)+37512>>2];r:{s:{t:{if(!c){a=0;break t}a=0;b=i<<((f|0)==31?0:25-(f>>>1|0)|0);while(1){u:{g=(x[c+4>>2]&-8)-i|0;if(g>>>0>=d>>>0){break u}e=c;d=g;if(d){break u}d=0;a=c;break s}g=x[c+20>>2];c=x[((b>>>29&4)+c|0)+16>>2];a=g?(g|0)==(c|0)?a:g:a;b=b<<1;if(c){continue}break}}if(!(a|e)){e=0;a=2<>>12&16;c=a;b=b>>>a|0;a=b>>>5&8;c=c|a;b=b>>>a|0;a=b>>>2&4;c=c|a;b=b>>>a|0;a=b>>>1&2;c=c|a;b=b>>>a|0;a=b>>>1&1;a=x[((c|a)+(b>>>a|0)<<2)+37512>>2]}if(!a){break r}}while(1){b=(x[a+4>>2]&-8)-i|0;c=b>>>0>>0;d=c?b:d;e=c?a:e;b=x[a+16>>2];if(b){a=b}else{a=x[a+20>>2]}if(a){continue}break}}if(!e|x[9304]-i>>>0<=d>>>0){break l}h=e+i|0;if(h>>>0<=e>>>0){break k}f=x[e+24>>2];b=x[e+12>>2];if((e|0)!=(b|0)){a=x[e+8>>2];x[a+12>>2]=b;x[b+8>>2]=a;break c}c=e+20|0;a=x[c>>2];if(!a){a=x[e+16>>2];if(!a){break i}c=e+16|0}while(1){g=c;b=a;c=a+20|0;a=x[c>>2];if(a){continue}c=b+16|0;a=x[b+16>>2];if(a){continue}break}x[g>>2]=0;break c}c=x[9304];if(c>>>0>=i>>>0){d=x[9307];b=c-i|0;v:{if(b>>>0>=16){x[9304]=b;a=d+i|0;x[9307]=a;x[a+4>>2]=b|1;x[c+d>>2]=b;x[d+4>>2]=i|3;break v}x[9307]=0;x[9304]=0;x[d+4>>2]=c|3;a=c+d|0;x[a+4>>2]=x[a+4>>2]|1}a=d+8|0;break a}h=x[9305];if(h>>>0>i>>>0){b=h-i|0;x[9305]=b;c=x[9308];a=c+i|0;x[9308]=a;x[a+4>>2]=b|1;x[c+4>>2]=i|3;a=c+8|0;break a}a=0;j=i+47|0;b=j;if(x[9420]){c=x[9422]}else{x[9423]=-1;x[9424]=-1;x[9421]=4096;x[9422]=4096;x[9420]=m+12&-16^1431655768;x[9425]=0;x[9413]=0;c=4096}g=b+c|0;e=0-c|0;c=g&e;if(c>>>0<=i>>>0){break a}d=x[9412];if(d){b=x[9410];f=b+c|0;if(d>>>0>>0|b>>>0>=f>>>0){break a}}if(y[37652]&4){break f}w:{x:{d=x[9308];if(d){a=37656;while(1){b=x[a>>2];if(d>>>0>2]>>>0?b>>>0<=d>>>0:0){break x}a=x[a+8>>2];if(a){continue}break}}b=tb(0);if((b|0)==-1){break g}f=c;d=x[9421];a=d-1|0;if(a&b){f=(c-b|0)+(a+b&0-d)|0}if(f>>>0<=i>>>0|f>>>0>2147483646){break g}d=x[9412];if(d){a=x[9410];e=a+f|0;if(d>>>0>>0|a>>>0>=e>>>0){break g}}a=tb(f);if((b|0)!=(a|0)){break w}break e}f=e&g-h;if(f>>>0>2147483646){break g}b=tb(f);if((b|0)==(x[a>>2]+x[a+4>>2]|0)){break h}a=b}if(!((a|0)==-1|i+48>>>0<=f>>>0)){b=x[9422];b=b+(j-f|0)&0-b;if(b>>>0>2147483646){b=a;break e}if((tb(b)|0)!=-1){f=b+f|0;b=a;break e}tb(0-f|0);break g}b=a;if((a|0)!=-1){break e}break g}N()}e=0;break b}b=0;break c}if((b|0)!=-1){break e}}x[9413]=x[9413]|4}if(c>>>0>2147483646){break d}b=tb(c);a=tb(0);if((b|0)==-1|(a|0)==-1|a>>>0<=b>>>0){break d}f=a-b|0;if(f>>>0<=i+40>>>0){break d}}a=x[9410]+f|0;x[9410]=a;if(a>>>0>A[9411]){x[9411]=a}y:{z:{A:{g=x[9308];if(g){a=37656;while(1){d=x[a>>2];c=x[a+4>>2];if((d+c|0)==(b|0)){break A}a=x[a+8>>2];if(a){continue}break}break z}a=x[9306];if(!(a>>>0<=b>>>0?a:0)){x[9306]=b}a=0;x[9415]=f;x[9414]=b;x[9310]=-1;x[9311]=x[9420];x[9417]=0;while(1){d=a<<3;c=d+37248|0;x[d+37256>>2]=c;x[d+37260>>2]=c;a=a+1|0;if((a|0)!=32){continue}break}d=f-40|0;a=b+8&7?-8-b&7:0;c=d-a|0;x[9305]=c;a=a+b|0;x[9308]=a;x[a+4>>2]=c|1;x[(b+d|0)+4>>2]=40;x[9309]=x[9424];break y}if(y[a+12|0]&8|d>>>0>g>>>0|b>>>0<=g>>>0){break z}x[a+4>>2]=c+f;a=g+8&7?-8-g&7:0;c=a+g|0;x[9308]=c;b=x[9305]+f|0;a=b-a|0;x[9305]=a;x[c+4>>2]=a|1;x[(b+g|0)+4>>2]=40;x[9309]=x[9424];break y}if(A[9306]>b>>>0){x[9306]=b}c=b+f|0;a=37656;B:{C:{D:{E:{F:{G:{while(1){if((c|0)!=x[a>>2]){a=x[a+8>>2];if(a){continue}break G}break}if(!(y[a+12|0]&8)){break F}}a=37656;while(1){c=x[a>>2];if(c>>>0<=g>>>0){e=c+x[a+4>>2]|0;if(e>>>0>g>>>0){break E}}a=x[a+8>>2];continue}}x[a>>2]=b;x[a+4>>2]=x[a+4>>2]+f;j=(b+8&7?-8-b&7:0)+b|0;x[j+4>>2]=i|3;f=c+(c+8&7?-8-c&7:0)|0;h=i+j|0;c=f-h|0;if((g|0)==(f|0)){x[9308]=h;a=x[9305]+c|0;x[9305]=a;x[h+4>>2]=a|1;break C}if(x[9307]==(f|0)){x[9307]=h;a=x[9304]+c|0;x[9304]=a;x[h+4>>2]=a|1;x[a+h>>2]=a;break C}a=x[f+4>>2];if((a&3)==1){g=a&-8;H:{if(a>>>0<=255){d=x[f+8>>2];a=a>>>3|0;b=x[f+12>>2];if((b|0)==(d|0)){n=37208,o=x[9302]&Gj(-2,a),x[n>>2]=o;break H}x[d+12>>2]=b;x[b+8>>2]=d;break H}i=x[f+24>>2];b=x[f+12>>2];I:{if((f|0)!=(b|0)){a=x[f+8>>2];x[a+12>>2]=b;x[b+8>>2]=a;break I}J:{a=f+20|0;d=x[a>>2];if(d){break J}a=f+16|0;d=x[a>>2];if(d){break J}b=0;break I}while(1){e=a;b=d;a=b+20|0;d=x[a>>2];if(d){continue}a=b+16|0;d=x[b+16>>2];if(d){continue}break}x[e>>2]=0}if(!i){break H}d=x[f+28>>2];a=(d<<2)+37512|0;K:{if(x[a>>2]==(f|0)){x[a>>2]=b;if(b){break K}n=37212,o=x[9303]&Gj(-2,d),x[n>>2]=o;break H}x[i+(x[i+16>>2]==(f|0)?16:20)>>2]=b;if(!b){break H}}x[b+24>>2]=i;a=x[f+16>>2];if(a){x[b+16>>2]=a;x[a+24>>2]=b}a=x[f+20>>2];if(!a){break H}x[b+20>>2]=a;x[a+24>>2]=b}f=g+f|0;c=c+g|0}x[f+4>>2]=x[f+4>>2]&-2;x[h+4>>2]=c|1;x[c+h>>2]=c;if(c>>>0<=255){a=c>>>3|0;b=(a<<3)+37248|0;c=x[9302];a=1<>2]}x[b+8>>2]=h;x[a+12>>2]=h;x[h+12>>2]=b;x[h+8>>2]=a;break C}a=31;if(c>>>0<=16777215){a=c>>>8|0;e=a+1048320>>>16&8;a=a<>>16&4;a=a<>>16&2;a=(a<>>15|0)-(b|(d|e))|0;a=(a<<1|c>>>a+21&1)+28|0}x[h+28>>2]=a;x[h+16>>2]=0;x[h+20>>2]=0;e=(a<<2)+37512|0;d=x[9303];b=1<>2]=h;x[h+24>>2]=e;break M}a=c<<((a|0)==31?0:25-(a>>>1|0)|0);b=x[e>>2];while(1){d=b;if((x[b+4>>2]&-8)==(c|0)){break D}b=a>>>29|0;a=a<<1;e=d+(b&4)|0;b=x[e+16>>2];if(b){continue}break}x[e+16>>2]=h;x[h+24>>2]=d}x[h+12>>2]=h;x[h+8>>2]=h;break C}d=f-40|0;a=b+8&7?-8-b&7:0;c=d-a|0;x[9305]=c;a=a+b|0;x[9308]=a;x[a+4>>2]=c|1;x[(b+d|0)+4>>2]=40;x[9309]=x[9424];a=(e+(e-39&7?39-e&7:0)|0)-47|0;c=a>>>0>>0?g:a;x[c+4>>2]=27;a=x[9417];x[c+16>>2]=x[9416];x[c+20>>2]=a;a=x[9415];x[c+8>>2]=x[9414];x[c+12>>2]=a;x[9416]=c+8;x[9415]=f;x[9414]=b;x[9417]=0;a=c+24|0;while(1){x[a+4>>2]=7;b=a+8|0;a=a+4|0;if(b>>>0>>0){continue}break}if((c|0)==(g|0)){break y}x[c+4>>2]=x[c+4>>2]&-2;e=c-g|0;x[g+4>>2]=e|1;x[c>>2]=e;if(e>>>0<=255){a=e>>>3|0;b=(a<<3)+37248|0;c=x[9302];a=1<>2]}x[b+8>>2]=g;x[a+12>>2]=g;x[g+12>>2]=b;x[g+8>>2]=a;break y}a=31;x[g+16>>2]=0;x[g+20>>2]=0;if(e>>>0<=16777215){a=e>>>8|0;d=a+1048320>>>16&8;a=a<>>16&4;a=a<>>16&2;a=(a<>>15|0)-(b|(c|d))|0;a=(a<<1|e>>>a+21&1)+28|0}x[g+28>>2]=a;d=(a<<2)+37512|0;c=x[9303];b=1<>2]=g;x[g+24>>2]=d;break O}a=e<<((a|0)==31?0:25-(a>>>1|0)|0);b=x[d>>2];while(1){c=b;if((e|0)==(x[b+4>>2]&-8)){break B}b=a>>>29|0;a=a<<1;d=c+(b&4)|0;b=x[d+16>>2];if(b){continue}break}x[d+16>>2]=g;x[g+24>>2]=c}x[g+12>>2]=g;x[g+8>>2]=g;break y}a=x[d+8>>2];x[a+12>>2]=h;x[d+8>>2]=h;x[h+24>>2]=0;x[h+12>>2]=d;x[h+8>>2]=a}a=j+8|0;break a}a=x[c+8>>2];x[a+12>>2]=g;x[c+8>>2]=g;x[g+24>>2]=0;x[g+12>>2]=c;x[g+8>>2]=a}a=x[9305];if(a>>>0<=i>>>0){break d}b=a-i|0;x[9305]=b;c=x[9308];a=c+i|0;x[9308]=a;x[a+4>>2]=b|1;x[c+4>>2]=i|3;a=c+8|0;break a}x[9301]=48;a=0;break a}P:{if(!f){break P}c=x[e+28>>2];a=(c<<2)+37512|0;Q:{if(x[a>>2]==(e|0)){x[a>>2]=b;if(b){break Q}j=Gj(-2,c)&j;x[9303]=j;break P}x[f+(x[f+16>>2]==(e|0)?16:20)>>2]=b;if(!b){break P}}x[b+24>>2]=f;a=x[e+16>>2];if(a){x[b+16>>2]=a;x[a+24>>2]=b}a=x[e+20>>2];if(!a){break P}x[b+20>>2]=a;x[a+24>>2]=b}R:{if(d>>>0<=15){a=d+i|0;x[e+4>>2]=a|3;a=a+e|0;x[a+4>>2]=x[a+4>>2]|1;break R}x[e+4>>2]=i|3;x[h+4>>2]=d|1;x[d+h>>2]=d;if(d>>>0<=255){a=d>>>3|0;b=(a<<3)+37248|0;c=x[9302];a=1<>2]}x[b+8>>2]=h;x[a+12>>2]=h;x[h+12>>2]=b;x[h+8>>2]=a;break R}a=31;if(d>>>0<=16777215){a=d>>>8|0;g=a+1048320>>>16&8;a=a<>>16&4;a=a<>>16&2;a=(a<>>15|0)-(b|(c|g))|0;a=(a<<1|d>>>a+21&1)+28|0}x[h+28>>2]=a;x[h+16>>2]=0;x[h+20>>2]=0;c=(a<<2)+37512|0;T:{b=1<>2]=h;x[h+24>>2]=c;break U}a=d<<((a|0)==31?0:25-(a>>>1|0)|0);i=x[c>>2];while(1){b=i;if((x[b+4>>2]&-8)==(d|0)){break T}c=a>>>29|0;a=a<<1;c=b+(c&4)|0;i=x[c+16>>2];if(i){continue}break}x[c+16>>2]=h;x[h+24>>2]=b}x[h+12>>2]=h;x[h+8>>2]=h;break R}a=x[b+8>>2];x[a+12>>2]=h;x[b+8>>2]=h;x[h+24>>2]=0;x[h+12>>2]=b;x[h+8>>2]=a}a=e+8|0;break a}V:{if(!l){break V}c=x[b+28>>2];a=(c<<2)+37512|0;W:{if(x[a>>2]==(b|0)){x[a>>2]=e;if(e){break W}n=37212,o=Gj(-2,c)&h,x[n>>2]=o;break V}x[(x[l+16>>2]==(b|0)?16:20)+l>>2]=e;if(!e){break V}}x[e+24>>2]=l;a=x[b+16>>2];if(a){x[e+16>>2]=a;x[a+24>>2]=e}a=x[b+20>>2];if(!a){break V}x[e+20>>2]=a;x[a+24>>2]=e}X:{if(d>>>0<=15){a=d+i|0;x[b+4>>2]=a|3;a=a+b|0;x[a+4>>2]=x[a+4>>2]|1;break X}x[b+4>>2]=i|3;x[j+4>>2]=d|1;x[d+j>>2]=d;if(k){a=k>>>3|0;c=(a<<3)+37248|0;e=x[9307];a=1<>2]}x[c+8>>2]=e;x[a+12>>2]=e;x[e+12>>2]=c;x[e+8>>2]=a}x[9307]=j;x[9304]=d}a=b+8|0}V=m+16|0;return a|0}function ma(a,b,c){var d=0,e=0,f=0,g=0,h=0,i=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0,r=0,s=0,t=0,u=0,v=0,w=0,y=0,z=0,A=0,B=0,C=0,E=0,F=0,G=0,H=0,I=0,J=0,K=0,L=0,M=0,N=0,O=0,P=0,Q=0,R=0,S=0,T=0,U=0,V=0,W=0,X=0,Z=0,_=0,$=0,aa=0,ba=0,ca=0,da=0,ea=0,fa=0,ga=0,ha=0,ia=0,ja=0,ka=0,la=0,ma=0,na=0,oa=0,pa=0,qa=0,ra=0,sa=0,ta=0,ua=0,va=0,wa=0,xa=0,ya=0,za=0,Aa=0,Ba=0,Ca=0,Da=0,Ea=0;j=a;V=x[c+4>>2];d=V;y=d;H=d>>31;r=x[b+20>>2];d=r<<1;ma=d;Z=d>>31;d=Fj(y,H,d,Z);f=Y;e=d;d=x[c>>2];z=d;A=d>>31;d=x[b+24>>2];I=d;B=d>>31;h=Fj(z,A,d,B);e=e+h|0;d=Y+f|0;d=e>>>0>>0?d+1|0:d;f=e;i=x[c+8>>2];e=i;na=e;P=e>>31;e=x[b+16>>2];J=e;C=e>>31;h=Fj(i,P,e,C);e=f+h|0;f=Y+d|0;f=e>>>0>>0?f+1|0:f;t=x[c+12>>2];d=t;oa=d;R=d>>31;o=x[b+12>>2];d=o<<1;pa=d;_=d>>31;h=Fj(t,R,d,_);d=h+e|0;e=Y+f|0;e=d>>>0>>0?e+1|0:e;f=d;s=x[c+16>>2];d=s;wa=d;W=d>>31;d=x[b+8>>2];K=d;E=d>>31;h=Fj(s,W,d,E);f=f+h|0;d=Y+e|0;d=f>>>0>>0?d+1|0:d;g=f;m=x[c+20>>2];e=m;xa=e;$=e>>31;l=x[b+4>>2];e=l<<1;qa=e;aa=e>>31;f=Fj(m,$,e,aa);e=g+f|0;d=Y+d|0;d=e>>>0>>0?d+1|0:d;f=e;n=x[c+24>>2];e=n;ya=e;ra=e>>31;e=x[b>>2];L=e;F=e>>31;h=Fj(n,ra,e,F);f=f+h|0;e=Y+d|0;e=f>>>0>>0?e+1|0:e;u=x[c+28>>2];d=D(u,19);S=d;T=d>>31;p=x[b+36>>2];d=p<<1;sa=d;ba=d>>31;h=Fj(S,T,d,ba);d=h+f|0;f=Y+e|0;f=d>>>0>>0?f+1|0:f;e=d;q=x[c+32>>2];d=D(q,19);v=d;w=d>>31;d=x[b+32>>2];M=d;G=d>>31;h=Fj(v,w,d,G);e=e+h|0;d=Y+f|0;d=e>>>0>>0?d+1|0:d;f=e;za=x[c+36>>2];c=D(za,19);N=c;O=c>>31;b=x[b+28>>2];c=b<<1;ta=c;ca=c>>31;e=Fj(N,O,c,ca);c=f+e|0;d=Y+d|0;k=c;c=c>>>0>>0?d+1|0:d;d=Fj(J,C,y,H);e=Y;h=r;da=h>>31;r=Fj(z,A,h,da);d=r+d|0;f=Y+e|0;f=d>>>0>>0?f+1|0:f;r=o;ea=o>>31;o=Fj(i,P,o,ea);d=o+d|0;e=Y+f|0;e=d>>>0>>0?e+1|0:e;o=Fj(K,E,t,R);f=o+d|0;d=Y+e|0;d=f>>>0>>0?d+1|0:d;e=f;o=l;fa=l>>31;f=Fj(s,W,l,fa);e=e+f|0;d=Y+d|0;d=e>>>0>>0?d+1|0:d;f=Fj(L,F,m,$);e=f+e|0;d=Y+d|0;d=e>>>0>>0?d+1|0:d;f=e;e=D(n,19);ga=e;X=e>>31;l=p;ha=l>>31;p=Fj(e,X,l,ha);e=f+p|0;f=Y+d|0;f=e>>>0

>>0?f+1|0:f;p=Fj(M,G,S,T);d=p+e|0;e=Y+f|0;e=d>>>0

>>0?e+1|0:e;p=b;ia=b>>31;f=Fj(v,w,b,ia);b=f+d|0;d=Y+e|0;d=b>>>0>>0?d+1|0:d;e=Fj(N,O,I,B);b=e+b|0;d=Y+d|0;U=b;b=b>>>0>>0?d+1|0:d;d=Fj(y,H,pa,_);f=Y;n=Fj(z,A,J,C);e=n+d|0;d=Y+f|0;d=e>>>0>>0?d+1|0:d;n=Fj(K,E,i,P);e=n+e|0;f=Y+d|0;f=e>>>0>>0?f+1|0:f;n=Fj(t,R,qa,aa);d=n+e|0;e=Y+f|0;e=d>>>0>>0?e+1|0:e;n=Fj(L,F,s,W);f=n+d|0;d=Y+e|0;d=f>>>0>>0?d+1|0:d;g=f;e=D(m,19);ua=e;ja=e>>31;f=Fj(e,ja,sa,ba);e=g+f|0;d=Y+d|0;d=e>>>0>>0?d+1|0:d;f=Fj(M,G,ga,X);e=f+e|0;d=Y+d|0;d=e>>>0>>0?d+1|0:d;m=Fj(S,T,ta,ca);e=m+e|0;f=Y+d|0;f=e>>>0>>0?f+1|0:f;m=Fj(v,w,I,B);d=m+e|0;e=Y+f|0;e=d>>>0>>0?e+1|0:e;m=Fj(N,O,ma,Z);f=m+d|0;d=Y+e|0;d=f>>>0>>0?d+1|0:d;m=f;Ba=d;e=f+33554432|0;d=e>>>0<33554432?d+1|0:d;n=e;Ca=d;f=U;U=(d&67108863)<<6|e>>>26;f=f+U|0;d=(d>>26)+b|0;d=f>>>0>>0?d+1|0:d;U=f;b=U+16777216|0;f=b>>>0<16777216?d+1|0:d;Da=b;e=f>>25;f=(f&33554431)<<7|b>>>25;b=f+k|0;d=c+e|0;d=b>>>0>>0?d+1|0:d;c=b;b=c+33554432|0;d=b>>>0<33554432?d+1|0:d;ka=b;b=d;d=ka&-67108864;x[j+24>>2]=c-d;k=j;c=Fj(y,H,qa,aa);d=Y;e=Fj(z,A,K,E);c=e+c|0;f=Y+d|0;f=c>>>0>>0?f+1|0:f;e=Fj(L,F,i,P);c=e+c|0;d=Y+f|0;d=c>>>0>>0?d+1|0:d;f=c;c=D(t,19);j=c;t=c>>31;e=Fj(c,t,sa,ba);c=f+e|0;d=Y+d|0;d=c>>>0>>0?d+1|0:d;e=c;c=D(s,19);Aa=c;va=c>>31;f=Fj(M,G,c,va);c=e+f|0;e=Y+d|0;e=c>>>0>>0?e+1|0:e;f=Fj(ta,ca,ua,ja);c=f+c|0;d=Y+e|0;d=c>>>0>>0?d+1|0:d;e=Fj(I,B,ga,X);c=e+c|0;f=Y+d|0;f=c>>>0>>0?f+1|0:f;e=Fj(S,T,ma,Z);c=e+c|0;d=Y+f|0;d=c>>>0>>0?d+1|0:d;e=Fj(v,w,J,C);c=e+c|0;d=Y+d|0;d=c>>>0>>0?d+1|0:d;f=Fj(N,O,pa,_);c=f+c|0;e=Y+d|0;g=c;c=c>>>0>>0?e+1|0:e;d=Fj(L,F,y,H);f=Y;s=Fj(z,A,o,fa);e=s+d|0;d=Y+f|0;d=e>>>0>>0?d+1|0:d;f=e;e=D(i,19);s=e;Q=e>>31;i=Fj(e,Q,l,ha);e=f+i|0;f=Y+d|0;f=e>>>0>>0?f+1|0:f;i=Fj(M,G,j,t);e=i+e|0;d=Y+f|0;d=e>>>0>>0?d+1|0:d;f=Fj(Aa,va,p,ia);e=f+e|0;d=Y+d|0;d=e>>>0>>0?d+1|0:d;i=Fj(I,B,ua,ja);f=i+e|0;e=Y+d|0;e=f>>>0>>0?e+1|0:e;i=Fj(ga,X,h,da);f=i+f|0;d=Y+e|0;d=f>>>0>>0?d+1|0:d;i=Fj(J,C,S,T);e=i+f|0;f=Y+d|0;f=e>>>0>>0?f+1|0:f;i=Fj(v,w,r,ea);e=i+e|0;d=Y+f|0;d=e>>>0>>0?d+1|0:d;f=Fj(N,O,K,E);e=f+e|0;d=Y+d|0;la=e;i=e>>>0>>0?d+1|0:d;d=D(y,19);d=Fj(d,d>>31,sa,ba);e=Y;f=Fj(z,A,L,F);d=f+d|0;e=Y+e|0;e=d>>>0>>0?e+1|0:e;V=Fj(M,G,s,Q);f=V+d|0;d=Y+e|0;j=Fj(j,t,ta,ca);e=j+f|0;f=Y+(f>>>0>>0?d+1|0:d)|0;f=e>>>0>>0?f+1|0:f;j=Fj(I,B,Aa,va);e=j+e|0;d=Y+f|0;d=e>>>0>>0?d+1|0:d;f=Fj(ma,Z,ua,ja);e=f+e|0;d=Y+d|0;d=e>>>0>>0?d+1|0:d;j=Fj(J,C,ga,X);f=j+e|0;e=Y+d|0;e=f>>>0>>0?e+1|0:e;j=Fj(S,T,pa,_);f=j+f|0;d=Y+e|0;d=f>>>0>>0?d+1|0:d;j=Fj(v,w,K,E);e=j+f|0;f=Y+d|0;f=e>>>0>>0?f+1|0:f;j=Fj(N,O,qa,aa);e=j+e|0;d=Y+f|0;d=e>>>0>>0?d+1|0:d;j=e;V=d;e=e+33554432|0;d=e>>>0<33554432?d+1|0:d;t=e;s=d;f=d>>26;Q=(d&67108863)<<6|e>>>26;d=Q+la|0;e=f+i|0;i=d;f=g;d=d>>>0>>0?e+1|0:e;e=i+16777216|0;d=e>>>0<16777216?d+1|0:d;Ea=e;g=(d&33554431)<<7|e>>>25;e=f+g|0;d=(d>>25)+c|0;d=e>>>0>>0?d+1|0:d;c=e+33554432|0;d=c>>>0<33554432?d+1|0:d;Q=c;c=d;d=Q&-67108864;x[k+8>>2]=e-d;g=k;d=Fj(I,B,y,H);f=Y;k=Fj(z,A,p,ia);e=k+d|0;d=Y+f|0;d=e>>>0>>0?d+1|0:d;f=Fj(na,P,h,da);e=f+e|0;d=Y+d|0;d=e>>>0>>0?d+1|0:d;f=Fj(J,C,oa,R);e=f+e|0;d=Y+d|0;d=e>>>0>>0?d+1|0:d;k=Fj(wa,W,r,ea);e=k+e|0;f=Y+d|0;f=e>>>0>>0?f+1|0:f;k=Fj(K,E,xa,$);d=k+e|0;e=Y+f|0;e=d>>>0>>0?e+1|0:e;k=Fj(o,fa,ya,ra);f=k+d|0;d=Y+e|0;d=f>>>0>>0?d+1|0:d;e=f;k=u;la=k>>31;f=Fj(L,F,k,la);e=e+f|0;d=Y+d|0;d=e>>>0>>0?d+1|0:d;f=Fj(v,w,l,ha);e=f+e|0;d=Y+d|0;d=e>>>0>>0?d+1|0:d;u=Fj(N,O,M,G);e=u+e|0;f=Y+d|0;f=e>>>0>>0?f+1|0:f;d=b>>26;u=(b&67108863)<<6|ka>>>26;b=u+e|0;e=d+f|0;e=b>>>0>>0?e+1|0:e;f=b;d=e;b=f+16777216|0;d=b>>>0<16777216?d+1|0:d;ka=b;b=d;d=ka&-33554432;x[g+28>>2]=f-d;u=g;d=Fj(K,E,y,H);e=Y;g=Fj(z,A,r,ea);d=g+d|0;f=Y+e|0;f=d>>>0>>0?f+1|0:f;g=Fj(na,P,o,fa);d=g+d|0;e=Y+f|0;e=d>>>0>>0?e+1|0:e;g=Fj(L,F,oa,R);f=g+d|0;d=Y+e|0;d=f>>>0>>0?d+1|0:d;e=f;f=Fj(Aa,va,l,ha);e=e+f|0;d=Y+d|0;d=e>>>0>>0?d+1|0:d;f=Fj(M,G,ua,ja);e=f+e|0;d=Y+d|0;d=e>>>0>>0?d+1|0:d;g=Fj(ga,X,p,ia);e=g+e|0;f=Y+d|0;f=e>>>0>>0?f+1|0:f;g=Fj(I,B,S,T);d=g+e|0;e=Y+f|0;e=d>>>0>>0?e+1|0:e;g=Fj(v,w,h,da);f=g+d|0;d=Y+e|0;d=f>>>0>>0?d+1|0:d;e=f;f=Fj(N,O,J,C);e=e+f|0;d=Y+d|0;d=e>>>0>>0?d+1|0:d;g=e;e=c>>26;f=(c&67108863)<<6|Q>>>26;c=g+f|0;d=d+e|0;d=c>>>0>>0?d+1|0:d;e=c;c=e+16777216|0;f=c>>>0<16777216?d+1|0:d;v=c;c=f;d=v&-33554432;x[u+12>>2]=e-d;d=Fj(y,H,ta,ca);f=Y;g=Fj(z,A,M,G);e=g+d|0;d=Y+f|0;d=e>>>0>>0?d+1|0:d;f=Fj(I,B,na,P);e=f+e|0;d=Y+d|0;d=e>>>0>>0?d+1|0:d;g=Fj(oa,R,ma,Z);e=g+e|0;f=Y+d|0;f=e>>>0>>0?f+1|0:f;g=Fj(J,C,wa,W);d=g+e|0;e=Y+f|0;e=d>>>0>>0?e+1|0:e;g=Fj(pa,_,xa,$);f=g+d|0;d=Y+e|0;d=f>>>0>>0?d+1|0:d;e=f;f=Fj(K,E,ya,ra);e=e+f|0;d=Y+d|0;d=e>>>0>>0?d+1|0:d;f=Fj(k,la,qa,aa);e=f+e|0;d=Y+d|0;d=e>>>0>>0?d+1|0:d;g=q;w=g>>31;q=Fj(L,F,g,w);e=q+e|0;f=Y+d|0;f=e>>>0>>0?f+1|0:f;q=Fj(N,O,sa,ba);d=q+e|0;e=Y+f|0;e=d>>>0>>0?e+1|0:e;q=d;d=b>>25;f=(b&33554431)<<7|ka>>>25;b=q+f|0;d=d+e|0;d=b>>>0>>0?d+1|0:d;e=b;b=e+33554432|0;d=b>>>0<33554432?d+1|0:d;q=b;b=d;d=q&-67108864;x[u+32>>2]=e-d;d=n&-67108864;e=m-d|0;d=Ba-((d>>>0>m>>>0)+Ca|0)|0;f=e;e=c>>25;m=(c&33554431)<<7|v>>>25;c=f+m|0;d=d+e|0;d=c>>>0>>0?d+1|0:d;e=c+33554432|0;if(e>>>0<33554432){d=d+1|0}d=(U-(Da&-33554432)|0)+((d&67108863)<<6|e>>>26)|0;x[a+20>>2]=d;d=e&-67108864;x[a+16>>2]=c-d;d=Fj(M,G,y,H);f=Y;l=Fj(z,A,l,ha);e=l+d|0;d=Y+f|0;d=e>>>0>>0?d+1|0:d;l=Fj(na,P,p,ia);f=l+e|0;e=Y+d|0;e=f>>>0>>0?e+1|0:e;l=Fj(I,B,oa,R);d=l+f|0;f=Y+e|0;h=Fj(wa,W,h,da);e=h+d|0;d=Y+(d>>>0>>0?f+1|0:f)|0;d=e>>>0>>0?d+1|0:d;f=Fj(J,C,xa,$);e=f+e|0;d=Y+d|0;d=e>>>0>>0?d+1|0:d;f=Fj(r,ea,ya,ra);e=f+e|0;d=Y+d|0;d=e>>>0>>0?d+1|0:d;h=Fj(K,E,k,la);f=h+e|0;e=Y+d|0;e=f>>>0>>0?e+1|0:e;h=Fj(g,w,o,fa);d=h+f|0;f=Y+e|0;f=d>>>0>>0?f+1|0:f;h=Fj(L,F,za,za>>31);e=h+d|0;d=Y+f|0;d=e>>>0>>0?d+1|0:d;c=e;e=b>>26;f=(b&67108863)<<6|q>>>26;b=c+f|0;d=d+e|0;d=b>>>0>>0?d+1|0:d;c=b;b=c+16777216|0;d=b>>>0<16777216?d+1|0:d;e=b;b=e&-33554432;x[a+36>>2]=c-b;f=i-(Ea&-33554432)|0;b=t&-67108864;h=j-b|0;r=V-((b>>>0>j>>>0)+s|0)|0;b=d;d=d>>25;d=Fj((b&33554431)<<7|e>>>25,d,19,0);b=d+h|0;e=Y+r|0;e=b>>>0>>0?e+1|0:e;d=e;c=b+33554432|0;d=c>>>0<33554432?d+1|0:d;e=c;c=((d&67108863)<<6|e>>>26)+f|0;x[a+4>>2]=c;c=a;a=e&-67108864;x[c>>2]=b-a}function qg(a,b){var c=0,d=0,e=0,f=0,g=0,h=0,i=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0,r=0,s=0,t=0,u=0,v=0,w=0,y=0,z=0,A=0,B=0,C=0,E=0,F=0,G=0,H=0,I=0,J=0,K=0,L=0,M=0,N=0,O=0,P=0,Q=0,R=0,S=0,T=0,U=0,V=0,W=0,X=0,Z=0,_=0,$=0,aa=0,ba=0,ca=0,da=0,ea=0,fa=0,ga=0,ha=0,ia=0;g=x[b+12>>2];c=g<<1;s=c;t=c>>31;k=x[b+4>>2];c=k<<1;u=c;o=c>>31;c=Fj(s,t,c,o);e=Y;d=c;G=x[b+8>>2];c=G;l=c>>31;R=c;f=Fj(c,l,c,l);d=d+f|0;c=Y+e|0;c=d>>>0>>0?c+1|0:c;f=d;H=x[b+16>>2];d=H;p=d;v=d>>31;L=x[b>>2];d=L<<1;w=d;q=d>>31;e=Fj(p,v,d,q);d=f+e|0;c=Y+c|0;c=d>>>0>>0?c+1|0:c;i=d;e=x[b+28>>2];d=D(e,38);M=d;I=d>>31;$=e;S=e>>31;f=Fj(d,I,e,S);d=i+f|0;c=Y+c|0;c=d>>>0>>0?c+1|0:c;h=d;i=x[b+32>>2];d=D(i,19);z=d;A=d>>31;f=x[b+24>>2];d=f<<1;j=Fj(z,A,d,d>>31);m=h+j|0;d=Y+c|0;d=j>>>0>m>>>0?d+1|0:d;h=m;B=x[b+36>>2];c=D(B,38);y=c;r=c>>31;m=x[b+20>>2];b=m<<1;J=b;E=b>>31;j=Fj(c,r,b,E);c=h+j|0;b=Y+d|0;T=c<<1;c=(c>>>0>>0?b+1|0:b)<<1|c>>>31;ea=c;b=T+33554432|0;c=b>>>0<33554432?c+1|0:c;aa=b;fa=c;b=c>>26;c=(c&67108863)<<6|aa>>>26;d=Fj(u,o,p,v);j=Y;h=c;c=G<<1;K=c;F=c>>31;N=g;U=g>>31;g=Fj(c,F,g,U);d=g+d|0;c=Y+j|0;c=d>>>0>>0?c+1|0:c;G=m;O=m>>31;j=Fj(m,O,w,q);g=j+d|0;d=Y+c|0;d=g>>>0>>0?d+1|0:d;H=g;c=e<<1;ba=c;V=c>>31;g=Fj(z,A,c,V);e=H+g|0;c=Y+d|0;c=e>>>0>>0?c+1|0:c;d=e;g=f;C=f>>31;e=Fj(y,r,f,C);d=d+e|0;c=Y+c|0;c=d>>>0>>0?c+1|0:c;e=d;d=c<<1|d>>>31;e=e<<1;c=h+e|0;b=b+d|0;P=c;c=c>>>0>>0?b+1|0:b;b=P+16777216|0;c=b>>>0<16777216?c+1|0:c;ga=b;b=(c&33554431)<<7|b>>>25;e=c>>25;c=Fj(s,t,N,U);d=Y;h=b;j=Fj(p,v,K,F);b=j+c|0;c=Y+d|0;c=b>>>0>>0?c+1|0:c;d=Fj(u,o,J,E);b=d+b|0;c=Y+c|0;c=b>>>0>>0?c+1|0:c;j=Fj(w,q,f,C);d=j+b|0;b=Y+c|0;b=d>>>0>>0?b+1|0:b;j=i;Q=i>>31;i=Fj(z,A,i,Q);d=i+d|0;c=Y+b|0;c=d>>>0>>0?c+1|0:c;i=Fj(y,r,ba,V);b=i+d|0;d=Y+c|0;c=b;b=(c>>>0>>0?d+1|0:d)<<1|c>>>31;i=c<<1;d=h+i|0;c=b+e|0;c=d>>>0>>0?c+1|0:c;b=d;d=b+33554432|0;c=d>>>0<33554432?c+1|0:c;W=d;e=c;c=d&-67108864;x[a+24>>2]=b-c;i=a;b=D(m,38);b=Fj(b,b>>31,m,O);c=Y;h=b;b=L;d=b>>31;m=Fj(b,d,b,d);b=h+m|0;d=Y+c|0;d=b>>>0>>0?d+1|0:d;c=b;b=D(f,19);n=b;X=b>>31;b=p<<1;ca=b;Z=b>>31;f=Fj(n,X,b,Z);b=c+f|0;c=Y+d|0;c=b>>>0>>0?c+1|0:c;d=Fj(s,t,M,I);b=d+b|0;c=Y+c|0;c=b>>>0>>0?c+1|0:c;f=Fj(z,A,K,F);d=f+b|0;b=Y+c|0;b=d>>>0>>0?b+1|0:b;f=Fj(u,o,y,r);d=f+d|0;c=Y+b|0;b=d;m=b<<1;c=(b>>>0>>0?c+1|0:c)<<1|b>>>31;ha=c;b=m+33554432|0;d=b>>>0<33554432?c+1|0:c;L=b;H=d;b=(d&67108863)<<6|b>>>26;f=d>>26;c=Fj(n,X,J,E);d=Y;_=b;h=k;da=h>>31;k=Fj(w,q,h,da);b=k+c|0;c=Y+d|0;c=b>>>0>>0?c+1|0:c;k=Fj(p,v,M,I);d=k+b|0;b=Y+c|0;b=d>>>0>>0?b+1|0:b;k=Fj(z,A,s,t);d=k+d|0;c=Y+b|0;c=d>>>0>>0?c+1|0:c;k=Fj(y,r,R,l);b=k+d|0;d=Y+c|0;c=b;b=(c>>>0>>0?d+1|0:d)<<1|c>>>31;k=c<<1;d=_+k|0;c=b+f|0;c=d>>>0>>0?c+1|0:c;k=d;b=d+16777216|0;if(b>>>0<16777216){c=c+1|0}_=b;d=b;b=c>>25;c=(c&33554431)<<7|d>>>25;f=b;b=Fj(w,q,R,l);d=Y;ia=c;h=Fj(u,o,h,da);b=h+b|0;c=Y+d|0;c=b>>>0>>0?c+1|0:c;h=Fj(n,X,g,C);b=h+b|0;d=Y+c|0;d=b>>>0>>0?d+1|0:d;h=Fj(J,E,M,I);b=h+b|0;c=Y+d|0;c=b>>>0>>0?c+1|0:c;d=Fj(z,A,ca,Z);b=d+b|0;c=Y+c|0;c=b>>>0>>0?c+1|0:c;h=Fj(y,r,s,t);d=h+b|0;b=Y+c|0;b=d>>>0>>0?b+1|0:b;c=b<<1|d>>>31;d=d<<1;b=ia+d|0;c=c+f|0;c=b>>>0>>0?c+1|0:c;d=c;c=b+33554432|0;d=c>>>0<33554432?d+1|0:d;h=c;f=d;c=c&-67108864;x[i+8>>2]=b-c;b=Fj(K,F,G,O);d=Y;n=Fj(p,v,s,t);c=n+b|0;b=Y+d|0;b=c>>>0>>0?b+1|0:b;n=Fj(u,o,g,C);d=n+c|0;c=Y+b|0;c=d>>>0>>0?c+1|0:c;n=Fj(w,q,$,S);b=n+d|0;d=Y+c|0;d=b>>>0>>0?d+1|0:d;n=Fj(y,r,j,Q);b=n+b|0;c=Y+d|0;c=b>>>0>>0?c+1|0:c;c=c<<1|b>>>31;d=e>>26;e=(e&67108863)<<6|W>>>26;b=e+(b<<1)|0;c=c+d|0;c=b>>>0>>0?c+1|0:c;d=b;b=c;c=d+16777216|0;b=c>>>0<16777216?b+1|0:b;W=c;e=b;b=c&-33554432;x[i+28>>2]=d-b;b=Fj(w,q,N,U);c=Y;d=Fj(u,o,R,l);b=d+b|0;c=Y+c|0;c=b>>>0>>0?c+1|0:c;d=Fj(g,C,M,I);b=d+b|0;c=Y+c|0;c=b>>>0>>0?c+1|0:c;l=Fj(z,A,J,E);d=l+b|0;b=Y+c|0;b=d>>>0>>0?b+1|0:b;l=Fj(y,r,p,v);c=l+d|0;d=Y+b|0;b=c;c=(c>>>0>>0?d+1|0:d)<<1|c>>>31;d=b<<1;b=f>>26;f=(f&67108863)<<6|h>>>26;d=d+f|0;c=b+c|0;c=d>>>0>>0?c+1|0:c;b=d;d=b+16777216|0;c=d>>>0<16777216?c+1|0:c;N=d;f=c;c=d&-33554432;x[i+12>>2]=b-c;l=a;b=Fj(g,C,K,F);c=Y;d=Fj(p,v,p,v);b=d+b|0;c=Y+c|0;c=b>>>0>>0?c+1|0:c;d=Fj(s,t,J,E);b=d+b|0;c=Y+c|0;c=b>>>0>>0?c+1|0:c;d=Fj(u,o,ba,V);b=d+b|0;c=Y+c|0;c=b>>>0>>0?c+1|0:c;i=Fj(w,q,j,Q);d=i+b|0;b=Y+c|0;b=d>>>0>>0?b+1|0:b;i=B;h=i>>31;B=Fj(y,r,i,h);c=B+d|0;d=Y+b|0;b=c;c=(c>>>0>>0?d+1|0:d)<<1|c>>>31;a=b<<1;b=e>>25;e=(e&33554431)<<7|W>>>25;d=a+e|0;c=b+c|0;c=d>>>0>>0?c+1|0:c;b=d;d=b+33554432|0;c=d>>>0<33554432?c+1|0:c;B=d;e=c;c=d&-67108864;x[l+32>>2]=b-c;P=P-(ga&-33554432)|0;c=f>>25;f=(f&33554431)<<7|N>>>25;b=aa&-67108864;d=f+(T-b|0)|0;b=c+(ea-((b>>>0>T>>>0)+fa|0)|0)|0;b=d>>>0>>0?b+1|0:b;c=b;b=d+33554432|0;c=b>>>0<33554432?c+1|0:c;f=b;b=((c&67108863)<<6|b>>>26)+P|0;x[l+20>>2]=b;b=f&-67108864;x[l+16>>2]=d-b;b=Fj(s,t,g,C);d=Y;g=Fj(G,O,ca,Z);c=g+b|0;b=Y+d|0;b=c>>>0>>0?b+1|0:b;g=Fj(K,F,$,S);d=g+c|0;c=Y+b|0;c=d>>>0>>0?c+1|0:c;g=Fj(u,o,j,Q);b=g+d|0;d=Y+c|0;d=b>>>0>>0?d+1|0:d;g=Fj(w,q,i,h);b=g+b|0;c=Y+d|0;c=b>>>0>>0?c+1|0:c;c=c<<1|b>>>31;d=e>>26;e=(e&67108863)<<6|B>>>26;b=e+(b<<1)|0;c=c+d|0;c=b>>>0>>0?c+1|0:c;d=b;e=b;b=c;c=d+16777216|0;b=c>>>0<16777216?b+1|0:b;d=c&-33554432;x[l+36>>2]=e-d;f=k-(_&-33554432)|0;c=Fj((b&33554431)<<7|c>>>25,b>>25,19,0);d=L&-67108864;b=c+(m-d|0)|0;d=Y+(ha-((d>>>0>m>>>0)+H|0)|0)|0;d=b>>>0>>0?d+1|0:d;c=b;b=d;d=c+33554432|0;b=d>>>0<33554432?b+1|0:b;b=((b&67108863)<<6|d>>>26)+f|0;x[l+4>>2]=b;a=d&-67108864;x[l>>2]=c-a}function Ec(a,b,c){var d=0,e=0,f=0,g=0,h=0,i=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0,r=0,s=0,t=0,u=0,v=0,w=0,y=0,z=0,A=0,B=0,C=0,D=0,E=0,F=0,G=0,H=0,I=0,J=0,K=0,L=0,M=0,N=0,O=0,P=0,Q=0,R=0,S=0,T=0,U=0,W=0,X=0,Z=0,_=0,$=0,aa=0,ba=0,ca=0,da=0,ea=0,fa=0;r=V-2048|0;V=r;pb(r+1024|0,b);xb(r+1024|0,a);pb(r,r+1024|0);xb(r,c);b=0;while(1){a=v<<7;m=(r+1024|0)+(a|64)|0;d=m;g=x[d>>2];l=(r+1024|0)+(a|96)|0;f=l;k=x[f>>2];f=x[f+4>>2];h=g;q=x[d+4>>2];j=k;d=a+(r+1024|0)|0;g=(r+1024|0)+(a|32)|0;i=x[g>>2];k=x[g+4>>2];u=ka(x[d>>2],x[d+4>>2],i,k);e=f;f=Y;j=ia(j^u,e^f,32);e=Y;p=ka(h,q,j,e);h=p^i;i=Y;k=ia(h,k^i,24);h=f;f=Y;D=ka(u,h,k,f);o=Y;K=ia(D^j,o^e,16);G=Y;L=ka(p,i,K,G);H=Y;f=ia(k^L,H^f,63);k=Y;i=(r+1024|0)+(a|104)|0;j=x[i>>2];p=x[i+4>>2];u=(r+1024|0)+(a|72)|0;e=u;A=x[e>>2];n=x[e+4>>2];w=j;j=(r+1024|0)+(a|8)|0;e=j;t=x[e>>2];q=x[e+4>>2];e=(r+1024|0)+(a|40)|0;F=x[e>>2];h=x[e+4>>2];y=ka(t,q,F,h);q=p;p=Y;w=ia(w^y,q^p,32);q=Y;t=ka(A,n,w,q);n=t^F;F=Y;h=ia(n,h^F,24);n=p;p=Y;I=ka(y,n,h,p);M=Y;S=ia(I^w,M^q,16);W=Y;Z=ka(t,F,S,W);_=Y;p=ia(h^Z,_^p,63);h=Y;F=(r+1024|0)+(a|112)|0;y=F;w=x[y>>2];t=x[y+4>>2];y=(r+1024|0)+(a|80)|0;E=x[y>>2];s=x[y+4>>2];A=w;w=(r+1024|0)+(a|16)|0;q=(r+1024|0)+(a|48)|0;C=q;B=x[C>>2];C=x[C+4>>2];J=ka(x[w>>2],x[w+4>>2],B,C);n=t;t=Y;A=ia(A^J,n^t,32);z=Y;n=ka(E,s,A,z);s=n^B;B=Y;C=ia(s,C^B,24);s=t;t=Y;$=ka(J,s,C,t);aa=Y;ba=ia($^A,aa^z,16);ca=Y;T=ka(n,B,ba,ca);Q=Y;t=ia(C^T,Q^t,63);C=Y;B=(r+1024|0)+(a|120)|0;A=x[B>>2];z=x[B+4>>2];J=(r+1024|0)+(a|88)|0;n=J;da=x[n>>2];R=x[n+4>>2];E=A;A=(r+1024|0)+(a|24)|0;n=A;X=x[n>>2];s=x[n+4>>2];a=(r+1024|0)+(a|56)|0;N=x[a>>2];n=x[a+4>>2];U=ka(X,s,N,n);s=z;z=Y;O=ia(E^U,s^z,32);P=Y;R=ka(da,R,O,P);s=R^N;N=Y;n=ia(s,n^N,24);E=N;s=z;z=Y;N=ka(U,s,n,z);U=Y;O=ia(N^O,U^P,16);P=Y;R=ka(R,E,O,P);X=Y;z=ia(n^R,X^z,63);n=Y;E=T;s=Q;D=ka(D,o,p,h);o=Y;T=ia(O^D,P^o,32);Q=Y;O=ka(E,s,T,Q);P=Y;p=ia(O^p,P^h,24);h=D;D=Y;h=ka(h,o,p,D);o=Y;x[d>>2]=h;x[d+4>>2]=o;d=ia(h^T,Q^o,16);h=Y;x[B>>2]=d;x[B+4>>2]=h;d=ka(O,P,d,h);h=Y;x[y>>2]=d;x[y+4>>2]=h;ea=e,fa=ia(d^p,h^D,63),x[ea>>2]=fa;x[e+4>>2]=Y;o=t;e=ka(I,M,t,C);p=Y;h=ia(K^e,G^p,32);y=Y;t=ka(R,X,h,y);d=C;C=Y;d=ia(o^t,d^C,24);o=p;p=Y;e=ka(e,o,d,p);B=Y;x[j>>2]=e;x[j+4>>2]=B;j=ia(e^h,y^B,16);e=Y;x[l>>2]=j;x[l+4>>2]=e;l=ka(t,C,j,e);x[J>>2]=l;j=Y;x[J+4>>2]=j;ea=q,fa=ia(d^l,j^p,63),x[ea>>2]=fa;x[q+4>>2]=Y;d=ka($,aa,z,n);j=Y;e=ia(S^d,W^j,32);p=Y;h=ka(L,H,e,p);y=Y;l=ia(h^z,y^n,24);q=j;j=Y;d=ka(d,q,l,j);q=Y;t=q;x[w>>2]=d;x[w+4>>2]=t;d=ia(d^e,p^t,16);e=Y;x[i>>2]=d;x[i+4>>2]=e;d=ka(h,y,d,e);x[m>>2]=d;e=m;m=Y;x[e+4>>2]=m;ea=a,fa=ia(d^l,m^j,63),x[ea>>2]=fa;x[a+4>>2]=Y;e=f;m=ka(N,U,f,k);l=Y;d=ia(ba^m,ca^l,32);f=Y;i=ka(Z,_,d,f);a=k;k=Y;a=ia(e^i,a^k,24);e=l;l=Y;m=ka(m,e,a,l);j=Y;e=j;x[A>>2]=m;x[A+4>>2]=e;m=ia(d^m,f^e,16);d=Y;x[F>>2]=m;x[F+4>>2]=d;m=ka(i,k,m,d);x[u>>2]=m;d=Y;x[u+4>>2]=d;ea=g,fa=ia(a^m,d^l,63),x[ea>>2]=fa;x[g+4>>2]=Y;v=v+1|0;if((v|0)!=8){continue}break}while(1){l=b<<4;a=l+(r+1024|0)|0;v=x[a+768>>2];m=x[a+772>>2];d=a+512|0;h=x[d>>2];j=x[d+4>>2];e=v;v=x[a+256>>2];d=x[a+260>>2];g=ka(x[a>>2],x[a+4>>2],v,d);f=m;m=Y;f=ia(e^g,f^m,32);k=Y;i=ka(h,j,f,k);e=i^v;v=Y;d=ia(e,d^v,24);q=v;v=Y;j=ka(g,m,d,v);e=Y;p=ia(j^f,e^k,16);h=Y;F=ka(i,q,p,h);y=Y;v=ia(d^F,y^v,63);m=Y;d=x[a+780>>2];t=x[a+520>>2];o=x[a+524>>2];w=x[a+776>>2];l=(r+1024|0)+(l|8)|0;g=l;q=x[g>>2];k=x[g+4>>2];g=x[a+264>>2];f=x[a+268>>2];k=ka(q,k,g,f);q=d;d=Y;i=ia(w^k,q^d,32);u=Y;w=ka(t,o,i,u);q=w^g;g=Y;f=ia(q,f^g,24);o=w;q=d;d=Y;w=ka(k,q,f,d);q=Y;t=ia(w^i,q^u,16);C=Y;B=ka(o,g,t,C);J=Y;d=ia(f^B,J^d,63);g=Y;f=x[a+900>>2];s=x[a+640>>2];D=x[a+644>>2];n=x[a+896>>2];k=x[a+384>>2];i=x[a+388>>2];u=ka(x[a+128>>2],x[a+132>>2],k,i);o=f;f=Y;A=ia(n^u,o^f,32);z=Y;n=ka(s,D,A,z);o=n^k;k=Y;i=ia(o,i^k,24);s=n;n=A;o=f;f=Y;A=ka(u,o,i,f);o=z;z=Y;n=ia(n^A,o^z,16);D=Y;o=ka(s,k,n,D);K=Y;f=ia(i^o,K^f,63);k=Y;i=x[a+908>>2];Q=x[a+648>>2];W=x[a+652>>2];E=x[a+904>>2];u=x[a+392>>2];G=x[a+396>>2];L=ka(x[a+136>>2],x[a+140>>2],u,G);s=i;i=Y;H=ia(E^L,s^i,32);I=Y;M=ka(Q,W,H,I);s=M^u;u=Y;G=ia(s,G^u,24);E=G;s=i;i=Y;G=ka(L,s,G,i);L=Y;H=ia(G^H,L^I,16);I=Y;M=ka(M,u,H,I);S=Y;i=ia(E^M,S^i,63);u=Y;E=o;s=K;j=ka(j,e,d,g);e=Y;o=ia(H^j,I^e,32);K=Y;H=ka(E,s,o,K);I=Y;d=ia(H^d,I^g,24);g=j;j=Y;g=ka(g,e,d,j);e=Y;x[a>>2]=g;x[a+4>>2]=e;g=ia(g^o,K^e,16);e=Y;x[a+904>>2]=g;x[a+908>>2]=e;g=ka(H,I,g,e);e=Y;x[a+640>>2]=g;x[a+644>>2]=e;ea=a,fa=ia(d^g,j^e,63),x[ea+264>>2]=fa;x[a+268>>2]=Y;o=f;g=ka(w,q,f,k);f=Y;j=ia(p^g,h^f,32);e=Y;p=ka(M,S,j,e);d=k;k=Y;d=ia(o^p,d^k,24);h=f;f=Y;g=ka(g,h,d,f);h=Y;x[l>>2]=g;x[l+4>>2]=h;l=ia(g^j,e^h,16);g=Y;x[a+768>>2]=l;x[a+772>>2]=g;l=ka(p,k,l,g);x[a+648>>2]=l;g=Y;x[a+652>>2]=g;ea=a,fa=ia(d^l,g^f,63),x[ea+384>>2]=fa;x[a+388>>2]=Y;j=i;d=ka(A,z,i,u);g=Y;f=ia(t^d,C^g,32);k=Y;i=ka(F,y,f,k);e=u;u=Y;l=ia(j^i,e^u,24);e=g;g=Y;d=ka(d,e,l,g);j=Y;e=j;x[a+128>>2]=d;x[a+132>>2]=e;d=ia(d^f,e^k,16);f=Y;x[a+776>>2]=d;x[a+780>>2]=f;d=ka(i,u,d,f);x[a+512>>2]=d;f=Y;x[a+516>>2]=f;ea=a,fa=ia(d^l,g^f,63),x[ea+392>>2]=fa;x[a+396>>2]=Y;l=ka(G,L,v,m);d=Y;g=ia(n^l,D^d,32);f=Y;k=ka(B,J,g,f);i=Y;v=ia(k^v,i^m,24);e=l;l=Y;m=ka(e,d,v,l);d=Y;x[a+136>>2]=m;x[a+140>>2]=d;m=ia(g^m,f^d,16);d=Y;x[a+896>>2]=m;x[a+900>>2]=d;m=ka(k,i,m,d);x[a+520>>2]=m;d=Y;x[a+524>>2]=d;ea=a,fa=ia(m^v,d^l,63),x[ea+256>>2]=fa;x[a+260>>2]=Y;b=b+1|0;if((b|0)!=8){continue}break}pb(c,r);xb(c,r+1024|0);V=r+2048|0}function hc(a,b,c,d){var e=0,f=0,g=0,h=0,i=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0,r=0,s=0,t=0,u=0,v=0,w=0,z=0,A=0,B=0,C=0,D=0,E=0,F=0,G=0,H=0;while(1){f=g<<2;n=f+b|0;n=y[n|0]|y[n+1|0]<<8|(y[n+2|0]<<16|y[n+3|0]<<24);x[c+f>>2]=n<<8&16711680|n<<24|(n>>>8&65280|n>>>24);g=g+1|0;if((g|0)!=16){continue}break}b=a;n=x[b+28>>2];x[d+24>>2]=x[b+24>>2];x[d+28>>2]=n;n=x[b+20>>2];x[d+16>>2]=x[b+16>>2];x[d+20>>2]=n;n=x[b+12>>2];x[d+8>>2]=x[b+8>>2];x[d+12>>2]=n;n=x[b+4>>2];x[d>>2]=x[b>>2];x[d+4>>2]=n;while(1){b=v<<2;n=b+c|0;i=x[d+16>>2];g=x[n>>2]+(ja(i,6)^ja(i,11)^ja(i,25))|0;f=x[d+24>>2];l=x[d+20>>2];g=x[d+28>>2]+((x[b+35984>>2]+g|0)+(i&(f^l)^f)|0)|0;j=g+x[d+12>>2]|0;x[d+12>>2]=j;h=x[d>>2];g=g+(ja(h,2)^ja(h,13)^ja(h,22))|0;k=x[d+8>>2];e=x[d+4>>2];g=g+(h&(k|e)|e&k)|0;x[d+28>>2]=g;o=(f+(l^j&(i^l))|0)+(ja(j,6)^ja(j,11)^ja(j,25))|0;f=b|4;s=f+c|0;f=(o+x[s>>2]|0)+x[f+35984>>2]|0;k=f+k|0;x[d+8>>2]=k;f=(f+(g&(e|h)|e&h)|0)+(ja(g,2)^ja(g,13)^ja(g,22))|0;x[d+24>>2]=f;m=e;e=b|8;o=e+c|0;e=(((l+(i^k&(j^i))|0)+(ja(k,6)^ja(k,11)^ja(k,25))|0)+x[o>>2]|0)+x[e+35984>>2]|0;l=m+e|0;x[d+4>>2]=l;e=(e+(f&(g|h)|g&h)|0)+(ja(f,2)^ja(f,13)^ja(f,22))|0;x[d+20>>2]=e;m=h;h=b|12;t=h+c|0;h=(((i+(j^l&(j^k))|0)+(ja(l,6)^ja(l,11)^ja(l,25))|0)+x[t>>2]|0)+x[h+35984>>2]|0;i=m+h|0;x[d>>2]=i;h=(h+(e&(f|g)|f&g)|0)+(ja(e,2)^ja(e,13)^ja(e,22))|0;x[d+16>>2]=h;m=g;g=b|16;p=g+c|0;g=(((j+(k^i&(k^l))|0)+(ja(i,6)^ja(i,11)^ja(i,25))|0)+x[p>>2]|0)+x[g+35984>>2]|0;j=m+g|0;x[d+28>>2]=j;g=(g+(h&(e|f)|e&f)|0)+(ja(h,2)^ja(h,13)^ja(h,22))|0;x[d+12>>2]=g;m=f;f=b|20;q=f+c|0;f=(((k+(l^j&(i^l))|0)+(ja(j,6)^ja(j,11)^ja(j,25))|0)+x[q>>2]|0)+x[f+35984>>2]|0;k=m+f|0;x[d+24>>2]=k;f=(f+(g&(e|h)|e&h)|0)+(ja(g,2)^ja(g,13)^ja(g,22))|0;x[d+8>>2]=f;m=e;e=b|24;r=e+c|0;e=(((l+(i^k&(j^i))|0)+(ja(k,6)^ja(k,11)^ja(k,25))|0)+x[r>>2]|0)+x[e+35984>>2]|0;l=m+e|0;x[d+20>>2]=l;e=(e+(f&(g|h)|g&h)|0)+(ja(f,2)^ja(f,13)^ja(f,22))|0;x[d+4>>2]=e;m=h;h=b|28;u=h+c|0;h=(((i+(j^l&(j^k))|0)+(ja(l,6)^ja(l,11)^ja(l,25))|0)+x[u>>2]|0)+x[h+35984>>2]|0;i=m+h|0;x[d+16>>2]=i;h=(h+(e&(f|g)|f&g)|0)+(ja(e,2)^ja(e,13)^ja(e,22))|0;x[d>>2]=h;m=g;g=b|32;z=g+c|0;g=(((j+(k^i&(k^l))|0)+(ja(i,6)^ja(i,11)^ja(i,25))|0)+x[z>>2]|0)+x[g+35984>>2]|0;j=m+g|0;x[d+12>>2]=j;g=(g+(h&(e|f)|e&f)|0)+(ja(h,2)^ja(h,13)^ja(h,22))|0;x[d+28>>2]=g;m=f;f=b|36;A=f+c|0;f=(((k+(l^j&(i^l))|0)+(ja(j,6)^ja(j,11)^ja(j,25))|0)+x[A>>2]|0)+x[f+35984>>2]|0;k=m+f|0;x[d+8>>2]=k;f=(f+(g&(e|h)|e&h)|0)+(ja(g,2)^ja(g,13)^ja(g,22))|0;x[d+24>>2]=f;m=e;e=b|40;B=e+c|0;e=(((l+(i^k&(j^i))|0)+(ja(k,6)^ja(k,11)^ja(k,25))|0)+x[B>>2]|0)+x[e+35984>>2]|0;l=m+e|0;x[d+4>>2]=l;e=(e+(f&(g|h)|g&h)|0)+(ja(f,2)^ja(f,13)^ja(f,22))|0;x[d+20>>2]=e;m=h;h=b|44;C=h+c|0;h=(((i+(j^l&(j^k))|0)+(ja(l,6)^ja(l,11)^ja(l,25))|0)+x[C>>2]|0)+x[h+35984>>2]|0;i=m+h|0;x[d>>2]=i;h=(h+(e&(f|g)|f&g)|0)+(ja(e,2)^ja(e,13)^ja(e,22))|0;x[d+16>>2]=h;m=g;g=b|48;D=g+c|0;g=(((j+(k^i&(k^l))|0)+(ja(i,6)^ja(i,11)^ja(i,25))|0)+x[D>>2]|0)+x[g+35984>>2]|0;j=m+g|0;x[d+28>>2]=j;g=(g+(h&(e|f)|e&f)|0)+(ja(h,2)^ja(h,13)^ja(h,22))|0;x[d+12>>2]=g;m=f;f=b|52;E=f+c|0;f=(((k+(l^j&(i^l))|0)+(ja(j,6)^ja(j,11)^ja(j,25))|0)+x[E>>2]|0)+x[f+35984>>2]|0;k=m+f|0;x[d+24>>2]=k;f=(f+(g&(e|h)|e&h)|0)+(ja(g,2)^ja(g,13)^ja(g,22))|0;x[d+8>>2]=f;m=e;e=b|56;F=e+c|0;l=(((l+(i^k&(j^i))|0)+(ja(k,6)^ja(k,11)^ja(k,25))|0)+x[F>>2]|0)+x[e+35984>>2]|0;e=m+l|0;x[d+20>>2]=e;l=(l+(f&(g|h)|g&h)|0)+(ja(f,2)^ja(f,13)^ja(f,22))|0;x[d+4>>2]=l;e=(i+(j^e&(j^k))|0)+(ja(e,6)^ja(e,11)^ja(e,25))|0;b=b|60;j=b+c|0;b=(e+x[j>>2]|0)+x[b+35984>>2]|0;x[d+16>>2]=b+h;G=d,H=(b+(l&(f|g)|f&g)|0)+(ja(l,2)^ja(l,13)^ja(l,22))|0,x[G>>2]=H;if((v|0)==48){while(1){b=w<<2;c=b+a|0;x[c>>2]=x[c>>2]+x[b+d>>2];w=w+1|0;if((w|0)!=8){continue}break}}else{v=v+16|0;b=x[F>>2];g=b>>>10^ja(b,17)^ja(b,19);e=x[A>>2];f=x[s>>2];g=((g+e|0)+x[n>>2]|0)+(f>>>3^ja(f,7)^ja(f,18))|0;x[(v<<2)+c>>2]=g;h=x[B>>2];k=h+f|0;f=x[j>>2];i=k+(f>>>10^ja(f,17)^ja(f,19))|0;k=x[o>>2];j=i+(k>>>3^ja(k,7)^ja(k,18))|0;x[n+68>>2]=j;i=k;k=x[C>>2];o=(i+k|0)+(ja(g,17)^g>>>10^ja(g,19))|0;i=x[t>>2];l=o+(i>>>3^ja(i,7)^ja(i,18))|0;x[n+72>>2]=l;o=i;i=x[D>>2];m=(o+i|0)+(ja(j,17)^j>>>10^ja(j,19))|0;o=x[p>>2];s=m+(o>>>3^ja(o,7)^ja(o,18))|0;x[n+76>>2]=s;m=o;o=x[E>>2];m=(m+o|0)+(ja(l,17)^l>>>10^ja(l,19))|0;p=x[q>>2];t=m+(p>>>3^ja(p,7)^ja(p,18))|0;x[n+80>>2]=t;m=(b+p|0)+(ja(s,17)^s>>>10^ja(s,19))|0;q=x[r>>2];p=m+(q>>>3^ja(q,7)^ja(q,18))|0;x[n+84>>2]=p;m=(f+q|0)+(ja(t,17)^t>>>10^ja(t,19))|0;r=x[u>>2];q=m+(r>>>3^ja(r,7)^ja(r,18))|0;x[n+88>>2]=q;m=(g+r|0)+(ja(p,17)^p>>>10^ja(p,19))|0;u=x[z>>2];r=m+(u>>>3^ja(u,7)^ja(u,18))|0;x[n+92>>2]=r;j=((j+u|0)+(ja(q,17)^q>>>10^ja(q,19))|0)+(ja(e,7)^e>>>3^ja(e,18))|0;x[n+96>>2]=j;e=((e+l|0)+(ja(r,17)^r>>>10^ja(r,19))|0)+(ja(h,7)^h>>>3^ja(h,18))|0;x[n+100>>2]=e;h=((h+s|0)+(ja(j,17)^j>>>10^ja(j,19))|0)+(ja(k,7)^k>>>3^ja(k,18))|0;x[n+104>>2]=h;e=((k+t|0)+(ja(e,17)^e>>>10^ja(e,19))|0)+(ja(i,7)^i>>>3^ja(i,18))|0;x[n+108>>2]=e;h=((i+p|0)+(ja(h,17)^h>>>10^ja(h,19))|0)+(ja(o,7)^o>>>3^ja(o,18))|0;x[n+112>>2]=h;e=((o+q|0)+(ja(e,17)^e>>>10^ja(e,19))|0)+(ja(b,7)^b>>>3^ja(b,18))|0;x[n+116>>2]=e;G=n,H=((b+r|0)+(ja(h,17)^h>>>10^ja(h,19))|0)+(ja(f,7)^f>>>3^ja(f,18))|0,x[G+120>>2]=H;G=n,H=((f+j|0)+(ja(e,17)^e>>>10^ja(e,19))|0)+(ja(g,7)^g>>>3^ja(g,18))|0,x[G+124>>2]=H;continue}break}}function qa(a,b){var c=0,d=0,e=0,f=0,g=0,h=0,i=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0,r=0,s=0,t=0,u=0,v=0,w=0,y=0,z=0,A=0,B=0,C=0,E=0,F=0,G=0,H=0,I=0,J=0,K=0,L=0,M=0,N=0,O=0,P=0,Q=0,R=0,S=0,T=0,U=0,V=0,W=0,X=0,Z=0,_=0,$=0,aa=0,ba=0,ca=0,da=0,ea=0;h=a;c=x[b+12>>2];d=c<<1;y=d;s=d>>31;j=c;S=c>>31;c=Fj(d,s,c,S);f=Y;d=c;T=x[b+16>>2];c=T;n=c;t=c>>31;l=x[b+8>>2];c=l<<1;J=c;E=c>>31;g=Fj(n,t,c,E);d=d+g|0;c=Y+f|0;c=d>>>0>>0?c+1|0:c;f=d;g=x[b+20>>2];d=g<<1;F=d;G=d>>31;m=x[b+4>>2];d=m<<1;u=d;o=d>>31;e=Fj(F,G,d,o);f=f+e|0;d=Y+c|0;d=f>>>0>>0?d+1|0:d;i=x[b+24>>2];c=i;O=c;z=c>>31;K=x[b>>2];c=K<<1;v=c;p=c>>31;e=Fj(i,z,c,p);f=e+f|0;c=Y+d|0;c=f>>>0>>0?c+1|0:c;k=f;d=x[b+32>>2];f=D(d,19);H=f;A=f>>31;U=d;P=d>>31;f=Fj(f,A,d,P);d=k+f|0;c=Y+c|0;c=d>>>0>>0?c+1|0:c;k=d;B=x[b+36>>2];d=D(B,38);w=d;q=d>>31;f=x[b+28>>2];b=f<<1;_=b;V=b>>31;e=Fj(d,q,b,V);d=k+e|0;b=Y+c|0;C=d;r=d>>>0>>0?b+1|0:b;b=Fj(u,o,n,t);c=Y;d=Fj(J,E,j,S);b=d+b|0;c=Y+c|0;c=b>>>0>>0?c+1|0:c;$=g;Q=g>>31;e=Fj(g,Q,v,p);b=e+b|0;d=Y+c|0;d=b>>>0>>0?d+1|0:d;e=Fj(H,A,_,V);b=e+b|0;c=Y+d|0;c=b>>>0>>0?c+1|0:c;d=Fj(w,q,i,z);b=d+b|0;c=Y+c|0;k=b;L=b>>>0>>0?c+1|0:c;b=Fj(u,o,y,s);d=Y;e=l;M=e>>31;l=Fj(e,M,e,M);c=l+b|0;b=Y+d|0;b=c>>>0>>0?b+1|0:b;l=Fj(v,p,n,t);d=l+c|0;c=Y+b|0;c=d>>>0>>0?c+1|0:c;b=D(f,38);R=b;N=b>>31;l=f;W=f>>31;f=Fj(b,N,f,W);b=f+d|0;d=Y+c|0;d=b>>>0>>0?d+1|0:d;c=b;b=i<<1;f=Fj(H,A,b,b>>31);b=c+f|0;c=Y+d|0;c=b>>>0>>0?c+1|0:c;d=Fj(w,q,F,G);b=d+b|0;c=Y+c|0;X=b;c=b>>>0>>0?c+1|0:c;ca=c;b=c;c=X+33554432|0;b=c>>>0<33554432?b+1|0:b;aa=c;da=b;c=b>>26;d=(b&67108863)<<6|aa>>>26;b=d+k|0;c=c+L|0;L=b;d=b>>>0>>0?c+1|0:c;b=b+16777216|0;d=b>>>0<16777216?d+1|0:d;ea=b;c=d>>25;d=(d&33554431)<<7|b>>>25;b=d+C|0;c=c+r|0;c=b>>>0>>0?c+1|0:c;d=b;b=c;c=d+33554432|0;b=c>>>0<33554432?b+1|0:b;k=c;f=b;b=c&-67108864;x[h+24>>2]=d-b;b=Fj(v,p,e,M);c=Y;h=m;I=h>>31;m=Fj(u,o,h,I);b=m+b|0;d=Y+c|0;d=b>>>0>>0?d+1|0:d;c=b;b=D(i,19);m=b;C=b>>31;i=Fj(b,C,i,z);b=c+i|0;c=Y+d|0;c=b>>>0>>0?c+1|0:c;i=Fj(F,G,R,N);d=i+b|0;b=Y+c|0;b=d>>>0>>0?b+1|0:b;c=n<<1;ba=c;Z=c>>31;i=Fj(H,A,c,Z);d=i+d|0;c=Y+b|0;c=d>>>0>>0?c+1|0:c;b=d;d=Fj(w,q,y,s);b=b+d|0;c=Y+c|0;r=b;i=b>>>0>>0?c+1|0:c;b=Fj(F,G,m,C);c=Y;h=Fj(v,p,h,I);b=h+b|0;d=Y+c|0;d=b>>>0>>0?d+1|0:d;h=Fj(n,t,R,N);b=h+b|0;c=Y+d|0;c=b>>>0>>0?c+1|0:c;h=Fj(H,A,y,s);d=h+b|0;b=Y+c|0;b=d>>>0>>0?b+1|0:b;h=Fj(w,q,e,M);d=h+d|0;c=Y+b|0;I=d;h=d>>>0>>0?c+1|0:c;b=D(g,38);b=Fj(b,b>>31,g,Q);c=Y;g=b;b=K;d=b>>31;d=Fj(b,d,b,d);b=g+d|0;c=Y+c|0;c=b>>>0>>0?c+1|0:c;g=Fj(m,C,ba,Z);b=g+b|0;d=Y+c|0;d=b>>>0>>0?d+1|0:d;g=Fj(y,s,R,N);b=g+b|0;c=Y+d|0;c=b>>>0>>0?c+1|0:c;g=Fj(H,A,J,E);d=g+b|0;b=Y+c|0;b=d>>>0>>0?b+1|0:b;g=Fj(u,o,w,q);d=g+d|0;c=Y+b|0;m=d;c=d>>>0>>0?c+1|0:c;C=c;b=d+33554432|0;c=b>>>0<33554432?c+1|0:c;K=b;T=c;b=c>>26;g=(c&67108863)<<6|K>>>26;c=g+I|0;d=b+h|0;h=c;c=c>>>0>>0?d+1|0:d;b=h+16777216|0;c=b>>>0<16777216?c+1|0:c;I=b;g=(c&33554431)<<7|b>>>25;d=g+r|0;c=(c>>25)+i|0;c=d>>>0>>0?c+1|0:c;b=d;d=b+33554432|0;c=d>>>0<33554432?c+1|0:c;i=d;g=c;c=d&-67108864;x[a+8>>2]=b-c;b=Fj(J,E,$,Q);c=Y;d=Fj(n,t,y,s);b=d+b|0;c=Y+c|0;c=b>>>0>>0?c+1|0:c;d=Fj(u,o,O,z);b=d+b|0;c=Y+c|0;c=b>>>0>>0?c+1|0:c;d=Fj(v,p,l,W);b=d+b|0;c=Y+c|0;c=b>>>0>>0?c+1|0:c;r=Fj(w,q,U,P);d=r+b|0;b=Y+c|0;b=d>>>0>>0?b+1|0:b;c=f>>26;k=(f&67108863)<<6|k>>>26;f=k+d|0;d=b+c|0;d=f>>>0>>0?d+1|0:d;b=f;c=d;d=b+16777216|0;c=d>>>0<16777216?c+1|0:c;k=d;f=c;c=d&-33554432;x[a+28>>2]=b-c;b=Fj(v,p,j,S);d=Y;e=Fj(u,o,e,M);c=e+b|0;b=Y+d|0;b=c>>>0>>0?b+1|0:b;e=Fj(O,z,R,N);c=e+c|0;d=Y+b|0;d=c>>>0>>0?d+1|0:d;e=Fj(H,A,F,G);b=e+c|0;c=Y+d|0;c=b>>>0>>0?c+1|0:c;d=Fj(w,q,n,t);b=d+b|0;c=Y+c|0;c=b>>>0>>0?c+1|0:c;d=g>>26;g=(g&67108863)<<6|i>>>26;b=g+b|0;c=c+d|0;c=b>>>0>>0?c+1|0:c;d=b;b=c;c=d+16777216|0;b=c>>>0<16777216?b+1|0:b;i=c;g=b;b=c&-33554432;x[a+12>>2]=d-b;e=a;b=Fj(O,z,J,E);c=Y;d=Fj(n,t,n,t);b=d+b|0;c=Y+c|0;c=b>>>0>>0?c+1|0:c;d=Fj(y,s,F,G);b=d+b|0;c=Y+c|0;c=b>>>0>>0?c+1|0:c;j=Fj(u,o,_,V);d=j+b|0;b=Y+c|0;b=d>>>0>>0?b+1|0:b;j=Fj(v,p,U,P);c=j+d|0;d=Y+b|0;d=c>>>0>>0?d+1|0:d;j=B;r=j>>31;B=Fj(w,q,j,r);b=B+c|0;c=Y+d|0;c=b>>>0>>0?c+1|0:c;a=b;b=f>>25;f=(f&33554431)<<7|k>>>25;d=a+f|0;c=b+c|0;c=d>>>0>>0?c+1|0:c;b=d;d=b+33554432|0;c=d>>>0<33554432?c+1|0:c;B=d;f=c;c=d&-67108864;x[e+32>>2]=b-c;L=L-(ea&-33554432)|0;c=g>>25;g=(g&33554431)<<7|i>>>25;b=aa&-67108864;d=g+(X-b|0)|0;b=c+(ca-((b>>>0>X>>>0)+da|0)|0)|0;b=d>>>0>>0?b+1|0:b;c=b;b=d+33554432|0;c=b>>>0<33554432?c+1|0:c;g=b;b=((c&67108863)<<6|b>>>26)+L|0;x[e+20>>2]=b;b=g&-67108864;x[e+16>>2]=d-b;g=e;b=Fj(y,s,O,z);d=Y;e=Fj($,Q,ba,Z);c=e+b|0;b=Y+d|0;b=c>>>0>>0?b+1|0:b;e=Fj(J,E,l,W);d=e+c|0;c=Y+b|0;c=d>>>0>>0?c+1|0:c;e=Fj(u,o,U,P);b=e+d|0;d=Y+c|0;d=b>>>0>>0?d+1|0:d;e=Fj(v,p,j,r);b=e+b|0;c=Y+d|0;d=b;b=b>>>0>>0?c+1|0:c;c=f>>26;f=(f&67108863)<<6|B>>>26;d=f+d|0;c=b+c|0;c=d>>>0>>0?c+1|0:c;f=d;b=c;c=d+16777216|0;b=c>>>0<16777216?b+1|0:b;d=c&-33554432;x[g+36>>2]=f-d;e=Fj((b&33554431)<<7|c>>>25,b>>25,19,0);d=K&-67108864;b=e+(m-d|0)|0;c=Y+(C-((d>>>0>m>>>0)+T|0)|0)|0;d=b;b=b>>>0>>0?c+1|0:c;c=d+33554432|0;b=c>>>0<33554432?b+1|0:b;b=(h-(I&-33554432)|0)+((b&67108863)<<6|c>>>26)|0;x[g+4>>2]=b;a=c&-67108864;x[g>>2]=d-a}function Eg(a,b,c,d,e){a=a|0;b=b|0;c=c|0;d=d|0;e=e|0;var f=0,g=0,h=0,i=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0,r=0,s=0,t=0,u=0;f=e;g=y[f+4|0]|y[f+5|0]<<8|(y[f+6|0]<<16|y[f+7|0]<<24);h=y[f|0]|y[f+1|0]<<8|(y[f+2|0]<<16|y[f+3|0]<<24);e=h^1886610805;j=g^1936682341;l=h^1852142177;n=g^1819895653;g=y[f+8|0]|y[f+9|0]<<8|(y[f+10|0]<<16|y[f+11|0]<<24);i=g^1852075907;f=y[f+12|0]|y[f+13|0]<<8|(y[f+14|0]<<16|y[f+15|0]<<24);k=f^1685025377;m=g^2037671283;o=f^1952801890;f=c;p=c&7;g=(b+c|0)-p|0;if((g|0)!=(b|0)){while(1){t=y[b|0]|y[b+1|0]<<8|(y[b+2|0]<<16|y[b+3|0]<<24);u=y[b+4|0]|y[b+5|0]<<8|(y[b+6|0]<<16|y[b+7|0]<<24);d=na(i,k,13);r=Y;c=j+k|0;h=e+i|0;c=h>>>0>>0?c+1|0:c;j=h;h=c;k=na(j,c,32);q=Y;e=o^u;o=e;c=m^t;e=na(c,e,16);m=Y;s=e;e=c;i=c+l|0;c=n+o|0;c=e>>>0>i>>>0?c+1|0:c;e=s^i;l=c^m;n=l;l=na(e,l,21);m=Y;h=h^r;j=d^j;d=na(j,h,17);r=Y;c=c+h|0;h=i+j|0;c=h>>>0>>0?c+1|0:c;i=h;h=na(h,c,32);o=Y;j=d^i;c=c^r;d=na(j,c,13);r=Y;i=c;s=j;c=n+q|0;j=e+k|0;c=j>>>0>>0?c+1|0:c;n=j;k=j;j=s+j|0;e=c;c=c+i|0;c=j>>>0>>0?c+1|0:c;k=j;i=c;c=na(j,c,32);q=Y;e=e^m;j=e;l=l^n;e=na(l,e,16);n=Y;m=c;s=e;c=j+o|0;e=h+l|0;c=e>>>0>>0?c+1|0:c;l=s^e;j=m+l|0;h=c;n=c^n;c=n+q|0;c=j>>>0>>0?c+1|0:c;q=j;m=na(l,n,21)^j;j=c;o=c^Y;c=i^r;l=c;i=d^k;c=na(i,c,17);k=Y;d=c;c=h+l|0;i=e+i|0;c=i>>>0>>0?c+1|0:c;h=i;i=d^h;k=c^k;e=q^t;j=j^u;l=na(h,c,32);n=Y;b=b+8|0;if((g|0)!=(b|0)){continue}break}b=g}h=0;d=f<<24;a:{switch(p-1|0){case 6:d=d|y[b+6|0]<<16;case 5:d=d|y[b+5|0]<<8;case 4:d=d|y[b+4|0];case 3:f=y[b+3|0];c=f>>>8|0;h=h|f<<24;d=c|d;case 2:f=y[b+2|0];c=f>>>16|0;h=h|f<<16;d=c|d;case 1:f=y[b+1|0];c=f>>>24|0;h=h|f<<8;d=c|d;case 0:h=y[b|0]|h;break;default:break a}}p=na(i,k,13);t=Y;c=j+k|0;b=e+i|0;c=b>>>0>>0?c+1|0:c;g=b;e=c;i=na(b,c,32);j=Y;c=d^o;k=c;b=h^m;c=na(b,c,16);m=Y;o=c;c=k+n|0;f=b+l|0;c=f>>>0>>0?c+1|0:c;b=o^f;k=c^m;l=k;k=na(b,k,21);n=Y;e=e^t;g=g^p;o=na(g,e,17);p=Y;c=c+e|0;e=f+g|0;c=e>>>0>>0?c+1|0:c;f=e;e=na(f,c,32);m=Y;g=f^o;c=c^p;o=na(g,c,13);p=Y;f=c;q=g;c=j+l|0;g=b+i|0;c=g>>>0>>0?c+1|0:c;j=g;i=g;g=q+g|0;b=c;c=c+f|0;c=g>>>0>>0?c+1|0:c;i=g;f=c;g=na(g,c,32);l=Y;b=b^n;c=b;j=j^k;b=na(j,c,16);k=Y;n=b;c=c+m|0;b=e+j|0;c=b>>>0>>0?c+1|0:c;e=n^b;j=c^k;k=j;j=na(e,j,21);n=Y;f=f^p;i=i^o;o=na(i,f,17);p=Y;c=c+f|0;f=b+i|0;c=f>>>0>>0?c+1|0:c;b=f;i=na(b,c,32);m=Y;f=b^o;b=c^p;o=na(f,b,13);p=Y;q=f;c=k+l|0;e=e+g|0;c=e>>>0>>0?c+1|0:c;g=e;f=e^h;e=q+f|0;h=b;b=c;c=h+(c^d)|0;c=e>>>0>>0?c+1|0:c;f=e;d=c;h=na(f,c,32);k=Y;c=b^n;l=c;b=g^j;c=na(b,c,16);g=Y;j=c;c=m+l|0;e=b+(i^238)|0;c=e>>>0>>0?c+1|0:c;b=j^e;g=c^g;i=g;j=na(b,g,21);l=Y;d=d^p;f=f^o;n=na(f,d,17);m=Y;c=c+d|0;d=e+f|0;c=d>>>0>>0?c+1|0:c;e=d;d=na(d,c,32);o=Y;f=e^n;c=c^m;n=na(f,c,13);m=Y;e=c;q=f;c=i+k|0;f=b+h|0;c=f>>>0>>0?c+1|0:c;h=f;g=f;f=q+f|0;b=c;c=c+e|0;c=f>>>0>>0?c+1|0:c;g=f;e=c;f=na(f,c,32);i=Y;b=b^l;c=b;h=h^j;b=na(h,c,16);j=Y;l=b;c=c+o|0;b=d+h|0;c=b>>>0>>0?c+1|0:c;d=l^b;h=c^j;j=h;h=na(d,h,21);k=Y;e=e^m;g=g^n;n=na(g,e,17);m=Y;c=c+e|0;e=b+g|0;c=e>>>0>>0?c+1|0:c;b=e;g=na(b,c,32);l=Y;e=b^n;b=c^m;n=na(e,b,13);m=Y;o=e;c=i+j|0;d=d+f|0;c=d>>>0>>0?c+1|0:c;i=d;e=d;d=o+d|0;f=b;b=c;c=f+c|0;f=d;c=f>>>0>>0?c+1|0:c;d=c;e=na(f,c,32);j=Y;c=b^k;k=c;b=h^i;c=na(b,c,16);h=Y;i=c;c=k+l|0;g=b+g|0;c=g>>>0>>0?c+1|0:c;b=g;g=i^b;h=c^h;i=h;h=na(g,h,21);k=Y;d=d^m;f=f^n;n=na(f,d,17);m=Y;c=c+d|0;d=b+f|0;c=d>>>0>>0?c+1|0:c;b=d;f=na(b,c,32);l=Y;d=b^n;b=c^m;n=na(d,b,13);m=Y;o=d;c=i+j|0;d=e+g|0;c=d>>>0>>0?c+1|0:c;i=d;e=d;d=o+d|0;g=b;b=c;c=g+c|0;g=d;c=d>>>0>>0?c+1|0:c;d=c;e=na(g,c,32);j=Y;c=b^k;k=c;b=h^i;c=na(b,c,16);i=Y;h=c;c=k+l|0;f=b+f|0;c=f>>>0>>0?c+1|0:c;b=f;h=h^b;f=c^i;k=f;l=na(h,f,21);o=Y;d=d^m;i=d;g=g^n;d=na(g,d,17);n=Y;f=d;c=c+i|0;d=b+g|0;c=d>>>0>>0?c+1|0:c;m=d;g=f^d;b=c;c=c^n;i=c;d=c;c=j+k|0;f=e+h|0;c=f>>>0>>0?c+1|0:c;b=na(m,b,32);e=f;f=f^l;h=c^o;j=Y;Ba(a,b^(e^g)^f,h^(j^(c^d)));d=g^221;k=na(d,i,13);l=Y;c=c+i|0;e=d+e|0;c=e>>>0>>0?c+1|0:c;g=e;d=c;e=na(e,c,32);i=Y;c=na(f,h,16);n=Y;m=c;c=h+j|0;f=b+f|0;c=f>>>0>>0?c+1|0:c;b=f;f=m^b;h=c^n;j=h;h=na(f,h,21);n=Y;d=d^l;g=g^k;k=na(g,d,17);m=Y;c=c+d|0;d=b+g|0;c=d>>>0>>0?c+1|0:c;b=d;g=na(b,c,32);l=Y;d=b^k;b=c^m;k=na(d,b,13);m=Y;o=d;c=i+j|0;d=e+f|0;c=d>>>0>>0?c+1|0:c;i=d;e=d;d=o+d|0;f=b;b=c;c=f+c|0;f=d;c=f>>>0>>0?c+1|0:c;d=c;e=na(f,c,32);j=Y;c=b^n;n=c;b=h^i;c=na(b,c,16);h=Y;i=c;c=l+n|0;g=b+g|0;c=g>>>0>>0?c+1|0:c;b=g;g=i^b;h=c^h;i=h;h=na(g,h,21);l=Y;d=d^m;f=f^k;k=na(f,d,17);m=Y;c=c+d|0;d=b+f|0;c=d>>>0>>0?c+1|0:c;b=d;f=na(b,c,32);n=Y;d=b^k;b=c^m;k=na(d,b,13);m=Y;o=d;c=i+j|0;d=e+g|0;c=d>>>0>>0?c+1|0:c;i=d;e=d;d=o+d|0;g=b;b=c;c=g+c|0;g=d;c=d>>>0>>0?c+1|0:c;d=c;e=na(g,c,32);j=Y;c=b^l;l=c;b=h^i;c=na(b,c,16);i=Y;h=c;c=l+n|0;f=b+f|0;c=f>>>0>>0?c+1|0:c;b=f;h=h^b;f=c^i;i=f;l=na(h,f,21);f=Y;d=d^m;g=g^k;k=na(g,d,17);m=Y;c=c+d|0;d=b+g|0;c=d>>>0>>0?c+1|0:c;b=d;g=na(b,c,32);n=Y;c=c^m;m=c;k=b^k;o=na(k,c,13);b=Y;p=a+8|0;c=i+j|0;a=e+h|0;c=a>>>0>>0?c+1|0:c;d=a;a=d^l;e=c;c=c^f;h=c;c=na(a,c,16);i=Y;j=c;c=h+n|0;f=a+g|0;c=f>>>0>>0?c+1|0:c;a=f;f=c;c=na(j^a,c^i,21);h=Y;i=c;c=e+m|0;g=d+k|0;c=g>>>0>>0?c+1|0:c;e=g^o;d=a+e|0;b=b^c;c=f+b|0;c=a>>>0>d>>>0?c+1|0:c;a=d;b=i^d^na(e,b,17);d=Y^(c^h);Ba(p,na(a,c,32)^b,Y^d);return 0}function Yd(a,b,c,d,e){a=a|0;b=b|0;c=c|0;d=d|0;e=e|0;var f=0,g=0,h=0,i=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0,r=0,s=0,t=0;d=a;a=y[e|0]|y[e+1|0]<<8|(y[e+2|0]<<16|y[e+3|0]<<24);g=a^1886610805;f=y[e+4|0]|y[e+5|0]<<8|(y[e+6|0]<<16|y[e+7|0]<<24);i=f^1936682341;h=a^1852142177;l=f^1819895653;a=y[e+8|0]|y[e+9|0]<<8|(y[e+10|0]<<16|y[e+11|0]<<24);f=a^1852075885;j=y[e+12|0]|y[e+13|0]<<8|(y[e+14|0]<<16|y[e+15|0]<<24);e=j^1685025377;k=a^2037671283;j=j^1952801890;p=c&7;a=(b+c|0)-p|0;if((a|0)!=(b|0)){while(1){m=y[b|0]|y[b+1|0]<<8|(y[b+2|0]<<16|y[b+3|0]<<24);o=y[b+4|0]|y[b+5|0]<<8|(y[b+6|0]<<16|y[b+7|0]<<24);n=na(f,e,13);q=Y;e=e+i|0;f=f+g|0;i=f>>>0>>0?e+1|0:e;r=na(f,i,32);s=Y;e=j^o;j=e;k=k^m;g=na(k,e,16);e=h+k|0;g=g^e;h=l+j|0;h=e>>>0>>0?h+1|0:h;l=h^Y;k=l;l=na(g,k,21);j=Y;i=i^q;f=f^n;n=na(f,i,17);t=Y;i=h+i|0;f=e+f|0;e=e>>>0>f>>>0?i+1|0:i;i=na(f,e,32);h=Y;f=f^n;n=e^t;q=na(f,n,13);t=Y;e=k+s|0;s=e+1|0;k=e;e=g+r|0;g=e>>>0>>0?s:k;f=e+f|0;r=f;k=g+n|0;n=e>>>0>f>>>0?k+1|0:k;k=na(f,n,32);s=Y;g=g^j;f=g;e=e^l;g=na(e,f,16);f=f+h|0;e=e+i|0;f=e>>>0>>0?f+1|0:f;h=e^g;g=k+h|0;k=f^Y;i=s+k|0;k=na(h,k,21)^g;i=g>>>0>>0?i+1|0:i;j=i^Y;h=n^t;n=q^r;q=na(n,h,17);f=f+h|0;h=e+n|0;l=h>>>0>>0?f+1|0:f;f=h^q;e=l^Y;g=g^m;i=i^o;h=na(h,l,32);l=Y;b=b+8|0;if((a|0)!=(b|0)){continue}break}b=a}a=c<<24;c=0;a:{switch(p-1|0){case 6:a=a|y[b+6|0]<<16;case 5:a=a|y[b+5|0]<<8;case 4:a=a|y[b+4|0];case 3:c=y[b+3|0];m=c>>>8|0;c=c<<24;a=a|m;case 2:m=y[b+2|0];o=m>>>16|0;c=c|m<<16;a=a|o;case 1:m=y[b+1|0];o=m>>>24|0;c=c|m<<8;a=a|o;case 0:c=y[b|0]|c;break;default:break a}}m=na(f,e,13);o=Y;b=e+i|0;e=f+g|0;g=e>>>0>>0?b+1|0:b;i=na(e,g,32);p=Y;b=a^j;f=c^k;k=na(f,b,16);b=l+b|0;j=b+1|0;l=b;b=f+h|0;h=f>>>0>b>>>0?j:l;l=h^Y;j=l;f=b^k;l=na(f,j,21);k=Y;g=g^o;e=e^m;m=na(e,g,17);n=Y;g=h+g|0;e=b+e|0;b=b>>>0>e>>>0?g+1|0:g;g=na(e,b,32);h=Y;m=e^m;o=b^n;n=na(m,o,13);q=Y;b=j+p|0;j=b+1|0;e=b;b=f+i|0;e=b>>>0>>0?j:e;f=b+m|0;i=f;j=e+o|0;j=b>>>0>f>>>0?j+1|0:j;f=na(f,j,32);m=Y;e=e^k;k=e;b=b^l;e=na(b,e,16);h=h+k|0;b=b+g|0;g=b>>>0>>0?h+1|0:h;h=g^Y;l=h;k=b^e;h=na(k,h,21);o=Y;e=j^q;i=i^n;p=na(i,e,17);n=Y;e=g+e|0;g=e+1|0;j=e;e=b+i|0;b=b>>>0>e>>>0?g:j;g=na(e,b,32);i=Y;j=e^p;p=b^n;n=na(j,p,13);q=Y;b=l+m|0;l=b+1|0;e=b;b=f+k|0;e=b>>>0>>0?l:e;c=b^c;f=j+c|0;l=f;a=p+(a^e)|0;f=c>>>0>f>>>0?a+1|0:a;c=na(l,f,32);k=Y;a=e^o;e=a;b=b^h;h=na(b,e,16);a=e+i|0;j=a+1|0;e=a;a=b+(g^255)|0;b=b>>>0>a>>>0?j:e;e=b^Y;g=e;i=a^h;e=na(i,e,21);h=Y;f=f^q;j=f;l=l^n;f=na(l,f,17);m=Y;b=b+j|0;r=b+1|0;j=b;b=a+l|0;a=a>>>0>b>>>0?r:j;l=na(b,a,32);j=Y;b=b^f;a=a^m;f=na(b,a,13);m=Y;r=a;a=g+k|0;k=a+1|0;g=a;a=c+i|0;g=a>>>0>>0?k:g;c=r+g|0;b=a+b|0;c=b>>>0>>0?c+1|0:c;i=c;c=na(b,c,32);k=Y;g=g^h;h=g;e=a^e;g=na(e,g,16);a=h+j|0;h=a+1|0;j=a;a=e+l|0;e=e>>>0>a>>>0?h:j;h=e^Y;l=h;g=a^g;h=na(g,h,21);j=Y;i=i^m;m=i;b=b^f;f=na(b,i,17);i=Y;e=e+m|0;b=a+b|0;a=a>>>0>b>>>0?e+1|0:e;m=na(b,a,32);o=Y;b=b^f;a=a^i;f=na(b,a,13);i=Y;r=a;a=k+l|0;l=a+1|0;e=a;a=c+g|0;e=a>>>0>>0?l:e;c=r+e|0;b=a+b|0;c=b>>>0>>0?c+1|0:c;g=c;c=na(b,g,32);l=Y;k=e^j;e=a^h;h=na(e,k,16);a=k+o|0;k=a+1|0;j=a;a=e+m|0;e=e>>>0>a>>>0?k:j;k=e^Y;j=k;h=a^h;k=na(h,k,21);m=Y;g=g^i;i=g;b=b^f;g=na(b,g,17);f=Y;e=e+i|0;b=a+b|0;a=a>>>0>b>>>0?e+1|0:e;e=na(b,a,32);i=Y;a=a^f;f=a;g=b^g;o=na(g,a,13);p=Y;a=l+j|0;l=a+1|0;b=a;a=c+h|0;h=a>>>0>>0?l:b;b=m^h;c=a^k;k=na(c,b,16);b=i+b|0;j=b+1|0;l=b;b=c+e|0;c=c>>>0>b>>>0?j:l;e=na(b^k,c^Y,21);i=Y;f=f+h|0;g=a+g|0;f=(a>>>0>g>>>0?f+1|0:f)^p;a=c+f|0;j=a+1|0;l=a;c=g^o;a=b+c|0;b=a>>>0>>0?j:l;c=na(c,f,17)^(a^e);e=Y^(b^i);Ba(d,na(a,b,32)^c,Y^e);return 0}function Bj(a,b,c){a=a|0;b=b|0;c=c|0;var d=0,e=0,f=0,g=0,h=0,i=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0,r=0,s=0,t=0,u=0,w=0,z=0,A=0,B=0,C=0,D=0,E=0,F=0;e=V-336|0;V=e;f=-1;g=V-16|0;v[g+11|0]=0;v[g+12|0]=0;v[g+13|0]=0;v[g+14|0]=0;x[g+8>>2]=0;while(1){h=y[c+j|0];d=0;while(1){k=(g+8|0)+d|0;v[k|0]=y[k|0]|h^y[((d<<5)+34752|0)+j|0];d=d+1|0;if((d|0)!=7){continue}break}j=j+1|0;if((j|0)!=31){continue}break}h=y[c+31|0]&127;j=0;d=0;while(1){k=(g+8|0)+d|0;v[k|0]=y[k|0]|h^y[(d<<5)+34783|0];d=d+1|0;if((d|0)!=7){continue}break}d=0;while(1){d=y[(g+8|0)+j|0]-1|d;j=j+1|0;if((j|0)!=7){continue}break}if(!(d>>>8&1)){f=0;while(1){v[a+f|0]=y[b+f|0];f=f+1|0;if((f|0)!=32){continue}break}v[a|0]=y[a|0]&248;v[a+31|0]=y[a+31|0]&63|64;db(e+288|0,c);Ea(e+240|0);vb(e+192|0);La(e+144|0,e+288|0);Ea(e+96|0);c=254;b=0;while(1){d=b;k=c;b=y[(c>>>3|0)+a|0]>>>(c&7)&1;d=d^b;xc(e+240|0,e+144|0,d);xc(e+192|0,e+96|0,d);c=c-1|0;xa(e+48|0,e+144|0,e+96|0);xa(e,e+240|0,e+192|0);va(e+240|0,e+240|0,e+192|0);va(e+192|0,e+144|0,e+96|0);ma(e+96|0,e+48|0,e+240|0);ma(e+192|0,e+192|0,e);qa(e+48|0,e);qa(e,e+240|0);va(e+144|0,e+96|0,e+192|0);xa(e+192|0,e+96|0,e+192|0);ma(e+240|0,e,e+48|0);xa(e,e,e+48|0);qa(e+192|0,e+192|0);d=x[e+4>>2];p=d;m=d>>31;d=x[e+8>>2];q=d;w=d>>31;d=x[e+12>>2];r=d;n=d>>31;d=x[e+16>>2];s=d;z=d>>31;d=x[e+20>>2];l=d;o=d>>31;d=x[e+24>>2];t=d;A=d>>31;d=x[e>>2];B=d;C=d>>31;d=x[e+36>>2];g=Fj(d,d>>31,121666,0);f=g;d=Y;g=f+16777216|0;d=g>>>0<16777216?d+1|0:d;D=g;j=d;u=f-(g&-33554432)|0;d=x[e+32>>2];d=Fj(d,d>>31,121666,0);g=Y;f=x[e+28>>2];h=Fj(f,f>>31,121666,0);f=Y;E=d;d=h+16777216|0;f=d>>>0<16777216?f+1|0:f;F=d;i=d;d=f>>25;i=(f&33554431)<<7|i>>>25;f=E+i|0;g=d+g|0;g=f>>>0>>0?g+1|0:g;d=g;g=f+33554432|0;d=g>>>0<33554432?d+1|0:d;d=((d&67108863)<<6|g>>>26)+u|0;x[e+132>>2]=d;d=g&-67108864;x[e+128>>2]=f-d;u=h-(F&-33554432)|0;f=Fj(t,A,121666,0);t=Y;g=Fj(l,o,121666,0);d=Y;i=f;f=g+16777216|0;d=f>>>0<16777216?d+1|0:d;l=f;o=(d&33554431)<<7|f>>>25;h=i+o|0;d=(d>>25)+t|0;d=h>>>0>>0?d+1|0:d;f=d;d=h+33554432|0;f=d>>>0<33554432?f+1|0:f;i=d;d=((f&67108863)<<6|d>>>26)+u|0;x[e+124>>2]=d;d=i&-67108864;x[e+120>>2]=h-d;l=g-(l&-33554432)|0;g=Fj(s,z,121666,0);s=Y;h=Fj(r,n,121666,0);f=Y;d=g;g=h+16777216|0;f=g>>>0<16777216?f+1|0:f;r=g;n=(f&33554431)<<7|g>>>25;i=d+n|0;f=(f>>25)+s|0;g=i;d=g>>>0>>0?f+1|0:f;f=g+33554432|0;d=f>>>0<33554432?d+1|0:d;d=((d&67108863)<<6|f>>>26)+l|0;x[e+116>>2]=d;d=f&-67108864;x[e+112>>2]=g-d;i=h-(r&-33554432)|0;d=Fj(q,w,121666,0);q=Y;h=Fj(p,m,121666,0);g=Y;f=d;d=h+16777216|0;g=d>>>0<16777216?g+1|0:g;p=d;m=d;d=g>>25;m=(g&33554431)<<7|m>>>25;g=f+m|0;d=d+q|0;d=g>>>0>>0?d+1|0:d;l=i;f=d;d=g+33554432|0;f=d>>>0<33554432?f+1|0:f;i=d;d=l+((f&67108863)<<6|d>>>26)|0;x[e+108>>2]=d;d=i&-67108864;x[e+104>>2]=g-d;h=h-(p&-33554432)|0;d=Fj((j&33554431)<<7|D>>>25,j>>25,19,0);j=Y;i=Fj(B,C,121666,0);g=i+d|0;d=Y+j|0;d=g>>>0>>0?d+1|0:d;f=d;d=g+33554432|0;f=d>>>0<33554432?f+1|0:f;j=d;d=((f&67108863)<<6|d>>>26)+h|0;x[e+100>>2]=d;d=j&-67108864;x[e+96>>2]=g-d;qa(e+144|0,e+144|0);va(e+48|0,e+48|0,e+96|0);ma(e+96|0,e+288|0,e+192|0);ma(e+192|0,e,e+48|0);if(k){continue}break}xc(e+240|0,e+144|0,b);xc(e+192|0,e+96|0,b);wb(e+192|0,e+192|0);ma(e+240|0,e+240|0,e+192|0);cb(a,e+240|0);f=0}V=e+336|0;return f|0}function Ka(a){a=a|0;var b=0,c=0,d=0,e=0,f=0,g=0,h=0,i=0,j=0;a:{if(!a){break a}d=a-8|0;b=x[a-4>>2];a=b&-8;f=d+a|0;b:{if(b&1){break b}if(!(b&3)){break a}b=x[d>>2];d=d-b|0;if(d>>>0>>0<=255){e=x[d+8>>2];b=b>>>3|0;c=x[d+12>>2];if((c|0)==(e|0)){i=37208,j=x[9302]&Gj(-2,b),x[i>>2]=j;break b}x[e+12>>2]=c;x[c+8>>2]=e;break b}h=x[d+24>>2];b=x[d+12>>2];c:{if((d|0)!=(b|0)){c=x[d+8>>2];x[c+12>>2]=b;x[b+8>>2]=c;break c}d:{e=d+20|0;c=x[e>>2];if(c){break d}e=d+16|0;c=x[e>>2];if(c){break d}b=0;break c}while(1){g=e;b=c;e=b+20|0;c=x[e>>2];if(c){continue}e=b+16|0;c=x[b+16>>2];if(c){continue}break}x[g>>2]=0}if(!h){break b}e=x[d+28>>2];c=(e<<2)+37512|0;e:{if(x[c>>2]==(d|0)){x[c>>2]=b;if(b){break e}i=37212,j=x[9303]&Gj(-2,e),x[i>>2]=j;break b}x[h+(x[h+16>>2]==(d|0)?16:20)>>2]=b;if(!b){break b}}x[b+24>>2]=h;c=x[d+16>>2];if(c){x[b+16>>2]=c;x[c+24>>2]=b}c=x[d+20>>2];if(!c){break b}x[b+20>>2]=c;x[c+24>>2]=b;break b}b=x[f+4>>2];if((b&3)!=3){break b}x[9304]=a;x[f+4>>2]=b&-2;x[d+4>>2]=a|1;x[a+d>>2]=a;return}if(d>>>0>=f>>>0){break a}b=x[f+4>>2];if(!(b&1)){break a}f:{if(!(b&2)){if(x[9308]==(f|0)){x[9308]=d;a=x[9305]+a|0;x[9305]=a;x[d+4>>2]=a|1;if(x[9307]!=(d|0)){break a}x[9304]=0;x[9307]=0;return}if(x[9307]==(f|0)){x[9307]=d;a=x[9304]+a|0;x[9304]=a;x[d+4>>2]=a|1;x[a+d>>2]=a;return}a=(b&-8)+a|0;g:{if(b>>>0<=255){e=x[f+8>>2];b=b>>>3|0;c=x[f+12>>2];if((c|0)==(e|0)){i=37208,j=x[9302]&Gj(-2,b),x[i>>2]=j;break g}x[e+12>>2]=c;x[c+8>>2]=e;break g}h=x[f+24>>2];b=x[f+12>>2];h:{if((f|0)!=(b|0)){c=x[f+8>>2];x[c+12>>2]=b;x[b+8>>2]=c;break h}i:{e=f+20|0;c=x[e>>2];if(c){break i}e=f+16|0;c=x[e>>2];if(c){break i}b=0;break h}while(1){g=e;b=c;e=b+20|0;c=x[e>>2];if(c){continue}e=b+16|0;c=x[b+16>>2];if(c){continue}break}x[g>>2]=0}if(!h){break g}e=x[f+28>>2];c=(e<<2)+37512|0;j:{if(x[c>>2]==(f|0)){x[c>>2]=b;if(b){break j}i=37212,j=x[9303]&Gj(-2,e),x[i>>2]=j;break g}x[h+(x[h+16>>2]==(f|0)?16:20)>>2]=b;if(!b){break g}}x[b+24>>2]=h;c=x[f+16>>2];if(c){x[b+16>>2]=c;x[c+24>>2]=b}c=x[f+20>>2];if(!c){break g}x[b+20>>2]=c;x[c+24>>2]=b}x[d+4>>2]=a|1;x[a+d>>2]=a;if(x[9307]!=(d|0)){break f}x[9304]=a;return}x[f+4>>2]=b&-2;x[d+4>>2]=a|1;x[a+d>>2]=a}if(a>>>0<=255){a=a>>>3|0;b=(a<<3)+37248|0;c=x[9302];a=1<>2]}x[b+8>>2]=d;x[a+12>>2]=d;x[d+12>>2]=b;x[d+8>>2]=a;return}e=31;x[d+16>>2]=0;x[d+20>>2]=0;if(a>>>0<=16777215){b=a>>>8|0;g=b+1048320>>>16&8;b=b<>>16&4;b=b<>>16&2;b=(b<>>15|0)-(c|(e|g))|0;e=(b<<1|a>>>b+21&1)+28|0}x[d+28>>2]=e;g=(e<<2)+37512|0;l:{m:{c=x[9303];b=1<>2]=d;x[d+24>>2]=g;break n}e=a<<((e|0)==31?0:25-(e>>>1|0)|0);b=x[g>>2];while(1){c=b;if((x[b+4>>2]&-8)==(a|0)){break m}b=e>>>29|0;e=e<<1;g=c+(b&4)|0;b=x[g+16>>2];if(b){continue}break}x[g+16>>2]=d;x[d+24>>2]=c}x[d+12>>2]=d;x[d+8>>2]=d;break l}a=x[c+8>>2];x[a+12>>2]=d;x[c+8>>2]=d;x[d+24>>2]=0;x[d+12>>2]=c;x[d+8>>2]=a}a=x[9310]-1|0;x[9310]=a?a:-1}}function Gf(a,b){var c=0,d=0,e=0,f=0,g=0,h=0,i=0,j=0;f=a+b|0;c=x[a+4>>2];a:{b:{if(c&1){break b}if(!(c&3)){break a}c=x[a>>2];b=c+b|0;c:{a=a-c|0;if((a|0)!=x[9307]){if(c>>>0<=255){e=x[a+8>>2];c=c>>>3|0;d=x[a+12>>2];if((d|0)!=(e|0)){break c}i=37208,j=x[9302]&Gj(-2,c),x[i>>2]=j;break b}h=x[a+24>>2];c=x[a+12>>2];d:{if((c|0)!=(a|0)){d=x[a+8>>2];x[d+12>>2]=c;x[c+8>>2]=d;break d}e:{e=a+20|0;d=x[e>>2];if(d){break e}e=a+16|0;d=x[e>>2];if(d){break e}c=0;break d}while(1){g=e;c=d;e=c+20|0;d=x[e>>2];if(d){continue}e=c+16|0;d=x[c+16>>2];if(d){continue}break}x[g>>2]=0}if(!h){break b}e=x[a+28>>2];d=(e<<2)+37512|0;f:{if(x[d>>2]==(a|0)){x[d>>2]=c;if(c){break f}i=37212,j=x[9303]&Gj(-2,e),x[i>>2]=j;break b}x[h+(x[h+16>>2]==(a|0)?16:20)>>2]=c;if(!c){break b}}x[c+24>>2]=h;d=x[a+16>>2];if(d){x[c+16>>2]=d;x[d+24>>2]=c}d=x[a+20>>2];if(!d){break b}x[c+20>>2]=d;x[d+24>>2]=c;break b}c=x[f+4>>2];if((c&3)!=3){break b}x[9304]=b;x[f+4>>2]=c&-2;x[a+4>>2]=b|1;x[f>>2]=b;return}x[e+12>>2]=d;x[d+8>>2]=e}c=x[f+4>>2];g:{if(!(c&2)){if(x[9308]==(f|0)){x[9308]=a;b=x[9305]+b|0;x[9305]=b;x[a+4>>2]=b|1;if(x[9307]!=(a|0)){break a}x[9304]=0;x[9307]=0;return}if(x[9307]==(f|0)){x[9307]=a;b=x[9304]+b|0;x[9304]=b;x[a+4>>2]=b|1;x[a+b>>2]=b;return}b=(c&-8)+b|0;h:{if(c>>>0<=255){e=x[f+8>>2];c=c>>>3|0;d=x[f+12>>2];if((d|0)==(e|0)){i=37208,j=x[9302]&Gj(-2,c),x[i>>2]=j;break h}x[e+12>>2]=d;x[d+8>>2]=e;break h}h=x[f+24>>2];c=x[f+12>>2];i:{if((f|0)!=(c|0)){d=x[f+8>>2];x[d+12>>2]=c;x[c+8>>2]=d;break i}j:{d=f+20|0;e=x[d>>2];if(e){break j}d=f+16|0;e=x[d>>2];if(e){break j}c=0;break i}while(1){g=d;c=e;d=c+20|0;e=x[d>>2];if(e){continue}d=c+16|0;e=x[c+16>>2];if(e){continue}break}x[g>>2]=0}if(!h){break h}e=x[f+28>>2];d=(e<<2)+37512|0;k:{if(x[d>>2]==(f|0)){x[d>>2]=c;if(c){break k}i=37212,j=x[9303]&Gj(-2,e),x[i>>2]=j;break h}x[h+(x[h+16>>2]==(f|0)?16:20)>>2]=c;if(!c){break h}}x[c+24>>2]=h;d=x[f+16>>2];if(d){x[c+16>>2]=d;x[d+24>>2]=c}d=x[f+20>>2];if(!d){break h}x[c+20>>2]=d;x[d+24>>2]=c}x[a+4>>2]=b|1;x[a+b>>2]=b;if(x[9307]!=(a|0)){break g}x[9304]=b;return}x[f+4>>2]=c&-2;x[a+4>>2]=b|1;x[a+b>>2]=b}if(b>>>0<=255){b=b>>>3|0;c=(b<<3)+37248|0;d=x[9302];b=1<>2]}x[c+8>>2]=a;x[b+12>>2]=a;x[a+12>>2]=c;x[a+8>>2]=b;return}e=31;x[a+16>>2]=0;x[a+20>>2]=0;if(b>>>0<=16777215){c=b>>>8|0;g=c+1048320>>>16&8;c=c<>>16&4;c=c<>>16&2;c=(c<>>15|0)-(d|(e|g))|0;e=(c<<1|b>>>c+21&1)+28|0}x[a+28>>2]=e;g=(e<<2)+37512|0;m:{d=x[9303];c=1<>2]=a;x[a+24>>2]=g;break n}e=b<<((e|0)==31?0:25-(e>>>1|0)|0);c=x[g>>2];while(1){d=c;if((x[c+4>>2]&-8)==(b|0)){break m}c=e>>>29|0;e=e<<1;g=d+(c&4)|0;c=x[g+16>>2];if(c){continue}break}x[g+16>>2]=a;x[a+24>>2]=d}x[a+12>>2]=a;x[a+8>>2]=a;return}b=x[d+8>>2];x[b+12>>2]=a;x[d+8>>2]=a;x[a+24>>2]=0;x[a+12>>2]=d;x[a+8>>2]=b}}function rc(a,b,c,d,e){var f=0,g=0,h=0,i=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0,r=0,s=0,t=0,u=0,w=0,z=0,A=0,B=0,C=0,D=0,E=0,F=0,G=0,H=0,I=0,J=0,K=0,L=0,M=0,N=0,O=0,P=0,Q=0,R=0,S=0,T=0,U=0,W=0,X=0,Y=0,Z=0,_=0,$=0,aa=0,ba=0,ca=0,da=0;I=V+-64|0;V=I;J=x[a+60>>2];K=x[a+56>>2];w=x[a+52>>2];u=x[a+48>>2];L=x[a+44>>2];M=x[a+40>>2];N=x[a+36>>2];O=x[a+32>>2];P=x[a+28>>2];Q=x[a+24>>2];R=x[a+20>>2];S=x[a+16>>2];T=x[a+12>>2];U=x[a+8>>2];W=x[a+4>>2];X=x[a>>2];while(1){a:{if(!e&d>>>0>63|e){i=c;break a}f=0;A=ya(I,0,64);i=A;if(d|e){while(1){v[f+A|0]=y[b+f|0];f=f+1|0;if(!e&f>>>0>>0|e){continue}break}}b=i;A=c}z=18;n=X;p=W;q=U;o=T;f=S;r=R;c=Q;s=P;l=O;k=N;B=M;C=J;j=K;g=w;h=u;m=L;while(1){t=f;f=f+n|0;n=la(f^h,16);l=n+l|0;h=la(t^l,12);t=n;n=f+h|0;D=la(t^n,8);E=D+l|0;F=la(h^E,7);f=k;l=r+p|0;k=la(l^g,16);g=f+k|0;h=la(g^r,12);p=h+l|0;l=la(p^k,8);G=l+g|0;r=la(h^G,7);k=j;j=c+q|0;g=la(k^j,16);h=g+B|0;c=la(h^c,12);k=c+j|0;f=la(k^g,8);j=f+h|0;H=la(c^j,7);g=o+s|0;h=la(g^C,16);m=h+m|0;c=la(m^s,12);t=c;o=c+g|0;c=la(o^h,8);g=c+m|0;q=la(t^g,7);h=n+r|0;m=la(h^c,16);c=m+j|0;j=la(c^r,12);n=h+j|0;C=la(m^n,8);B=c+C|0;r=la(j^B,7);h=p+H|0;m=la(h^D,16);c=m+g|0;g=la(c^H,12);p=g+h|0;h=la(m^p,8);m=c+h|0;c=la(g^m,7);k=k+q|0;g=la(k^l,16);j=g+E|0;s=la(j^q,12);q=k+s|0;g=la(g^q,8);l=j+g|0;s=la(s^l,7);o=o+F|0;j=la(o^f,16);k=j+G|0;f=la(k^F,12);o=f+o|0;j=la(j^o,8);k=k+j|0;f=la(f^k,7);if(z){z=z-2|0;continue}break}Y=y[b+4|0]|y[b+5|0]<<8|(y[b+6|0]<<16|y[b+7|0]<<24);Z=y[b+8|0]|y[b+9|0]<<8|(y[b+10|0]<<16|y[b+11|0]<<24);_=y[b+12|0]|y[b+13|0]<<8|(y[b+14|0]<<16|y[b+15|0]<<24);$=y[b+16|0]|y[b+17|0]<<8|(y[b+18|0]<<16|y[b+19|0]<<24);aa=y[b+20|0]|y[b+21|0]<<8|(y[b+22|0]<<16|y[b+23|0]<<24);ba=y[b+24|0]|y[b+25|0]<<8|(y[b+26|0]<<16|y[b+27|0]<<24);ca=y[b+28|0]|y[b+29|0]<<8|(y[b+30|0]<<16|y[b+31|0]<<24);da=y[b+32|0]|y[b+33|0]<<8|(y[b+34|0]<<16|y[b+35|0]<<24);t=y[b+36|0]|y[b+37|0]<<8|(y[b+38|0]<<16|y[b+39|0]<<24);z=y[b+40|0]|y[b+41|0]<<8|(y[b+42|0]<<16|y[b+43|0]<<24);F=y[b+44|0]|y[b+45|0]<<8|(y[b+46|0]<<16|y[b+47|0]<<24);H=y[b+48|0]|y[b+49|0]<<8|(y[b+50|0]<<16|y[b+51|0]<<24);D=y[b+52|0]|y[b+53|0]<<8|(y[b+54|0]<<16|y[b+55|0]<<24);E=y[b+56|0]|y[b+57|0]<<8|(y[b+58|0]<<16|y[b+59|0]<<24);G=y[b+60|0]|y[b+61|0]<<8|(y[b+62|0]<<16|y[b+63|0]<<24);ra(i,n+X^(y[b|0]|y[b+1|0]<<8|(y[b+2|0]<<16|y[b+3|0]<<24)));ra(i+4|0,p+W^Y);ra(i+8|0,q+U^Z);ra(i+12|0,o+T^_);ra(i+16|0,f+S^$);ra(i+20|0,r+R^aa);ra(i+24|0,c+Q^ba);ra(i+28|0,s+P^ca);ra(i+32|0,l+O^da);ra(i+36|0,k+N^t);ra(i+40|0,z^B+M);ra(i+44|0,F^m+L);ra(i+48|0,H^h+u);ra(i+52|0,D^g+w);ra(i+56|0,E^j+K);ra(i+60|0,G^C+J);c=u;u=c+1|0;w=(u>>>0>>0)+w|0;if(!e&d>>>0<=64){if(!(!d|(!e&d>>>0>63|(e|0)!=0))){f=0;while(1){v[f+A|0]=y[f+i|0];f=f+1|0;if((d|0)!=(f|0)){continue}break}}x[a+52>>2]=w;x[a+48>>2]=u;V=I- -64|0}else{b=b- -64|0;c=i- -64|0;e=e-1|0;d=d+-64|0;e=d>>>0<4294967232?e+1|0:e;continue}break}}function Bc(a,b,c,d){var e=0,f=0,g=0,h=0,i=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0,r=0,s=0,t=0,u=0,v=0,w=0,z=0,A=0,B=0,C=0,E=0,F=0,G=0,H=0;n=x[a+36>>2];l=x[a+32>>2];g=x[a+28>>2];j=x[a+24>>2];e=x[a+20>>2];if(!d&c>>>0>=16|d){C=!y[a+80|0]<<24;t=x[a+16>>2];E=t;i=x[a+12>>2];A=i;h=x[a+8>>2];w=h;f=x[a+4>>2];u=f;F=D(f,5);B=D(h,5);z=D(i,5);v=D(t,5);o=x[a>>2];while(1){m=((y[b+3|0]|y[b+4|0]<<8|(y[b+5|0]<<16|y[b+6|0]<<24))>>>2&67108863)+j|0;h=Fj(m,0,A,0);f=Y;j=h;p=((y[b|0]|y[b+1|0]<<8|(y[b+2|0]<<16|y[b+3|0]<<24))&67108863)+e|0;h=Fj(p,0,E,0);i=j+h|0;f=Y+f|0;f=h>>>0>i>>>0?f+1|0:f;q=((y[b+6|0]|y[b+7|0]<<8|(y[b+8|0]<<16|y[b+9|0]<<24))>>>4&67108863)+g|0;h=Fj(q,0,w,0);i=h+i|0;e=Y+f|0;e=h>>>0>i>>>0?e+1|0:e;r=((y[b+9|0]|y[b+10|0]<<8|(y[b+11|0]<<16|y[b+12|0]<<24))>>>6|0)+l|0;f=Fj(r,0,u,0);h=f+i|0;e=Y+e|0;e=f>>>0>h>>>0?e+1|0:e;s=n+C+((y[b+12|0]|y[b+13|0]<<8|(y[b+14|0]<<16|y[b+15|0]<<24))>>>8)|0;f=Fj(s,0,o,0);h=f+h|0;e=Y+e|0;G=h;t=f>>>0>h>>>0?e+1|0:e;f=Fj(m,0,w,0);h=Y;g=f;f=Fj(p,0,A,0);i=g+f|0;k=Y+h|0;k=f>>>0>i>>>0?k+1|0:k;h=Fj(q,0,u,0);i=h+i|0;f=Y+k|0;f=h>>>0>i>>>0?f+1|0:f;h=Fj(r,0,o,0);i=h+i|0;e=Y+f|0;e=h>>>0>i>>>0?e+1|0:e;f=Fj(s,0,v,0);h=f+i|0;e=Y+e|0;n=h;i=f>>>0>h>>>0?e+1|0:e;f=Fj(m,0,u,0);h=Y;g=f;f=Fj(p,0,w,0);g=g+f|0;e=Y+h|0;e=f>>>0>g>>>0?e+1|0:e;f=Fj(q,0,o,0);h=f+g|0;k=Y+e|0;k=f>>>0>h>>>0?k+1|0:k;f=h;h=Fj(r,0,v,0);e=f+h|0;f=Y+k|0;f=e>>>0>>0?f+1|0:f;h=Fj(s,0,z,0);g=h+e|0;e=Y+f|0;l=g;h=h>>>0>g>>>0?e+1|0:e;f=Fj(m,0,o,0);e=Y;g=f;f=Fj(p,0,u,0);g=g+f|0;e=Y+e|0;e=f>>>0>g>>>0?e+1|0:e;f=Fj(q,0,v,0);g=f+g|0;e=Y+e|0;e=f>>>0>g>>>0?e+1|0:e;f=Fj(r,0,z,0);g=f+g|0;k=Y+e|0;k=f>>>0>g>>>0?k+1|0:k;e=Fj(s,0,B,0);g=e+g|0;f=Y+k|0;f=e>>>0>g>>>0?f+1|0:f;j=g;g=Fj(m,0,v,0);e=Y;m=l;H=j;j=g;g=Fj(p,0,o,0);j=j+g|0;e=Y+e|0;e=g>>>0>j>>>0?e+1|0:e;g=Fj(q,0,z,0);j=g+j|0;e=Y+e|0;e=g>>>0>j>>>0?e+1|0:e;g=Fj(r,0,B,0);j=g+j|0;e=Y+e|0;e=g>>>0>j>>>0?e+1|0:e;g=Fj(s,0,F,0);j=g+j|0;k=Y+e|0;l=j;e=j;k=g>>>0>e>>>0?k+1|0:k;e=(k&67108863)<<6|e>>>26;g=H+e|0;f=e>>>0>g>>>0?f+1|0:f;j=g;e=g;f=(f&67108863)<<6|e>>>26;g=m+f|0;e=h;e=f>>>0>g>>>0?e+1|0:e;f=g;f=(e&67108863)<<6|f>>>26;h=f+n|0;k=f>>>0>h>>>0?i+1|0:i;e=h;h=(k&67108863)<<6|e>>>26;i=h+G|0;f=t;f=h>>>0>i>>>0?f+1|0:f;h=i;f=D((f&67108863)<<6|h>>>26,5)+(l&67108863)|0;j=(j&67108863)+(f>>>26|0)|0;g=g&67108863;l=e&67108863;n=h&67108863;e=f&67108863;b=b+16|0;d=d-(c>>>0<16)|0;c=c-16|0;if(!d&c>>>0>15|d){continue}break}}x[a+20>>2]=e;x[a+36>>2]=n;x[a+32>>2]=l;x[a+28>>2]=g;x[a+24>>2]=j}function yd(a,b,c,d,e){var f=0,g=0,h=0,i=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0,r=0,s=0,t=0,u=0,v=0,w=0,x=0,z=0,A=0,B=0,C=0,D=0,E=0,F=0,G=0,H=0,I=0,J=0,K=0,L=0,M=0,N=0,O=0,P=0;E=y[c|0]|y[c+1|0]<<8|(y[c+2|0]<<16|y[c+3|0]<<24);F=y[c+4|0]|y[c+5|0]<<8|(y[c+6|0]<<16|y[c+7|0]<<24);G=y[c+8|0]|y[c+9|0]<<8|(y[c+10|0]<<16|y[c+11|0]<<24);H=y[c+12|0]|y[c+13|0]<<8|(y[c+14|0]<<16|y[c+15|0]<<24);I=y[c+16|0]|y[c+17|0]<<8|(y[c+18|0]<<16|y[c+19|0]<<24);J=y[c+24|0]|y[c+25|0]<<8|(y[c+26|0]<<16|y[c+27|0]<<24);K=y[c+28|0]|y[c+29|0]<<8|(y[c+30|0]<<16|y[c+31|0]<<24);L=y[c+20|0]|y[c+21|0]<<8|(y[c+22|0]<<16|y[c+23|0]<<24);c=L;f=J;k=K;a:{if(!d){v=1634760805;w=2036477234;x=857760878;z=1797285236;break a}v=y[d|0]|y[d+1|0]<<8|(y[d+2|0]<<16|y[d+3|0]<<24);x=y[d+4|0]|y[d+5|0]<<8|(y[d+6|0]<<16|y[d+7|0]<<24);w=y[d+8|0]|y[d+9|0]<<8|(y[d+10|0]<<16|y[d+11|0]<<24);z=y[d+12|0]|y[d+13|0]<<8|(y[d+14|0]<<16|y[d+15|0]<<24)}d=z;n=I;q=w;A=y[b+12|0]|y[b+13|0]<<8|(y[b+14|0]<<16|y[b+15|0]<<24);l=A;M=y[b+8|0]|y[b+9|0]<<8|(y[b+10|0]<<16|y[b+11|0]<<24);m=M;N=y[b+4|0]|y[b+5|0]<<8|(y[b+6|0]<<16|y[b+7|0]<<24);g=N;O=y[b|0]|y[b+1|0]<<8|(y[b+2|0]<<16|y[b+3|0]<<24);b=O;r=x;o=H;h=G;i=F;p=E;j=v;b:{if((e|0)<1){break b}B=2;l=A;while(1){s=la(c+j|0,7)^o;C=la(s+j|0,9)^m;P=la(s+C|0,13)^c;m=la(C+P|0,18);t=la(r+p|0,7)^l;D=la(t+r|0,9)^f;f=la(t+D|0,13)^p;o=la(D+f|0,18);u=la(b+q|0,7)^k;i=la(u+q|0,9)^i;b=la(i+u|0,13)^b;l=la(i+b|0,18);h=la(d+n|0,7)^h;g=la(h+d|0,9)^g;k=la(g+h|0,13)^n;c=la(g+k|0,18);j=j^m;p=la(j+h|0,7)^f;i=la(p+j|0,9)^i;h=la(i+p|0,13)^h;j=la(h+i|0,18)^j;f=r^o;b=la(f+s|0,7)^b;g=la(b+f|0,9)^g;o=la(b+g|0,13)^s;r=la(g+o|0,18)^f;f=l^q;n=la(f+t|0,7)^k;m=la(n+f|0,9)^C;l=la(m+n|0,13)^t;q=la(l+m|0,18)^f;d=c^d;c=la(d+u|0,7)^P;f=la(c+d|0,9)^D;k=la(c+f|0,13)^u;d=la(f+k|0,18)^d;if((e|0)<=(B|0)){break b}B=B+2|0;continue}}ra(a,j+v|0);ra(a+4|0,p+E|0);ra(a+8|0,i+F|0);ra(a+12|0,h+G|0);ra(a+16|0,o+H|0);ra(a+20|0,r+x|0);ra(a+24|0,b+O|0);ra(a+28|0,g+N|0);ra(a+32|0,m+M|0);ra(a+36|0,l+A|0);ra(a+40|0,q+w|0);ra(a+44|0,n+I|0);ra(a+48|0,c+L|0);ra(a+52|0,f+J|0);ra(a+56|0,k+K|0);ra(a+60|0,d+z|0)}function Tc(a,b,c){a=a|0;b=b|0;c=c|0;var d=0,e=0,f=0,g=0,h=0,i=0,j=0,k=0,l=0;k=V-160|0;V=k;Qb(b,c,32,0);v[b|0]=y[b|0]&248;v[b+31|0]=y[b+31|0]&63|64;Yb(k,b);mb(a,k);f=c;g=y[f+8|0]|y[f+9|0]<<8|(y[f+10|0]<<16|y[f+11|0]<<24);e=y[f+12|0]|y[f+13|0]<<8|(y[f+14|0]<<16|y[f+15|0]<<24);h=y[f+16|0]|y[f+17|0]<<8|(y[f+18|0]<<16|y[f+19|0]<<24);i=y[f+20|0]|y[f+21|0]<<8|(y[f+22|0]<<16|y[f+23|0]<<24);j=y[f|0]|y[f+1|0]<<8|(y[f+2|0]<<16|y[f+3|0]<<24);c=y[f+4|0]|y[f+5|0]<<8|(y[f+6|0]<<16|y[f+7|0]<<24);d=b;l=y[f+28|0]|y[f+29|0]<<8|(y[f+30|0]<<16|y[f+31|0]<<24);b=y[f+24|0]|y[f+25|0]<<8|(y[f+26|0]<<16|y[f+27|0]<<24);v[d+24|0]=b;v[d+25|0]=b>>>8;v[d+26|0]=b>>>16;v[d+27|0]=b>>>24;v[d+28|0]=l;v[d+29|0]=l>>>8;v[d+30|0]=l>>>16;v[d+31|0]=l>>>24;v[d+16|0]=h;v[d+17|0]=h>>>8;v[d+18|0]=h>>>16;v[d+19|0]=h>>>24;v[d+20|0]=i;v[d+21|0]=i>>>8;v[d+22|0]=i>>>16;v[d+23|0]=i>>>24;v[d+8|0]=g;v[d+9|0]=g>>>8;v[d+10|0]=g>>>16;v[d+11|0]=g>>>24;v[d+12|0]=e;v[d+13|0]=e>>>8;v[d+14|0]=e>>>16;v[d+15|0]=e>>>24;v[d|0]=j;v[d+1|0]=j>>>8;v[d+2|0]=j>>>16;v[d+3|0]=j>>>24;v[d+4|0]=c;v[d+5|0]=c>>>8;v[d+6|0]=c>>>16;v[d+7|0]=c>>>24;e=a;h=y[e+8|0]|y[e+9|0]<<8|(y[e+10|0]<<16|y[e+11|0]<<24);i=y[e+12|0]|y[e+13|0]<<8|(y[e+14|0]<<16|y[e+15|0]<<24);j=y[e+16|0]|y[e+17|0]<<8|(y[e+18|0]<<16|y[e+19|0]<<24);c=y[e+20|0]|y[e+21|0]<<8|(y[e+22|0]<<16|y[e+23|0]<<24);b=y[e|0]|y[e+1|0]<<8|(y[e+2|0]<<16|y[e+3|0]<<24);a=y[e+4|0]|y[e+5|0]<<8|(y[e+6|0]<<16|y[e+7|0]<<24);g=y[e+28|0]|y[e+29|0]<<8|(y[e+30|0]<<16|y[e+31|0]<<24);e=y[e+24|0]|y[e+25|0]<<8|(y[e+26|0]<<16|y[e+27|0]<<24);v[d+56|0]=e;v[d+57|0]=e>>>8;v[d+58|0]=e>>>16;v[d+59|0]=e>>>24;v[d+60|0]=g;v[d+61|0]=g>>>8;v[d+62|0]=g>>>16;v[d+63|0]=g>>>24;v[d+48|0]=j;v[d+49|0]=j>>>8;v[d+50|0]=j>>>16;v[d+51|0]=j>>>24;v[d+52|0]=c;v[d+53|0]=c>>>8;v[d+54|0]=c>>>16;v[d+55|0]=c>>>24;v[d+40|0]=h;v[d+41|0]=h>>>8;v[d+42|0]=h>>>16;v[d+43|0]=h>>>24;v[d+44|0]=i;v[d+45|0]=i>>>8;v[d+46|0]=i>>>16;v[d+47|0]=i>>>24;v[d+32|0]=b;v[d+33|0]=b>>>8;v[d+34|0]=b>>>16;v[d+35|0]=b>>>24;v[d+36|0]=a;v[d+37|0]=a>>>8;v[d+38|0]=a>>>16;v[d+39|0]=a>>>24;V=k+160|0;return 0}function bb(a,b,c,d){a=a|0;b=b|0;c=c|0;d=d|0;var e=0,f=0,g=0,h=0,i=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0,r=0,s=0,t=0,u=0,v=0;a:{if(!d){e=2036477234;f=857760878;o=1634760805;g=1797285236;break a}o=y[d|0]|y[d+1|0]<<8|(y[d+2|0]<<16|y[d+3|0]<<24);f=y[d+4|0]|y[d+5|0]<<8|(y[d+6|0]<<16|y[d+7|0]<<24);e=y[d+8|0]|y[d+9|0]<<8|(y[d+10|0]<<16|y[d+11|0]<<24);g=y[d+12|0]|y[d+13|0]<<8|(y[d+14|0]<<16|y[d+15|0]<<24)}d=y[c|0]|y[c+1|0]<<8|(y[c+2|0]<<16|y[c+3|0]<<24);h=y[c+4|0]|y[c+5|0]<<8|(y[c+6|0]<<16|y[c+7|0]<<24);i=y[c+8|0]|y[c+9|0]<<8|(y[c+10|0]<<16|y[c+11|0]<<24);k=y[c+12|0]|y[c+13|0]<<8|(y[c+14|0]<<16|y[c+15|0]<<24);q=y[c+16|0]|y[c+17|0]<<8|(y[c+18|0]<<16|y[c+19|0]<<24);m=y[c+20|0]|y[c+21|0]<<8|(y[c+22|0]<<16|y[c+23|0]<<24);s=y[c+24|0]|y[c+25|0]<<8|(y[c+26|0]<<16|y[c+27|0]<<24);t=y[c+28|0]|y[c+29|0]<<8|(y[c+30|0]<<16|y[c+31|0]<<24);n=y[b|0]|y[b+1|0]<<8|(y[b+2|0]<<16|y[b+3|0]<<24);p=y[b+4|0]|y[b+5|0]<<8|(y[b+6|0]<<16|y[b+7|0]<<24);j=y[b+8|0]|y[b+9|0]<<8|(y[b+10|0]<<16|y[b+11|0]<<24);b=y[b+12|0]|y[b+13|0]<<8|(y[b+14|0]<<16|y[b+15|0]<<24);c=1;while(1){l=d;d=d+o|0;o=la(d^n,16);n=o+q|0;q=la(l^n,12);l=q;r=n;n=o;o=d+q|0;n=la(n^o,8);q=r+n|0;d=la(l^q,7);l=h;f=f+h|0;h=la(f^p,16);p=h+m|0;m=la(l^p,12);l=m;r=p;p=f+m|0;m=la(p^h,8);r=r+m|0;f=la(l^r,7);l=i;e=e+i|0;h=la(e^j,16);i=h+s|0;j=la(l^i,12);l=j;j=e+j|0;u=la(h^j,8);h=u+i|0;e=la(l^h,7);i=b;b=g+k|0;g=la(i^b,16);i=g+t|0;k=la(i^k,12);v=b+k|0;b=la(g^v,8);i=b+i|0;g=la(k^i,7);l=h;h=b;b=f+o|0;h=la(h^b,16);k=l+h|0;f=la(k^f,12);o=b+f|0;b=la(h^o,8);s=k+b|0;h=la(f^s,7);l=i;f=e+p|0;i=la(f^n,16);k=l+i|0;e=la(k^e,12);f=e+f|0;n=la(i^f,8);t=k+n|0;i=la(e^t,7);e=g+j|0;k=la(e^m,16);j=k+q|0;g=la(j^g,12);e=e+g|0;p=la(k^e,8);q=j+p|0;k=la(g^q,7);g=d+v|0;j=la(g^u,16);m=j+r|0;d=la(m^d,12);g=d+g|0;j=la(j^g,8);m=m+j|0;d=la(d^m,7);if((c|0)!=10){c=c+1|0;continue}break}ra(a,o);ra(a+4|0,f);ra(a+8|0,e);ra(a+12|0,g);ra(a+16|0,n);ra(a+20|0,p);ra(a+24|0,j);ra(a+28|0,b);return 0}function Gc(a,b,c){var d=0,e=0,f=0,g=0;e=V+-64|0;V=e;d=-1;a:{if((c-1&255)>>>0<64){if(!(y[a+80|0]|y[a+81|0]<<8|(y[a+82|0]<<16|y[a+83|0]<<24)|(y[a+84|0]|y[a+85|0]<<8|(y[a+86|0]<<16|y[a+87|0]<<24)))){f=a;d=y[a+352|0]|y[a+353|0]<<8|(y[a+354|0]<<16|y[a+355|0]<<24);if(d>>>0>=129){Jc(a,128);g=a+96|0;Wc(a,g);d=(y[a+352|0]|y[a+353|0]<<8|(y[a+354|0]<<16|y[a+355|0]<<24))-128|0;v[a+352|0]=d;v[a+353|0]=d>>>8;v[a+354|0]=d>>>16;v[a+355|0]=d>>>24;if(d>>>0>=129){break a}za(g,a+224|0,d);d=y[a+352|0]|y[a+353|0]<<8|(y[a+354|0]<<16|y[a+355|0]<<24)}Jc(f,d);if(y[a+356|0]){v[a+88|0]=255;v[a+89|0]=255;v[a+90|0]=255;v[a+91|0]=255;v[a+92|0]=255;v[a+93|0]=255;v[a+94|0]=255;v[a+95|0]=255}v[a+80|0]=255;v[a+81|0]=255;v[a+82|0]=255;v[a+83|0]=255;v[a+84|0]=255;v[a+85|0]=255;v[a+86|0]=255;v[a+87|0]=255;d=a+96|0;f=y[a+352|0]|y[a+353|0]<<8|(y[a+354|0]<<16|y[a+355|0]<<24);ya(d+f|0,0,256-f|0);Wc(a,d);Ba(e,y[a|0]|y[a+1|0]<<8|(y[a+2|0]<<16|y[a+3|0]<<24),y[a+4|0]|y[a+5|0]<<8|(y[a+6|0]<<16|y[a+7|0]<<24));Ba(e|8,y[a+8|0]|y[a+9|0]<<8|(y[a+10|0]<<16|y[a+11|0]<<24),y[a+12|0]|y[a+13|0]<<8|(y[a+14|0]<<16|y[a+15|0]<<24));Ba(e+16|0,y[a+16|0]|y[a+17|0]<<8|(y[a+18|0]<<16|y[a+19|0]<<24),y[a+20|0]|y[a+21|0]<<8|(y[a+22|0]<<16|y[a+23|0]<<24));Ba(e+24|0,y[a+24|0]|y[a+25|0]<<8|(y[a+26|0]<<16|y[a+27|0]<<24),y[a+28|0]|y[a+29|0]<<8|(y[a+30|0]<<16|y[a+31|0]<<24));Ba(e+32|0,y[a+32|0]|y[a+33|0]<<8|(y[a+34|0]<<16|y[a+35|0]<<24),y[a+36|0]|y[a+37|0]<<8|(y[a+38|0]<<16|y[a+39|0]<<24));Ba(e+40|0,y[a+40|0]|y[a+41|0]<<8|(y[a+42|0]<<16|y[a+43|0]<<24),y[a+44|0]|y[a+45|0]<<8|(y[a+46|0]<<16|y[a+47|0]<<24));Ba(e+48|0,y[a+48|0]|y[a+49|0]<<8|(y[a+50|0]<<16|y[a+51|0]<<24),y[a+52|0]|y[a+53|0]<<8|(y[a+54|0]<<16|y[a+55|0]<<24));Ba(e+56|0,y[a+56|0]|y[a+57|0]<<8|(y[a+58|0]<<16|y[a+59|0]<<24),y[a+60|0]|y[a+61|0]<<8|(y[a+62|0]<<16|y[a+63|0]<<24));za(b,e,c);oa(a,64);oa(d,256);d=0}V=e- -64|0;return d}Aa();N()}Q(1369,1217,306,1142);N()}function db(a,b){var c=0,d=0,e=0,f=0,g=0,h=0,i=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0,r=0,s=0,t=0,u=0,v=0,w=0;n=y[b|0]|y[b+1|0]<<8|(y[b+2|0]<<16|y[b+3|0]<<24);k=sa(b+4|0);c=Y;i=sa(b+7|0);e=Y;j=sa(b+10|0);d=Y;o=sa(b+13|0);g=Y;f=y[b+16|0]|y[b+17|0]<<8|(y[b+18|0]<<16|y[b+19|0]<<24);p=sa(b+20|0);l=Y;q=sa(b+23|0);r=Y;s=sa(b+26|0);t=Y;u=sa(b+29|0);b=d<<3|j>>>29;d=j<<3;m=d;d=d+16777216|0;b=d>>>0<16777216?b+1|0:b;j=d;d=b;b=e<<5|i>>>27;h=i<<5;e=b;i=k;b=c<<6|i>>>26;i=i<<6;v=a;w=h;c=b;b=i+16777216|0;c=b>>>0<16777216?c+1|0:c;k=b;h=b;b=c>>25;h=(c&33554431)<<7|h>>>25;c=w+h|0;b=b+e|0;b=c>>>0>>0?b+1|0:b;e=c+33554432|0;if(e>>>0<33554432){b=b+1|0}b=(m-(j&-33554432)|0)+((b&67108863)<<6|e>>>26)|0;x[v+12>>2]=b;b=e&-67108864;x[a+8>>2]=c-b;e=f;b=0;f=e+16777216|0;b=f>>>0<16777216?1:b;h=f;f=b;m=e-(h&-33554432)|0;e=o;b=g<<2|e>>>30;g=e<<2;e=b;c=g;b=d>>25;g=(d&33554431)<<7|j>>>25;d=c+g|0;b=b+e|0;b=d>>>0>>0?b+1|0:b;c=b;b=d+33554432|0;c=b>>>0<33554432?c+1|0:c;e=b;b=((c&67108863)<<6|b>>>26)+m|0;x[a+20>>2]=b;b=e&-67108864;x[a+16>>2]=d-b;d=a;c=p;b=l<<7|c>>>25;g=c<<7;c=f>>25;e=(f&33554431)<<7|h>>>25;f=g+e|0;b=b+c|0;b=f>>>0>>0?b+1|0:b;c=f;f=c;c=c+33554432|0;b=c>>>0<33554432?b+1|0:b;e=c;c=b;b=e&-67108864;x[d+24>>2]=f-b;f=d;d=q;b=r<<5|d>>>27;d=d<<5;l=d;d=d+16777216|0;b=d>>>0<16777216?b+1|0:b;g=d;d=b;b=(l-(g&-33554432)|0)+((c&67108863)<<6|e>>>26)|0;x[f+28>>2]=b;c=s;b=t<<4|c>>>28;e=c<<4;c=b;h=e;b=d>>25;e=(d&33554431)<<7|g>>>25;d=h+e|0;b=b+c|0;b=d>>>0>>0?b+1|0:b;c=d;d=c;c=c+33554432|0;b=c>>>0<33554432?b+1|0:b;e=c;c=b;b=e&-67108864;x[f+32>>2]=d-b;b=0;f=u;f=f<<2&33554428;d=f;f=f+16777216|0;b=f>>>0<16777216?b+1|0:b;c=(d-(f&33554432)|0)+((c&67108863)<<6|e>>>26)|0;x[a+36>>2]=c;f=Fj((b&33554431)<<7|f>>>25,b>>>25|0,19,0);c=f+n|0;b=Y;b=c>>>0>>0?b+1|0:b;d=c+33554432|0;if(d>>>0<33554432){b=b+1|0}b=(i-(k&-33554432)|0)+((b&67108863)<<6|d>>>26)|0;x[a+4>>2]=b;b=a;a=d&-67108864;x[b>>2]=c-a}function ig(a,b){var c=0,d=0,e=0,f=0,g=0,h=0,i=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0,r=0,s=0,t=0,u=0,v=0,w=0,y=0,z=0;c=b;d=x[c+4>>2];m=d;k=d>>31;d=x[c+8>>2];n=d;r=d>>31;d=x[c+12>>2];i=d;l=d>>31;d=x[c+16>>2];o=d;s=d>>31;d=x[c+20>>2];j=d;h=d>>31;d=x[c+24>>2];p=d;t=d>>31;d=x[c>>2];u=d;v=d>>31;c=x[c+36>>2];d=Fj(c,c>>31,486662,0);f=d;c=Y;d=d+16777216|0;c=d>>>0<16777216?c+1|0:c;q=d;d=c;w=f-(q&-33554432)|0;c=x[b+32>>2];e=Fj(c,c>>31,486662,0);y=Y;b=x[b+28>>2];f=Fj(b,b>>31,486662,0);c=Y;g=e;b=f+16777216|0;c=b>>>0<16777216?c+1|0:c;z=b;e=b;b=c>>25;e=(c&33554431)<<7|e>>>25;c=g+e|0;b=b+y|0;b=c>>>0>>0?b+1|0:b;e=c;c=b;b=e+33554432|0;c=b>>>0<33554432?c+1|0:c;g=b;b=((c&67108863)<<6|b>>>26)+w|0;x[a+36>>2]=b;b=g&-67108864;x[a+32>>2]=e-b;g=f-(z&-33554432)|0;c=Fj(p,t,486662,0);p=Y;f=Fj(j,h,486662,0);b=Y;e=c;c=f+16777216|0;b=c>>>0<16777216?b+1|0:b;j=c;h=c;c=b>>25;h=(b&33554431)<<7|h>>>25;b=e+h|0;c=c+p|0;c=b>>>0>>0?c+1|0:c;e=b+33554432|0;if(e>>>0<33554432){c=c+1|0}c=g+((c&67108863)<<6|e>>>26)|0;x[a+28>>2]=c;c=e&-67108864;x[a+24>>2]=b-c;j=f-(j&-33554432)|0;b=Fj(o,s,486662,0);o=Y;f=Fj(i,l,486662,0);c=Y;g=b;b=f+16777216|0;c=b>>>0<16777216?c+1|0:c;i=b;l=(c&33554431)<<7|b>>>25;e=g+l|0;c=(c>>25)+o|0;c=e>>>0>>0?c+1|0:c;b=c;c=e+33554432|0;b=c>>>0<33554432?b+1|0:b;b=((b&67108863)<<6|c>>>26)+j|0;x[a+20>>2]=b;b=c&-67108864;x[a+16>>2]=e-b;i=f-(i&-33554432)|0;c=Fj(n,r,486662,0);n=Y;f=Fj(m,k,486662,0);b=Y;g=c;c=f+16777216|0;b=c>>>0<16777216?b+1|0:b;m=c;k=(b&33554431)<<7|c>>>25;e=g+k|0;b=(b>>25)+n|0;b=e>>>0>>0?b+1|0:b;c=b;b=e+33554432|0;c=b>>>0<33554432?c+1|0:c;g=b;b=((c&67108863)<<6|b>>>26)+i|0;x[a+12>>2]=b;b=g&-67108864;x[a+8>>2]=e-b;b=Fj((d&33554431)<<7|q>>>25,d>>25,19,0);c=Y;g=f-(m&-33554432)|0;d=Fj(u,v,486662,0);b=d+b|0;c=Y+c|0;c=b>>>0>>0?c+1|0:c;d=b+33554432|0;if(d>>>0<33554432){c=c+1|0}c=g+((c&67108863)<<6|d>>>26)|0;x[a+4>>2]=c;c=a;a=d&-67108864;x[c>>2]=b-a}function Fc(a,b,c,d){var e=0,f=0;e=V;f=e;e=e-576&-64;V=e;x[e+188>>2]=0;ra(e+188|0,b);a:{if(b>>>0<=64){if((Ib(e+192|0,0,0,b)|0)<0){break a}if((Ja(e+192|0,e+188|0,4,0)|0)<0){break a}if((Ja(e+192|0,c,d,0)|0)<0){break a}Hb(e+192|0,a,b);break a}if((Ib(e+192|0,0,0,64)|0)<0){break a}if((Ja(e+192|0,e+188|0,4,0)|0)<0){break a}if((Ja(e+192|0,c,d,0)|0)<0){break a}if((Hb(e+192|0,e+112|0,64)|0)<0){break a}c=x[e+116>>2];d=x[e+112>>2];v[a|0]=d;v[a+1|0]=d>>>8;v[a+2|0]=d>>>16;v[a+3|0]=d>>>24;v[a+4|0]=c;v[a+5|0]=c>>>8;v[a+6|0]=c>>>16;v[a+7|0]=c>>>24;c=x[e+124>>2];d=x[e+120>>2];v[a+8|0]=d;v[a+9|0]=d>>>8;v[a+10|0]=d>>>16;v[a+11|0]=d>>>24;v[a+12|0]=c;v[a+13|0]=c>>>8;v[a+14|0]=c>>>16;v[a+15|0]=c>>>24;c=x[e+140>>2];d=x[e+136>>2];v[a+24|0]=d;v[a+25|0]=d>>>8;v[a+26|0]=d>>>16;v[a+27|0]=d>>>24;v[a+28|0]=c;v[a+29|0]=c>>>8;v[a+30|0]=c>>>16;v[a+31|0]=c>>>24;c=x[e+132>>2];d=x[e+128>>2];v[a+16|0]=d;v[a+17|0]=d>>>8;v[a+18|0]=d>>>16;v[a+19|0]=d>>>24;v[a+20|0]=c;v[a+21|0]=c>>>8;v[a+22|0]=c>>>16;v[a+23|0]=c>>>24;a=a+32|0;b=b-32|0;if(b>>>0>=65){while(1){za(e+48|0,e+112|0,64);if((ac(e+112|0,64,e+48|0,64,0,0,0)|0)<0){break a}c=x[e+116>>2];d=x[e+112>>2];v[a|0]=d;v[a+1|0]=d>>>8;v[a+2|0]=d>>>16;v[a+3|0]=d>>>24;v[a+4|0]=c;v[a+5|0]=c>>>8;v[a+6|0]=c>>>16;v[a+7|0]=c>>>24;c=x[e+124>>2];d=x[e+120>>2];v[a+8|0]=d;v[a+9|0]=d>>>8;v[a+10|0]=d>>>16;v[a+11|0]=d>>>24;v[a+12|0]=c;v[a+13|0]=c>>>8;v[a+14|0]=c>>>16;v[a+15|0]=c>>>24;c=x[e+140>>2];d=x[e+136>>2];v[a+24|0]=d;v[a+25|0]=d>>>8;v[a+26|0]=d>>>16;v[a+27|0]=d>>>24;v[a+28|0]=c;v[a+29|0]=c>>>8;v[a+30|0]=c>>>16;v[a+31|0]=c>>>24;c=x[e+132>>2];d=x[e+128>>2];v[a+16|0]=d;v[a+17|0]=d>>>8;v[a+18|0]=d>>>16;v[a+19|0]=d>>>24;v[a+20|0]=c;v[a+21|0]=c>>>8;v[a+22|0]=c>>>16;v[a+23|0]=c>>>24;a=a+32|0;b=b-32|0;if(b>>>0>64){continue}break}}za(e+48|0,e+112|0,64);if((ac(e+112|0,b,e+48|0,64,0,0,0)|0)<0){break a}za(a,e+112|0,b)}oa(e+192|0,384);V=f}function De(a,b,c,d,e,f){var g=0,h=0,i=0,j=0,k=0,l=0,m=0,n=0,o=0;g=V-592|0;V=g;j=-1;h=a+32|0;a:{if(!kg(h)){break a}if(Wb(a)){break a}if(!Ad(e)){break a}if(Wb(e)){break a}if(Fd(g+128|0,e)){break a}hd(g+384|0,f);Na(g+384|0,a,32,0);Na(g+384|0,e,32,0);Na(g+384|0,b,c,d);_a(g+384|0,g+320|0);Eb(g+320|0);d=V-2272|0;V=d;rg(d+2016|0,g+320|0);rg(d+1760|0,h);b=g+128|0;Ca(d+480|0,b);kb(d+320|0,b);wa(d,d+320|0);Da(d+320|0,d,d+480|0);wa(d+160|0,d+320|0);b=d+640|0;Ca(b,d+160|0);Da(d+320|0,d,b);wa(d+160|0,d+320|0);b=d+800|0;Ca(b,d+160|0);Da(d+320|0,d,b);wa(d+160|0,d+320|0);b=d+960|0;Ca(b,d+160|0);Da(d+320|0,d,b);wa(d+160|0,d+320|0);b=d+1120|0;Ca(b,d+160|0);Da(d+320|0,d,b);wa(d+160|0,d+320|0);b=d+1280|0;Ca(b,d+160|0);Da(d+320|0,d,b);wa(d+160|0,d+320|0);b=d+1440|0;Ca(b,d+160|0);Da(d+320|0,d,b);wa(d+160|0,d+320|0);Ca(d+1600|0,d+160|0);f=g+8|0;vb(f);Ea(f+40|0);Ea(f+80|0);e=255;b:{while(1){b=e;if(!(y[b+(d+2016|0)|0]|y[(d+1760|0)+b|0])){e=b-1|0;if(b){continue}break b}break}if((b|0)<0){break b}while(1){Va(d+320|0,f);c=b;b=v[(d+2016|0)+b|0];c:{if((b|0)>=1){wa(d+160|0,d+320|0);Da(d+320|0,d+160|0,(d+480|0)+D((b&254)>>>1|0,160)|0);break c}if((b|0)>-1){break c}wa(d+160|0,d+320|0);zc(d+320|0,d+160|0,(d+480|0)+D((0-b&254)>>>1|0,160)|0)}i=v[c+(d+1760|0)|0];d:{if((i|0)>=1){wa(d+160|0,d+320|0);Ed(d+320|0,d+160|0,D((i&254)>>>1|0,120)+2320|0);break d}if((i|0)>-1){break d}wa(d+160|0,d+320|0);j=V-48|0;V=j;b=d+320|0;h=d+160|0;k=h+40|0;va(b,k,h);e=b+40|0;xa(e,k,h);k=b+80|0;l=D((0-i&254)>>>1|0,120)+2320|0;ma(k,b,l+40|0);ma(e,e,l);i=b+120|0;ma(i,l+80|0,h+120|0);h=h+80|0;va(j,h,h);xa(b,k,e);va(e,k,e);xa(k,j,i);va(i,j,i);V=j+48|0}ab(f,d+320|0);b=c-1|0;if((c|0)>0){continue}break}}V=d+2272|0;mb(g+288|0,g+8|0);j=(m=-1,n=_b(g+288|0,a),o=(g+288|0)==(a|0),o?m:n)|rb(a,g+288|0,32)}V=g+592|0;return j}function Ab(a,b,c,d){a=a|0;b=b|0;c=c|0;d=d|0;var e=0,f=0,g=0,h=0,i=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0,r=0,s=0,t=0,u=0,v=0,w=0,x=0;a:{if(!d){e=2036477234;f=857760878;g=1634760805;d=1797285236;break a}g=y[d|0]|y[d+1|0]<<8|(y[d+2|0]<<16|y[d+3|0]<<24);f=y[d+4|0]|y[d+5|0]<<8|(y[d+6|0]<<16|y[d+7|0]<<24);e=y[d+8|0]|y[d+9|0]<<8|(y[d+10|0]<<16|y[d+11|0]<<24);d=y[d+12|0]|y[d+13|0]<<8|(y[d+14|0]<<16|y[d+15|0]<<24)}r=20;k=y[c|0]|y[c+1|0]<<8|(y[c+2|0]<<16|y[c+3|0]<<24);q=y[c+4|0]|y[c+5|0]<<8|(y[c+6|0]<<16|y[c+7|0]<<24);s=y[c+8|0]|y[c+9|0]<<8|(y[c+10|0]<<16|y[c+11|0]<<24);p=y[c+12|0]|y[c+13|0]<<8|(y[c+14|0]<<16|y[c+15|0]<<24);l=y[c+16|0]|y[c+17|0]<<8|(y[c+18|0]<<16|y[c+19|0]<<24);i=y[c+20|0]|y[c+21|0]<<8|(y[c+22|0]<<16|y[c+23|0]<<24);m=y[c+24|0]|y[c+25|0]<<8|(y[c+26|0]<<16|y[c+27|0]<<24);n=y[c+28|0]|y[c+29|0]<<8|(y[c+30|0]<<16|y[c+31|0]<<24);c=y[b|0]|y[b+1|0]<<8|(y[b+2|0]<<16|y[b+3|0]<<24);j=y[b+4|0]|y[b+5|0]<<8|(y[b+6|0]<<16|y[b+7|0]<<24);h=y[b+8|0]|y[b+9|0]<<8|(y[b+10|0]<<16|y[b+11|0]<<24);b=y[b+12|0]|y[b+13|0]<<8|(y[b+14|0]<<16|y[b+15|0]<<24);while(1){o=h;h=la(g+i|0,7)^p;o=o^la(h+g|0,9);t=la(h+o|0,13)^i;p=la(o+t|0,18);b=la(f+k|0,7)^b;m=la(b+f|0,9)^m;k=la(b+m|0,13)^k;v=la(m+k|0,18);n=la(c+e|0,7)^n;i=la(n+e|0,9)^q;u=la(i+n|0,13)^c;w=la(i+u|0,18);c=la(d+l|0,7)^s;j=la(c+d|0,9)^j;l=la(c+j|0,13)^l;x=la(j+l|0,18);g=g^p;k=la(g+c|0,7)^k;q=la(k+g|0,9)^i;s=la(k+q|0,13)^c;g=la(q+s|0,18)^g;f=f^v;c=la(f+h|0,7)^u;j=la(c+f|0,9)^j;p=la(c+j|0,13)^h;f=la(j+p|0,18)^f;e=e^w;l=la(e+b|0,7)^l;h=la(l+e|0,9)^o;b=la(h+l|0,13)^b;e=la(b+h|0,18)^e;d=d^x;i=la(d+n|0,7)^t;m=la(i+d|0,9)^m;n=la(i+m|0,13)^n;d=la(m+n|0,18)^d;o=r>>>0>2;r=r-2|0;if(o){continue}break}ra(a,g);ra(a+4|0,f);ra(a+8|0,e);ra(a+12|0,d);ra(a+16|0,c);ra(a+20|0,j);ra(a+24|0,h);ra(a+28|0,b);return 0}function nd(a,b,c,d,e,f,g,h){a=a|0;b=b|0;c=c|0;d=d|0;e=e|0;f=f|0;g=g|0;h=h|0;var i=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0,r=0;m=V-16|0;V=m;pd(h);a:{b:{if(!d){break b}q=h&4;c:while(1){k=j;while(1){i=v[c+k|0];d:{e:{if(q){l=i-65|0;l=i+4&(i+65488>>>8^-1)&(57-i>>>8^-1)&255|((l>>>8^-1)&l&(90-i>>>8^-1)&255|(i+185&(i+65439>>>8^-1)&(122-i>>>8^-1)&255|(((i^16288)+1>>>8^-1)&63|((i^16338)+1>>>8^-1)&62)));l=(0-l>>>8^-1)&(i^65470)+1>>>8&255|l;break e}l=i-65|0;l=i+4&(i+65488>>>8^-1)&(57-i>>>8^-1)&255|((l>>>8^-1)&l&(90-i>>>8^-1)&255|(i+185&(i+65439>>>8^-1)&(122-i>>>8^-1)&255|(((i^16336)+1>>>8^-1)&63|((i^16340)+1>>>8^-1)&62)));l=(0-l>>>8^-1)&(i^65470)+1>>>8&255|l}if((l|0)==255){if(!e){break b}if(Pb(e,i)){break d}j=k;break b}p=l+(p<<6)|0;j=n+6|0;f:{if(j>>>0<8){n=j;break f}n=n-2|0;if(b>>>0<=o>>>0){x[m+12>>2]=k;x[9301]=68;r=1;j=k;break a}v[a+o|0]=p>>>n;o=o+1|0}j=k+1|0;if(j>>>0>>0){continue c}break b}k=k+1|0;if(k>>>0>>0){continue}break}break}a=j+1|0;j=a>>>0>>0?d:a}x[m+12>>2]=j}g:{if(n>>>0>4){a=0;k=-1;break g}k=-1;a=0;if((-1<>>1|0;if(h){b=x[m+12>>2];while(1){if(b>>>0>=d>>>0){j=68;break i}k=v[b+c|0];j:{if((k|0)==61){h=h-1|0;break j}j=28;if(!e){break i}if(!Pb(e,k)){break i}}b=b+1|0;x[m+12>>2]=b;if(h){continue}break}}k=0;break h}x[9301]=j;k=-1}if(k){break g}j=x[m+12>>2]}k=0;if(!(!e|d>>>0<=j>>>0)){k:{if(!Pb(e,v[c+j|0])){break k}a=d-1|0;while(1){if((a|0)!=(j|0)){j=j+1|0;if(Pb(e,v[j+c|0])){continue}break k}break}j=d}x[m+12>>2]=j}a=o}b=x[m+12>>2];l:{if(g){x[g>>2]=b+c;break l}if((b|0)==(d|0)){break l}x[9301]=28;k=-1}if(f){x[f>>2]=a}V=m+16|0;return k|0}function Wf(a,b){a=a|0;b=b|0;var c=0,d=0;c=V-128|0;V=c;x[c+80>>2]=0;x[c+84>>2]=0;x[c+88>>2]=0;x[c+92>>2]=0;x[c+40>>2]=0;x[c+44>>2]=0;x[c+48>>2]=0;x[c+52>>2]=0;x[c+56>>2]=0;x[c+60>>2]=0;d=x[8751];x[c+104>>2]=x[8750];x[c+108>>2]=d;d=x[8753];x[c+112>>2]=x[8752];x[c+116>>2]=d;d=x[8755];x[c+120>>2]=x[8754];x[c+124>>2]=d;x[c+64>>2]=0;x[c+68>>2]=0;x[c+72>>2]=0;x[c+76>>2]=0;v[c+64|0]=1;x[c+32>>2]=0;x[c+36>>2]=0;d=x[8749];x[c+96>>2]=x[8748];x[c+100>>2]=d;d=y[b+28|0]|y[b+29|0]<<8|(y[b+30|0]<<16|y[b+31|0]<<24);x[c+24>>2]=y[b+24|0]|y[b+25|0]<<8|(y[b+26|0]<<16|y[b+27|0]<<24);x[c+28>>2]=d;d=y[b+20|0]|y[b+21|0]<<8|(y[b+22|0]<<16|y[b+23|0]<<24);x[c+16>>2]=y[b+16|0]|y[b+17|0]<<8|(y[b+18|0]<<16|y[b+19|0]<<24);x[c+20>>2]=d;d=y[b+12|0]|y[b+13|0]<<8|(y[b+14|0]<<16|y[b+15|0]<<24);x[c+8>>2]=y[b+8|0]|y[b+9|0]<<8|(y[b+10|0]<<16|y[b+11|0]<<24);x[c+12>>2]=d;d=y[b+4|0]|y[b+5|0]<<8|(y[b+6|0]<<16|y[b+7|0]<<24);x[c>>2]=y[b|0]|y[b+1|0]<<8|(y[b+2|0]<<16|y[b+3|0]<<24);x[c+4>>2]=d;bf(c- -64|0,c);Eb(c- -64|0);b=x[c+92>>2];d=x[c+88>>2];v[a+24|0]=d;v[a+25|0]=d>>>8;v[a+26|0]=d>>>16;v[a+27|0]=d>>>24;v[a+28|0]=b;v[a+29|0]=b>>>8;v[a+30|0]=b>>>16;v[a+31|0]=b>>>24;b=x[c+84>>2];d=x[c+80>>2];v[a+16|0]=d;v[a+17|0]=d>>>8;v[a+18|0]=d>>>16;v[a+19|0]=d>>>24;v[a+20|0]=b;v[a+21|0]=b>>>8;v[a+22|0]=b>>>16;v[a+23|0]=b>>>24;b=x[c+76>>2];d=x[c+72>>2];v[a+8|0]=d;v[a+9|0]=d>>>8;v[a+10|0]=d>>>16;v[a+11|0]=d>>>24;v[a+12|0]=b;v[a+13|0]=b>>>8;v[a+14|0]=b>>>16;v[a+15|0]=b>>>24;b=x[c+68>>2];d=x[c+64>>2];v[a|0]=d;v[a+1|0]=d>>>8;v[a+2|0]=d>>>16;v[a+3|0]=d>>>24;v[a+4|0]=b;v[a+5|0]=b>>>8;v[a+6|0]=b>>>16;v[a+7|0]=b>>>24;V=c+128|0}function ud(a,b){a=a|0;b=b|0;var c=0,d=0;c=V-128|0;V=c;x[c+80>>2]=0;x[c+84>>2]=0;x[c+88>>2]=0;x[c+92>>2]=0;x[c+40>>2]=0;x[c+44>>2]=0;x[c+48>>2]=0;x[c+52>>2]=0;x[c+56>>2]=0;x[c+60>>2]=0;d=x[8751];x[c+104>>2]=x[8750];x[c+108>>2]=d;d=x[8753];x[c+112>>2]=x[8752];x[c+116>>2]=d;d=x[8755];x[c+120>>2]=x[8754];x[c+124>>2]=d;x[c+64>>2]=0;x[c+68>>2]=0;x[c+72>>2]=0;x[c+76>>2]=0;x[c+32>>2]=0;x[c+36>>2]=0;d=x[8749];x[c+96>>2]=x[8748];x[c+100>>2]=d;d=y[b+20|0]|y[b+21|0]<<8|(y[b+22|0]<<16|y[b+23|0]<<24);x[c+16>>2]=y[b+16|0]|y[b+17|0]<<8|(y[b+18|0]<<16|y[b+19|0]<<24);x[c+20>>2]=d;d=y[b+28|0]|y[b+29|0]<<8|(y[b+30|0]<<16|y[b+31|0]<<24);x[c+24>>2]=y[b+24|0]|y[b+25|0]<<8|(y[b+26|0]<<16|y[b+27|0]<<24);x[c+28>>2]=d;d=y[b+4|0]|y[b+5|0]<<8|(y[b+6|0]<<16|y[b+7|0]<<24);x[c>>2]=y[b|0]|y[b+1|0]<<8|(y[b+2|0]<<16|y[b+3|0]<<24);x[c+4>>2]=d;d=y[b+12|0]|y[b+13|0]<<8|(y[b+14|0]<<16|y[b+15|0]<<24);x[c+8>>2]=y[b+8|0]|y[b+9|0]<<8|(y[b+10|0]<<16|y[b+11|0]<<24);x[c+12>>2]=d;bf(c- -64|0,c);Eb(c- -64|0);b=x[c+92>>2];d=x[c+88>>2];v[a+24|0]=d;v[a+25|0]=d>>>8;v[a+26|0]=d>>>16;v[a+27|0]=d>>>24;v[a+28|0]=b;v[a+29|0]=b>>>8;v[a+30|0]=b>>>16;v[a+31|0]=b>>>24;b=x[c+84>>2];d=x[c+80>>2];v[a+16|0]=d;v[a+17|0]=d>>>8;v[a+18|0]=d>>>16;v[a+19|0]=d>>>24;v[a+20|0]=b;v[a+21|0]=b>>>8;v[a+22|0]=b>>>16;v[a+23|0]=b>>>24;b=x[c+76>>2];d=x[c+72>>2];v[a+8|0]=d;v[a+9|0]=d>>>8;v[a+10|0]=d>>>16;v[a+11|0]=d>>>24;v[a+12|0]=b;v[a+13|0]=b>>>8;v[a+14|0]=b>>>16;v[a+15|0]=b>>>24;b=x[c+68>>2];d=x[c+64>>2];v[a|0]=d;v[a+1|0]=d>>>8;v[a+2|0]=d>>>16;v[a+3|0]=d>>>24;v[a+4|0]=b;v[a+5|0]=b>>>8;v[a+6|0]=b>>>16;v[a+7|0]=b>>>24;V=c+128|0}function Xe(a,b,c,d,e,f,g,h,i,j,k){var l=0,m=0,n=0,o=0,p=0,q=0,r=0,s=0,t=0,u=0,v=0;n=Fj(i,0,h,0);l=Y;if(!l&n>>>0>=1073741824|l){x[9301]=22;return-1}if((g|0)==1|g>>>0>1){x[9301]=22;return-1}p=!g&f>>>0>=2|(g|0)!=0;n=f;o=g;l=0;while(1){m=l;r=q;if(n|o){m=n;n=m-1&m;o=o-(m>>>0<1)&o;l=l+1|0;q=l>>>0<1?q+1|0:q;continue}break}Y=r;if(!(!Y&m>>>0<2?p:0)){x[9301]=28;return-1}if(!(i?h:0)){x[9301]=28;return-1}a:{if(!g&f>>>0<=33554431/(h>>>0)>>>0?33554431/(i>>>0)>>>0>>0|h>>>0>16777215:1){break a}u=h<<7;q=D(u,i);p=D(f,u);l=p+q|0;if(q>>>0>l>>>0){break a}n=l+(h<<8|64)|0;if(l>>>0>n>>>0){break a}b:{if(n>>>0>A[a+8>>2]){o=-1;if(af(a)){break b}l=V-16|0;V=l;m=Lf(l+12|0,n);x[9301]=m;m=m?0:x[l+12>>2];x[a+4>>2]=m;x[a>>2]=m;x[a+8>>2]=m?n:0;V=l+16|0;if(!m){break b}}t=x[a+4>>2];Ye(b,c,d,e,t,q);r=q+t|0;l=p+r|0;a=0;while(1){v=D(a,u)+t|0;e=0;n=0;m=h<<5;if(m){while(1){d=e<<2;o=d+l|0;d=d+v|0;x[o>>2]=y[d|0]|y[d+1|0]<<8|(y[d+2|0]<<16|y[d+3|0]<<24);e=e+1|0;if((m|0)!=(e|0)){continue}break}}c:{if(!(f|g)){break c}p=l+(h<<8)|0;s=h<<7;o=s+l|0;e=2;d=0;while(1){We(r+(D(n,m)<<2)|0,l,s);ec(l,o,p,h);We(r+(D(m,n|1)<<2)|0,o,s);ec(o,l,p,h);if((d|0)==(g|0)&e>>>0>>0|d>>>0>>0){n=e;e=e+2|0;d=e>>>0<2?d+1|0:d;continue}break}n=f-1|0;e=2;d=0;while(1){Ue(l,r+(D(m,Ve(l,h)&n)<<2)|0,s);ec(l,o,p,h);Ue(o,r+(D(m,Ve(o,h)&n)<<2)|0,s);ec(o,l,p,h);if((d|0)==(g|0)&e>>>0>=f>>>0|d>>>0>g>>>0){break c}e=e+2|0;d=e>>>0<2?d+1|0:d;continue}}if(m){e=0;while(1){d=e<<2;ra(d+v|0,x[d+l>>2]);e=e+1|0;if((m|0)!=(e|0)){continue}break}}a=a+1|0;if((i|0)!=(a|0)){continue}break}Ye(b,c,t,q,j,k);o=0}return o}x[9301]=48;return-1}function td(a,b,c){a=a|0;b=b|0;c=c|0;var d=0,e=0,f=0,g=0;d=V-128|0;V=d;x[d+104>>2]=0;x[d+108>>2]=0;x[d+112>>2]=0;x[d+116>>2]=0;x[d+120>>2]=0;x[d+124>>2]=0;x[d+96>>2]=0;x[d+100>>2]=0;e=y[b+20|0]|y[b+21|0]<<8|(y[b+22|0]<<16|y[b+23|0]<<24);x[d+80>>2]=y[b+16|0]|y[b+17|0]<<8|(y[b+18|0]<<16|y[b+19|0]<<24);x[d+84>>2]=e;e=y[b+28|0]|y[b+29|0]<<8|(y[b+30|0]<<16|y[b+31|0]<<24);x[d+88>>2]=y[b+24|0]|y[b+25|0]<<8|(y[b+26|0]<<16|y[b+27|0]<<24);x[d+92>>2]=e;e=y[b+8|0]|y[b+9|0]<<8|(y[b+10|0]<<16|y[b+11|0]<<24);f=y[b+12|0]|y[b+13|0]<<8|(y[b+14|0]<<16|y[b+15|0]<<24);g=y[b|0]|y[b+1|0]<<8|(y[b+2|0]<<16|y[b+3|0]<<24);b=y[b+4|0]|y[b+5|0]<<8|(y[b+6|0]<<16|y[b+7|0]<<24);x[d+40>>2]=0;x[d+44>>2]=0;x[d+48>>2]=0;x[d+52>>2]=0;x[d+56>>2]=0;x[d+60>>2]=0;x[d+64>>2]=g;x[d+68>>2]=b;x[d+72>>2]=e;x[d+76>>2]=f;x[d+32>>2]=0;x[d+36>>2]=0;b=y[c+20|0]|y[c+21|0]<<8|(y[c+22|0]<<16|y[c+23|0]<<24);x[d+16>>2]=y[c+16|0]|y[c+17|0]<<8|(y[c+18|0]<<16|y[c+19|0]<<24);x[d+20>>2]=b;b=y[c+28|0]|y[c+29|0]<<8|(y[c+30|0]<<16|y[c+31|0]<<24);x[d+24>>2]=y[c+24|0]|y[c+25|0]<<8|(y[c+26|0]<<16|y[c+27|0]<<24);x[d+28>>2]=b;b=y[c+4|0]|y[c+5|0]<<8|(y[c+6|0]<<16|y[c+7|0]<<24);x[d>>2]=y[c|0]|y[c+1|0]<<8|(y[c+2|0]<<16|y[c+3|0]<<24);x[d+4>>2]=b;b=y[c+12|0]|y[c+13|0]<<8|(y[c+14|0]<<16|y[c+15|0]<<24);x[d+8>>2]=y[c+8|0]|y[c+9|0]<<8|(y[c+10|0]<<16|y[c+11|0]<<24);x[d+12>>2]=b;e=d- -64|0;b=0;c=0;while(1){f=b+e|0;c=y[b+d|0]+(y[f|0]+c|0)|0;v[f|0]=c;c=c>>>8|0;b=b+1|0;if((b|0)!=32){continue}break}sd(a,d- -64|0);V=d+128|0}function Mc(a){a=a|0;var b=0,c=0,d=0;c=V-48|0;V=c;b=y[a+28|0]|y[a+29|0]<<8|(y[a+30|0]<<16|y[a+31|0]<<24);x[c+24>>2]=y[a+24|0]|y[a+25|0]<<8|(y[a+26|0]<<16|y[a+27|0]<<24);x[c+28>>2]=b;b=y[a+20|0]|y[a+21|0]<<8|(y[a+22|0]<<16|y[a+23|0]<<24);x[c+16>>2]=y[a+16|0]|y[a+17|0]<<8|(y[a+18|0]<<16|y[a+19|0]<<24);x[c+20>>2]=b;b=y[a+4|0]|y[a+5|0]<<8|(y[a+6|0]<<16|y[a+7|0]<<24);x[c>>2]=y[a|0]|y[a+1|0]<<8|(y[a+2|0]<<16|y[a+3|0]<<24);x[c+4>>2]=b;b=y[a+12|0]|y[a+13|0]<<8|(y[a+14|0]<<16|y[a+15|0]<<24);x[c+8>>2]=y[a+8|0]|y[a+9|0]<<8|(y[a+10|0]<<16|y[a+11|0]<<24);x[c+12>>2]=b;b=y[a+40|0]|y[a+41|0]<<8|(y[a+42|0]<<16|y[a+43|0]<<24);x[c+32>>2]=y[a+36|0]|y[a+37|0]<<8|(y[a+38|0]<<16|y[a+39|0]<<24);x[c+36>>2]=b;cg(c,c,40,0,a+32|0,a);b=x[c+28>>2];d=x[c+24>>2];v[a+24|0]=d;v[a+25|0]=d>>>8;v[a+26|0]=d>>>16;v[a+27|0]=d>>>24;v[a+28|0]=b;v[a+29|0]=b>>>8;v[a+30|0]=b>>>16;v[a+31|0]=b>>>24;b=x[c+20>>2];d=x[c+16>>2];v[a+16|0]=d;v[a+17|0]=d>>>8;v[a+18|0]=d>>>16;v[a+19|0]=d>>>24;v[a+20|0]=b;v[a+21|0]=b>>>8;v[a+22|0]=b>>>16;v[a+23|0]=b>>>24;b=x[c+12>>2];d=x[c+8>>2];v[a+8|0]=d;v[a+9|0]=d>>>8;v[a+10|0]=d>>>16;v[a+11|0]=d>>>24;v[a+12|0]=b;v[a+13|0]=b>>>8;v[a+14|0]=b>>>16;v[a+15|0]=b>>>24;b=x[c+4>>2];d=x[c>>2];v[a|0]=d;v[a+1|0]=d>>>8;v[a+2|0]=d>>>16;v[a+3|0]=d>>>24;v[a+4|0]=b;v[a+5|0]=b>>>8;v[a+6|0]=b>>>16;v[a+7|0]=b>>>24;b=x[c+36>>2];d=x[c+32>>2];v[a+36|0]=d;v[a+37|0]=d>>>8;v[a+38|0]=d>>>16;v[a+39|0]=d>>>24;v[a+40|0]=b;v[a+41|0]=b>>>8;v[a+42|0]=b>>>16;v[a+43|0]=b>>>24;Nc(a);V=c+48|0}function yj(a,b,c,d,e,f,g,h){a=a|0;b=b|0;c=c|0;d=d|0;e=e|0;f=f|0;g=g|0;h=h|0;var i=0,j=0,k=0;j=V-112|0;V=j;if(c|d){i=y[h+28|0]|y[h+29|0]<<8|(y[h+30|0]<<16|y[h+31|0]<<24);x[j+24>>2]=y[h+24|0]|y[h+25|0]<<8|(y[h+26|0]<<16|y[h+27|0]<<24);x[j+28>>2]=i;i=y[h+20|0]|y[h+21|0]<<8|(y[h+22|0]<<16|y[h+23|0]<<24);x[j+16>>2]=y[h+16|0]|y[h+17|0]<<8|(y[h+18|0]<<16|y[h+19|0]<<24);x[j+20>>2]=i;i=y[h+4|0]|y[h+5|0]<<8|(y[h+6|0]<<16|y[h+7|0]<<24);x[j>>2]=y[h|0]|y[h+1|0]<<8|(y[h+2|0]<<16|y[h+3|0]<<24);x[j+4>>2]=i;i=8;k=y[h+12|0]|y[h+13|0]<<8|(y[h+14|0]<<16|y[h+15|0]<<24);x[j+8>>2]=y[h+8|0]|y[h+9|0]<<8|(y[h+10|0]<<16|y[h+11|0]<<24);x[j+12>>2]=k;h=y[e+4|0]|y[e+5|0]<<8|(y[e+6|0]<<16|y[e+7|0]<<24);x[j+96>>2]=y[e|0]|y[e+1|0]<<8|(y[e+2|0]<<16|y[e+3|0]<<24);x[j+100>>2]=h;while(1){v[(j+96|0)+i|0]=f;f=(g&255)<<24|f>>>8;g=g>>>8|0;i=i+1|0;if((i|0)!=16){continue}break}if(!d&c>>>0>63|d){while(1){i=0;Ub(j+32|0,j+96|0,j,0);while(1){v[a+i|0]=y[(j+32|0)+i|0]^y[b+i|0];h=1;i=i+1|0;if((i|0)!=64){continue}break}i=8;while(1){f=(j+96|0)+i|0;e=y[f|0]+h|0;v[f|0]=e;h=e>>>8|0;i=i+1|0;if((i|0)!=16){continue}break}b=b- -64|0;a=a- -64|0;d=d-1|0;c=c+-64|0;d=c>>>0<4294967232?d+1|0:d;if(!d&c>>>0>63|d){continue}break}}if(c|d){i=0;Ub(j+32|0,j+96|0,j,0);while(1){v[a+i|0]=y[(j+32|0)+i|0]^y[b+i|0];i=i+1|0;if((c|0)!=(i|0)){continue}break}}oa(j+32|0,64);oa(j,32)}V=j+112|0;return 0}function Cg(a,b,c,d,e,f){a=a|0;b=b|0;c=c|0;d=d|0;e=e|0;f=f|0;var g=0,h=0,i=0;g=V-112|0;V=g;i=c;h=d;if(c|h){c=y[f+28|0]|y[f+29|0]<<8|(y[f+30|0]<<16|y[f+31|0]<<24);x[g+24>>2]=y[f+24|0]|y[f+25|0]<<8|(y[f+26|0]<<16|y[f+27|0]<<24);x[g+28>>2]=c;c=y[f+20|0]|y[f+21|0]<<8|(y[f+22|0]<<16|y[f+23|0]<<24);x[g+16>>2]=y[f+16|0]|y[f+17|0]<<8|(y[f+18|0]<<16|y[f+19|0]<<24);x[g+20>>2]=c;c=y[f+4|0]|y[f+5|0]<<8|(y[f+6|0]<<16|y[f+7|0]<<24);x[g>>2]=y[f|0]|y[f+1|0]<<8|(y[f+2|0]<<16|y[f+3|0]<<24);x[g+4>>2]=c;c=y[f+12|0]|y[f+13|0]<<8|(y[f+14|0]<<16|y[f+15|0]<<24);x[g+8>>2]=y[f+8|0]|y[f+9|0]<<8|(y[f+10|0]<<16|y[f+11|0]<<24);x[g+12>>2]=c;c=y[e|0]|y[e+1|0]<<8|(y[e+2|0]<<16|y[e+3|0]<<24);d=y[e+4|0]|y[e+5|0]<<8|(y[e+6|0]<<16|y[e+7|0]<<24);x[g+104>>2]=0;x[g+108>>2]=0;x[g+96>>2]=c;x[g+100>>2]=d;a:{if(!h&i>>>0>=64|h){while(1){c=0;Tb(g+32|0,g+96|0,g,0);while(1){v[a+c|0]=y[(g+32|0)+c|0]^y[b+c|0];d=1;c=c+1|0;if((c|0)!=64){continue}break}c=8;while(1){e=(g+96|0)+c|0;d=y[e|0]+d|0;v[e|0]=d;d=d>>>8|0;c=c+1|0;if((c|0)!=16){continue}break}b=b- -64|0;a=a- -64|0;h=h-1|0;c=i+-64|0;h=c>>>0<4294967232?h+1|0:h;i=c;if(!h&c>>>0>63|h){continue}break}if(!(h|i)){break a}}c=0;Tb(g+32|0,g+96|0,g,0);while(1){v[a+c|0]=y[(g+32|0)+c|0]^y[b+c|0];c=c+1|0;if((i|0)!=(c|0)){continue}break}}oa(g+32|0,64);oa(g,32)}V=g+112|0;return 0}function Ag(a,b,c,d,e,f){a=a|0;b=b|0;c=c|0;d=d|0;e=e|0;f=f|0;var g=0,h=0,i=0;g=V-112|0;V=g;i=c;h=d;if(c|h){c=y[f+28|0]|y[f+29|0]<<8|(y[f+30|0]<<16|y[f+31|0]<<24);x[g+24>>2]=y[f+24|0]|y[f+25|0]<<8|(y[f+26|0]<<16|y[f+27|0]<<24);x[g+28>>2]=c;c=y[f+20|0]|y[f+21|0]<<8|(y[f+22|0]<<16|y[f+23|0]<<24);x[g+16>>2]=y[f+16|0]|y[f+17|0]<<8|(y[f+18|0]<<16|y[f+19|0]<<24);x[g+20>>2]=c;c=y[f+4|0]|y[f+5|0]<<8|(y[f+6|0]<<16|y[f+7|0]<<24);x[g>>2]=y[f|0]|y[f+1|0]<<8|(y[f+2|0]<<16|y[f+3|0]<<24);x[g+4>>2]=c;c=y[f+12|0]|y[f+13|0]<<8|(y[f+14|0]<<16|y[f+15|0]<<24);x[g+8>>2]=y[f+8|0]|y[f+9|0]<<8|(y[f+10|0]<<16|y[f+11|0]<<24);x[g+12>>2]=c;c=y[e|0]|y[e+1|0]<<8|(y[e+2|0]<<16|y[e+3|0]<<24);d=y[e+4|0]|y[e+5|0]<<8|(y[e+6|0]<<16|y[e+7|0]<<24);x[g+104>>2]=0;x[g+108>>2]=0;x[g+96>>2]=c;x[g+100>>2]=d;a:{if(!h&i>>>0>=64|h){while(1){c=0;Sb(g+32|0,g+96|0,g,0);while(1){v[a+c|0]=y[(g+32|0)+c|0]^y[b+c|0];d=1;c=c+1|0;if((c|0)!=64){continue}break}c=8;while(1){e=(g+96|0)+c|0;d=y[e|0]+d|0;v[e|0]=d;d=d>>>8|0;c=c+1|0;if((c|0)!=16){continue}break}b=b- -64|0;a=a- -64|0;h=h-1|0;c=i+-64|0;h=c>>>0<4294967232?h+1|0:h;i=c;if(!h&c>>>0>63|h){continue}break}if(!(h|i)){break a}}c=0;Sb(g+32|0,g+96|0,g,0);while(1){v[a+c|0]=y[(g+32|0)+c|0]^y[b+c|0];c=c+1|0;if((i|0)!=(c|0)){continue}break}}oa(g+32|0,64);oa(g,32)}V=g+112|0;return 0}function jg(a,b,c){var d=0,e=0;d=V-832|0;V=d;qg(d+688|0,b);x[d+688>>2]=x[d+688>>2]+1;wb(d+688|0,d+688|0);ig(d+640|0,d+688|0);Wa(d+640|0,d+640|0);qa(d+592|0,d+640|0);ma(d+544|0,d+640|0,d+592|0);va(d+784|0,d+544|0,d+640|0);ig(d+592|0,d+592|0);va(d+784|0,d+592|0,d+784|0);b=V-464|0;V=b;e=d+784|0;ma(b+416|0,e,e);ma(b+368|0,e,b+416|0);qa(b+320|0,b+368|0);qa(b+320|0,b+320|0);ma(b+272|0,b+368|0,b+320|0);qa(b+224|0,b+272|0);qa(b+224|0,b+224|0);qa(b+224|0,b+224|0);qa(b+224|0,b+224|0);ma(b+176|0,b+272|0,b+224|0);La(b+128|0,b+176|0);lb(b+128|0,2,b+368|0);La(b+80|0,b+128|0);lb(b+128|0,10,b+80|0);lb(b+128|0,10,b+80|0);La(b+32|0,b+128|0);lb(b+128|0,30,b+32|0);La(b+32|0,b+128|0);lb(b+128|0,60,b+32|0);La(b+32|0,b+128|0);lb(b+128|0,120,b+32|0);lb(b+128|0,10,b+80|0);lb(b+128|0,3,b+368|0);qa(b+128|0,b+128|0);cb(b,b+128|0);V=b+464|0;b=v[b+1|0]&1;Wa(d+736|0,d+640|0);Ma(d+640|0,d+736|0,b);vb(d+592|0);Ma(d+592|0,34560,b);xa(d+640|0,d+640|0,d+592|0);Ea(d+384|0);va(d+224|0,d+640|0,d+384|0);xa(d+48|0,d+640|0,d+384|0);wb(d+96|0,d+224|0);ma(d,d+48|0,d+96|0);cb(a,d);v[a+31|0]=y[a+31|0]|c;if(ob(d+384|0,a)){R();N()}kb(d+224|0,d+384|0);ab(d+96|0,d+224|0);Va(d+224|0,d+96|0);ab(d+96|0,d+224|0);Va(d+224|0,d+96|0);wa(d+384|0,d+224|0);mb(a,d+384|0);V=d+832|0}function Se(a){var b=0,c=0,d=0,e=0,f=0,g=0,h=0,i=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0,r=0,s=0,t=0,u=0,v=0,w=0,y=0;b=V+-64|0;V=b;dc(b,a);h=x[b+28>>2];i=x[b+12>>2];d=x[b+44>>2];e=x[b+60>>2];j=x[b+8>>2];r=x[b+56>>2];f=x[b+24>>2];o=x[b+40>>2];p=x[b+52>>2];s=x[b+36>>2];g=x[b+4>>2];q=x[b+20>>2];m=x[b+32>>2];k=x[b+16>>2];n=x[b+48>>2];c=x[b>>2];while(1){l=Gj(g+q|0,7)^s;t=Gj(l+q|0,9)^p;k=Gj(c+n|0,7)^k;u=Gj(k+c|0,9)^m;v=Gj(u+k|0,13)^n;i=Gj(d+e|0,7)^i;h=Gj(i+e|0,9)^h;m=Gj(h+i|0,13)^d;e=Gj(h+m|0,18)^e;d=Gj(f+o|0,7)^r;n=v^Gj(e+d|0,7);p=t^Gj(n+e|0,9);r=Gj(n+p|0,13)^d;e=Gj(p+r|0,18)^e;j=Gj(d+o|0,9)^j;w=Gj(j+d|0,13)^f;f=Gj(w+j|0,18)^o;d=Gj(f+l|0,7)^m;m=Gj(d+f|0,9)^u;s=Gj(d+m|0,13)^l;o=Gj(m+s|0,18)^f;l=Gj(l+t|0,13)^g;g=Gj(l+t|0,18)^q;f=Gj(g+k|0,7)^w;h=Gj(f+g|0,9)^h;k=Gj(f+h|0,13)^k;q=Gj(h+k|0,18)^g;c=Gj(u+v|0,18)^c;g=Gj(c+i|0,7)^l;j=Gj(g+c|0,9)^j;i=Gj(j+g|0,13)^i;c=Gj(j+i|0,18)^c;l=y>>>0<6;y=y+2|0;if(l){continue}break}x[b+48>>2]=n;x[b+32>>2]=m;x[b+16>>2]=k;x[b+20>>2]=q;x[b+52>>2]=p;x[b+36>>2]=s;x[b+4>>2]=g;x[b+40>>2]=o;x[b+56>>2]=r;x[b+24>>2]=f;x[b+60>>2]=e;x[b+8>>2]=j;x[b+44>>2]=d;x[b+28>>2]=h;x[b+12>>2]=i;x[b>>2]=c;x[a>>2]=x[a>>2]+c;c=1;while(1){d=c<<2;e=d+a|0;x[e>>2]=x[e>>2]+x[b+d>>2];c=c+1|0;if((c|0)!=16){continue}break}V=b- -64|0}function pg(a,b,c){var d=0,e=0,f=0,g=0;d=V-4032|0;V=d;Ca(d+160|0,c);kb(d+3528|0,c);wa(d+2408|0,d+3528|0);e=d+320|0;Ca(e,d+2408|0);Da(d+3368|0,c,e);wa(d+2248|0,d+3368|0);Ca(d+480|0,d+2248|0);kb(d+3208|0,d+2408|0);wa(d+2088|0,d+3208|0);e=d+640|0;Ca(e,d+2088|0);Da(d+3048|0,c,e);wa(d+1928|0,d+3048|0);Ca(d+800|0,d+1928|0);kb(d+2888|0,d+2248|0);wa(d+1768|0,d+2888|0);e=d+960|0;Ca(e,d+1768|0);Da(d+2728|0,c,e);wa(d+1608|0,d+2728|0);Ca(d+1120|0,d+1608|0);kb(d+2568|0,d+2088|0);wa(d+1448|0,d+2568|0);Ca(d+1280|0,d+1448|0);e=0;c=0;while(1){f=c<<1;g=y[b+c|0];v[f+(d+3968|0)|0]=g&15;v[(d+3968|0)+(f|1)|0]=g>>>4;c=c+1|0;if((c|0)!=32){continue}break}c=0;while(1){b=c;c=(d+3968|0)+e|0;f=b+y[c|0]|0;b=(f<<24)- -134217728|0;v[c|0]=f-(b>>24&240);c=b>>28;e=e+1|0;if((e|0)!=63){continue}break}e=y[d+4031|0]+c|0;v[d+4031|0]=e;Cd(a);c=62;while(1){og(d,d+160|0,e<<24>>24);Da(d+3808|0,a,d);ab(d+3688|0,d+3808|0);Va(d+3808|0,d+3688|0);ab(d+3688|0,d+3808|0);Va(d+3808|0,d+3688|0);ab(d+3688|0,d+3808|0);Va(d+3808|0,d+3688|0);ab(d+3688|0,d+3808|0);Va(d+3808|0,d+3688|0);wa(a,d+3808|0);if(c){e=y[(d+3968|0)+c|0];c=c-1|0;continue}break}og(d,d+160|0,v[d+3968|0]);Da(d+3808|0,a,d);wa(a,d+3808|0);V=d+4032|0}function Dg(a,b,c,d,e){a=a|0;b=b|0;c=c|0;d=d|0;e=e|0;var f=0,g=0,h=0;f=V-112|0;V=f;h=b;g=c;if(b|g){b=y[e+28|0]|y[e+29|0]<<8|(y[e+30|0]<<16|y[e+31|0]<<24);x[f+24>>2]=y[e+24|0]|y[e+25|0]<<8|(y[e+26|0]<<16|y[e+27|0]<<24);x[f+28>>2]=b;b=y[e+20|0]|y[e+21|0]<<8|(y[e+22|0]<<16|y[e+23|0]<<24);x[f+16>>2]=y[e+16|0]|y[e+17|0]<<8|(y[e+18|0]<<16|y[e+19|0]<<24);x[f+20>>2]=b;b=y[e+4|0]|y[e+5|0]<<8|(y[e+6|0]<<16|y[e+7|0]<<24);x[f>>2]=y[e|0]|y[e+1|0]<<8|(y[e+2|0]<<16|y[e+3|0]<<24);x[f+4>>2]=b;b=y[e+12|0]|y[e+13|0]<<8|(y[e+14|0]<<16|y[e+15|0]<<24);x[f+8>>2]=y[e+8|0]|y[e+9|0]<<8|(y[e+10|0]<<16|y[e+11|0]<<24);x[f+12>>2]=b;b=y[d|0]|y[d+1|0]<<8|(y[d+2|0]<<16|y[d+3|0]<<24);c=y[d+4|0]|y[d+5|0]<<8|(y[d+6|0]<<16|y[d+7|0]<<24);x[f+104>>2]=0;x[f+108>>2]=0;x[f+96>>2]=b;x[f+100>>2]=c;a:{if(!g&h>>>0>=64|g){while(1){Tb(a,f+96|0,f,0);b=8;c=1;while(1){d=(f+96|0)+b|0;c=y[d|0]+c|0;v[d|0]=c;c=c>>>8|0;b=b+1|0;if((b|0)!=16){continue}break}a=a- -64|0;g=g-1|0;b=h+-64|0;g=b>>>0<4294967232?g+1|0:g;h=b;if(!g&b>>>0>63|g){continue}break}if(!(g|h)){break a}}b=0;Tb(f+32|0,f+96|0,f,0);while(1){v[a+b|0]=y[(f+32|0)+b|0];b=b+1|0;if((h|0)!=(b|0)){continue}break}}oa(f+32|0,64);oa(f,32)}V=f+112|0;return 0}function Bg(a,b,c,d,e){a=a|0;b=b|0;c=c|0;d=d|0;e=e|0;var f=0,g=0,h=0;f=V-112|0;V=f;h=b;g=c;if(b|g){b=y[e+28|0]|y[e+29|0]<<8|(y[e+30|0]<<16|y[e+31|0]<<24);x[f+24>>2]=y[e+24|0]|y[e+25|0]<<8|(y[e+26|0]<<16|y[e+27|0]<<24);x[f+28>>2]=b;b=y[e+20|0]|y[e+21|0]<<8|(y[e+22|0]<<16|y[e+23|0]<<24);x[f+16>>2]=y[e+16|0]|y[e+17|0]<<8|(y[e+18|0]<<16|y[e+19|0]<<24);x[f+20>>2]=b;b=y[e+4|0]|y[e+5|0]<<8|(y[e+6|0]<<16|y[e+7|0]<<24);x[f>>2]=y[e|0]|y[e+1|0]<<8|(y[e+2|0]<<16|y[e+3|0]<<24);x[f+4>>2]=b;b=y[e+12|0]|y[e+13|0]<<8|(y[e+14|0]<<16|y[e+15|0]<<24);x[f+8>>2]=y[e+8|0]|y[e+9|0]<<8|(y[e+10|0]<<16|y[e+11|0]<<24);x[f+12>>2]=b;b=y[d|0]|y[d+1|0]<<8|(y[d+2|0]<<16|y[d+3|0]<<24);c=y[d+4|0]|y[d+5|0]<<8|(y[d+6|0]<<16|y[d+7|0]<<24);x[f+104>>2]=0;x[f+108>>2]=0;x[f+96>>2]=b;x[f+100>>2]=c;a:{if(!g&h>>>0>=64|g){while(1){Sb(a,f+96|0,f,0);b=8;c=1;while(1){d=(f+96|0)+b|0;c=y[d|0]+c|0;v[d|0]=c;c=c>>>8|0;b=b+1|0;if((b|0)!=16){continue}break}a=a- -64|0;g=g-1|0;b=h+-64|0;g=b>>>0<4294967232?g+1|0:g;h=b;if(!g&b>>>0>63|g){continue}break}if(!(g|h)){break a}}b=0;Sb(f+32|0,f+96|0,f,0);while(1){v[a+b|0]=y[(f+32|0)+b|0];b=b+1|0;if((h|0)!=(b|0)){continue}break}}oa(f+32|0,64);oa(f,32)}V=f+112|0;return 0}function zj(a,b,c,d,e){a=a|0;b=b|0;c=c|0;d=d|0;e=e|0;var f=0,g=0;f=V-112|0;V=f;if(b|c){g=y[e+28|0]|y[e+29|0]<<8|(y[e+30|0]<<16|y[e+31|0]<<24);x[f+24>>2]=y[e+24|0]|y[e+25|0]<<8|(y[e+26|0]<<16|y[e+27|0]<<24);x[f+28>>2]=g;g=y[e+20|0]|y[e+21|0]<<8|(y[e+22|0]<<16|y[e+23|0]<<24);x[f+16>>2]=y[e+16|0]|y[e+17|0]<<8|(y[e+18|0]<<16|y[e+19|0]<<24);x[f+20>>2]=g;g=y[e+4|0]|y[e+5|0]<<8|(y[e+6|0]<<16|y[e+7|0]<<24);x[f>>2]=y[e|0]|y[e+1|0]<<8|(y[e+2|0]<<16|y[e+3|0]<<24);x[f+4>>2]=g;g=y[e+12|0]|y[e+13|0]<<8|(y[e+14|0]<<16|y[e+15|0]<<24);x[f+8>>2]=y[e+8|0]|y[e+9|0]<<8|(y[e+10|0]<<16|y[e+11|0]<<24);x[f+12>>2]=g;e=y[d|0]|y[d+1|0]<<8|(y[d+2|0]<<16|y[d+3|0]<<24);d=y[d+4|0]|y[d+5|0]<<8|(y[d+6|0]<<16|y[d+7|0]<<24);x[f+104>>2]=0;x[f+108>>2]=0;x[f+96>>2]=e;x[f+100>>2]=d;a:{if(!c&b>>>0>=64|c){while(1){Ub(a,f+96|0,f,0);e=8;d=1;while(1){g=(f+96|0)+e|0;d=y[g|0]+d|0;v[g|0]=d;d=d>>>8|0;e=e+1|0;if((e|0)!=16){continue}break}a=a- -64|0;c=c-1|0;b=b+-64|0;c=b>>>0<4294967232?c+1|0:c;if(!c&b>>>0>63|c){continue}break}if(!(b|c)){break a}}e=0;Ub(f+32|0,f+96|0,f,0);while(1){v[a+e|0]=y[(f+32|0)+e|0];e=e+1|0;if((b|0)!=(e|0)){continue}break}}oa(f+32|0,64);oa(f,32)}V=f+112|0;return 0}function Na(a,b,c,d){var e=0,f=0,g=0,h=0,i=0,j=0,k=0,l=0;k=V-704|0;V=k;a:{if(!(c|d)){break a}f=a;g=c;e=d<<3|g>>>29;j=x[f+72>>2];i=g<<3;g=j+i|0;h=x[f+76>>2];e=e+h|0;l=g;x[f+72>>2]=g;e=g>>>0>>0?e+1|0:e;x[f+76>>2]=e;g=f- -64|0;f=g;i=(e|0)==(h|0)&l>>>0>>0|e>>>0>>0;l=i+x[f>>2]|0;e=x[f+4>>2];e=i>>>0>l>>>0?e+1|0:e;i=d>>>29|0;g=i+l|0;x[f>>2]=g;x[f+4>>2]=g>>>0>>0?e+1|0:e;f=0;e=0;h=((h&7)<<29|j>>>3)&127;g=128-h|0;j=0-(h>>>0>128)|0;i=j;if((i|0)==(d|0)&c>>>0>>0|d>>>0>>0){while(1){l=f+h|0;v[(a+l|0)+80|0]=y[b+f|0];f=f+1|0;e=f>>>0<1?e+1|0:e;if((c|0)!=(f|0)|(d|0)!=(e|0)){continue}break a}}while(1){i=f+h|0;v[(a+i|0)+80|0]=y[b+f|0];f=f+1|0;e=f>>>0<1?e+1|0:e;if((g|0)!=(f|0)|(e|0)!=(j|0)){continue}break}e=k+640|0;pc(a,a+80|0,k,e);b=b+g|0;d=d-((c>>>0>>0)+j|0)|0;c=c-g|0;if(!d&c>>>0>127|d){while(1){pc(a,b,k,e);b=b+128|0;d=d-(c>>>0<128)|0;c=c-128|0;if(!d&c>>>0>127|d){continue}break}}b:{if(!(c|d)){break b}h=0;f=1;e=0;while(1){v[(a+h|0)+80|0]=y[b+h|0];if((c|0)==(f|0)&(d|0)==(e|0)){break b}h=f;f=f+1|0;e=f>>>0<1?e+1|0:e;continue}}oa(k,704)}V=k+704|0;return 0}function Zf(a,b){a=a|0;b=b|0;var c=0,d=0,e=0;e=V-48|0;V=e;c=y[b+28|0]|y[b+29|0]<<8|(y[b+30|0]<<16|y[b+31|0]<<24);d=y[b+24|0]|y[b+25|0]<<8|(y[b+26|0]<<16|y[b+27|0]<<24);v[a+24|0]=d;v[a+25|0]=d>>>8;v[a+26|0]=d>>>16;v[a+27|0]=d>>>24;v[a+28|0]=c;v[a+29|0]=c>>>8;v[a+30|0]=c>>>16;v[a+31|0]=c>>>24;c=y[b+4|0]|y[b+5|0]<<8|(y[b+6|0]<<16|y[b+7|0]<<24);d=y[b|0]|y[b+1|0]<<8|(y[b+2|0]<<16|y[b+3|0]<<24);v[a|0]=d;v[a+1|0]=d>>>8;v[a+2|0]=d>>>16;v[a+3|0]=d>>>24;v[a+4|0]=c;v[a+5|0]=c>>>8;v[a+6|0]=c>>>16;v[a+7|0]=c>>>24;c=y[b+20|0]|y[b+21|0]<<8|(y[b+22|0]<<16|y[b+23|0]<<24);d=y[b+16|0]|y[b+17|0]<<8|(y[b+18|0]<<16|y[b+19|0]<<24);v[a+16|0]=d;v[a+17|0]=d>>>8;v[a+18|0]=d>>>16;v[a+19|0]=d>>>24;v[a+20|0]=c;v[a+21|0]=c>>>8;v[a+22|0]=c>>>16;v[a+23|0]=c>>>24;c=y[b+12|0]|y[b+13|0]<<8|(y[b+14|0]<<16|y[b+15|0]<<24);b=y[b+8|0]|y[b+9|0]<<8|(y[b+10|0]<<16|y[b+11|0]<<24);v[a+8|0]=b;v[a+9|0]=b>>>8;v[a+10|0]=b>>>16;v[a+11|0]=b>>>24;v[a+12|0]=c;v[a+13|0]=c>>>8;v[a+14|0]=c>>>16;v[a+15|0]=c>>>24;b=y[a+31|0];v[a+31|0]=b&127;db(e,a);jg(a,e,b&128);V=e+48|0;return 0}function Ci(a,b){a=a|0;b=b|0;var c=0,d=0,e=0,f=0,g=0,h=0,i=0;c=b;d=y[c+32|0]|y[c+33|0]<<8|(y[c+34|0]<<16|y[c+35|0]<<24);e=y[c+36|0]|y[c+37|0]<<8|(y[c+38|0]<<16|y[c+39|0]<<24);f=y[c+40|0]|y[c+41|0]<<8|(y[c+42|0]<<16|y[c+43|0]<<24);g=y[c+44|0]|y[c+45|0]<<8|(y[c+46|0]<<16|y[c+47|0]<<24);h=y[c+48|0]|y[c+49|0]<<8|(y[c+50|0]<<16|y[c+51|0]<<24);b=y[c+52|0]|y[c+53|0]<<8|(y[c+54|0]<<16|y[c+55|0]<<24);i=y[c+60|0]|y[c+61|0]<<8|(y[c+62|0]<<16|y[c+63|0]<<24);c=y[c+56|0]|y[c+57|0]<<8|(y[c+58|0]<<16|y[c+59|0]<<24);v[a+24|0]=c;v[a+25|0]=c>>>8;v[a+26|0]=c>>>16;v[a+27|0]=c>>>24;v[a+28|0]=i;v[a+29|0]=i>>>8;v[a+30|0]=i>>>16;v[a+31|0]=i>>>24;v[a+16|0]=h;v[a+17|0]=h>>>8;v[a+18|0]=h>>>16;v[a+19|0]=h>>>24;v[a+20|0]=b;v[a+21|0]=b>>>8;v[a+22|0]=b>>>16;v[a+23|0]=b>>>24;v[a+8|0]=f;v[a+9|0]=f>>>8;v[a+10|0]=f>>>16;v[a+11|0]=f>>>24;v[a+12|0]=g;v[a+13|0]=g>>>8;v[a+14|0]=g>>>16;v[a+15|0]=g>>>24;v[a|0]=d;v[a+1|0]=d>>>8;v[a+2|0]=d>>>16;v[a+3|0]=d>>>24;v[a+4|0]=e;v[a+5|0]=e>>>8;v[a+6|0]=e>>>16;v[a+7|0]=e>>>24;return 0}function Di(a,b){a=a|0;b=b|0;var c=0,d=0,e=0,f=0,g=0,h=0,i=0;c=b;d=y[c+8|0]|y[c+9|0]<<8|(y[c+10|0]<<16|y[c+11|0]<<24);e=y[c+12|0]|y[c+13|0]<<8|(y[c+14|0]<<16|y[c+15|0]<<24);f=y[c+16|0]|y[c+17|0]<<8|(y[c+18|0]<<16|y[c+19|0]<<24);g=y[c+20|0]|y[c+21|0]<<8|(y[c+22|0]<<16|y[c+23|0]<<24);h=y[c|0]|y[c+1|0]<<8|(y[c+2|0]<<16|y[c+3|0]<<24);b=y[c+4|0]|y[c+5|0]<<8|(y[c+6|0]<<16|y[c+7|0]<<24);i=y[c+28|0]|y[c+29|0]<<8|(y[c+30|0]<<16|y[c+31|0]<<24);c=y[c+24|0]|y[c+25|0]<<8|(y[c+26|0]<<16|y[c+27|0]<<24);v[a+24|0]=c;v[a+25|0]=c>>>8;v[a+26|0]=c>>>16;v[a+27|0]=c>>>24;v[a+28|0]=i;v[a+29|0]=i>>>8;v[a+30|0]=i>>>16;v[a+31|0]=i>>>24;v[a+16|0]=f;v[a+17|0]=f>>>8;v[a+18|0]=f>>>16;v[a+19|0]=f>>>24;v[a+20|0]=g;v[a+21|0]=g>>>8;v[a+22|0]=g>>>16;v[a+23|0]=g>>>24;v[a+8|0]=d;v[a+9|0]=d>>>8;v[a+10|0]=d>>>16;v[a+11|0]=d>>>24;v[a+12|0]=e;v[a+13|0]=e>>>8;v[a+14|0]=e>>>16;v[a+15|0]=e>>>24;v[a|0]=h;v[a+1|0]=h>>>8;v[a+2|0]=h>>>16;v[a+3|0]=h>>>24;v[a+4|0]=b;v[a+5|0]=b>>>8;v[a+6|0]=b>>>16;v[a+7|0]=b>>>24;return 0}function wb(a,b){var c=0;c=V-192|0;V=c;qa(c+144|0,b);qa(c+96|0,c+144|0);qa(c+96|0,c+96|0);ma(c+96|0,b,c+96|0);ma(c+144|0,c+144|0,c+96|0);qa(c+48|0,c+144|0);ma(c+96|0,c+96|0,c+48|0);qa(c+48|0,c+96|0);b=2;while(1){qa(c+48|0,c+48|0);if((b|0)!=5){b=b+1|0;continue}break}ma(c+96|0,c+48|0,c+96|0);qa(c+48|0,c+96|0);b=2;while(1){qa(c+48|0,c+48|0);if((b|0)!=10){b=b+1|0;continue}break}ma(c+48|0,c+48|0,c+96|0);qa(c,c+48|0);b=2;while(1){qa(c,c);if((b|0)!=20){b=b+1|0;continue}break}ma(c+48|0,c,c+48|0);b=2;while(1){qa(c+48|0,c+48|0);if((b|0)!=11){b=b+1|0;continue}break}ma(c+96|0,c+48|0,c+96|0);qa(c+48|0,c+96|0);b=2;while(1){qa(c+48|0,c+48|0);if((b|0)!=50){b=b+1|0;continue}break}ma(c+48|0,c+48|0,c+96|0);qa(c,c+48|0);b=2;while(1){qa(c,c);if((b|0)!=100){b=b+1|0;continue}break}ma(c+48|0,c,c+48|0);b=2;while(1){qa(c+48|0,c+48|0);if((b|0)!=51){b=b+1|0;continue}break}ma(c+96|0,c+48|0,c+96|0);b=2;while(1){qa(c+96|0,c+96|0);if((b|0)!=6){b=b+1|0;continue}break}ma(a,c+96|0,c+144|0);V=c+192|0}function If(a,b,c){var d=0,e=0,f=0,g=0;d=V-16|0;V=d;f=x[a+20>>2];x[a+20>>2]=0;g=x[a+4>>2];x[a+4>>2]=0;e=-26;a:{b:{c:{d:{switch(c-1|0){case 1:e=-32;if(Ya(b,1165,9)){break a}b=b+9|0;break c;case 0:break d;default:break a}}e=-32;if(Ya(b,1156,8)){break a}b=b+8|0}if(Ya(b,1422,3)){break b}b=mc(b+3|0,d+12|0);if(!b){break b}e=-26;if(x[d+12>>2]!=19){break a}if(Ya(b,1434,3)){break b}b=mc(b+3|0,d+12|0);if(!b){break b}x[a+44>>2]=x[d+12>>2];if(Ya(b,1426,3)){break b}b=mc(b+3|0,d+12|0);if(!b){break b}x[a+40>>2]=x[d+12>>2];if(Ya(b,1430,3)){break b}b=mc(b+3|0,d+12|0);if(!b){break b}c=x[d+12>>2];x[a+48>>2]=c;x[a+52>>2]=c;c=y[b|0];if((c|0)!=36){break b}x[d+12>>2]=f;b=(c|0)==36?b+1|0:b;if(nd(x[a+16>>2],f,b,Ta(b),0,d+12|0,d+8|0,3)){break b}x[a+20>>2]=x[d+12>>2];b=x[d+8>>2];c=y[b|0];if((c|0)!=36){break b}x[d+12>>2]=g;b=(c|0)==36?b+1|0:b;if(nd(x[a>>2],g,b,Ta(b),0,d+12|0,d+8|0,3)){break b}x[a+4>>2]=x[d+12>>2];b=x[d+8>>2];e=Dc(a);if(e){break a}e=y[b|0]?-32:0;break a}e=-32}V=d+16|0;return e}function Ej(a,b,c){var d=0,e=0,f=0,g=0,h=0,i=0,j=0,k=0,l=0;a:{b:{c:{d:{e:{f:{g:{h:{i:{e=b;if(e){d=c;if(!d){break i}break h}b=a;a=(a>>>0)/(c>>>0)|0;W=b-D(a,c)|0;X=0;Y=0;return a}if(!a){break g}break f}g=d-1|0;if(!(g&d)){break e}g=(G(d)+33|0)-G(e)|0;i=0-g|0;break c}W=0;a=(e>>>0)/0|0;X=e-D(a,0)|0;Y=0;return a}d=32-G(e)|0;if(d>>>0<31){break d}break b}W=a&g;X=0;if((d|0)==1){break a}if(d){d=31-G(d-1^d)|0}else{d=32}c=d&31;if((d&63)>>>0>=32){e=0;a=b>>>c|0}else{e=b>>>c|0;a=((1<>>c}Y=e;return a}g=d+1|0;i=63-d|0}d=b;e=g&63;f=e&31;if(e>>>0>=32){e=0;f=d>>>f|0}else{e=d>>>f|0;f=((1<>>f}i=i&63;d=i&31;if(i>>>0>=32){b=a<>>32-d|b<>>31;j=h;e=e<<1|f>>>31;h=i-(e+(d>>>0>>0)|0)>>31;k=c&h;f=j-k|0;e=e-(j>>>0>>0)|0;b=b<<1|a>>>31;a=l|a<<1;h=h&1;l=h;g=g-1|0;if(g){continue}break}}W=f;X=e;Y=b<<1|a>>>31;return h|a<<1}W=a;X=b;a=0;b=0}Y=b;return a}function Kd(a,b){var c=0,d=0,e=0,f=0,g=0,h=0,i=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0,r=0,s=0;e=x[a+60>>2];d=e;c=x[a+56>>2];if(d|c){e=c;g=c+a|0;v[g- -64|0]=1;c=c+1|0;d=c>>>0<1?d+1|0:d;if(!d&c>>>0<=15){ya(g+65|0,0,15-e|0)}v[a+80|0]=1;Bc(a,a- -64|0,16,0)}q=x[a+52>>2];r=x[a+48>>2];s=x[a+44>>2];f=x[a+24>>2];h=x[a+28>>2]+(f>>>26|0)|0;c=x[a+32>>2]+(h>>>26|0)|0;k=x[a+36>>2]+(c>>>26|0)|0;d=x[a+20>>2]+D(k>>>26|0,5)|0;g=d&67108863;m=g+5|0;n=c&67108863;e=h&67108863;c=(f&67108863)+(d>>>26|0)|0;d=c+(m>>>26|0)|0;f=e+(d>>>26|0)|0;o=n+(f>>>26|0)|0;l=(k|-67108864)+(o>>>26|0)|0;i=l>>31;p=(l>>>31|0)-1|0;j=p&67108863;h=c&i|j&d;c=h<<26|(j&m|g&i);g=c+x[a+40>>2]|0;d=0;d=c>>>0>g>>>0?1:d;ra(b,g);f=e&i|f&j;c=f<<20|h>>>6;h=c+s|0;e=0;e=c>>>0>h>>>0?1:e;c=d;h=c+h|0;d=e;d=c>>>0>h>>>0?d+1|0:d;ra(b+4|0,h);g=i&n|j&o;c=g<<14|f>>>12;f=c+r|0;e=0;e=c>>>0>f>>>0?1:e;c=d;f=c+f|0;d=e;d=c>>>0>f>>>0?d+1|0:d;ra(b+8|0,f);e=b+12|0;b=(l&p|i&k)<<8|g>>>18;g=b+q|0;d=d+g|0;ra(e,d);oa(a,88)}function Ac(a,b){var c=0,d=0;c=V-144|0;V=c;qa(c+96|0,b);qa(c+48|0,c+96|0);qa(c+48|0,c+48|0);ma(c+48|0,b,c+48|0);ma(c+96|0,c+96|0,c+48|0);qa(c+96|0,c+96|0);ma(c+96|0,c+48|0,c+96|0);qa(c+48|0,c+96|0);d=2;while(1){qa(c+48|0,c+48|0);if((d|0)!=5){d=d+1|0;continue}break}ma(c+96|0,c+48|0,c+96|0);qa(c+48|0,c+96|0);d=2;while(1){qa(c+48|0,c+48|0);if((d|0)!=10){d=d+1|0;continue}break}ma(c+48|0,c+48|0,c+96|0);qa(c,c+48|0);d=2;while(1){qa(c,c);if((d|0)!=20){d=d+1|0;continue}break}ma(c+48|0,c,c+48|0);d=2;while(1){qa(c+48|0,c+48|0);if((d|0)!=11){d=d+1|0;continue}break}ma(c+96|0,c+48|0,c+96|0);qa(c+48|0,c+96|0);d=2;while(1){qa(c+48|0,c+48|0);if((d|0)!=50){d=d+1|0;continue}break}ma(c+48|0,c+48|0,c+96|0);qa(c,c+48|0);d=2;while(1){qa(c,c);if((d|0)!=100){d=d+1|0;continue}break}ma(c+48|0,c,c+48|0);d=2;while(1){qa(c+48|0,c+48|0);if((d|0)!=51){d=d+1|0;continue}break}ma(c+96|0,c+48|0,c+96|0);qa(c+96|0,c+96|0);qa(c+96|0,c+96|0);ma(a,c+96|0,b);V=c+144|0}function qb(a,b,c,d){var e=0,f=0,g=0,h=0,i=0,j=0,k=0,l=0;k=V-288|0;V=k;a:{if(!(c|d)){break a}e=x[a+36>>2];i=e;l=x[a+32>>2];f=c<<3;j=l+f|0;e=e+(d<<3|c>>>29)|0;x[a+32>>2]=j;x[a+36>>2]=f>>>0>j>>>0?e+1|0:e;f=((i&7)<<29|l>>>3)&63;i=64-f|0;j=0-(f>>>0>64)|0;if((j|0)==(d|0)&c>>>0>>0|d>>>0>>0){while(1){e=h+f|0;v[(a+e|0)+40|0]=y[b+h|0];e=g;g=h+1|0;e=g>>>0<1?e+1|0:e;h=g;g=e;if((c|0)!=(h|0)|(d|0)!=(e|0)){continue}break a}}while(1){e=h+f|0;v[(a+e|0)+40|0]=y[b+h|0];e=h+1|0;g=e>>>0<1?g+1|0:g;h=e;if((i|0)!=(e|0)|(g|0)!=(j|0)){continue}break}f=k+256|0;hc(a,a+40|0,k,f);b=b+i|0;g=c;c=i;d=d-((g>>>0>>0)+j|0)|0;c=g-c|0;if(!d&c>>>0>63|d){while(1){hc(a,b,k,f);b=b- -64|0;d=d-1|0;c=c+-64|0;d=c>>>0<4294967232?d+1|0:d;if(!d&c>>>0>63|d){continue}break}}b:{if(!(c|d)){break b}f=0;h=1;g=0;while(1){v[(a+f|0)+40|0]=y[b+f|0];if((c|0)==(h|0)&(d|0)==(g|0)){break b}f=h;e=f+1|0;g=e>>>0<1?g+1|0:g;h=e;continue}}oa(k,288)}V=k+288|0;return 0}function od(a,b,c,d,e){a=a|0;b=b|0;c=c|0;d=d|0;e=e|0;var f=0,g=0,h=0,i=0,j=0,k=0,l=0,m=0;pd(e);f=(d>>>0)/3|0;g=f<<2;f=D(f,-3)+d|0;a:{if(!f){break a}if(!(e&2)){g=g+4|0;break a}g=(g|2)+(f>>>1|0)|0}b:{c:{d:{e:{if(b>>>0>g>>>0){f:{if(e&4){if(!d){break c}f=8;e=0;break f}if(!d){break c}f=8;e=0;break e}while(1){j=y[c+h|0];k=j|i;while(1){i=f;f=f-6|0;l=a+e|0,m=Kf(k>>>f&63),v[l|0]=m;e=e+1|0;if(f>>>0>5){continue}break}h=h+1|0;if((h|0)!=(d|0)){f=f+8|0;i=k<<8;continue}break}if(!f){break b}c=Kf(j<<12-i&63);break d}Aa();N()}while(1){j=y[c+h|0];k=j|i;while(1){i=f;f=f-6|0;l=a+e|0,m=Jf(k>>>f&63),v[l|0]=m;e=e+1|0;if(f>>>0>5){continue}break}h=h+1|0;if((h|0)!=(d|0)){f=f+8|0;i=k<<8;continue}break}if(!f){break b}c=Jf(j<<12-i&63)}v[a+e|0]=c;e=e+1|0;break b}e=0}g:{h:{if(e>>>0<=g>>>0){if(e>>>0>>0){break h}g=e;break g}Q(1104,1201,230,1505);N()}ya(a+e|0,61,g-e|0)}c=g+1|0;ya(a+g|0,0,(b>>>0>c>>>0?b:c)-g|0);return a|0}function gh(a,b,c,d,e,f,g,h,i,j){a=a|0;b=b|0;c=c|0;d=d|0;e=e|0;f=f|0;g=g|0;h=h|0;i=i|0;j=j|0;var k=0,l=0,m=0,n=0,o=0,p=0;n=i;p=j;k=V-352|0;V=k;if(c){x[c>>2]=0;x[c+4>>2]=0}if(d){v[d|0]=255}i=-1;a:{b:{c:{if(!g&f>>>0<17){break c}j=f;l=g-(j>>>0<17)|0;m=j-17|0;j=l;if(!j&m>>>0>=4294967279|j){break b}l=a+32|0;Bb(k+32|0,64,0,l,a);Sa(k+96|0,k+32|0);oa(k+32|0,64);ta(k+96|0,h,n,p);ta(k+96|0,36304,0-n&15,0);ya(k+32|0,0,64);v[k+32|0]=y[e|0];ub(k+32|0,k+32|0,64,0,l,1,a);h=y[k+32|0];v[k+32|0]=y[e|0];ta(k+96|0,k+32|0,64,0);o=e+1|0;ta(k+96|0,o,m,j);ta(k+96|0,36304,f-1&15,0);Ba(k+24|0,n,p);ta(k+96|0,k+24|0,8,0);e=f+47|0;g=e>>>0<47?g+1|0:g;Ba(k+24|0,e,g);ta(k+96|0,k+24|0,8,0);Ra(k+96|0,k);oa(k+96|0,256);if(rb(k,m+o|0,16)){oa(k,16);break c}ub(b,o,m,j,l,2,a);oe(a+36|0,k);gf(l);d:{if(!(h&2)){if(!fb(l,4)){break d}}Mc(a)}if(c){x[c>>2]=m;x[c+4>>2]=j}i=0;if(!d){break c}v[d|0]=h}V=k+352|0;break a}Aa();N()}return i|0}function Xf(a,b){a=a|0;b=b|0;var c=0;c=V-736|0;V=c;Fb(c+704|0,b);Ga(c+224|0,b,c+704|0);Ga(c+672|0,b,c+224|0);Fb(c+640|0,c+672|0);Ga(c+416|0,c+704|0,c+640|0);Ga(c+320|0,b,c+416|0);Fb(c+608|0,c+640|0);Fb(c+288|0,c+320|0);Ga(c+576|0,c+416|0,c+288|0);Ga(c+448|0,c+608|0,c+288|0);Fb(c+544|0,c+576|0);Ga(c+384|0,c+608|0,c+544|0);Ga(c+352|0,c+224|0,c+384|0);Ga(c+192|0,c+608|0,c+352|0);Ga(c+160|0,c+672|0,c+192|0);Ga(c+96|0,c+672|0,c+160|0);Ga(c+512|0,c+544|0,c+352|0);Ga(c+480|0,c+672|0,c+512|0);Ga(c+256|0,c+448|0,c+480|0);Ga(c+128|0,c+288|0,c+256|0);Ga(c- -64|0,c+384|0,c+480|0);Ga(c+32|0,c+672|0,c- -64|0);Ga(c,c+416|0,c+32|0);Ga(a,c+320|0,c);Qa(a,126,c+352|0);Qa(a,9,c+704|0);Ga(a,a,c);Qa(a,7,c+160|0);Qa(a,9,c);Qa(a,11,c+256|0);Qa(a,8,c- -64|0);Qa(a,9,c+96|0);Qa(a,6,c+320|0);Qa(a,14,c+512|0);Qa(a,10,c+192|0);Qa(a,9,c+480|0);Qa(a,10,c);Qa(a,8,c+128|0);Qa(a,8,c+32|0);V=c+736|0;return 0-fb(b,32)|0}function Bd(a){var b=0,c=0,d=0;c=V-160|0;V=c;b=V-1760|0;V=b;Ca(b+480|0,a);kb(b+320|0,a);wa(b,b+320|0);Da(b+320|0,b,b+480|0);wa(b+160|0,b+320|0);a=b+640|0;Ca(a,b+160|0);Da(b+320|0,b,a);wa(b+160|0,b+320|0);a=b+800|0;Ca(a,b+160|0);Da(b+320|0,b,a);wa(b+160|0,b+320|0);a=b+960|0;Ca(a,b+160|0);Da(b+320|0,b,a);wa(b+160|0,b+320|0);a=b+1120|0;Ca(a,b+160|0);Da(b+320|0,b,a);wa(b+160|0,b+320|0);a=b+1280|0;Ca(a,b+160|0);Da(b+320|0,b,a);wa(b+160|0,b+320|0);a=b+1440|0;Ca(a,b+160|0);Da(b+320|0,b,a);wa(b+160|0,b+320|0);Ca(b+1600|0,b+160|0);Cd(c);a=252;while(1){kb(b+320|0,c);d=a;a=v[a+34304|0];a:{if((a|0)>=1){wa(b+160|0,b+320|0);Da(b+320|0,b+160|0,(b+480|0)+D((a&254)>>>1|0,160)|0);break a}if((a|0)>-1){break a}wa(b+160|0,b+320|0);zc(b+320|0,b+160|0,(b+480|0)+D((0-a&254)>>>1|0,160)|0)}wa(c,b+320|0);a=d-1|0;if(d){continue}break}V=b+1760|0;a=Xa(c);V=c+160|0;return a}function Ld(a,b,c,d){var e=0,f=0,g=0,h=0,i=0,j=0;a:{g=x[a+56>>2];i=x[a+60>>2];if(g|i){e=g;h=16-e|0;e=0-((e>>>0>16)+i|0)|0;f=(e|0)==(d|0)&c>>>0>>0|d>>>0>>0;h=f?c:h;e=f?d:e;j=e;if(e|h){f=0;e=0;while(1){i=f+g|0;v[(a+i|0)- -64|0]=y[b+f|0];g=x[a+56>>2];i=x[a+60>>2];f=f+1|0;e=f>>>0<1?e+1|0:e;if((h|0)!=(f|0)|(e|0)!=(j|0)){continue}break}}e=g;g=h;f=e+g|0;e=i+j|0;e=g>>>0>f>>>0?e+1|0:e;g=f;x[a+56>>2]=g;x[a+60>>2]=e;if(!e&g>>>0<16){break a}Bc(a,a- -64|0,16,0);x[a+56>>2]=0;x[a+60>>2]=0;e=c;g=h;c=e-g|0;d=d-((e>>>0>>0)+j|0)|0;b=b+g|0}if(!d&c>>>0>=16|d){e=c&-16;Bc(a,b,e,d);c=c&15;d=0;b=b+e|0}if(!(c|d)){break a}f=0;e=0;while(1){g=f+x[a+56>>2]|0;v[(a+g|0)- -64|0]=y[b+f|0];h=f+1|0;e=h>>>0<1?e+1|0:e;f=h;if((c|0)!=(f|0)|(d|0)!=(e|0)){continue}break}b=a;e=c+x[a+56>>2]|0;a=d+x[a+60>>2]|0;x[b+56>>2]=e;x[b+60>>2]=c>>>0>e>>>0?a+1|0:a}}function Ng(a,b,c,d,e){a=a|0;b=b|0;c=c|0;d=d|0;e=e|0;var f=0,g=0;g=c;c=d;f=V-96|0;V=f;d=-1;if(!oc(f+32|0,f)){ic(f- -64|0,f+32|0,e);d=kf(a+32|0,b,g,c,f- -64|0,e,f);b=x[f+60>>2];c=x[f+56>>2];v[a+24|0]=c;v[a+25|0]=c>>>8;v[a+26|0]=c>>>16;v[a+27|0]=c>>>24;v[a+28|0]=b;v[a+29|0]=b>>>8;v[a+30|0]=b>>>16;v[a+31|0]=b>>>24;b=x[f+52>>2];c=x[f+48>>2];v[a+16|0]=c;v[a+17|0]=c>>>8;v[a+18|0]=c>>>16;v[a+19|0]=c>>>24;v[a+20|0]=b;v[a+21|0]=b>>>8;v[a+22|0]=b>>>16;v[a+23|0]=b>>>24;b=x[f+44>>2];c=x[f+40>>2];v[a+8|0]=c;v[a+9|0]=c>>>8;v[a+10|0]=c>>>16;v[a+11|0]=c>>>24;v[a+12|0]=b;v[a+13|0]=b>>>8;v[a+14|0]=b>>>16;v[a+15|0]=b>>>24;b=x[f+36>>2];c=x[f+32>>2];v[a|0]=c;v[a+1|0]=c>>>8;v[a+2|0]=c>>>16;v[a+3|0]=c>>>24;v[a+4|0]=b;v[a+5|0]=b>>>8;v[a+6|0]=b>>>16;v[a+7|0]=b>>>24;oa(f,32);oa(f+32|0,32);oa(f- -64|0,24)}V=f+96|0;return d|0}function Bh(a,b,c,d,e){a=a|0;b=b|0;c=c|0;d=d|0;e=e|0;var f=0,g=0;g=c;c=d;f=V-96|0;V=f;d=-1;if(!ve(f+32|0,f)){ic(f- -64|0,f+32|0,e);d=te(a+32|0,b,g,c,f- -64|0,e,f);b=x[f+60>>2];c=x[f+56>>2];v[a+24|0]=c;v[a+25|0]=c>>>8;v[a+26|0]=c>>>16;v[a+27|0]=c>>>24;v[a+28|0]=b;v[a+29|0]=b>>>8;v[a+30|0]=b>>>16;v[a+31|0]=b>>>24;b=x[f+52>>2];c=x[f+48>>2];v[a+16|0]=c;v[a+17|0]=c>>>8;v[a+18|0]=c>>>16;v[a+19|0]=c>>>24;v[a+20|0]=b;v[a+21|0]=b>>>8;v[a+22|0]=b>>>16;v[a+23|0]=b>>>24;b=x[f+44>>2];c=x[f+40>>2];v[a+8|0]=c;v[a+9|0]=c>>>8;v[a+10|0]=c>>>16;v[a+11|0]=c>>>24;v[a+12|0]=b;v[a+13|0]=b>>>8;v[a+14|0]=b>>>16;v[a+15|0]=b>>>24;b=x[f+36>>2];c=x[f+32>>2];v[a|0]=c;v[a+1|0]=c>>>8;v[a+2|0]=c>>>16;v[a+3|0]=c>>>24;v[a+4|0]=b;v[a+5|0]=b>>>8;v[a+6|0]=b>>>16;v[a+7|0]=b>>>24;oa(f,32);oa(f+32|0,32);oa(f- -64|0,24)}V=f+96|0;return d|0}function xc(a,b,c){var d=0,e=0,f=0,g=0,h=0,i=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0,r=0,s=0,t=0,u=0,v=0,w=0,y=0;m=x[b+4>>2];n=x[a+4>>2];o=x[b+8>>2];e=x[a+8>>2];p=x[b+12>>2];f=x[a+12>>2];q=x[b+16>>2];g=x[a+16>>2];r=x[b+20>>2];h=x[a+20>>2];s=x[b+24>>2];i=x[a+24>>2];t=x[b+28>>2];j=x[a+28>>2];u=x[b+32>>2];k=x[a+32>>2];v=x[b+36>>2];l=x[a+36>>2];c=0-c|0;w=x[b>>2];d=x[a>>2];y=c&(w^d);x[a>>2]=y^d;d=l;l=c&(l^v);x[a+36>>2]=d^l;d=k;k=c&(k^u);x[a+32>>2]=d^k;d=j;j=c&(j^t);x[a+28>>2]=d^j;d=i;i=c&(i^s);x[a+24>>2]=d^i;d=h;h=c&(h^r);x[a+20>>2]=d^h;d=g;g=c&(g^q);x[a+16>>2]=d^g;d=f;f=c&(f^p);x[a+12>>2]=d^f;d=e;e=c&(e^o);x[a+8>>2]=d^e;d=a;a=c&(m^n);x[d+4>>2]=a^n;x[b+36>>2]=l^v;x[b+32>>2]=k^u;x[b+28>>2]=j^t;x[b+24>>2]=i^s;x[b+20>>2]=h^r;x[b+16>>2]=g^q;x[b+12>>2]=f^p;x[b+8>>2]=e^o;x[b+4>>2]=a^m;x[b>>2]=w^y}function gg(a,b){var c=0,d=0;c=V-672|0;V=c;Ea(c+528|0);qa(c+480|0,b);ma(c+480|0,2224,c+480|0);va(c+240|0,c+480|0,c+528|0);ma(c+240|0,c+240|0,34608);Ea(c+624|0);Wa(c+624|0,c+624|0);va(c+432|0,c+480|0,2176);ma(c+192|0,c+480|0,2176);xa(c+192|0,c+624|0,c+192|0);ma(c+192|0,c+192|0,c+432|0);d=zd(c+384|0,c+240|0,c+192|0);ma(c+336|0,c+384|0,b);yc(c+336|0,c+336|0);Wa(c+336|0,c+336|0);b=1-d|0;Ma(c+384|0,c+336|0,b);Ma(c+624|0,c+480|0,b);xa(c+576|0,c+480|0,c+528|0);ma(c+576|0,c+576|0,c+624|0);ma(c+576|0,c+576|0,34656);xa(c+576|0,c+576|0,c+192|0);va(c+144|0,c+384|0,c+384|0);ma(c+144|0,c+144|0,c+192|0);ma(c+96|0,c+576|0,34704);qa(c+288|0,c+384|0);xa(c+48|0,c+528|0,c+288|0);va(c,c+528|0,c+288|0);ma(a,c+144|0,c);ma(a+40|0,c+48|0,c+96|0);ma(a+80|0,c+96|0,c);ma(a+120|0,c+144|0,c+48|0);V=c+672|0}function Md(a,b){var c=0;x[a>>2]=(y[b|0]|y[b+1|0]<<8|(y[b+2|0]<<16|y[b+3|0]<<24))&67108863;x[a+4>>2]=(y[b+3|0]|y[b+4|0]<<8|(y[b+5|0]<<16|y[b+6|0]<<24))>>>2&67108611;x[a+8>>2]=(y[b+6|0]|y[b+7|0]<<8|(y[b+8|0]<<16|y[b+9|0]<<24))>>>4&67092735;x[a+12>>2]=(y[b+9|0]|y[b+10|0]<<8|(y[b+11|0]<<16|y[b+12|0]<<24))>>>6&66076671;c=y[b+12|0]|y[b+13|0]<<8|(y[b+14|0]<<16|y[b+15|0]<<24);x[a+20>>2]=0;x[a+24>>2]=0;x[a+28>>2]=0;x[a+32>>2]=0;x[a+36>>2]=0;x[a+16>>2]=c>>>8&1048575;x[a+40>>2]=y[b+16|0]|y[b+17|0]<<8|(y[b+18|0]<<16|y[b+19|0]<<24);x[a+44>>2]=y[b+20|0]|y[b+21|0]<<8|(y[b+22|0]<<16|y[b+23|0]<<24);x[a+48>>2]=y[b+24|0]|y[b+25|0]<<8|(y[b+26|0]<<16|y[b+27|0]<<24);b=y[b+28|0]|y[b+29|0]<<8|(y[b+30|0]<<16|y[b+31|0]<<24);v[a+80|0]=0;x[a+56>>2]=0;x[a+60>>2]=0;x[a+52>>2]=b}function hh(a,b,c,d,e,f,g,h,i,j){a=a|0;b=b|0;c=c|0;d=d|0;e=e|0;f=f|0;g=g|0;h=h|0;i=i|0;j=j|0;var k=0,l=0;k=e;e=f;f=k|0;k=V-336|0;V=k;if(c){x[c>>2]=0;x[c+4>>2]=0}a:{if(!e&f>>>0<4294967279){l=a+32|0;Bb(k+16|0,64,0,l,a);Sa(k+80|0,k+16|0);oa(k+16|0,64);ta(k+80|0,g,h,i);ta(k+80|0,36304,0-h&15,0);ya(k+16|0,0,64);v[k+16|0]=j;ub(k+16|0,k+16|0,64,0,l,1,a);ta(k+80|0,k+16|0,64,0);v[b|0]=y[k+16|0];g=b+1|0;ub(g,d,f,e,l,2,a);ta(k+80|0,g,f,e);ta(k+80|0,36304,f&15,0);Ba(k+8|0,h,i);ta(k+80|0,k+8|0,8,0);Ba(k+8|0,f- -64|0,e-((f>>>0<4294967232)-1|0)|0);ta(k+80|0,k+8|0,8,0);b=f+g|0;Ra(k+80|0,b);oa(k+80|0,256);oe(a+36|0,b);gf(l);b:{if(!(j&2)){if(!fb(l,4)){break b}}Mc(a)}if(c){a=f+17|0;e=a>>>0<17?e+1|0:e;x[c>>2]=a;x[c+4>>2]=e}V=k+336|0;break a}Aa();N()}return 0}function kj(a,b,c,d,e,f,g){a=a|0;b=b|0;c=c|0;d=d|0;e=e|0;f=f|0;g=g|0;var h=0,i=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0;a:{b:{if(!d){break b}c:{d:{e:while(1){i=h;while(1){f:{m=y[c+i|0];j=(m&223)-55&255;n=(j+65526^j+65520)>>>8|0;o=m^48;p=o+65526>>>8|0;if(!((n|p)&255)){j=1;if(!e|l&255){break d}if(Pb(e,m)){break f}h=i;break b}if(b>>>0<=k>>>0){x[9301]=68;j=0;break d}h=j&n|o&p;g:{if(!(l&255)){q=h<<4;break g}v[a+k|0]=h|q;k=k+1|0}l=l^-1;j=1;h=i+1|0;if(h>>>0>>0){continue e}break c}l=0;i=i+1|0;if(i>>>0>>0){continue}break}break}a=h+1|0;h=a>>>0>>0?d:a;break b}h=i}if(l&255){x[9301]=28;h=h-1|0;k=0;i=-1;break a}if(j){break b}k=0;i=-1;break a}i=0}h:{if(g){x[g>>2]=c+h;break h}if((d|0)==(h|0)){break h}x[9301]=28;i=-1}if(f){x[f>>2]=k}return i|0}function cb(a,b){var c=0,d=0;d=V-48|0;V=d;Hd(d,b);b=x[d>>2];v[a|0]=b;v[a+2|0]=b>>>16;v[a+1|0]=b>>>8;c=x[d+4>>2];v[a+5|0]=c>>>14;v[a+4|0]=c>>>6;v[a+3|0]=c<<2|b>>>24;b=x[d+8>>2];v[a+8|0]=b>>>13;v[a+7|0]=b>>>5;v[a+6|0]=b<<3|c>>>22;c=x[d+12>>2];v[a+11|0]=c>>>11;v[a+10|0]=c>>>3;v[a+9|0]=c<<5|b>>>21;b=x[d+16>>2];v[a+15|0]=b>>>18;v[a+14|0]=b>>>10;v[a+13|0]=b>>>2;v[a+12|0]=b<<6|c>>>19;b=x[d+20>>2];v[a+16|0]=b;v[a+18|0]=b>>>16;v[a+17|0]=b>>>8;c=x[d+24>>2];v[a+21|0]=c>>>15;v[a+20|0]=c>>>7;v[a+19|0]=c<<1|b>>>24;b=x[d+28>>2];v[a+24|0]=b>>>13;v[a+23|0]=b>>>5;v[a+22|0]=b<<3|c>>>23;c=x[d+32>>2];v[a+27|0]=c>>>12;v[a+26|0]=c>>>4;v[a+25|0]=c<<4|b>>>21;b=x[d+36>>2];v[a+31|0]=b>>>18;v[a+30|0]=b>>>10;v[a+29|0]=b>>>2;v[a+28|0]=b<<6|c>>>20;V=d+48|0}function Jb(a,b,c,d){var e=0,f=0,g=0,h=0,i=0,j=0;a:{if(!(c|d)){break a}j=a+224|0;g=a+96|0;e=y[a+352|0]|y[a+353|0]<<8|(y[a+354|0]<<16|y[a+355|0]<<24);while(1){h=(a+e|0)+96|0;f=256-e|0;i=f;if(!d&c>>>0<=f>>>0){za(h,b,c);b=c+(y[a+352|0]|y[a+353|0]<<8|(y[a+354|0]<<16|y[a+355|0]<<24))|0;v[a+352|0]=b;v[a+353|0]=b>>>8;v[a+354|0]=b>>>16;v[a+355|0]=b>>>24;break a}za(h,b,f);e=(y[a+352|0]|y[a+353|0]<<8|(y[a+354|0]<<16|y[a+355|0]<<24))+f|0;v[a+352|0]=e;v[a+353|0]=e>>>8;v[a+354|0]=e>>>16;v[a+355|0]=e>>>24;Jc(a,128);Wc(a,g);za(g,j,128);e=(y[a+352|0]|y[a+353|0]<<8|(y[a+354|0]<<16|y[a+355|0]<<24))-128|0;v[a+352|0]=e;v[a+353|0]=e>>>8;v[a+354|0]=e>>>16;v[a+355|0]=e>>>24;b=b+f|0;f=c;c=f-i|0;d=d-(f>>>0>>0)|0;if(c|d){continue}break}}return 0}function Uc(a,b,c,d,e,f){var g=0,h=0,i=0;x[f>>2]=8;i=d;a:{b:{h=a;a=!b&a>>>0>32768|(b|0)!=0;g=a?h:32768;h=a?b:0;a=h;if(!a&c>>>5>>>0<=g>>>0|a){c=c>>>11|0;a=1;b=0;while(1){if(!((a&63)>>>0>=32?0:c>>>a|0)){break b}a=a+1|0;b=a>>>0<1?b+1|0:b;if(b|(a|0)!=63){continue}break}a=63;break b}x[e>>2]=1;a=Ej(g,h,x[f>>2]<<2);b=Y;c=b>>>1|0;f=(b&1)<<31|a>>>1;a=1;b=0;while(1){d=c;h=f;g=a&31;if((a&63)>>>0>=32){e=0;d=d>>>g|0}else{e=d>>>g|0;d=((1<>>g}if(!(d|e)){break a}a=a+1|0;b=a>>>0<1?b+1|0:b;if(b|(a|0)!=63){continue}break}a=63;break a}x[d>>2]=a;c=h>>>2|0;d=(h&3)<<30|g>>>2;b=a&31;if((a&63)>>>0>=32){a=0;b=c>>>b|0}else{a=c>>>b|0;b=((1<>>b}x[e>>2]=((!a&b>>>0<1073741823?b:1073741823)>>>0)/A[f>>2];return}x[i>>2]=a}function Ei(a,b){a=a|0;b=b|0;var c=0,d=0;d=V+-64|0;V=d;Qb(d,b,32,0);v[d|0]=y[d|0]&248;v[d+31|0]=y[d+31|0]&63|64;b=x[d+20>>2];c=x[d+16>>2];v[a+16|0]=c;v[a+17|0]=c>>>8;v[a+18|0]=c>>>16;v[a+19|0]=c>>>24;v[a+20|0]=b;v[a+21|0]=b>>>8;v[a+22|0]=b>>>16;v[a+23|0]=b>>>24;b=x[d+12>>2];c=x[d+8>>2];v[a+8|0]=c;v[a+9|0]=c>>>8;v[a+10|0]=c>>>16;v[a+11|0]=c>>>24;v[a+12|0]=b;v[a+13|0]=b>>>8;v[a+14|0]=b>>>16;v[a+15|0]=b>>>24;b=x[d+4>>2];c=x[d>>2];v[a|0]=c;v[a+1|0]=c>>>8;v[a+2|0]=c>>>16;v[a+3|0]=c>>>24;v[a+4|0]=b;v[a+5|0]=b>>>8;v[a+6|0]=b>>>16;v[a+7|0]=b>>>24;b=x[d+28>>2];c=x[d+24>>2];v[a+24|0]=c;v[a+25|0]=c>>>8;v[a+26|0]=c>>>16;v[a+27|0]=c>>>24;v[a+28|0]=b;v[a+29|0]=b>>>8;v[a+30|0]=b>>>16;v[a+31|0]=b>>>24;oa(d,64);V=d- -64|0;return 0}function Yb(a,b){var c=0,d=0,e=0,f=0,g=0;c=V-464|0;V=c;while(1){e=d<<1;g=y[b+d|0];v[e+(c+400|0)|0]=g&15;v[(c+400|0)+(e|1)|0]=g>>>4;d=d+1|0;if((d|0)!=32){continue}break}d=0;while(1){b=d;d=(c+400|0)+f|0;e=b+y[d|0]|0;b=(e<<24)- -134217728|0;v[d|0]=e-(b>>24&240);d=b>>28;f=f+1|0;if((f|0)!=63){continue}break}v[c+463|0]=y[c+463|0]+d;Cd(a);d=1;while(1){mg(c,d>>>1|0,v[(c+400|0)+d|0]);Ed(c+240|0,a,c);wa(a,c+240|0);b=d>>>0<62;d=d+2|0;if(b){continue}break}kb(c+240|0,a);ab(c+120|0,c+240|0);Va(c+240|0,c+120|0);ab(c+120|0,c+240|0);Va(c+240|0,c+120|0);ab(c+120|0,c+240|0);Va(c+240|0,c+120|0);wa(a,c+240|0);d=0;while(1){mg(c,d>>>1|0,v[(c+400|0)+d|0]);Ed(c+240|0,a,c);wa(a,c+240|0);b=d>>>0<62;d=d+2|0;if(b){continue}break}V=c+464|0}function qd(a,b,c){a=a|0;b=b|0;c=c|0;var d=0,e=0;e=V+-64|0;V=e;Qb(e,c,32,0);c=x[e+28>>2];d=x[e+24>>2];v[b+24|0]=d;v[b+25|0]=d>>>8;v[b+26|0]=d>>>16;v[b+27|0]=d>>>24;v[b+28|0]=c;v[b+29|0]=c>>>8;v[b+30|0]=c>>>16;v[b+31|0]=c>>>24;c=x[e+20>>2];d=x[e+16>>2];v[b+16|0]=d;v[b+17|0]=d>>>8;v[b+18|0]=d>>>16;v[b+19|0]=d>>>24;v[b+20|0]=c;v[b+21|0]=c>>>8;v[b+22|0]=c>>>16;v[b+23|0]=c>>>24;c=x[e+12>>2];d=x[e+8>>2];v[b+8|0]=d;v[b+9|0]=d>>>8;v[b+10|0]=d>>>16;v[b+11|0]=d>>>24;v[b+12|0]=c;v[b+13|0]=c>>>8;v[b+14|0]=c>>>16;v[b+15|0]=c>>>24;c=x[e+4>>2];d=x[e>>2];v[b|0]=d;v[b+1|0]=d>>>8;v[b+2|0]=d>>>16;v[b+3|0]=d>>>24;v[b+4|0]=c;v[b+5|0]=c>>>8;v[b+6|0]=c>>>16;v[b+7|0]=c>>>24;oa(e,64);a=vc(a,b);V=e- -64|0;return a|0}function Vb(a,b){var c=0,d=0,e=0,f=0;c=V-864|0;V=c;f=b+80|0;e=b+40|0;va(c+336|0,f,e);xa(c,f,e);ma(c+336|0,c+336|0,c);ma(c+288|0,b,e);qa(c+240|0,c+288|0);ma(c+240|0,c+336|0,c+240|0);Ea(c+480|0);zd(c+624|0,c+480|0,c+240|0);ma(c+816|0,c+624|0,c+336|0);ma(c+768|0,c+624|0,c+288|0);ma(c+48|0,c+816|0,c+768|0);d=b+120|0;ma(c+48|0,c+48|0,d);ma(c+576|0,b,2224);ma(c+528|0,e,2224);ma(c+672|0,c+816|0,3536);ma(c+384|0,d,c+48|0);d=nb(c+384|0);La(c+192|0,b);La(c+144|0,e);La(c+720|0,c+768|0);Ma(c+192|0,c+528|0,d);Ma(c+144|0,c+576|0,d);Ma(c+720|0,c+672|0,d);ma(c+96|0,c+192|0,c+48|0);hg(c+144|0,c+144|0,nb(c+96|0));xa(c+432|0,f,c+144|0);ma(c+432|0,c+720|0,c+432|0);yc(c+432|0,c+432|0);cb(a,c+432|0);V=c+864|0}function Jg(a,b,c,d,e,f,g){a=a|0;b=b|0;c=c|0;d=d|0;e=e|0;f=f|0;g=g|0;var h=0,i=0,j=0,k=0,l=0;h=e;e=V-128|0;V=e;j=ya(a,0,102);k=c;a:{b:{if((d|0)==1|d>>>0>1){x[9301]=22;break b}Uc(h,f,g,e+12|0,e+8|0,e+4|0);Pa(e+96|0,32);g=e+96|0;c=e+32|0;a=0;d=x[e+12>>2];h=x[e+8>>2];f=x[e+4>>2];l=Fj(h,0,f,0);i=Y;c:{if(d>>>0>63|(!i&l>>>0>1073741823|i)){break c}v[c|0]=36;v[c+1|0]=55;v[c+2|0]=36;v[c+3|0]=y[d+1024|0];d=Vc(c+4|0,54,f,30);if(!d){break c}f=c+58|0;d=Vc(d,f-d|0,h,30);if(!d){break c}d=Ne(d,f-d|0,g);if(!d|d>>>0>=f>>>0){break c}v[d|0]=0;a=c}if(!a){x[9301]=28;break b}a=-1;if(_c(e+16|0)){break a}b=Oe(e+16|0,b,k,e+32|0,j);Zc(e+16|0);a=0;if(b){break a}x[9301]=28}a=-1}V=e+128|0;return a|0}function sd(a,b){a=a|0;b=b|0;var c=0,d=0;c=V+-64|0;V=c;b=za(c,b,64);Eb(b);c=x[b+28>>2];d=x[b+24>>2];v[a+24|0]=d;v[a+25|0]=d>>>8;v[a+26|0]=d>>>16;v[a+27|0]=d>>>24;v[a+28|0]=c;v[a+29|0]=c>>>8;v[a+30|0]=c>>>16;v[a+31|0]=c>>>24;c=x[b+20>>2];d=x[b+16>>2];v[a+16|0]=d;v[a+17|0]=d>>>8;v[a+18|0]=d>>>16;v[a+19|0]=d>>>24;v[a+20|0]=c;v[a+21|0]=c>>>8;v[a+22|0]=c>>>16;v[a+23|0]=c>>>24;c=x[b+12>>2];d=x[b+8>>2];v[a+8|0]=d;v[a+9|0]=d>>>8;v[a+10|0]=d>>>16;v[a+11|0]=d>>>24;v[a+12|0]=c;v[a+13|0]=c>>>8;v[a+14|0]=c>>>16;v[a+15|0]=c>>>24;c=x[b+4>>2];d=x[b>>2];v[a|0]=d;v[a+1|0]=d>>>8;v[a+2|0]=d>>>16;v[a+3|0]=d>>>24;v[a+4|0]=c;v[a+5|0]=c>>>8;v[a+6|0]=c>>>16;v[a+7|0]=c>>>24;oa(b,64);V=b- -64|0}function Db(a,b){var c=0,d=0,e=0,f=0;c=V-480|0;V=c;f=y[b+31|0];e=(f^-1)&127;d=30;while(1){e=y[b+d|0]^-1|e;d=d-1|0;if(d){continue}break}d=(e&255)-1|0;e=y[b|0];if((((d&236-e)>>>8|(e|f>>>7))^-1)&1){db(c+336|0,b);qa(c+288|0,c+336|0);Ea(c+240|0);xa(c+240|0,c+240|0,c+288|0);qa(c+144|0,c+240|0);Ea(c+192|0);va(c+192|0,c+192|0,c+288|0);qa(c+96|0,c+192|0);ma(c+48|0,2176,c+144|0);Wa(c+48|0,c+48|0);xa(c+48|0,c+48|0,c+96|0);ma(c,c+48|0,c+96|0);Ea(c+384|0);e=zd(c+432|0,c+384|0,c);ma(a,c+432|0,c+192|0);b=a+40|0;ma(b,c+432|0,a);ma(b,b,c+48|0);ma(a,a,c+336|0);va(a,a,a);yc(a,a);ma(b,c+240|0,b);Ea(a+80|0);d=a+120|0;ma(d,a,b);a=0-(nb(d)|1-e|Xa(b))|0}else{a=-1}V=c+480|0;return a}function ke(a,b){a=a|0;b=b|0;var c=0,d=0;d=V+-64|0;V=d;ed(a,d);c=x[d+28>>2];a=x[d+24>>2];v[b+24|0]=a;v[b+25|0]=a>>>8;v[b+26|0]=a>>>16;v[b+27|0]=a>>>24;v[b+28|0]=c;v[b+29|0]=c>>>8;v[b+30|0]=c>>>16;v[b+31|0]=c>>>24;c=x[d+20>>2];a=x[d+16>>2];v[b+16|0]=a;v[b+17|0]=a>>>8;v[b+18|0]=a>>>16;v[b+19|0]=a>>>24;v[b+20|0]=c;v[b+21|0]=c>>>8;v[b+22|0]=c>>>16;v[b+23|0]=c>>>24;c=x[d+12>>2];a=x[d+8>>2];v[b+8|0]=a;v[b+9|0]=a>>>8;v[b+10|0]=a>>>16;v[b+11|0]=a>>>24;v[b+12|0]=c;v[b+13|0]=c>>>8;v[b+14|0]=c>>>16;v[b+15|0]=c>>>24;c=x[d+4>>2];a=x[d>>2];v[b|0]=a;v[b+1|0]=a>>>8;v[b+2|0]=a>>>16;v[b+3|0]=a>>>24;v[b+4|0]=c;v[b+5|0]=c>>>8;v[b+6|0]=c>>>16;v[b+7|0]=c>>>24;V=d- -64|0;return 0}function Lf(a,b){var c=0,d=0,e=0,f=0,g=0,h=0;if(b>>>0>4294967168){a=48}else{a:{if(b>>>0>=4294967168){x[9301]=48;c=0;break a}f=b>>>0<11?16:b+11&-8;b=Za(f+76|0);c=0;if(!b){break a}c=b-8|0;b:{if(!(b&63)){b=c;break b}g=b-4|0;h=x[g>>2];b=(b+63&-64)-8|0;b=b-c>>>0>15?b:b- -64|0;d=b-c|0;e=(h&-8)-d|0;if(!(h&3)){c=x[c>>2];x[b+4>>2]=e;x[b>>2]=c+d;break b}x[b+4>>2]=e|x[b+4>>2]&1|2;e=b+e|0;x[e+4>>2]=x[e+4>>2]|1;x[g>>2]=d|x[g>>2]&1|2;e=c+d|0;x[e+4>>2]=x[e+4>>2]|1;Gf(c,d)}c=x[b+4>>2];c:{if(!(c&3)){break c}d=c&-8;if(d>>>0<=f+16>>>0){break c}x[b+4>>2]=f|c&1|2;c=b+f|0;f=d-f|0;x[c+4>>2]=f|3;d=b+d|0;x[d+4>>2]=x[d+4>>2]|1;Gf(c,f)}c=b+8|0}if(!c){return 48}x[a>>2]=c;a=0}return a}function Hd(a,b){var c=0,d=0,e=0,f=0,g=0,h=0,i=0,j=0,k=0;e=x[b+28>>2];f=x[b+24>>2];g=x[b+20>>2];h=x[b+16>>2];i=x[b+12>>2];j=x[b+8>>2];k=x[b+4>>2];c=x[b>>2];d=x[b+36>>2];b=x[b+32>>2];c=D(((e+(f+(g+(h+(i+(j+(k+(c+(D(d,19)+16777216>>>25|0)>>26)>>25)>>26)>>25)>>26)>>25)>>26)>>25)+b>>26)+d>>25,19)+c|0;x[a>>2]=c&67108863;c=k+(c>>26)|0;x[a+4>>2]=c&33554431;c=j+(c>>25)|0;x[a+8>>2]=c&67108863;c=i+(c>>26)|0;x[a+12>>2]=c&33554431;c=h+(c>>25)|0;x[a+16>>2]=c&67108863;c=g+(c>>26)|0;x[a+20>>2]=c&33554431;c=f+(c>>25)|0;x[a+24>>2]=c&67108863;c=e+(c>>26)|0;x[a+28>>2]=c&33554431;b=b+(c>>25)|0;x[a+32>>2]=b&67108863;x[a+36>>2]=d+(b>>26)&33554431}function df(a,b,c,d,e,f,g,h,i,j){var k=0;k=V-48|0;V=k;x[k+8>>2]=0;x[k>>2]=0;x[k+4>>2]=0;bb(k+16|0,i,j,0);j=y[i+20|0]|y[i+21|0]<<8|(y[i+22|0]<<16|y[i+23|0]<<24);x[k+4>>2]=y[i+16|0]|y[i+17|0]<<8|(y[i+18|0]<<16|y[i+19|0]<<24);x[k+8>>2]=j;i=V-352|0;V=i;j=k+16|0;wd(i+32|0,64,0,k,j);Sa(i+96|0,i+32|0);oa(i+32|0,64);ta(i+96|0,f,g,h);ta(i+96|0,35936,0-g&15,0);ta(i+96|0,b,c,d);ta(i+96|0,35936,0-c&15,0);Ba(i+24|0,g,h);ta(i+96|0,i+24|0,8,0);Ba(i+24|0,c,d);ta(i+96|0,i+24|0,8,0);Ra(i+96|0,i);oa(i+96|0,256);e=Gb(i,e);oa(i,16);a:{if(!a){break a}if(e){ya(a,0,c);e=-1;break a}vd(a,b,c,d,k,1,j);e=0}V=i+352|0;oa(k+16|0,32);V=k+48|0;return e}function dd(a,b,c,d,e,f,g){var h=0,i=0,j=0,k=0,l=0;h=V-352|0;V=h;bb(h,f,g,0);if(!e&d>>>0<=c-a>>>0|a>>>0>=c>>>0?!e&d>>>0>a-c>>>0|e?a>>>0>c>>>0:0:1){c=yb(a,c,d)}x[h+56>>2]=0;x[h+60>>2]=0;x[h+48>>2]=0;x[h+52>>2]=0;x[h+40>>2]=0;x[h+44>>2]=0;x[h+32>>2]=0;x[h+36>>2]=0;i=!e&d>>>0>32|(e|0)!=0;g=i?32:d;j=i?0:e;i=j;k=!(g|i);if(!k){za(h- -64|0,c,g)}j=f+16|0;l=g+32|0;f=l>>>0<32?i+1|0:i;qc(h+32|0,h+32|0,l,f,j,h);Sa(h+96|0,h+32|0);if(!k){za(a,h- -64|0,g)}oa(h+32|0,64);if(!e&d>>>0>=33|e){f=c+g|0;c=d;Cb(a+g|0,f,c-g|0,e-(i+(c>>>0>>0)|0)|0,j,1,0,h)}oa(h,32);ta(h+96|0,a,d,e);Ra(h+96|0,b);oa(h+96|0,256);V=h+352|0;return 0}function Rc(a,b,c,d,e,f,g){var h=0,i=0,j=0,k=0,l=0;h=V-352|0;V=h;Ab(h,f,g,0);if(!e&d>>>0<=c-a>>>0|a>>>0>=c>>>0?!e&d>>>0>a-c>>>0|e?a>>>0>c>>>0:0:1){c=yb(a,c,d)}x[h+56>>2]=0;x[h+60>>2]=0;x[h+48>>2]=0;x[h+52>>2]=0;x[h+40>>2]=0;x[h+44>>2]=0;x[h+32>>2]=0;x[h+36>>2]=0;i=!e&d>>>0>32|(e|0)!=0;g=i?32:d;j=i?0:e;i=j;k=!(g|i);if(!k){za(h- -64|0,c,g)}j=f+16|0;l=g+32|0;f=l>>>0<32?i+1|0:i;tc(h+32|0,h+32|0,l,f,j,h);Sa(h+96|0,h+32|0);if(!k){za(a,h- -64|0,g)}oa(h+32|0,64);if(!e&d>>>0>=33|e){f=c+g|0;c=d;uc(a+g|0,f,c-g|0,e-(i+(c>>>0>>0)|0)|0,j,1,0,h)}oa(h,32);ta(h+96|0,a,d,e);Ra(h+96|0,b);oa(h+96|0,256);V=h+352|0;return 0}function Jc(a,b){var c=0,d=0,e=0,f=0,g=0;c=a- -64|0;d=c;e=y[c+4|0]|y[c+5|0]<<8|(y[c+6|0]<<16|y[c+7|0]<<24);f=e;g=f+1|0;f=y[c|0]|y[c+1|0]<<8|(y[c+2|0]<<16|y[c+3|0]<<24);c=f;b=b+c|0;c=b>>>0>>0?g:e;v[d|0]=b;v[d+1|0]=b>>>8;v[d+2|0]=b>>>16;v[d+3|0]=b>>>24;v[d+4|0]=c;v[d+5|0]=c>>>8;v[d+6|0]=c>>>16;v[d+7|0]=c>>>24;c=(c|0)==(e|0)&b>>>0>>0|c>>>0>>0;b=c+(y[a+72|0]|y[a+73|0]<<8|(y[a+74|0]<<16|y[a+75|0]<<24))|0;d=y[a+76|0]|y[a+77|0]<<8|(y[a+78|0]<<16|y[a+79|0]<<24);c=b>>>0>>0?d+1|0:d;v[a+72|0]=b;v[a+73|0]=b>>>8;v[a+74|0]=b>>>16;v[a+75|0]=b>>>24;v[a+76|0]=c;v[a+77|0]=c>>>8;v[a+78|0]=c>>>16;v[a+79|0]=c>>>24}function sc(a,b){x[a>>2]=1634760805;x[a+4>>2]=857760878;x[a+8>>2]=2036477234;x[a+12>>2]=1797285236;x[a+16>>2]=y[b|0]|y[b+1|0]<<8|(y[b+2|0]<<16|y[b+3|0]<<24);x[a+20>>2]=y[b+4|0]|y[b+5|0]<<8|(y[b+6|0]<<16|y[b+7|0]<<24);x[a+24>>2]=y[b+8|0]|y[b+9|0]<<8|(y[b+10|0]<<16|y[b+11|0]<<24);x[a+28>>2]=y[b+12|0]|y[b+13|0]<<8|(y[b+14|0]<<16|y[b+15|0]<<24);x[a+32>>2]=y[b+16|0]|y[b+17|0]<<8|(y[b+18|0]<<16|y[b+19|0]<<24);x[a+36>>2]=y[b+20|0]|y[b+21|0]<<8|(y[b+22|0]<<16|y[b+23|0]<<24);x[a+40>>2]=y[b+24|0]|y[b+25|0]<<8|(y[b+26|0]<<16|y[b+27|0]<<24);x[a+44>>2]=y[b+28|0]|y[b+29|0]<<8|(y[b+30|0]<<16|y[b+31|0]<<24)}function Oe(a,b,c,d,e){var f=0,g=0,h=0,i=0,j=0,k=0,l=0,m=0;f=V-48|0;V=f;j=Re(d,f+12|0,f+8|0,f+4|0);a:{if(!j){break a}k=x[f+12>>2];g=Ta(j)+1|0;while(1){b:{h=0;if(!g){break b}g=g-1|0;h=g+j|0;if(y[h|0]!=36){continue}}break}i=h-j|0;c:{if(h){break c}i=Ta(j)}h=i;g=h+(j-d|0)|0;i=g+45|0;if(i>>>0>102|h>>>0>i>>>0){break a}i=a;l=b;a=k&31;if((k&63)>>>0>=32){b=1<>>32-a;a=1<>2],x[f+4>>2],f+16|0,32)){break a}a=za(e,d,g);b=a+g|0;v[b|0]=36;b=b+1|0;c=a+102|0;b=Ne(b,c-b|0,f+16|0);oa(f+16|0,32);if(!b|b>>>0>=c>>>0){break a}v[b|0]=0;m=a}V=f+48|0;return m}function ef(a,b,c,d,e,f,g,h,i,j,k){var l=0;l=V-48|0;V=l;x[l+8>>2]=0;x[l>>2]=0;x[l+4>>2]=0;bb(l+16|0,j,k,0);k=y[j+20|0]|y[j+21|0]<<8|(y[j+22|0]<<16|y[j+23|0]<<24);x[l+4>>2]=y[j+16|0]|y[j+17|0]<<8|(y[j+18|0]<<16|y[j+19|0]<<24);x[l+8>>2]=k;j=V-336|0;V=j;k=l+16|0;wd(j+16|0,64,0,l,k);Sa(j+80|0,j+16|0);oa(j+16|0,64);ta(j+80|0,g,h,i);ta(j+80|0,35936,0-h&15,0);vd(a,d,e,f,l,1,k);ta(j+80|0,a,e,f);ta(j+80|0,35936,0-e&15,0);Ba(j+8|0,h,i);ta(j+80|0,j+8|0,8,0);Ba(j+8|0,e,f);ta(j+80|0,j+8|0,8,0);Ra(j+80|0,b);oa(j+80|0,256);if(c){x[c>>2]=16;x[c+4>>2]=0}V=j+336|0;oa(l+16|0,32);V=l+48|0;return 0}function Dc(a){var b=0,c=0,d=0;if(!a){return-25}if(!x[a>>2]){return-1}a:{b=-2;b:{if(A[a+4>>2]<16){break b}if(!x[a+8>>2]){b=-18;if(x[a+12>>2]){break b}}c=x[a+20>>2];if(!x[a+16>>2]){break a}b=-6;if(c>>>0<8){break b}if(!x[a+24>>2]){b=-20;if(x[a+28>>2]){break b}}if(!x[a+32>>2]){b=-21;if(x[a+36>>2]){break b}}c=x[a+48>>2];if(!c){return-16}b=-17;if(c>>>0>16777215){break b}d=x[a+44>>2];b=-14;if(d>>>0<8){break b}b=-15;if(d>>>0>2097152){break b}b=-14;if(c<<3>>>0>d>>>0){break b}if(!x[a+40>>2]){return-12}a=x[a+52>>2];if(!a){return-28}b=a>>>0>16777215?-29:0}return b}return c?-19:-6}function gd(a,b,c){a=a|0;b=b|0;c=c|0;var d=0,e=0,f=0;d=V-192|0;V=d;if(c>>>0>=129){sb(a);Na(a,b,c,0);_a(a,d);c=64;b=d}sb(a);ya(d- -64|0,54,128);a:{if(!c){break a}v[d+64|0]=y[b|0]^54;e=1;if((c|0)==1){break a}while(1){f=(d- -64|0)+e|0;v[f|0]=y[f|0]^y[b+e|0];e=e+1|0;if((e|0)!=(c|0)){continue}break}}Na(a,d- -64|0,128,0);a=a+208|0;sb(a);ya(d- -64|0,92,128);b:{if(!c){break b}v[d+64|0]=y[b|0]^92;e=1;if((c|0)==1){break b}while(1){f=(d- -64|0)+e|0;v[f|0]=y[f|0]^y[b+e|0];e=e+1|0;if((e|0)!=(c|0)){continue}break}}Na(a,d- -64|0,128,0);oa(d- -64|0,128);oa(d,64);V=d+192|0;return 0}function cd(a,b,c,d,e,f,g){var h=0,i=0,j=0,k=0;h=V-96|0;V=h;bb(h,f,g,0);j=f+16|0;Rb(h+32|0,32,0,j,h);f=-1;a:{b:{if(Zb(c,b,d,e,h+32|0)){break b}f=0;if(!a){break a}if(!e&d>>>0<=a-b>>>0|a>>>0<=b>>>0?!e&d>>>0>b-a>>>0|e?a>>>0>>0:0:1){b=yb(a,b,d)}f=!e&d>>>0>32|(e|0)!=0;c=f?32:d;f=f?0:e;g=f;c:{if(!(c|f)){f=g;i=c+32|0;f=i>>>0<32?f+1|0:f;qc(h+32|0,h+32|0,i,f,j,h);break c}k=za(h- -64|0,b,c);f=g;i=c+32|0;f=i>>>0<32?f+1|0:f;qc(h+32|0,h+32|0,i,f,j,h);za(a,k,c)}f=0;if(!e&d>>>0<33){break b}i=a;a=c;Cb(i+a|0,a+b|0,d-a|0,e-(g+(a>>>0>d>>>0)|0)|0,j,1,0,h)}oa(h,32)}V=h+96|0;return f}function Qc(a,b,c,d,e,f,g){var h=0,i=0,j=0,k=0;h=V-96|0;V=h;Ab(h,f,g,0);j=f+16|0;xd(h+32|0,32,0,j,h);f=-1;a:{b:{if(Zb(c,b,d,e,h+32|0)){break b}f=0;if(!a){break a}if(!e&d>>>0<=a-b>>>0|a>>>0<=b>>>0?!e&d>>>0>b-a>>>0|e?a>>>0>>0:0:1){b=yb(a,b,d)}f=!e&d>>>0>32|(e|0)!=0;c=f?32:d;f=f?0:e;g=f;c:{if(!(c|f)){f=g;i=c+32|0;f=i>>>0<32?f+1|0:f;tc(h+32|0,h+32|0,i,f,j,h);break c}k=za(h- -64|0,b,c);f=g;i=c+32|0;f=i>>>0<32?f+1|0:f;tc(h+32|0,h+32|0,i,f,j,h);za(a,k,c)}f=0;if(!e&d>>>0<33){break b}i=a;a=c;uc(i+a|0,a+b|0,d-a|0,e-(g+(a>>>0>d>>>0)|0)|0,j,1,0,h)}oa(h,32)}V=h+96|0;return f}function Af(a,b,c,d,e){var f=0,g=0,h=0,i=0;f=V+-64|0;V=f;a:{b:{g=Ta(a);c:{if(g>>>0<128?c:1){x[9301]=28;break c}x[f+56>>2]=0;x[f+48>>2]=0;x[f+52>>2]=0;x[f+40>>2]=0;x[f+44>>2]=0;h=0;d:{if(!g){break d}c=g;i=c;h=c;if((c|1)>>>0<65536){break d}h=i}i=h;c=Za(h);if(!(!c|!(y[c-4|0]&3))){ya(c,0,i)}if(c){break b}}a=-1;break a}x[f+32>>2]=0;x[f+36>>2]=0;x[f+8>>2]=c;x[f+16>>2]=c;x[f+20>>2]=g;x[f>>2]=c;x[f+12>>2]=g;x[f+24>>2]=0;x[f+28>>2]=0;x[f+4>>2]=g;e:{if(If(f,a,e)){x[9301]=28;a=-1;break e}a=1;if((b|0)!=x[f+40>>2]){break e}a=x[f+44>>2]!=(d>>>10|0)}Ka(c)}V=f- -64|0;return a}function Ma(a,b,c){var d=0,e=0,f=0,g=0,h=0,i=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0,r=0,s=0,t=0,u=0,v=0,w=0;n=x[b+4>>2];d=x[a+4>>2];o=x[b+8>>2];e=x[a+8>>2];p=x[b+12>>2];f=x[a+12>>2];q=x[b+16>>2];g=x[a+16>>2];r=x[b+20>>2];h=x[a+20>>2];s=x[b+24>>2];i=x[a+24>>2];t=x[b+28>>2];j=x[a+28>>2];u=x[b+32>>2];k=x[a+32>>2];v=x[b+36>>2];l=x[a+36>>2];m=x[a>>2];w=x[b>>2]^m;b=0-c|0;x[a>>2]=m^w&b;x[a+36>>2]=b&(l^v)^l;x[a+32>>2]=b&(k^u)^k;x[a+28>>2]=b&(j^t)^j;x[a+24>>2]=b&(i^s)^i;x[a+20>>2]=b&(h^r)^h;x[a+16>>2]=b&(g^q)^g;x[a+12>>2]=b&(f^p)^f;x[a+8>>2]=b&(e^o)^e;x[a+4>>2]=b&(d^n)^d}function wj(){var a=0,b=0;if(x[9432]){b=1}else{x[9289]=0;a=V-16|0;V=a;Gd(a);if(x[a>>2]){Gd(a);ya(37160,0,40)}V=a+16|0;x[9288]=1;lg();b=w[830];a:{if(!b){x[9301]=28;a=-1;break a}b:{c:{if((b|0)>-2){break c}a=200809;d:{switch((b&255)-1|0){case 1:a=131072;break a;case 2:a=32768;break a;case 3:a=65536;break a;case 4:a=2147483647;break a;case 5:case 6:a=1;break a;case 7:case 8:a=T()>>>16|0;break a;case 9:break d;case 0:break b;default:break c}}a=0;break a}a=b}}e:{if((a|0)>=1){x[9081]=a;break e}a=x[9081]}if(a>>>0<=15){Aa();N()}Pa(37712,16);x[9432]=1;b=0}return b|0}function Of(a,b,c,d,e,f){var g=0,h=0;g=V-32|0;V=g;h=-1;a:{if(!d&c>>>0<32){break a}Rf(g,32,0,e,f);if(Zb(b+16|0,b+32|0,c-32|0,d-(c>>>0<32)|0,g)){break a}rd(a,b,c,d,e,f);v[a+24|0]=0;v[a+25|0]=0;v[a+26|0]=0;v[a+27|0]=0;v[a+28|0]=0;v[a+29|0]=0;v[a+30|0]=0;v[a+31|0]=0;v[a+16|0]=0;v[a+17|0]=0;v[a+18|0]=0;v[a+19|0]=0;v[a+20|0]=0;v[a+21|0]=0;v[a+22|0]=0;v[a+23|0]=0;v[a+8|0]=0;v[a+9|0]=0;v[a+10|0]=0;v[a+11|0]=0;v[a+12|0]=0;v[a+13|0]=0;v[a+14|0]=0;v[a+15|0]=0;v[a|0]=0;v[a+1|0]=0;v[a+2|0]=0;v[a+3|0]=0;v[a+4|0]=0;v[a+5|0]=0;v[a+6|0]=0;v[a+7|0]=0;h=0}V=g+32|0;return h}function rg(a,b){var c=0,d=0,e=0,f=0,g=0,h=0,i=0,j=0;while(1){v[a+c|0]=y[(c>>>3|0)+b|0]>>>(c&7)&1;c=c+1|0;if((c|0)!=256){continue}break}while(1){b=h;h=b+1|0;g=a+b|0;a:{if(!y[g|0]){break a}c=h;e=1;if(b>>>0>254){break a}while(1){d=a+c|0;f=v[d|0];b:{if(!f){break b}i=v[g|0];f=f<>>0<255;c=c+1|0;if(d){continue}break}}if(e>>>0>5){break a}e=e+1|0;c=b+e|0;if(c>>>0<256){continue}break}}if((h|0)!=256){continue}break}}function Yc(a,b,c){a=a|0;b=b|0;c=c|0;var d=0,e=0,f=0;d=V-96|0;V=d;if(c>>>0>=65){Lb(a);qb(a,b,c,0);Kb(a,d);c=32;b=d}Lb(a);ya(d+32|0,54,64);a:{if(!c){break a}v[d+32|0]=y[b|0]^54;e=1;if((c|0)==1){break a}while(1){f=(d+32|0)+e|0;v[f|0]=y[f|0]^y[b+e|0];e=e+1|0;if((e|0)!=(c|0)){continue}break}}qb(a,d+32|0,64,0);a=a+104|0;Lb(a);ya(d+32|0,92,64);b:{if(!c){break b}v[d+32|0]=y[b|0]^92;e=1;if((c|0)==1){break b}while(1){f=(d+32|0)+e|0;v[f|0]=y[f|0]^y[b+e|0];e=e+1|0;if((e|0)!=(c|0)){continue}break}}qb(a,d+32|0,64,0);oa(d+32|0,64);oa(d,32);V=d+96|0;return 0}function Hf(a,b,c,d){var e=0,f=0,g=0,h=0,i=0;e=V+-64|0;V=e;ya(e+8|0,0,52);f=Ta(a);x[e+20>>2]=f;x[e+36>>2]=f;x[e+4>>2]=f;g=Za(f);x[e+32>>2]=g;h=Za(f);x[e+16>>2]=h;i=Za(f);x[e>>2]=i;a:{b:{if(!i|(!g|!h)){break b}f=Za(f);if(!f){break b}a=If(e,a,d);if(a){Ka(x[e+32>>2]);Ka(x[e+16>>2]);Ka(x[e>>2]);Ka(f);break a}a=0;b=Ob(x[e+40>>2],x[e+44>>2],x[e+52>>2],b,c,x[e+16>>2],x[e+20>>2],f,x[e+4>>2],0,0,d);Ka(x[e+32>>2]);Ka(x[e+16>>2]);c:{if(!b){if(!rb(f,x[e>>2],x[e+4>>2])){break c}}a=-35}Ka(f);Ka(x[e>>2]);break a}Ka(g);Ka(h);Ka(i);a=-22}V=e- -64|0;return a}function ob(a,b){var c=0,d=0,e=0,f=0;c=V-384|0;V=c;e=a+40|0;db(e,b);d=a+80|0;Ea(d);qa(c+336|0,e);ma(c+288|0,c+336|0,2176);xa(c+336|0,c+336|0,d);va(c+288|0,c+288|0,d);qa(c+240|0,c+288|0);ma(c+240|0,c+240|0,c+288|0);qa(a,c+240|0);ma(a,a,c+288|0);ma(a,a,c+336|0);Ac(a,a);ma(a,a,c+240|0);ma(a,a,c+336|0);qa(c+192|0,a);ma(c+192|0,c+192|0,c+288|0);xa(c+144|0,c+192|0,c+336|0);va(c+96|0,c+192|0,c+336|0);d=Xa(c+144|0);f=Xa(c+96|0);ma(c,a,2224);Ma(a,c,1-d|0);Wa(c+48|0,a);Ma(a,c+48|0,nb(a)^y[b+31|0]>>>7);ma(a+120|0,a,e);V=c+384|0;return(d|f)-1|0}function Fd(a,b){var c=0,d=0,e=0;c=V-288|0;V=c;e=a+40|0;db(e,b);d=a+80|0;Ea(d);qa(c+240|0,e);ma(c+192|0,c+240|0,2176);xa(c+240|0,c+240|0,d);va(c+192|0,c+192|0,d);qa(c+144|0,c+192|0);ma(c+144|0,c+144|0,c+192|0);qa(a,c+144|0);ma(a,a,c+192|0);ma(a,a,c+240|0);Ac(a,a);ma(a,a,c+144|0);ma(a,a,c+240|0);qa(c+96|0,a);ma(c+96|0,c+96|0,c+192|0);xa(c+48|0,c+96|0,c+240|0);a:{if(!Xa(c+48|0)){va(c,c+96|0,c+240|0);d=-1;if(!Xa(c)){break a}ma(a,a,2224)}if((nb(a)|0)==(y[b+31|0]>>>7|0)){Wa(a,a)}ma(a+120|0,a,e);d=0}V=c+288|0;return d}function ge(a,b,c,d,e,f){var g=0;g=V-192|0;V=g;if(!(!c|(b-1&255)>>>0>=64|(!d|d>>>0>=65))){w[g+130>>1]=257;v[g+129|0]=d;v[g+128|0]=b;bc(g+128|4);Ba(g+128|8,0,0);x[g+152>>2]=0;x[g+156>>2]=0;x[g+144>>2]=0;x[g+148>>2]=0;a:{if(e){se(g+128|0,e);break a}x[g+168>>2]=0;x[g+172>>2]=0;x[g+160>>2]=0;x[g+164>>2]=0}b:{if(f){pe(g+128|0,f);break b}x[g+184>>2]=0;x[g+188>>2]=0;x[g+176>>2]=0;x[g+180>>2]=0}cc(a,g+128|0);ya(d+g|0,0,d<<24>>24<0?0:128-d|0);b=a;a=za(g,c,d);Jb(b,a,128,0);oa(a,128);V=a+192|0;return 0}Aa();N()}function Ye(a,b,c,d,e,f){var g=0,h=0;g=V-496|0;V=g;Yc(g+288|0,a,b);fc(g+288|0,c,d,0);a:{if(!f){break a}d=1;while(1){_e(g+76|0,d);za(g+80|0,g+288|0,208);fc(g+80|0,g+76|0,4,0);Xc(g+80|0,g+32|0);a=x[g+60>>2];x[g+24>>2]=x[g+56>>2];x[g+28>>2]=a;a=x[g+52>>2];x[g+16>>2]=x[g+48>>2];x[g+20>>2]=a;a=x[g+44>>2];x[g+8>>2]=x[g+40>>2];x[g+12>>2]=a;a=x[g+36>>2];x[g>>2]=x[g+32>>2];x[g+4>>2]=a;a=f-h|0;za(e+h|0,g,a>>>0<32?a:32);h=d<<5;if(h>>>0>=f>>>0){break a}d=d+1|0;continue}}oa(g+288|0,208);V=g+496|0}function se(a,b){var c=0,d=0;c=y[b+4|0]|y[b+5|0]<<8|(y[b+6|0]<<16|y[b+7|0]<<24);d=y[b|0]|y[b+1|0]<<8|(y[b+2|0]<<16|y[b+3|0]<<24);v[a+32|0]=d;v[a+33|0]=d>>>8;v[a+34|0]=d>>>16;v[a+35|0]=d>>>24;v[a+36|0]=c;v[a+37|0]=c>>>8;v[a+38|0]=c>>>16;v[a+39|0]=c>>>24;c=y[b+12|0]|y[b+13|0]<<8|(y[b+14|0]<<16|y[b+15|0]<<24);b=y[b+8|0]|y[b+9|0]<<8|(y[b+10|0]<<16|y[b+11|0]<<24);v[a+40|0]=b;v[a+41|0]=b>>>8;v[a+42|0]=b>>>16;v[a+43|0]=b>>>24;v[a+44|0]=c;v[a+45|0]=c>>>8;v[a+46|0]=c>>>16;v[a+47|0]=c>>>24}function pe(a,b){var c=0,d=0;c=y[b+4|0]|y[b+5|0]<<8|(y[b+6|0]<<16|y[b+7|0]<<24);d=y[b|0]|y[b+1|0]<<8|(y[b+2|0]<<16|y[b+3|0]<<24);v[a+48|0]=d;v[a+49|0]=d>>>8;v[a+50|0]=d>>>16;v[a+51|0]=d>>>24;v[a+52|0]=c;v[a+53|0]=c>>>8;v[a+54|0]=c>>>16;v[a+55|0]=c>>>24;c=y[b+12|0]|y[b+13|0]<<8|(y[b+14|0]<<16|y[b+15|0]<<24);b=y[b+8|0]|y[b+9|0]<<8|(y[b+10|0]<<16|y[b+11|0]<<24);v[a+56|0]=b;v[a+57|0]=b>>>8;v[a+58|0]=b>>>16;v[a+59|0]=b>>>24;v[a+60|0]=c;v[a+61|0]=c>>>8;v[a+62|0]=c>>>16;v[a+63|0]=c>>>24}function xa(a,b,c){var d=0,e=0,f=0,g=0,h=0,i=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0,r=0,s=0,t=0,u=0;d=x[c+4>>2];e=x[b+4>>2];f=x[c+8>>2];g=x[b+8>>2];h=x[c+12>>2];i=x[b+12>>2];j=x[c+16>>2];k=x[b+16>>2];l=x[c+20>>2];m=x[b+20>>2];n=x[c+24>>2];o=x[b+24>>2];p=x[c+28>>2];q=x[b+28>>2];r=x[c+32>>2];s=x[b+32>>2];t=x[c+36>>2];u=x[b+36>>2];x[a>>2]=x[b>>2]-x[c>>2];x[a+36>>2]=u-t;x[a+32>>2]=s-r;x[a+28>>2]=q-p;x[a+24>>2]=o-n;x[a+20>>2]=m-l;x[a+16>>2]=k-j;x[a+12>>2]=i-h;x[a+8>>2]=g-f;x[a+4>>2]=e-d}function va(a,b,c){var d=0,e=0,f=0,g=0,h=0,i=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0,r=0,s=0,t=0,u=0;d=x[c+4>>2];e=x[b+4>>2];f=x[c+8>>2];g=x[b+8>>2];h=x[c+12>>2];i=x[b+12>>2];j=x[c+16>>2];k=x[b+16>>2];l=x[c+20>>2];m=x[b+20>>2];n=x[c+24>>2];o=x[b+24>>2];p=x[c+28>>2];q=x[b+28>>2];r=x[c+32>>2];s=x[b+32>>2];t=x[c+36>>2];u=x[b+36>>2];x[a>>2]=x[c>>2]+x[b>>2];x[a+36>>2]=t+u;x[a+32>>2]=r+s;x[a+28>>2]=p+q;x[a+24>>2]=n+o;x[a+20>>2]=l+m;x[a+16>>2]=j+k;x[a+12>>2]=h+i;x[a+8>>2]=f+g;x[a+4>>2]=d+e}function nj(a,b){a=a|0;b=b|0;var c=0,d=0,e=0,f=0;c=V-160|0;V=c;f=y[b|0];while(1){e=b-d|0;v[(c+128|0)+d|0]=y[e+63|0];v[(c+96|0)+d|0]=y[e+31|0];d=d+1|0;if((d|0)!=32){continue}break}v[c+159|0]=y[c+159|0]&127;v[c+127|0]=y[c+127|0]&127;db(c+48|0,c+128|0);db(c,c+96|0);x[c+48>>2]=(x[c+48>>2]+(v[b+32|0]>>>7&19)|0)+D(x[c>>2],38);d=1;while(1){b=d<<2;e=b+(c+48|0)|0;x[e>>2]=x[e>>2]+D(x[b+c>>2],38);d=d+1|0;if((d|0)!=10){continue}break}Hd(c+48|0,c+48|0);jg(a,c+48|0,f&128);V=c+160|0;return 0}function Wb(a){var b=0,c=0,d=0,e=0,f=0;c=V-16|0;v[c+11|0]=0;v[c+12|0]=0;v[c+13|0]=0;v[c+14|0]=0;x[c+8>>2]=0;while(1){e=y[a+d|0];b=0;while(1){f=(c+8|0)+b|0;v[f|0]=y[f|0]|e^y[((b<<5)+3280|0)+d|0];b=b+1|0;if((b|0)!=7){continue}break}d=d+1|0;if((d|0)!=31){continue}break}d=y[a+31|0]&127;a=0;b=0;while(1){e=(c+8|0)+b|0;v[e|0]=y[e|0]|d^y[(b<<5)+3311|0];b=b+1|0;if((b|0)!=7){continue}break}b=0;while(1){b=y[(c+8|0)+a|0]-1|b;a=a+1|0;if((a|0)!=7){continue}break}return b>>>8&1}function cc(a,b){var c=0,d=0,e=0,f=0,g=0;ya(za(a,2112,64)- -64|0,0,293);while(1){c=f<<3;d=c+a|0;e=d;c=b+c|0;g=y[d|0]|y[d+1|0]<<8|(y[d+2|0]<<16|y[d+3|0]<<24);d=(y[c+4|0]|y[c+5|0]<<8|(y[c+6|0]<<16|y[c+7|0]<<24))^(y[d+4|0]|y[d+5|0]<<8|(y[d+6|0]<<16|y[d+7|0]<<24));c=(y[c|0]|y[c+1|0]<<8|(y[c+2|0]<<16|y[c+3|0]<<24))^g;v[e|0]=c;v[e+1|0]=c>>>8;v[e+2|0]=c>>>16;v[e+3|0]=c>>>24;v[e+4|0]=d;v[e+5|0]=d>>>8;v[e+6|0]=d>>>16;v[e+7|0]=d>>>24;f=f+1|0;if((f|0)!=8){continue}break}}function Pb(a,b){var c=0,d=0;d=b&255;a:{if(d){if(a&3){while(1){c=y[a|0];if(!c|(c|0)==(b&255)){break a}a=a+1|0;if(a&3){continue}break}}c=x[a>>2];b:{if((c^-1)&c-16843009&-2139062144){break b}d=D(d,16843009);while(1){c=c^d;if((c^-1)&c-16843009&-2139062144){break b}c=x[a+4>>2];a=a+4|0;if(!(c-16843009&(c^-1)&-2139062144)){continue}break}}while(1){c=a;d=y[a|0];if(d){a=c+1|0;if((d|0)!=(b&255)){continue}}break}a=c;break a}a=Ta(a)+a|0}return y[a|0]==(b&255)?a:0}function Kg(a,b,c,d,e,f,g,h,i,j){a=a|0;b=b|0;c=c|0;d=d|0;e=e|0;f=f|0;g=g|0;h=h|0;i=i|0;j=j|0;var k=0,l=0;k=h;h=i;l=k|0;k=V-16|0;V=k;i=a;a=b;b=a;i=ya(i,0,a);a:{if(c>>>0<1?f:1){x[9301]=22;a=-1;break a}if(!c&a>>>0>=16|c){Uc(l,h,j,k+12|0,k+8|0,k+4|0);if((d|0)==(i|0)){x[9301]=28;a=-1;break a}c=x[k+12>>2];a=c&31;if((c&63)>>>0>=32){h=1<>>32-a;a=1<>2],x[k+8>>2],i,b);break a}x[9301]=28;a=-1}V=k+16|0;return a|0}function Ti(a,b,c,d,e){a=a|0;b=b|0;c=c|0;d=d|0;e=e|0;var f=0,g=0,h=0,i=0;g=V-16|0;V=g;a:{b:{if(!d){i=-1;break b}f=d-1|0;c:{if(!(f&d)){h=c&f;break c}h=(c>>>0)%(d>>>0)|0}i=-1;f=f-h|0;if(f>>>0>=(c^-1)>>>0){break a}c=c+f|0;if(c>>>0>=e>>>0){break b}if(a){x[a>>2]=c+1}a=b+c|0;i=0;v[g+15|0]=0;c=0;while(1){b=a-c|0;e=b;h=y[b|0]&y[g+15|0];b=(c^f)-1>>>24|0;v[e|0]=h|b&128;v[g+15|0]=b|y[g+15|0];c=c+1|0;if((d|0)!=(c|0)){continue}break}}V=g+16|0;return i|0}Aa();N()}function gi(a,b,c,d,e){a=a|0;b=b|0;c=c|0;d=d|0;e=e|0;var f=0,g=0,h=0,i=0;f=V;i=f;f=f-512&-64;V=f;g=a?a:b;if(g){h=-1;if(!Kc(f+96|0,d,e)){b=b?b:a;a=0;kc(f+128|0,0,0,64);gb(f+128|0,f+96|0,32,0);oa(f+96|0,32);gb(f+128|0,c,32,0);gb(f+128|0,e,32,0);jc(f+128|0,f+32|0,64);oa(f+128|0,384);while(1){c=(f+32|0)+a|0;v[a+g|0]=y[c|0];v[a+b|0]=y[c+32|0];a=a+1|0;if((a|0)!=32){continue}break}oa(f+32|0,64);h=0}V=i;return h|0}Aa();N()}function fi(a,b,c,d,e){a=a|0;b=b|0;c=c|0;d=d|0;e=e|0;var f=0,g=0,h=0,i=0;f=V;i=f;f=f-512&-64;V=f;g=a?a:b;if(g){h=-1;if(!Kc(f+96|0,d,e)){b=b?b:a;a=0;kc(f+128|0,0,0,64);gb(f+128|0,f+96|0,32,0);oa(f+96|0,32);gb(f+128|0,e,32,0);gb(f+128|0,c,32,0);jc(f+128|0,f+32|0,64);oa(f+128|0,384);while(1){c=(f+32|0)+a|0;v[a+b|0]=y[c|0];v[a+g|0]=y[c+32|0];a=a+1|0;if((a|0)!=32){continue}break}oa(f+32|0,64);h=0}V=i;return h|0}Aa();N()}function ia(a,b,c){var d=0,e=0,f=0,g=0,h=0;g=a;f=c&63;a=f;d=a&31;if(a>>>0>=32){a=-1<>>32-d|-1<>>0>=32){a=0;f=e>>>d|0}else{a=e>>>d|0;f=((1<>>d}d=a;e=0-c&63;a=e;c=a&31;if(a>>>0>=32){a=0;c=-1>>>c|0}else{a=-1>>>c|0;c=(1<>>c}c=c&g;b=a&b;a=e&31;if(e>>>0>=32){b=c<>>32-a|b<>>0>=32){a=-1>>>a|0}else{e=-1>>>a|0;a=(1<>>a}d=a&g;a=b&e;e=f&31;if(f>>>0>=32){a=d<>>32-e|a<>>0>=32){a=-1<>>32-c|-1<>>0>=32){c=0;a=b>>>a|0}else{c=b>>>a|0;a=((1<>>a}a=a|f;Y=c|e;return a}function oi(a,b,c){a=a|0;b=b|0;c=c|0;Pa(b,24);bb(a,b,c,0);Nc(a);c=y[b+16|0]|y[b+17|0]<<8|(y[b+18|0]<<16|y[b+19|0]<<24);b=y[b+20|0]|y[b+21|0]<<8|(y[b+22|0]<<16|y[b+23|0]<<24);v[a+44|0]=0;v[a+45|0]=0;v[a+46|0]=0;v[a+47|0]=0;v[a+48|0]=0;v[a+49|0]=0;v[a+50|0]=0;v[a+51|0]=0;v[a+36|0]=c;v[a+37|0]=c>>>8;v[a+38|0]=c>>>16;v[a+39|0]=c>>>24;v[a+40|0]=b;v[a+41|0]=b>>>8;v[a+42|0]=b>>>16;v[a+43|0]=b>>>24;return 0}function _f(a,b,c,d,e,f,g,h,i,j){var k=0;k=V-352|0;V=k;Bb(k+32|0,64,0,i,j);Sa(k+96|0,k+32|0);oa(k+32|0,64);ta(k+96|0,f,g,h);ta(k+96|0,34976,0-g&15,0);ta(k+96|0,b,c,d);ta(k+96|0,34976,0-c&15,0);Ba(k+24|0,g,h);ta(k+96|0,k+24|0,8,0);Ba(k+24|0,c,d);ta(k+96|0,k+24|0,8,0);Ra(k+96|0,k);oa(k+96|0,256);e=Gb(k,e);oa(k,16);a:{if(!a){break a}if(e){ya(a,0,c);e=-1;break a}ub(a,b,c,d,i,1,j);e=0}V=k+352|0;return e}function Kb(a,b){a=a|0;b=b|0;var c=0,d=0,e=0,f=0;e=V-288|0;V=e;d=x[a+36>>2];f=x[a+32>>2];c=f>>>3&63;a:{if(c>>>0<=55){za((a+c|0)+40|0,36240,56-c|0);break a}d=a+40|0;za(d+c|0,36240,64-c|0);hc(a,d,e,e+256|0);ya(d,0,56);f=x[a+32>>2];d=x[a+36>>2]}Sf(a+96|0,f,d);hc(a,a+40|0,e,e+256|0);c=0;while(1){d=c<<2;_e(d+b|0,x[a+d>>2]);c=c+1|0;if((c|0)!=8){continue}break}oa(e,288);oa(a,104);V=e+288|0;return 0}function ni(a,b,c){a=a|0;b=b|0;c=c|0;bb(a,b,c,0);Nc(a);c=y[b+16|0]|y[b+17|0]<<8|(y[b+18|0]<<16|y[b+19|0]<<24);b=y[b+20|0]|y[b+21|0]<<8|(y[b+22|0]<<16|y[b+23|0]<<24);v[a+44|0]=0;v[a+45|0]=0;v[a+46|0]=0;v[a+47|0]=0;v[a+48|0]=0;v[a+49|0]=0;v[a+50|0]=0;v[a+51|0]=0;v[a+36|0]=c;v[a+37|0]=c>>>8;v[a+38|0]=c>>>16;v[a+39|0]=c>>>24;v[a+40|0]=b;v[a+41|0]=b>>>8;v[a+42|0]=b>>>16;v[a+43|0]=b>>>24;return 0}function Wd(a,b,c,d,e,f){a=a|0;b=b|0;c=c|0;d=d|0;e=e|0;f=f|0;var g=0,h=0;a:{b:{c:{d:{if(!e&d>>>0<64){break d}e=e-1|0;h=e+1|0;g=e;e=d+-64|0;d=e>>>0<4294967232?h:g;if(d|!d&e>>>0>4294967231){break d}g=c;c=c- -64|0;if(!Ce(g,c,e,d,f)){break c}if(!a){break d}ya(a,0,e)}d=-1;if(!b){break b}x[b>>2]=0;x[b+4>>2]=0;d=-1;break a}if(b){x[b>>2]=e;x[b+4>>2]=d}d=0;if(!a){break b}yb(a,c,e)}}return d|0}function og(a,b,c){var d=0,e=0;d=V-160|0;V=d;e=ng(c);Ea(a);Ea(a+40|0);Ea(a+80|0);vb(a+120|0);c=c-((0-e&c)<<1)<<24>>24;jb(a,b,Oa(c,1));jb(a,b+160|0,Oa(c,2));jb(a,b+320|0,Oa(c,3));jb(a,b+480|0,Oa(c,4));jb(a,b+640|0,Oa(c,5));jb(a,b+800|0,Oa(c,6));jb(a,b+960|0,Oa(c,7));jb(a,b+1120|0,Oa(c,8));La(d,a+40|0);La(d+40|0,a);La(d+80|0,a+80|0);Wa(d+120|0,a+120|0);jb(a,d,e);V=d+160|0}function we(a,b,c,d){var e=0;e=V+-64|0;V=e;if((b-1&255)>>>0<64){v[e+3|0]=1;v[e+1|0]=0;v[e+2|0]=1;v[e|0]=b;bc(e|4);Ba(e|8,0,0);x[e+24>>2]=0;x[e+28>>2]=0;x[e+16>>2]=0;x[e+20>>2]=0;a:{if(c){se(e,c);break a}x[e+40>>2]=0;x[e+44>>2]=0;x[e+32>>2]=0;x[e+36>>2]=0}b:{if(d){pe(e,d);break b}x[e+56>>2]=0;x[e+60>>2]=0;x[e+48>>2]=0;x[e+52>>2]=0}cc(a,e);V=e- -64|0;return 0}Aa();N()}function ce(a,b,c,d,e,f){a=a|0;b=b|0;c=c|0;d=d|0;e=e|0;f=f|0;var g=0,h=0;g=V-32|0;V=g;h=y[e|0]|y[e+1|0]<<8|(y[e+2|0]<<16|y[e+3|0]<<24);e=y[e+4|0]|y[e+5|0]<<8|(y[e+6|0]<<16|y[e+7|0]<<24);x[g+24>>2]=0;x[g+28>>2]=0;x[g+16>>2]=h;x[g+20>>2]=e;Ba(g,c,d);x[g+8>>2]=0;x[g+12>>2]=0;a:{if(b-16>>>0>=49){x[9301]=28;a=-1;break a}a=Zd(a,b,0,0,0,f,32,g,g+16|0)}V=g+32|0;return a|0}function zd(a,b,c){var d=0,e=0;d=V-288|0;V=d;qa(d+240|0,c);ma(d+240|0,d+240|0,c);qa(a,d+240|0);ma(a,a,c);ma(a,a,b);Ac(a,a);ma(a,a,d+240|0);ma(a,a,b);qa(d+192|0,a);ma(d+192|0,d+192|0,c);xa(d+144|0,d+192|0,b);va(d+96|0,d+192|0,b);ma(d+48|0,b,2224);va(d+48|0,d+192|0,d+48|0);c=Xa(d+144|0);b=Xa(d+96|0);e=Xa(d+48|0);ma(d,a,2224);Ma(a,d,b|e);yc(a,a);V=d+288|0;return b|c}function mg(a,b,c){var d=0,e=0;d=V-128|0;V=d;e=ng(c);Ea(a);Ea(a+40|0);vb(a+80|0);b=D(b,960)+3584|0;c=c-((0-e&c)<<1)<<24>>24;ib(a,b,Oa(c,1));ib(a,b+120|0,Oa(c,2));ib(a,b+240|0,Oa(c,3));ib(a,b+360|0,Oa(c,4));ib(a,b+480|0,Oa(c,5));ib(a,b+600|0,Oa(c,6));ib(a,b+720|0,Oa(c,7));ib(a,b+840|0,Oa(c,8));La(d+8|0,a+40|0);La(d+48|0,a);Wa(d+88|0,a+80|0);ib(a,d+8|0,e);V=d+128|0}function Ef(a,b,c,d,e,f,g,h,i,j,k){var l=0;l=a;a=b;l=ya(l,0,a);a:{if((c|0)==1|c>>>0>1){x[9301]=22;break a}if(!c&b>>>0<=15){x[9301]=28;break a}if(j>>>0<2147483649?f|i:1){x[9301]=22;break a}if(!(j>>>0>8191?!i&h>>>0>=3|(i|0)!=0:0)){x[9301]=28;break a}if((d|0)==(l|0)){x[9301]=28;break a}if((k|0)==1){return Ob(h,j>>>10|0,1,d,e,g,16,l,a,0,0,1)?-1:0}x[9301]=28}return-1}function vf(a,b,c,d,e,f,g,h,i,j,k){var l=0;l=a;a=b;l=ya(l,0,b);a:{if((c|0)==1|c>>>0>1){x[9301]=22;break a}if(!c&b>>>0<=15){x[9301]=28;break a}if(j>>>0<2147483649?f|i:1){x[9301]=22;break a}b=j>>>0>8191;if(!((b?h:0)|(b?i:0))){x[9301]=28;break a}if((d|0)==(l|0)){x[9301]=28;break a}if((k|0)==2){return Ob(h,j>>>10|0,1,d,e,g,16,l,a,0,0,2)?-1:0}x[9301]=28}return-1}function ag(a,b,c,d,e,f,g,h,i,j,k){var l=0;l=V-336|0;V=l;Bb(l+16|0,64,0,j,k);Sa(l+80|0,l+16|0);oa(l+16|0,64);ta(l+80|0,g,h,i);ta(l+80|0,34976,0-h&15,0);ub(a,d,e,f,j,1,k);ta(l+80|0,a,e,f);ta(l+80|0,34976,0-e&15,0);Ba(l+8|0,h,i);ta(l+80|0,l+8|0,8,0);Ba(l+8|0,e,f);ta(l+80|0,l+8|0,8,0);Ra(l+80|0,b);oa(l+80|0,256);if(c){x[c>>2]=16;x[c+4>>2]=0}V=l+336|0;return 0}function lj(a,b,c,d){a=a|0;b=b|0;c=c|0;d=d|0;var e=0,f=0,g=0;a:{if(!(d>>>0>2147483646|d<<1>>>0>=b>>>0)){if(d){b=0;while(1){e=b<<1;g=y[b+c|0];f=g>>>4|0;v[e+a|0]=(f+(f+65526>>>8&217)|0)+87;f=(e|1)+a|0;e=g&15;v[f|0]=((e<<8)+(e+65526&55552)|0)+22272>>>8;b=b+1|0;if((d|0)!=(b|0)){continue}break}b=(d<<1)+a|0;break a}b=a;break a}Aa();N()}v[b|0]=0;return a|0}function $f(a,b,c,d,e,f,g,h,i,j){var k=0;k=V-352|0;V=k;Rb(k+32|0,64,0,i,j);Sa(k+96|0,k+32|0);oa(k+32|0,64);ta(k+96|0,f,g,h);Ba(k+24|0,g,h);ta(k+96|0,k+24|0,8,0);ta(k+96|0,b,c,d);Ba(k+24|0,c,d);ta(k+96|0,k+24|0,8,0);Ra(k+96|0,k);oa(k+96|0,256);e=Gb(k,e);oa(k,16);a:{if(!a){break a}if(e){ya(a,0,c);e=-1;break a}Cb(a,b,c,d,i,1,0,j);e=0}V=k+352|0;return e}function Qe(a,b){var c=0,d=0,e=0,f=0;f=a;c=65;a=1024;a:{if(y[1024]==(b&255)){break a}d=D(b&255,16843009);while(1){e=x[a>>2]^d;if((e^-1)&e-16843009&-2139062144){break a}a=a+4|0;c=c-4|0;if(c>>>0>3){continue}break}}b:{if(c){d=b&255;while(1){b=a;if((d|0)==y[a|0]){break b}a=a+1|0;c=c-1|0;if(c){continue}break}}b=0}x[f>>2]=b?b-1024|0:0;return b?0:-1}function mc(a,b){var c=0,d=0,e=0,f=0,g=0,h=0;e=y[a|0];a:{if((e-48&255)>>>0>9){break a}d=e;c=a;while(1){g=c;if(f>>>0>429496729){break a}d=(d&255)-48|0;c=D(f,10);if(d>>>0>(c^-1)>>>0){break a}f=c+d|0;c=g+1|0;d=y[c|0];if((d-48&255)>>>0<10){continue}break}if((a|0)==(c|0)|((a|0)!=(g|0)?(e|0)==48:0)){break a}x[b>>2]=f;h=c}return h}function Si(a,b,c,d){a=a|0;b=b|0;c=c|0;d=d|0;var e=0,f=0,g=0,h=0,i=0,j=0;e=V-16|0;x[e+12>>2]=0;if(d-1>>>0>>0){f=c-1|0;j=f+b|0;c=0;b=0;while(1){g=y[j-c|0];i=((g^128)-1&(x[e+12>>2]-1&h-1))>>>8&1;x[e+12>>2]=x[e+12>>2]|0-i&c;b=b|i;h=h|g;c=c+1|0;if((d|0)!=(c|0)){continue}break}x[a>>2]=f-x[e+12>>2];a=b-1|0}else{a=-1}return a|0}function Wa(a,b){var c=0,d=0,e=0,f=0,g=0,h=0,i=0,j=0,k=0;c=x[b+4>>2];d=x[b+8>>2];e=x[b+12>>2];f=x[b+16>>2];g=x[b+20>>2];h=x[b+24>>2];i=x[b+28>>2];j=x[b+32>>2];k=x[b+36>>2];x[a>>2]=0-x[b>>2];x[a+36>>2]=0-k;x[a+32>>2]=0-j;x[a+28>>2]=0-i;x[a+24>>2]=0-h;x[a+20>>2]=0-g;x[a+16>>2]=0-f;x[a+12>>2]=0-e;x[a+8>>2]=0-d;x[a+4>>2]=0-c}function Sf(a,b,c){var d=0,e=0,f=0,g=0;d=b<<8&16711680|b<<24;e=c<<24|b>>>8;f=e&65280;e=c<<8|b>>>24;d=e&255|f|d;b=((c&255)<<24|b>>>8)&-16777216|((c&16777215)<<8|b>>>24)&16711680|(c>>>8&65280|c>>>24)|g;v[a|0]=b;v[a+1|0]=b>>>8;v[a+2|0]=b>>>16;v[a+3|0]=b>>>24;b=d;v[a+4|0]=b;v[a+5|0]=b>>>8;v[a+6|0]=b>>>16;v[a+7|0]=b>>>24}function Je(a,b,c,d){var e=0,f=0;e=V-320|0;V=e;f=-1;a:{if(!Ad(c)){break a}if(Wb(c)){break a}if(ob(e,c)){break a}if(!Bd(e)){break a}c=0;while(1){v[a+c|0]=y[b+c|0];c=c+1|0;if((c|0)!=32){continue}break}if(d){Ie(a)}v[a+31|0]=y[a+31|0]&127;pg(e+160|0,a,e);mb(a,e+160|0);if(He(a)){break a}f=fb(b,32)?-1:0}V=e+320|0;return f}function Xd(a,b,c,d,e,f){a=a|0;b=b|0;c=c|0;d=d|0;e=e|0;f=f|0;var g=0,h=0;g=V-16|0;V=g;h=c;c=d;of(a,g+8|0,yb(a- -64|0,h,d),d,e,f);a:{if(x[g+12>>2]|x[g+8>>2]!=64){if(b){x[b>>2]=0;x[b+4>>2]=0}ya(a,0,c- -64|0);a=-1;break a}a=0;if(!b){break a}x[b>>2]=d- -64;x[b+4>>2]=e-((d>>>0<4294967232)-1|0)}V=g+16|0;return a|0}function bg(a,b,c,d,e,f,g,h,i,j,k){var l=0;l=V-336|0;V=l;Rb(l+16|0,64,0,j,k);Sa(l+80|0,l+16|0);oa(l+16|0,64);ta(l+80|0,g,h,i);Ba(l+8|0,h,i);ta(l+80|0,l+8|0,8,0);Cb(a,d,e,f,j,1,0,k);ta(l+80|0,a,e,f);Ba(l+8|0,e,f);ta(l+80|0,l+8|0,8,0);Ra(l+80|0,b);oa(l+80|0,256);if(c){x[c>>2]=16;x[c+4>>2]=0}V=l+336|0;return 0}function fg(a,b,c){var d=0;d=a;a:{if(c){x[a+48>>2]=y[c|0]|y[c+1|0]<<8|(y[c+2|0]<<16|y[c+3|0]<<24);c=y[c+4|0]|y[c+5|0]<<8|(y[c+6|0]<<16|y[c+7|0]<<24);break a}x[a+48>>2]=0;c=0}x[d+52>>2]=c;x[a+56>>2]=y[b|0]|y[b+1|0]<<8|(y[b+2|0]<<16|y[b+3|0]<<24);x[a+60>>2]=y[b+4|0]|y[b+5|0]<<8|(y[b+6|0]<<16|y[b+7|0]<<24)}function Pf(a,b,c,d,e,f){if(!d&c>>>0>=32|d){rd(a,b,c,d,e,f);Jd(a+16|0,a+32|0,c-32|0,d-(c>>>0<32)|0,a);v[a+8|0]=0;v[a+9|0]=0;v[a+10|0]=0;v[a+11|0]=0;v[a+12|0]=0;v[a+13|0]=0;v[a+14|0]=0;v[a+15|0]=0;v[a|0]=0;v[a+1|0]=0;v[a+2|0]=0;v[a+3|0]=0;v[a+4|0]=0;v[a+5|0]=0;v[a+6|0]=0;v[a+7|0]=0;a=0}else{a=-1}return a}function Hg(a,b,c,d){a=a|0;b=b|0;c=c|0;d=d|0;var e=0;e=V-32|0;V=e;Uc(b,c,d,e+28|0,e+20|0,e+12|0);a:{if((Ke(a)|0)!=101){x[9301]=28;a=-1;break a}if(!Re(a,e+24|0,e+8|0,e+16|0)){x[9301]=28;a=-1;break a}a=1;if(x[e+28>>2]!=x[e+24>>2]|x[e+12>>2]!=x[e+8>>2]){break a}a=x[e+20>>2]!=x[e+16>>2]}V=e+32|0;return a|0}function La(a,b){var c=0,d=0,e=0,f=0,g=0,h=0,i=0,j=0,k=0;c=x[b+8>>2];d=x[b+12>>2];e=x[b+16>>2];f=x[b+20>>2];g=x[b+24>>2];h=x[b+28>>2];i=x[b>>2];j=x[b+4>>2];k=x[b+36>>2];x[a+32>>2]=x[b+32>>2];x[a+36>>2]=k;x[a+24>>2]=g;x[a+28>>2]=h;x[a+16>>2]=e;x[a+20>>2]=f;x[a+8>>2]=c;x[a+12>>2]=d;x[a>>2]=i;x[a+4>>2]=j}function _a(a,b){a=a|0;b=b|0;var c=0,d=0,e=0;c=V-704|0;V=c;d=x[a+72>>2]>>>3&127;a:{if(d>>>0<=111){za((a+d|0)+80|0,35728,112-d|0);break a}e=a+80|0;za(e+d|0,35728,128-d|0);pc(a,e,c,c+640|0);ya(e,0,112)}Tf(a+192|0,a- -64|0,16);pc(a,a+80|0,c,c+640|0);Tf(b,a,64);oa(c,704);oa(a,208);V=c+704|0;return 0}function Aj(a,b){a=a|0;b=b|0;var c=0,d=0,e=0;c=V-208|0;V=c;while(1){v[a+d|0]=y[b+d|0];d=d+1|0;if((d|0)!=32){continue}break}v[a|0]=y[a|0]&248;v[a+31|0]=y[a+31|0]&63|64;Yb(c+48|0,a);b=V-96|0;V=b;d=c+128|0;e=c+88|0;va(b+48|0,d,e);xa(b,d,e);wb(b,b);ma(c,b+48|0,b);V=b+96|0;cb(a,c);V=c+208|0;return 0}function Zd(a,b,c,d,e,f,g,h,i){var j=0,k=0;if(b-1>>>0>63|g>>>0>64){a=-1}else{j=V;k=j;j=j-384&-64;V=j;a:{b=b&255;g=g&255;if(!(!(d|e?c:1)|(!a|(b-1&255)>>>0>=64)|(!(g?f:1)|g>>>0>=65))){b:{if(g){ge(j,b,f,g,h,i);break b}we(j,b,h,i)}Jb(j,c,d,e);Gc(j,a,b);V=k;break a}Aa();N()}a=0}return a}function Ta(a){var b=0,c=0,d=0;b=a;a:{if(b&3){while(1){if(!y[b|0]){break a}b=b+1|0;if(b&3){continue}break}}while(1){c=b;b=b+4|0;d=x[c>>2];if(!((d^-1)&d-16843009&-2139062144)){continue}break}if(!(d&255)){return c-a|0}while(1){d=y[c+1|0];b=c+1|0;c=b;if(d){continue}break}}return b-a|0}function ne(a,b,c,d){var e=0;e=V-192|0;V=e;if(!(!c|(b-1&255)>>>0>=64|(!d|d>>>0>=65))){w[e+130>>1]=257;v[e+129|0]=d;v[e+128|0]=b;bc(e+128|4);Ba(e+128|8,0,0);ya(e+144|0,0,48);cc(a,e+128|0);ya(d+e|0,0,128-d|0);b=a;a=za(e,c,d);Jb(b,a,128,0);oa(a,128);V=a+192|0;return 0}Aa();N()}function ac(a,b,c,d,e,f,g){var h=0,i=0;if(b-1>>>0>63|g>>>0>64){a=-1}else{h=V;i=h;h=h-384&-64;V=h;a:{b=b&255;g=g&255;if(!(!(d|e?c:1)|(!a|(b-1&255)>>>0>=64)|(!(g?f:1)|g>>>0>=65))){b:{if(g){ne(h,b,f,g);break b}Ee(h,b)}Jb(h,c,d,e);Gc(h,a,b);V=i;break a}Aa();N()}a=0}return a}function pj(a,b,c){a=a|0;b=b|0;c=c|0;var d=0,e=0;d=V-800|0;V=d;e=-1;a:{if(ob(d+640|0,b)){break a}if(!Xb(d+640|0)){break a}if(ob(d+480|0,c)){break a}if(!Xb(d+480|0)){break a}Ca(d,d+480|0);Da(d+160|0,d+640|0,d);wa(d+320|0,d+160|0);mb(a,d+320|0);e=0}V=d+800|0;return e|0}function oj(a,b,c){a=a|0;b=b|0;c=c|0;var d=0,e=0;d=V-800|0;V=d;e=-1;a:{if(ob(d+640|0,b)){break a}if(!Xb(d+640|0)){break a}if(ob(d+480|0,c)){break a}if(!Xb(d+480|0)){break a}Ca(d,d+480|0);zc(d+160|0,d+640|0,d);wa(d+320|0,d+160|0);mb(a,d+320|0);e=0}V=d+800|0;return e|0}function Xb(a){var b=0;b=V-288|0;V=b;qa(b+240|0,a);qa(b+192|0,a+40|0);qa(b+144|0,a+80|0);xa(b+48|0,b+192|0,b+240|0);ma(b+48|0,b+48|0,b+144|0);ma(b,b+240|0,b+192|0);ma(b,b,2176);qa(b+96|0,b+144|0);va(b,b,b+96|0);xa(b+48|0,b+48|0,b);a=Xa(b+48|0);V=b+288|0;return a}function eg(a,b,c){x[a+48>>2]=c?y[c|0]|y[c+1|0]<<8|(y[c+2|0]<<16|y[c+3|0]<<24):0;x[a+52>>2]=y[b|0]|y[b+1|0]<<8|(y[b+2|0]<<16|y[b+3|0]<<24);x[a+56>>2]=y[b+4|0]|y[b+5|0]<<8|(y[b+6|0]<<16|y[b+7|0]<<24);x[a+60>>2]=y[b+8|0]|y[b+9|0]<<8|(y[b+10|0]<<16|y[b+11|0]<<24)}function Ne(a,b,c){var d=0,e=0,f=0,g=0,h=0;a:{while(1){f=0;e=0;if(d>>>0>=32){break a}while(1){b:{g=e+8|0;h=d+1|0;f=y[c+d|0]<>>0>15){break b}e=g;d=h;if(d>>>0<32){continue}}break}d=a+b|0;a=Vc(a,b,f,g);b=d-a|0;d=h;if(a){continue}break}a=0}return a}function _h(a,b,c,d,e,f,g,h,i,j,k){a=a|0;b=b|0;c=c|0;d=d|0;e=e|0;f=f|0;g=g|0;h=h|0;i=i|0;j=j|0;k=k|0;i=d;d=e;e=i|0;a:{if(!d&e>>>0<4294967280){bg(a,a+e|0,0,c,e,d,f,g,h,j,k);if(b){a=e+16|0;d=a>>>0<16?d+1|0:d;x[b>>2]=a;x[b+4>>2]=d}break a}Aa();N()}return 0}function Yh(a,b,c,d,e,f,g,h,i,j,k){a=a|0;b=b|0;c=c|0;d=d|0;e=e|0;f=f|0;g=g|0;h=h|0;i=i|0;j=j|0;k=k|0;i=d;d=e;e=i|0;a:{if(!d&e>>>0<4294967280){ag(a,a+e|0,0,c,e,d,f,g,h,j,k);if(b){a=e+16|0;d=a>>>0<16?d+1|0:d;x[b>>2]=a;x[b+4>>2]=d}break a}Aa();N()}return 0}function Sh(a,b,c,d,e,f,g,h,i,j,k){a=a|0;b=b|0;c=c|0;d=d|0;e=e|0;f=f|0;g=g|0;h=h|0;i=i|0;j=j|0;k=k|0;i=d;d=e;e=i|0;a:{if(!d&e>>>0<4294967280){ef(a,a+e|0,0,c,e,d,f,g,h,j,k);if(b){a=e+16|0;d=a>>>0<16?d+1|0:d;x[b>>2]=a;x[b+4>>2]=d}break a}Aa();N()}return 0}function Df(a,b,c,d,e,f,g){var h=0;h=V-16|0;V=h;a=ya(a,0,128);a:{if(g>>>0<2147483649?d|f:1){x[9301]=22;a=-1;break a}if(!(g>>>0>8191?!f&e>>>0>=3|(f|0)!=0:0)){x[9301]=28;a=-1;break a}Pa(h,16);a=Ob(e,g>>>10|0,1,b,c,h,16,0,32,a,128,1)?-1:0}V=h+16|0;return a}function Fi(a,b){a=a|0;b=b|0;var c=0,d=0;c=V-256|0;V=c;d=-1;a:{if(Wb(b)){break a}if(Fd(c+96|0,b)){break a}if(!Bd(c+96|0)){break a}Ea(c);b=c+136|0;xa(c,c,b);Ea(c+48|0);va(c+48|0,c+48|0,b);wb(c,c);ma(c+48|0,c+48|0,c);cb(a,c+48|0);d=0}V=c+256|0;return d|0}function nh(a,b,c,d,e,f,g,h,i,j,k){a=a|0;b=b|0;c=c|0;d=d|0;e=e|0;f=f|0;g=g|0;h=h|0;i=i|0;j=j|0;k=k|0;a:{b:{switch(k-1|0){case 0:a=Ef(a,b,c,d,e,f,g,h,i,j,1);break a;case 1:a=vf(a,b,c,d,e,f,g,h,i,j,2);break a;default:break b}}x[9301]=28;a=-1}return a|0}function uf(a,b,c,d,e,f,g){var h=0;h=V-16|0;V=h;a=ya(a,0,128);a:{if(g>>>0<2147483649?d|f:1){x[9301]=22;a=-1;break a}d=g>>>0>8191;if(!((d?e:0)|(d?f:0))){x[9301]=28;a=-1;break a}Pa(h,16);a=Ob(e,g>>>10|0,1,b,c,h,16,0,32,a,128,2)?-1:0}V=h+16|0;return a}function Wh(a,b,c,d,e,f,g,h,i,j,k){a=a|0;b=b|0;c=c|0;d=d|0;e=e|0;f=f|0;g=g|0;h=h|0;i=i|0;j=j|0;k=k|0;c=-1;if(!f&e>>>0>=16|f){c=$f(a,d,e-16|0,f-(e>>>0<16)|0,(d+e|0)-16|0,g,h,i,j,k)}if(b){x[b>>2]=c?0:e-16|0;x[b+4>>2]=c?0:f-(e>>>0<16)|0}return c|0}function Uh(a,b,c,d,e,f,g,h,i,j,k){a=a|0;b=b|0;c=c|0;d=d|0;e=e|0;f=f|0;g=g|0;h=h|0;i=i|0;j=j|0;k=k|0;c=-1;if(!f&e>>>0>=16|f){c=_f(a,d,e-16|0,f-(e>>>0<16)|0,(d+e|0)-16|0,g,h,i,j,k)}if(b){x[b>>2]=c?0:e-16|0;x[b+4>>2]=c?0:f-(e>>>0<16)|0}return c|0}function Qh(a,b,c,d,e,f,g,h,i,j,k){a=a|0;b=b|0;c=c|0;d=d|0;e=e|0;f=f|0;g=g|0;h=h|0;i=i|0;j=j|0;k=k|0;c=-1;if(!f&e>>>0>=16|f){c=df(a,d,e-16|0,f-(e>>>0<16)|0,(d+e|0)-16|0,g,h,i,j,k)}if(b){x[b>>2]=c?0:e-16|0;x[b+4>>2]=c?0:f-(e>>>0<16)|0}return c|0}function vi(a,b,c){a=a|0;b=b|0;c=c|0;var d=0,e=0;e=V-320|0;V=e;d=-1;if(!Db(e,c)){d=0;while(1){v[a+d|0]=y[b+d|0];d=d+1|0;if((d|0)!=32){continue}break}v[a+31|0]=y[a+31|0]&127;pg(e+160|0,a,e);Vb(a,e+160|0);d=fb(a,32)?-1:0}V=e+320|0;return d|0}function Qd(a,b){var c=0;a:{if(!(b&4)){break a}b=x[a>>2];if(b){oa(x[b+4>>2],x[a+16>>2]<<10)}b=x[a+4>>2];if(!b){break a}oa(b,x[a+20>>2]<<3)}Ka(x[a+4>>2]);x[a+4>>2]=0;b=x[a>>2];b:{if(!b){break b}c=x[b>>2];if(!c){break b}Ka(c)}Ka(b);x[a>>2]=0}function lc(a,b){var c=0,d=0,e=0,f=0,g=0,h=0,i=0;d=V-16|0;V=d;c=10;while(1){a:{g=c;c=c-1|0;e=c+(d+6|0)|0;f=(b>>>0)/10|0;v[e|0]=b-D(f,10)|48;if(b>>>0<10){break a}b=f;if(c){continue}}break}b=a;a=11-g|0;h=za(b,e,a)+a|0,i=0,v[h|0]=i;V=d+16|0}function Ig(a,b,c,d){a=a|0;b=b|0;c=c|0;d=d|0;var e=0;e=c;c=V-128|0;V=c;d=-1;a:{if((Ke(a)|0)!=101){break a}if(_c(c)){break a}ya(c+16|0,0,102);b=Oe(c,b,e,a,c+16|0);Zc(c);if(!b){break a}d=rb(c+16|0,a,102);oa(c+16|0,102)}V=c+128|0;return d|0}function zc(a,b,c){var d=0,e=0,f=0,g=0;f=V-48|0;V=f;d=b+40|0;va(a,d,b);e=a+40|0;xa(e,d,b);d=a+80|0;ma(d,a,c+40|0);ma(e,e,c);g=a+120|0;ma(g,c+120|0,b+120|0);ma(a,b+80|0,c+80|0);va(f,a,a);xa(a,d,e);va(e,d,e);xa(d,f,g);va(g,f,g);V=f+48|0}function Da(a,b,c){var d=0,e=0,f=0,g=0;f=V-48|0;V=f;d=b+40|0;va(a,d,b);e=a+40|0;xa(e,d,b);d=a+80|0;ma(d,a,c);ma(e,e,c+40|0);g=a+120|0;ma(g,c+120|0,b+120|0);ma(a,b+80|0,c+80|0);va(f,a,a);xa(a,d,e);va(e,d,e);va(d,f,g);xa(g,f,g);V=f+48|0}function wc(a,b,c){a=a|0;b=b|0;c=c|0;var d=0,e=0,f=0;d=V-16|0;V=d;v[d+15|0]=0;f=-1;if(!(Z[x[9087]](a,b,c)|0)){while(1){v[d+15|0]=y[a+e|0]|y[d+15|0];e=e+1|0;if((e|0)!=32){continue}break}f=0-(y[d+15|0]-1>>>8&1)|0}V=d+16|0;return f|0}function Pd(a,b){var c=0,d=0,e=0,f=0;while(1){c=d<<3;e=c+a|0;c=b+c|0;f=y[c|0]|y[c+1|0]<<8|(y[c+2|0]<<16|y[c+3|0]<<24);c=y[c+4|0]|y[c+5|0]<<8|(y[c+6|0]<<16|y[c+7|0]<<24);x[e>>2]=f;x[e+4>>2]=c;d=d+1|0;if((d|0)!=128){continue}break}}function Ya(a,b,c){var d=0,e=0;if(!c){return 0}d=y[a|0];a:{if(d){while(1){e=y[b|0];if(!e){break a}c=c-1|0;if(!c){break a}b:{if((d|0)==(e|0)){break b}break a}b=b+1|0;d=y[a+1|0];a=a+1|0;if(d){continue}break}}d=0}return d-y[b|0]|0}function Lb(a){a=a|0;var b=0;x[a+32>>2]=0;x[a+36>>2]=0;b=x[8989];x[a>>2]=x[8988];x[a+4>>2]=b;b=x[8991];x[a+8>>2]=x[8990];x[a+12>>2]=b;b=x[8993];x[a+16>>2]=x[8992];x[a+20>>2]=b;b=x[8995];x[a+24>>2]=x[8994];x[a+28>>2]=b;return 0}function ec(a,b,c,d){var e=0,f=0,g=0;dc(c,((d<<7)+a|0)+-64|0);e=d<<1;if(e){g=d<<4;d=0;while(1){f=d<<6;Te(c,f+a|0);Se(c);dc((d<<5)+b|0,c);Te(c,(f|64)+a|0);Se(c);dc(((d<<3)+g<<2)+b|0,c);d=d+2|0;if(e>>>0>d>>>0){continue}break}}}function Cc(a,b,c){var d=0;d=V-16|0;x[d+12>>2]=a;x[d+8>>2]=b;b=0;x[d+4>>2]=0;if((c|0)>=1){while(1){x[d+4>>2]=x[d+4>>2]|y[x[d+8>>2]+b|0]^y[x[d+12>>2]+b|0];b=b+1|0;if((c|0)!=(b|0)){continue}break}}return(x[d+4>>2]-1>>>8&1)-1|0}function Ed(a,b,c){var d=0,e=0,f=0,g=0;f=V-48|0;V=f;d=b+40|0;va(a,d,b);e=a+40|0;xa(e,d,b);d=a+80|0;ma(d,a,c);ma(e,e,c+40|0);g=a+120|0;ma(g,c+80|0,b+120|0);b=b+80|0;va(f,b,b);xa(a,d,e);va(e,d,e);va(d,f,g);xa(g,f,g);V=f+48|0}function cj(a,b,c){a=a|0;b=b|0;c=c|0;var d=0,e=0;d=V-800|0;V=d;e=-1;a:{if(Db(d+640|0,b)){break a}if(Db(d+480|0,c)){break a}Ca(d,d+480|0);Da(d+160|0,d+640|0,d);wa(d+320|0,d+160|0);Vb(a,d+320|0);e=0}V=d+800|0;return e|0}function bj(a,b,c){a=a|0;b=b|0;c=c|0;var d=0,e=0;d=V-800|0;V=d;e=-1;a:{if(Db(d+640|0,b)){break a}if(Db(d+480|0,c)){break a}Ca(d,d+480|0);zc(d+160|0,d+640|0,d);wa(d+320|0,d+160|0);Vb(a,d+320|0);e=0}V=d+800|0;return e|0}function Fj(a,b,c,d){var e=0,f=0,g=0,h=0,i=0,j=0;e=c>>>16|0;f=a>>>16|0;j=D(e,f);g=c&65535;h=a&65535;i=D(g,h);f=(i>>>16|0)+D(f,g)|0;e=(f&65535)+D(e,h)|0;Y=(D(b,c)+j|0)+D(a,d)+(f>>>16)+(e>>>16)|0;return i&65535|e<<16}function sj(a,b,c,d,e,f,g,h){a=a|0;b=b|0;c=c|0;d=d|0;e=e|0;f=f|0;g=g|0;h=h|0;var i=0;i=V-80|0;V=i;if(c|d){ra(i+8|0,f);ra(i+12|0,g);sc(i+16|0,h);fg(i+16|0,e,i+8|0);rc(i+16|0,b,a,c,d);oa(i+16|0,64)}V=i+80|0;return 0}function rb(a,b,c){var d=0;d=V-16|0;x[d+12>>2]=a;x[d+8>>2]=b;b=0;v[d+7|0]=0;if(c){while(1){v[d+7|0]=y[d+7|0]|y[x[d+8>>2]+b|0]^y[x[d+12>>2]+b|0];b=b+1|0;if((c|0)!=(b|0)){continue}break}}return(y[d+7|0]-1>>>8&1)-1|0}function eh(a,b,c,d,e,f){a=a|0;b=b|0;c=c|0;d=d|0;e=e|0;f=f|0;var g=0;g=-1;a:{if(d-1>>>0>63|c>>>0>64){break a}b:{if(!(c?b:0)){if(!we(a,d&255,e,f)){break b}break a}if(ge(a,d&255,b,c&255,e,f)){break a}}g=0}return g|0}function cf(a,b){a=a|0;b=b|0;var c=0;c=V-896|0;V=c;db(c+848|0,b);db(c+800|0,b+32|0);gg(c+320|0,c+848|0);gg(c+160|0,c+800|0);Ca(c+640|0,c+160|0);Da(c+480|0,c+320|0,c+640|0);wa(c,c+480|0);Vb(a,c);V=c+896|0;return 0}function Ge(a,b,c){var d=0,e=0;e=V-160|0;V=e;while(1){v[a+d|0]=y[b+d|0];d=d+1|0;if((d|0)!=32){continue}break}if(c){Ie(a)}v[a+31|0]=y[a+31|0]&127;Yb(e,a);mb(a,e);d=-1;if(!He(a)){d=fb(b,32)?-1:0}V=e+160|0;return d}function Pe(a,b){var c=0,d=0,e=0,f=0;c=V-16|0;V=c;a:{while(1){if(Qe(c+12|0,y[b|0])){b=0;x[a>>2]=0;break a}b=b+1|0;e=x[c+12>>2]<>>0<24;d=d+6|0;if(f){continue}break}x[a>>2]=e}V=c+16|0;return b}function ui(a,b){a=a|0;b=b|0;var c=0,d=0;c=V-160|0;V=c;while(1){v[a+d|0]=y[b+d|0];d=d+1|0;if((d|0)!=32){continue}break}v[a+31|0]=y[a+31|0]&127;Yb(c,a);Vb(a,c);a=fb(a,32);V=c+160|0;return(a?-1:0)|0}function mh(a,b,c,d,e,f,g,h){a=a|0;b=b|0;c=c|0;d=d|0;e=e|0;f=f|0;g=g|0;h=h|0;a:{b:{switch(h-1|0){case 1:a=uf(a,b,c,d,e,f,g);break a;default:Aa();N();case 0:break b}}a=Df(a,b,c,d,e,f,g)}return a|0}function rj(a,b,c,d,e,f,g){a=a|0;b=b|0;c=c|0;d=d|0;e=e|0;f=f|0;g=g|0;var h=0;h=V-80|0;V=h;if(c|d){ra(h+12|0,f);sc(h+16|0,g);eg(h+16|0,e,h+12|0);rc(h+16|0,b,a,c,d);oa(h+16|0,64)}V=h+80|0;return 0}function Mg(a,b,c,d,e,f){a=a|0;b=b|0;c=c|0;d=d|0;e=e|0;f=f|0;var g=0,h=0,i=0;g=V-32|0;V=g;h=-1;i=d;if(!d&c>>>0>=48|d){ic(g,b,e);h=hf(a,b+32|0,c-32|0,i-(c>>>0<32)|0,g,b,f)}V=g+32|0;return h|0}function Ah(a,b,c,d,e,f){a=a|0;b=b|0;c=c|0;d=d|0;e=e|0;f=f|0;var g=0,h=0,i=0;g=V-32|0;V=g;h=-1;i=d;if(!d&c>>>0>=48|d){ic(g,b,e);h=qe(a,b+32|0,c-32|0,i-(c>>>0<32)|0,g,b,f)}V=g+32|0;return h|0}function Ib(a,b,c,d){a=a|0;b=b|0;c=c|0;d=d|0;var e=0;e=-1;a:{if(d-1>>>0>63|c>>>0>64){break a}b:{if(!(c?b:0)){if(!Ee(a,d&255)){break b}break a}if(ne(a,d&255,b,c&255)){break a}}e=0}return e|0}function Va(a,b){var c=0,d=0,e=0,f=0,g=0;d=V-48|0;V=d;qa(a,b);c=a+80|0;g=b+40|0;qa(c,g);f=a+120|0;qg(f,b+80|0);e=a+40|0;va(e,b,g);qa(d,e);va(e,c,a);xa(c,c,a);xa(a,d,e);xa(f,f,c);V=d+48|0}function ub(a,b,c,d,e,f,g){var h=0,i=0,j=0;h=d;i=c+63|0;h=i>>>0<63?h+1|0:h;j=h>>>6|0;h=(h&63)<<26|i>>>6;i=0-h|0;if((j+((h|0)!=0)|0)==1&i>>>0>>0){Aa();N()}return vd(a,b,c,d,e,f,g)}function Ee(a,b){var c=0;c=V+-64|0;V=c;if((b-1&255)>>>0>=64){Aa();N()}v[c+3|0]=1;v[c+1|0]=0;v[c+2|0]=1;v[c|0]=b;bc(c|4);Ba(c|8,0,0);ya(c+16|0,0,48);cc(a,c);V=c- -64|0;return 0}function tb(a){var b=0,c=0;b=x[9080];c=a+3&-4;a=b+c|0;a:{if(a>>>0<=b>>>0?c:0){break a}if(a>>>0>_()<<16>>>0){if(!(U(a|0)|0)){break a}}x[9080]=a;return b}x[9301]=48;return-1}function xb(a,b){var c=0,d=0,e=0,f=0;while(1){c=e<<3;d=c+a|0;c=b+c|0;f=x[c>>2];c=x[d+4>>2]^x[c+4>>2];x[d>>2]=x[d>>2]^f;x[d+4>>2]=c;e=e+1|0;if((e|0)!=128){continue}break}}function Kf(a){var b=0,c=0;b=a+65510>>>8&255;c=a+65484>>>8|0;return((a^32704)+1>>>8^-1)&95|(((a^16321)+1>>>8^-1)&45|b&a+65)|c&a+71&(b^255)|a+252&a+65474>>>8&(c^-1)&255}function Jf(a){var b=0,c=0;b=a+65510>>>8&255;c=a+65484>>>8|0;return((a^16320)+1>>>8^-1)&47|(((a^16321)+1>>>8^-1)&43|b&a+65)|c&a+71&(b^255)|a+252&a+65474>>>8&(c^-1)&255}function kg(a){var b=0,c=0,d=0,e=0,f=0;d=1;b=31;while(1){e=y[a+b|0];f=y[b+3504|0];c=e-f>>8&d|c;if(b){d=(e^f)+65535>>>8&d;b=b-1|0;c=c&255;continue}break}return(c|0)!=0}function mb(a,b){var c=0,d=0,e=0;c=V-144|0;V=c;wb(c+96|0,b+80|0);ma(c+48|0,b,c+96|0);ma(c,b+40|0,c+96|0);cb(a,c);d=a,e=nb(c+48|0)<<7^y[a+31|0],v[d+31|0]=e;V=c+144|0}function qj(a){a=a|0;var b=0,c=0;b=V-160|0;V=b;a:{if(!Ad(a)){break a}if(Wb(a)){break a}if(ob(b,a)){break a}if(!Xb(b)){break a}c=(Bd(b)|0)!=0}V=b+160|0;return c|0}function fe(a,b,c,d,e,f,g){a=a|0;b=b|0;c=c|0;d=d|0;e=e|0;f=f|0;g=g|0;var h=0,i=0;h=V-32|0;V=h;i=-1;if(!nc(h,f,g)){i=Nf(a,b,c,d,e,h);oa(h,32)}V=h+32|0;return i|0}function ee(a,b,c,d,e,f,g){a=a|0;b=b|0;c=c|0;d=d|0;e=e|0;f=f|0;g=g|0;var h=0,i=0;h=V-32|0;V=h;i=-1;if(!nc(h,f,g)){i=Mf(a,b,c,d,e,h);oa(h,32)}V=h+32|0;return i|0}function yb(a,b,c){var d=0;if(a>>>0>>0){return za(a,b,c)}if(c){d=a+c|0;b=b+c|0;while(1){d=d-1|0;b=b-1|0;v[d|0]=y[b|0];c=c-1|0;if(c){continue}break}}return a}function fb(a,b){var c=0,d=0;c=V-16|0;v[c+15|0]=0;if(b){while(1){v[c+15|0]=y[a+d|0]|y[c+15|0];d=d+1|0;if((d|0)!=(b|0)){continue}break}}return y[c+15|0]-1>>>8&1}function Vc(a,b,c,d){var e=0;if(d){while(1){if(!b){return 0}v[a|0]=y[(c&63)+1024|0];c=c>>>6|0;b=b-1|0;a=a+1|0;e=e+6|0;if(e>>>0>>0){continue}break}}return a} +function Tf(a,b,c){var d=0,e=0,f=0;if(c>>>0>=8){e=c>>>3|0;c=0;while(1){d=c<<3;f=d+a|0;d=b+d|0;Sf(f,x[d>>2],x[d+4>>2]);c=c+1|0;if((e|0)!=(c|0)){continue}break}}}function vj(a,b,c,d,e){a=a|0;b=b|0;c=c|0;d=d|0;e=e|0;var f=0;f=V+-64|0;V=f;if(b|c){sc(f,e);fg(f,d,0);a=ya(a,0,b);rc(f,a,a,b,c);oa(f,64)}V=f- -64|0;return 0}function tj(a,b,c,d,e){a=a|0;b=b|0;c=c|0;d=d|0;e=e|0;var f=0;f=V+-64|0;V=f;if(b|c){sc(f,e);eg(f,d,0);a=ya(a,0,b);rc(f,a,a,b,c);oa(f,64)}V=f- -64|0;return 0}function lh(a,b,c,d){a=a|0;b=b|0;c=c|0;d=d|0;a:{if(!Ya(a,1559,10)){a=tf(a,b,c,d);break a}if(!Ya(a,1549,9)){a=Cf(a,b,c,d);break a}x[9301]=28;a=-1}return a|0}function kh(a,b,c,d){a=a|0;b=b|0;c=c|0;d=d|0;a:{if(!Ya(a,1559,10)){a=zf(a,b,c,d);break a}if(!Ya(a,1549,9)){a=Bf(a,b,c,d);break a}x[9301]=28;a=-1}return a|0}function ih(a,b,c,d,e,f){a=a|0;b=b|0;c=c|0;d=d|0;e=e|0;f=f|0;var g=0;g=d;if(!d&c>>>0>=16|d){a=Qc(a,b+16|0,b,c-16|0,g-(c>>>0<16)|0,e,f)}else{a=-1}return a|0}function Re(a,b,c,d){var e=0;a:{if(y[a|0]!=36|y[a+1|0]!=55|y[a+2|0]!=36){break a}if(Qe(b,y[a+3|0])){break a}a=Pe(c,a+4|0);if(!a){break a}e=Pe(d,a)}return e}function Pg(a,b,c,d,e,f){a=a|0;b=b|0;c=c|0;d=d|0;e=e|0;f=f|0;var g=0;g=d;if(!d&c>>>0>=16|d){a=$c(a,b+16|0,b,c-16|0,g-(c>>>0<16)|0,e,f)}else{a=-1}return a|0}function Fg(a,b,c,d,e,f){a=a|0;b=b|0;c=c|0;d=d|0;e=e|0;f=f|0;var g=0;g=d;if(!d&c>>>0>=16|d){a=cd(a,b+16|0,b,c-16|0,g-(c>>>0<16)|0,e,f)}else{a=-1}return a|0}function Dh(a,b,c,d,e,f){a=a|0;b=b|0;c=c|0;d=d|0;e=e|0;f=f|0;var g=0;g=d;if(!d&c>>>0>=16|d){a=Oc(a,b+16|0,b,c-16|0,g-(c>>>0<16)|0,e,f)}else{a=-1}return a|0}function Me(a,b,c,d,e,f,g,h,i,j){var k=0,l=0,m=0,n=0,o=0;k=V-16|0;V=k;l=-1;if(!_c(k)){l=(m=-1,n=Xe(k,a,b,c,d,e,f,g,h,i,j),o=Zc(k),o?m:n)}V=k+16|0;return l}function Cj(a){a=a|0;var b=0,c=0;if(a>>>0>=2){c=(0-a>>>0)%(a>>>0)|0;while(1){b=Dd();if(b>>>0>>0){continue}break}a=(b>>>0)%(a>>>0)|0}else{a=0}return a|0}function ka(a,b,c,d){var e=0;d=b+d|0;e=a+c|0;d=e>>>0>>0?d+1|0:d;b=b<<1|a>>>31;c=Fj(a<<1&-2,b&1,c,0);b=c+e|0;a=Y+d|0;a=b>>>0>>0?a+1|0:a;Y=a;return b}function Ue(a,b,c){var d=0,e=0,f=0;if(c>>>0>=4){f=c>>>2|0;c=0;while(1){d=c<<2;e=d+a|0;x[e>>2]=x[e>>2]^x[b+d>>2];c=c+1|0;if((f|0)!=(c|0)){continue}break}}}function Lh(a,b,c,d,e){a=a|0;b=b|0;c=c|0;d=d|0;e=e|0;var f=0;f=V+-64|0;V=f;mf(f,b,c,d,e);b=Od(a,f);c=rb(f,a,64);V=f- -64|0;return c|((a|0)==(f|0)?-1:b)}function he(a,b,c,d,e){a=a|0;b=b|0;c=c|0;d=d|0;e=e|0;var f=0;f=V-32|0;V=f;je(f,b,c,d,e);b=_b(a,f);c=rb(f,a,32);V=f+32|0;return c|((a|0)==(f|0)?-1:b)}function Nh(a,b,c,d,e){a=a|0;b=b|0;c=c|0;d=d|0;e=e|0;var f=0;f=V-32|0;V=f;Ze(f,b,c,d,e);b=_b(a,f);c=rb(f,a,32);V=f+32|0;return c|((a|0)==(f|0)?-1:b)}function Ad(a){var b=0,c=0;c=(y[a+31|0]^-1)&127;b=30;while(1){c=y[a+b|0]^-1|c;b=b-1|0;if(b){continue}break}return(((c&255)-1&236-y[a|0])>>>8^-1)&1}function tf(a,b,c,d){a:{b:{if((d|0)==1|d>>>0>1){x[9301]=22;break b}a=Hf(a,b,c,2);if(!a){break a}if((a|0)!=-35){break b}x[9301]=28}a=-1}return a}function Zh(a,b,c,d,e,f,g,h,i,j,k,l){a=a|0;b=b|0;c=c|0;d=d|0;e=e|0;f=f|0;g=g|0;h=h|0;i=i|0;j=j|0;k=k|0;l=l|0;return ag(a,b,c,d,e,f,g,h,i,k,l)|0}function Th(a,b,c,d,e,f,g,h,i,j,k,l){a=a|0;b=b|0;c=c|0;d=d|0;e=e|0;f=f|0;g=g|0;h=h|0;i=i|0;j=j|0;k=k|0;l=l|0;return ef(a,b,c,d,e,f,g,h,i,k,l)|0}function Cf(a,b,c,d){a:{b:{if((d|0)==1|d>>>0>1){x[9301]=22;break b}a=Hf(a,b,c,1);if(!a){break a}if((a|0)!=-35){break b}x[9301]=28}a=-1}return a}function $h(a,b,c,d,e,f,g,h,i,j,k,l){a=a|0;b=b|0;c=c|0;d=d|0;e=e|0;f=f|0;g=g|0;h=h|0;i=i|0;j=j|0;k=k|0;l=l|0;return bg(a,b,c,d,e,f,g,h,i,k,l)|0}function jh(a,b,c,d,e,f){a=a|0;b=b|0;c=c|0;d=d|0;e=e|0;f=f|0;var g=0;g=d;if(!d&c>>>0>=4294967280|d){Aa();N()}Rc(a+16|0,a,b,c,g,e,f);return 0}function Tg(a,b,c,d,e,f){a=a|0;b=b|0;c=c|0;d=d|0;e=e|0;f=f|0;var g=0;g=d;if(!d&c>>>0>=4294967280|d){Aa();N()}return ad(a+16|0,a,b,c,g,e,f)|0}function Hh(a,b,c,d,e,f){a=a|0;b=b|0;c=c|0;d=d|0;e=e|0;f=f|0;var g=0;g=d;if(!d&c>>>0>=4294967280|d){Aa();N()}return Pc(a+16|0,a,b,c,g,e,f)|0}function Gg(a,b,c,d,e,f){a=a|0;b=b|0;c=c|0;d=d|0;e=e|0;f=f|0;var g=0;g=d;if(!d&c>>>0>=4294967280|d){Aa();N()}dd(a+16|0,a,b,c,g,e,f);return 0}function He(a){var b=0,c=0;c=y[a|0]^1;b=1;while(1){c=y[a+b|0]|c;b=b+1|0;if((b|0)!=31){continue}break}return(y[a+31|0]&127|c&255)-1>>>8&1}function uh(a,b,c,d,e,f,g,h,i,j,k){a=a|0;b=b|0;c=c|0;d=d|0;e=e|0;f=f|0;g=g|0;h=h|0;i=i|0;j=j|0;k=k|0;return Ef(a,b,c,d,e,f,g,h,i,j,k)|0}function ph(a,b,c,d,e,f,g,h,i,j,k){a=a|0;b=b|0;c=c|0;d=d|0;e=e|0;f=f|0;g=g|0;h=h|0;i=i|0;j=j|0;k=k|0;return vf(a,b,c,d,e,f,g,h,i,j,k)|0}function We(a,b,c){var d=0,e=0;if(c>>>0>=4){e=c>>>2|0;c=0;while(1){d=c<<2;x[d+a>>2]=x[b+d>>2];c=c+1|0;if((e|0)!=(c|0)){continue}break}}}function Xh(a,b,c,d,e,f,g,h,i,j,k){a=a|0;b=b|0;c=c|0;d=d|0;e=e|0;f=f|0;g=g|0;h=h|0;i=i|0;j=j|0;k=k|0;return $f(a,c,d,e,f,g,h,i,j,k)|0}function Vh(a,b,c,d,e,f,g,h,i,j,k){a=a|0;b=b|0;c=c|0;d=d|0;e=e|0;f=f|0;g=g|0;h=h|0;i=i|0;j=j|0;k=k|0;return _f(a,c,d,e,f,g,h,i,j,k)|0}function Rh(a,b,c,d,e,f,g,h,i,j,k){a=a|0;b=b|0;c=c|0;d=d|0;e=e|0;f=f|0;g=g|0;h=h|0;i=i|0;j=j|0;k=k|0;return df(a,c,d,e,f,g,h,i,j,k)|0}function bf(a,b){var c=0,d=0,e=0;while(1){e=a+c|0;d=y[e|0]-(y[b+c|0]+d|0)|0;v[e|0]=d;d=d>>>8&1;c=c+1|0;if((c|0)!=64){continue}break}}function Ba(a,b,c){v[a|0]=b;v[a+1|0]=b>>>8;v[a+2|0]=b>>>16;v[a+3|0]=b>>>24;v[a+4|0]=c;v[a+5|0]=c>>>8;v[a+6|0]=c>>>16;v[a+7|0]=c>>>24}function oa(a,b){var c=0;c=V-16|0;x[c+12>>2]=a;if(b){a=0;while(1){v[x[c+12>>2]+a|0]=0;a=a+1|0;if((b|0)!=(a|0)){continue}break}}}function zg(a,b,c,d,e){a=a|0;b=b|0;c=c|0;d=d|0;e=e|0;var f=0;f=V-32|0;V=f;bb(f,d,e,0);a=Rb(a,b,c,d+16|0,f);V=f+32|0;return a|0}function jj(a,b){a=a|0;b=b|0;var c=0;pd(b);c=(a>>>0)/3|0;a=D(c,-3)+a|0;return D(4-(3-a&0-(b>>>1&1))|0,(a|a>>>1)&1)+(c<<2|1)|0}function Pa(a,b){a=a|0;b=b|0;var c=0,d=0,e=0;if(b){while(1){d=a+c|0,e=Dd(),v[d|0]=e;c=c+1|0;if((c|0)!=(b|0)){continue}break}}}function Nd(a,b,c,d,e){a=a|0;b=b|0;c=c|0;d=d|0;e=e|0;var f=0,g=0;g=V;f=g-128&-64;V=f;Md(f,e);Ld(f,b,c,d);Kd(f,a);V=g;return 0}function Lg(a,b,c,d,e,f,g,h,i,j){a=a|0;b=b|0;c=c|0;d=d|0;e=e|0;f=f|0;g=g|0;h=h|0;i=i|0;j=j|0;return Me(a,b,c,d,e,f,g,h,i,j)|0}function vh(a,b,c,d){a=a|0;b=b|0;c=c|0;d=d|0;var e=0;e=V-112|0;V=e;Lb(e+8|0);qb(e+8|0,b,c,d);Kb(e+8|0,a);V=e+112|0;return 0}function lb(a,b,c){var d=0;a:{if((b|0)<1){break a}d=1;while(1){qa(a,a);if((b|0)==(d|0)){break a}d=d+1|0;continue}}ma(a,a,c)}function Qa(a,b,c){var d=0;a:{if((b|0)<1){break a}d=1;while(1){Fb(a,a);if((b|0)==(d|0)){break a}d=d+1|0;continue}}Ga(a,a,c)}function ue(a,b,c,d,e,f,g,h){var i=0,j=0;i=V-32|0;V=i;j=-1;if(!Sc(i,g,h)){j=Pc(a,b,c,d,e,f,i);oa(i,32)}V=i+32|0;return j}function re(a,b,c,d,e,f,g,h){var i=0,j=0;i=V-32|0;V=i;j=-1;if(!Sc(i,g,h)){j=Oc(a,b,c,d,e,f,i);oa(i,32)}V=i+32|0;return j}function lf(a,b,c,d,e,f,g,h){var i=0,j=0;i=V-32|0;V=i;j=-1;if(!bd(i,g,h)){j=ad(a,b,c,d,e,f,i);oa(i,32)}V=i+32|0;return j}function jf(a,b,c,d,e,f,g,h){var i=0,j=0;i=V-32|0;V=i;j=-1;if(!bd(i,g,h)){j=$c(a,b,c,d,e,f,i);oa(i,32)}V=i+32|0;return j}function gf(a){var b=0,c=0,d=0;b=1;while(1){d=a+c|0;b=y[d|0]+b|0;v[d|0]=b;b=b>>>8|0;c=c+1|0;if((c|0)!=4){continue}break}}function Te(a,b){var c=0,d=0,e=0;while(1){d=c<<2;e=d+a|0;x[e>>2]=x[e>>2]^x[b+d>>2];c=c+1|0;if((c|0)!=16){continue}break}}function nc(a,b,c){a=a|0;b=b|0;c=c|0;var d=0,e=0;d=V-32|0;V=d;e=-1;if(!wc(d,c,b)){e=Ab(a,35856,d,0)}V=d+32|0;return e|0}function bd(a,b,c){a=a|0;b=b|0;c=c|0;var d=0,e=0;d=V-32|0;V=d;e=-1;if(!wc(d,c,b)){e=bb(a,35920,d,0)}V=d+32|0;return e|0}function ed(a,b){a=a|0;b=b|0;var c=0;c=V+-64|0;V=c;_a(a,c);a=a+208|0;Na(a,c,64,0);_a(a,b);oa(c,64);V=c- -64|0;return 0}function ze(a,b,c,d){a=a|0;b=b|0;c=c|0;d=d|0;var e=0;e=V+-64|0;V=e;_a(a,e);a=pf(b,c,e,64,0,d,1);V=e- -64|0;return a|0}function wg(a,b,c,d,e){a=a|0;b=b|0;c=c|0;d=d|0;e=e|0;var f=0;f=V-16|0;V=f;Nd(f,b,c,d,e);a=Gb(a,f);V=f+16|0;return a|0}function wa(a,b){var c=0,d=0,e=0;c=b+120|0;ma(a,b,c);d=b+40|0;e=b+80|0;ma(a+40|0,d,e);ma(a+80|0,e,c);ma(a+120|0,b,d)}function kb(a,b){var c=0,d=0;c=V-128|0;V=c;d=c+8|0;La(d,b);La(d+40|0,b+40|0);La(d+80|0,b+80|0);Va(a,c+8|0);V=c+128|0}function xh(a,b,c,d,e,f,g,h,i){a=a|0;b=b|0;c=c|0;d=d|0;e=e|0;f=f|0;g=g|0;h=h|0;i=i|0;return Zd(a,b,c,d,e,f,g,h,i)|0}function _e(a,b){b=b<<8&16711680|b<<24|(b>>>8&65280|b>>>24);v[a|0]=b;v[a+1|0]=b>>>8;v[a+2|0]=b>>>16;v[a+3|0]=b>>>24}function Xc(a,b){a=a|0;b=b|0;var c=0;c=V-32|0;V=c;Kb(a,c);a=a+104|0;qb(a,c,32,0);Kb(a,b);oa(c,32);V=c+32|0;return 0}function Qf(a,b,c,d,e,f,g,h){var i=0;i=V-32|0;V=i;Ab(i,e,h,0);a=uc(a,b,c,d,e+16|0,f,g,i);oa(i,32);V=i+32|0;return a}function za(a,b,c){var d=0;if(c){d=a;while(1){v[d|0]=y[b|0];d=d+1|0;b=b+1|0;c=c-1|0;if(c){continue}break}}return a}function Yf(a){a=a|0;while(1){Pa(a,32);v[a+31|0]=y[a+31|0]&31;if(!kg(a)){continue}if(fb(a,32)){continue}break}}function qe(a,b,c,d,e,f,g){if(!d&c>>>0>=16|d){a=re(a,b+16|0,b,c-16|0,d-(c>>>0<16)|0,e,f,g)}else{a=-1}return a}function hf(a,b,c,d,e,f,g){if(!d&c>>>0>=16|d){a=jf(a,b+16|0,b,c-16|0,d-(c>>>0<16)|0,e,f,g)}else{a=-1}return a}function ye(a,b,c){a=a|0;b=b|0;c=c|0;var d=0;d=V+-64|0;V=d;_a(a,d);a=De(b,d,64,0,c,1);V=d- -64|0;return a|0}function xe(a,b,c,d,e,f,g,h){var i=0;i=V-32|0;V=i;bb(i,e,h,0);a=Cb(a,b,c,d,e+16|0,f,g,i);V=i+32|0;return a}function yg(a,b,c,d,e,f,g,h){a=a|0;b=b|0;c=c|0;d=d|0;e=e|0;f=f|0;g=g|0;h=h|0;return xe(a,b,c,d,e,f,g,h)|0}function uj(){var a=0,b=0;a=x[9300];a:{if(!a){break a}a=x[a+20>>2];if(!a){break a}b=Z[a|0]()|0}return b|0}function oe(a,b){var c=0,d=0;while(1){d=a+c|0;v[d|0]=y[d|0]^y[b+c|0];c=c+1|0;if((c|0)!=8){continue}break}}function dh(a,b,c,d,e,f,g,h){a=a|0;b=b|0;c=c|0;d=d|0;e=e|0;f=f|0;g=g|0;h=h|0;return Cb(a,b,c,d,e,f,g,h)|0}function Zg(a,b,c,d,e,f,g,h){a=a|0;b=b|0;c=c|0;d=d|0;e=e|0;f=f|0;g=g|0;h=h|0;return uc(a,b,c,d,e,f,g,h)|0}function Xg(a,b,c,d,e,f,g,h){a=a|0;b=b|0;c=c|0;d=d|0;e=e|0;f=f|0;g=g|0;h=h|0;return Qf(a,b,c,d,e,f,g,h)|0}function Ug(a,b,c,d,e,f,g,h){a=a|0;b=b|0;c=c|0;d=d|0;e=e|0;f=f|0;g=g|0;h=h|0;return lf(a,b,c,d,e,f,g,h)|0}function Qg(a,b,c,d,e,f,g,h){a=a|0;b=b|0;c=c|0;d=d|0;e=e|0;f=f|0;g=g|0;h=h|0;return jf(a,b,c,d,e,f,g,h)|0}function Ih(a,b,c,d,e,f,g,h){a=a|0;b=b|0;c=c|0;d=d|0;e=e|0;f=f|0;g=g|0;h=h|0;return ue(a,b,c,d,e,f,g,h)|0}function Eh(a,b,c,d,e,f,g,h){a=a|0;b=b|0;c=c|0;d=d|0;e=e|0;f=f|0;g=g|0;h=h|0;return re(a,b,c,d,e,f,g,h)|0}function ic(a,b,c){var d=0,e=0;e=V;d=e-384&-64;V=d;kc(d,0,0,24);gb(d,b,32,0);gb(d,c,32,0);jc(d,a,24);V=e}function Rf(a,b,c,d,e){var f=0;f=V-32|0;V=f;Ab(f,d,e,0);a=xd(a,b,c,d+16|0,f);oa(f,32);V=f+32|0;return a}function Ke(a){var b=0;while(1){if(!y[a+b|0]){return b}b=b+1|0;if((b|0)!=102){continue}break}return 102}function dc(a,b){var c=0,d=0;while(1){d=c<<2;x[d+a>>2]=x[b+d>>2];c=c+1|0;if((c|0)!=16){continue}break}}function ya(a,b,c){var d=0;if(c){d=a;while(1){v[d|0]=b;d=d+1|0;c=c-1|0;if(c){continue}break}}return a}function Ca(a,b){var c=0;c=b+40|0;va(a,c,b);xa(a+40|0,c,b);La(a+80|0,b+80|0);ma(a+120|0,b+120|0,2272)}function Hb(a,b,c){a=a|0;b=b|0;c=c|0;if(c>>>0>=256){Q(1349,1262,107,1123);N()}return Gc(a,b,c&255)|0}function sb(a){a=a|0;x[a+64>>2]=0;x[a+68>>2]=0;x[a+72>>2]=0;x[a+76>>2]=0;za(a,35024,64);return 0}function ab(a,b){var c=0,d=0;c=b+120|0;ma(a,b,c);d=b+40|0;b=b+80|0;ma(a+40|0,d,b);ma(a+80|0,b,c)}function zh(a,b,c,d,e,f,g){a=a|0;b=b|0;c=c|0;d=d|0;e=e|0;f=f|0;g=g|0;return qf(a,b,c,d,e,f,g)|0}function th(a,b,c,d,e,f,g){a=a|0;b=b|0;c=c|0;d=d|0;e=e|0;f=f|0;g=g|0;return Df(a,b,c,d,e,f,g)|0}function ah(a,b,c,d,e,f,g){a=a|0;b=b|0;c=c|0;d=d|0;e=e|0;f=f|0;g=g|0;return ub(a,b,c,d,e,f,g)|0}function _d(a,b,c,d,e,f,g){a=a|0;b=b|0;c=c|0;d=d|0;e=e|0;f=f|0;g=g|0;return uf(a,b,c,d,e,f,g)|0}function Vg(a,b,c,d,e,f,g){a=a|0;b=b|0;c=c|0;d=d|0;e=e|0;f=f|0;g=g|0;return ad(a,b,c,d,e,f,g)|0}function Sg(a,b,c,d,e,f,g){a=a|0;b=b|0;c=c|0;d=d|0;e=e|0;f=f|0;g=g|0;return kf(a,b,c,d,e,f,g)|0}function Rg(a,b,c,d,e,f,g){a=a|0;b=b|0;c=c|0;d=d|0;e=e|0;f=f|0;g=g|0;return $c(a,b,c,d,e,f,g)|0}function Og(a,b,c,d,e,f,g){a=a|0;b=b|0;c=c|0;d=d|0;e=e|0;f=f|0;g=g|0;return hf(a,b,c,d,e,f,g)|0}function Jh(a,b,c,d,e,f,g){a=a|0;b=b|0;c=c|0;d=d|0;e=e|0;f=f|0;g=g|0;return Pc(a,b,c,d,e,f,g)|0}function Gh(a,b,c,d,e,f,g){a=a|0;b=b|0;c=c|0;d=d|0;e=e|0;f=f|0;g=g|0;return te(a,b,c,d,e,f,g)|0}function Fh(a,b,c,d,e,f,g){a=a|0;b=b|0;c=c|0;d=d|0;e=e|0;f=f|0;g=g|0;return Oc(a,b,c,d,e,f,g)|0}function Fe(a,b){a=a|0;b=b|0;var c=0;c=V-32|0;V=c;Pa(c,32);Tc(a,b,c);oa(c,32);V=c+32|0;return 0}function Ch(a,b,c,d,e,f,g){a=a|0;b=b|0;c=c|0;d=d|0;e=e|0;f=f|0;g=g|0;return qe(a,b,c,d,e,f,g)|0}function Cb(a,b,c,d,e,f,g,h){if((d|0)==1|d>>>0>1){Aa();N()}return Z[x[9093]](a,b,c,d,e,f,g,h)|0}function te(a,b,c,d,e,f,g){if(!d&c>>>0>=4294967280|d){Aa();N()}return ue(a+16|0,a,b,c,d,e,f,g)}function mf(a,b,c,d,e){var f=0;f=V-416|0;V=f;gd(f,e,32);fd(f,b,c,d);ed(f,a);V=f+416|0;return 0}function kf(a,b,c,d,e,f,g){if(!d&c>>>0>=4294967280|d){Aa();N()}return lf(a+16|0,a,b,c,d,e,f,g)}function je(a,b,c,d,e){var f=0;f=V-416|0;V=f;me(f,e,32);le(f,b,c,d);ke(f,a);V=f+416|0;return 0}function Ze(a,b,c,d,e){var f=0;f=V-208|0;V=f;Yc(f,e,32);fc(f,b,c,d);Xc(f,a);V=f+208|0;return 0}function sa(a){var b=0,c=0;b=y[a|0]|y[a+1|0]<<8;a=y[a+2|0];c=a>>>16|0;a=b|a<<16;Y=c;return a}function Dd(){var a=0,b=0;a=V-16|0;V=a;v[a+15|0]=0;b=S(36380,a+15|0,0)|0;V=a+16|0;return b|0}function vd(a,b,c,d,e,f,g){if((d|0)==1|d>>>0>1){Aa();N()}return Z[x[9094]](a,b,c,d,e,f,g)|0}function qc(a,b,c,d,e,f){if((d|0)==1|d>>>0>1){Aa();N()}return Z[x[9093]](a,b,c,d,e,0,0,f)|0}function Wg(a,b,c){a=a|0;b=b|0;c=c|0;if((c|0)==1|c>>>0>1){Q(1329,1175,197,1092);N()}Pa(a,b)}function jb(a,b,c){Ma(a,b,c);Ma(a+40|0,b+40|0,c);Ma(a+80|0,b+80|0,c);Ma(a+120|0,b+120|0,c)}function xg(a,b,c,d,e,f){a=a|0;b=b|0;c=c|0;d=d|0;e=e|0;f=f|0;return xe(a,b,c,d,e,0,0,f)|0}function cg(a,b,c,d,e,f){if((d|0)==1|d>>>0>1){Aa();N()}return Z[x[9094]](a,b,c,d,e,0,f)|0}function Gj(a,b){var c=0,d=0;c=b&31;d=(-1>>>c&a)<>>a} +function ja(a,b){var c=0,d=0;c=0-b&31;d=(a&-1>>>c)<>>a}function Qb(a,b,c,d){var e=0;e=V-208|0;V=e;sb(e);Na(e,b,c,d);_a(e,a);V=e+208|0;return 0}function ch(a,b,c,d,e,f){a=a|0;b=b|0;c=c|0;d=d|0;e=e|0;f=f|0;return qc(a,b,c,d,e,f)|0}function Yg(a,b,c,d,e,f){a=a|0;b=b|0;c=c|0;d=d|0;e=e|0;f=f|0;return tc(a,b,c,d,e,f)|0}function Vd(a,b,c,d,e,f){a=a|0;b=b|0;c=c|0;d=d|0;e=e|0;f=f|0;return of(a,b,c,d,e,f)|0}function Rd(a,b,c,d,e,f){a=a|0;b=b|0;c=c|0;d=d|0;e=e|0;f=f|0;return rd(a,b,c,d,e,f)|0}function Ic(a,b,c,d,e,f){a=a|0;b=b|0;c=c|0;d=d|0;e=e|0;f=f|0;return Nf(a,b,c,d,e,f)|0}function Hc(a,b,c,d,e,f){a=a|0;b=b|0;c=c|0;d=d|0;e=e|0;f=f|0;return Mf(a,b,c,d,e,f)|0}function $g(a,b,c,d,e,f){a=a|0;b=b|0;c=c|0;d=d|0;e=e|0;f=f|0;return cg(a,b,c,d,e,f)|0}function Vf(a,b,c){a=a|0;b=b|0;c=c|0;var d=0;d=V-32|0;V=d;ud(d,c);td(a,b,d);V=d+32|0}function wd(a,b,c,d,e){if((c|0)==1|c>>>0>1){Aa();N()}return Z[x[9092]](a,b,c,d,e)|0}function Rb(a,b,c,d,e){if((c|0)==1|c>>>0>1){Aa();N()}return Z[x[9091]](a,b,c,d,e)|0}function lg(){var a=0;a=V-16|0;V=a;v[a+15|0]=0;S(36416,a+15|0,0)|0;V=a+16|0}function ie(a,b,c,d,e){a=a|0;b=b|0;c=c|0;d=d|0;e=e|0;return je(a,b,c,d,e)|0}function fh(a,b,c,d,e){a=a|0;b=b|0;c=c|0;d=d|0;e=e|0;return Rb(a,b,c,d,e)|0}function bh(a,b,c,d,e){a=a|0;b=b|0;c=c|0;d=d|0;e=e|0;return Bb(a,b,c,d,e)|0}function be(a,b,c,d,e){a=a|0;b=b|0;c=c|0;d=d|0;e=e|0;return Jd(a,b,c,d,e)|0}function ae(a,b,c,d,e){a=a|0;b=b|0;c=c|0;d=d|0;e=e|0;return Zb(a,b,c,d,e)|0}function _g(a,b,c,d,e){a=a|0;b=b|0;c=c|0;d=d|0;e=e|0;return xd(a,b,c,d,e)|0}function Ud(a,b,c,d,e){a=a|0;b=b|0;c=c|0;d=d|0;e=e|0;return Ce(a,b,c,d,e)|0}function Sd(a,b,c,d,e){a=a|0;b=b|0;c=c|0;d=d|0;e=e|0;return Rf(a,b,c,d,e)|0}function Oh(a,b,c,d,e){a=a|0;b=b|0;c=c|0;d=d|0;e=e|0;return Ze(a,b,c,d,e)|0}function Mh(a,b,c,d,e){a=a|0;b=b|0;c=c|0;d=d|0;e=e|0;return mf(a,b,c,d,e)|0}function hg(a,b,c){var d=0;d=V-48|0;V=d;Wa(d,b);La(a,b);Ma(a,d,c);V=d+48|0}function ii(a,b,c){a=a|0;b=b|0;c=c|0;qf(b,32,c,32,0,0,0);return Lc(a,b)|0}function dj(a){a=a|0;var b=0;b=V-160|0;V=b;a=Db(b,a);V=b+160|0;return!a|0}function Bb(a,b,c,d,e){if((c|0)==1|c>>>0>1){Aa();N()}return wd(a,b,c,d,e)}function ra(a,b){v[a|0]=b;v[a+1|0]=b>>>8;v[a+2|0]=b>>>16;v[a+3|0]=b>>>24}function Xa(a){var b=0;b=V-32|0;V=b;cb(b,a);a=fb(b,32);V=b+32|0;return a}function aj(a){a=a|0;var b=0;b=V+-64|0;V=b;Pa(b,64);cf(a,b);V=b- -64|0}function nb(a){var b=0;b=V-32|0;V=b;cb(b,a);V=b+32|0;return v[b|0]&1}function ib(a,b,c){Ma(a,b,c);Ma(a+40|0,b+40|0,c);Ma(a+80|0,b+80|0,c)}function Ve(a,b){a=((b<<7)+a|0)+-64|0;b=x[a>>2];Y=x[a+4>>2];return b}function Ub(a,b,c,d){a=a|0;b=b|0;c=c|0;d=d|0;yd(a,b,c,d,20);return 0}function Tb(a,b,c,d){a=a|0;b=b|0;c=c|0;d=d|0;yd(a,b,c,d,12);return 0}function mj(a){a=a|0;var b=0;b=V-32|0;V=b;Pa(b,32);Zf(a,b);V=b+32|0}function Sb(a,b,c,d){a=a|0;b=b|0;c=c|0;d=d|0;yd(a,b,c,d,8);return 0}function yh(a,b,c,d){a=a|0;b=b|0;c=c|0;d=d|0;return gb(a,b,c,d)|0}function xi(a,b,c,d){a=a|0;b=b|0;c=c|0;d=d|0;return ze(a,b,c,d)|0}function wh(a,b,c,d){a=a|0;b=b|0;c=c|0;d=d|0;return qb(a,b,c,d)|0}function ug(a,b,c,d){a=a|0;b=b|0;c=c|0;d=d|0;Ld(a,b,c,d);return 0}function uc(a,b,c,d,e,f,g,h){return Z[x[9090]](a,b,c,d,e,f,g,h)|0}function sh(a,b,c,d){a=a|0;b=b|0;c=c|0;d=d|0;return Cf(a,b,c,d)|0}function rh(a,b,c,d){a=a|0;b=b|0;c=c|0;d=d|0;return Bf(a,b,c,d)|0}function qh(a,b,c,d){a=a|0;b=b|0;c=c|0;d=d|0;return zf(a,b,c,d)|0}function oh(a,b,c,d){a=a|0;b=b|0;c=c|0;d=d|0;return tf(a,b,c,d)|0}function kc(a,b,c,d){a=a|0;b=b|0;c=c|0;d=d|0;return Ib(a,b,c,d)|0}function de(a,b,c,d){a=a|0;b=b|0;c=c|0;d=d|0;return Qb(a,b,c,d)|0}function Td(a,b,c,d){a=a|0;b=b|0;c=c|0;d=d|0;return Na(a,b,c,d)|0}function Ph(a,b,c,d){a=a|0;b=b|0;c=c|0;d=d|0;return fc(a,b,c,d)|0}function Kh(a,b,c,d){a=a|0;b=b|0;c=c|0;d=d|0;return le(a,b,c,d)|0}function $d(a,b,c,d){a=a|0;b=b|0;c=c|0;d=d|0;return ta(a,b,c,d)|0}function Nc(a){v[a+32|0]=1;v[a+33|0]=0;v[a+34|0]=0;v[a+35|0]=0}function tc(a,b,c,d,e,f){return Z[x[9090]](a,b,c,d,e,0,0,f)|0}function Gd(a){x[a>>2]=0;x[a+4>>2]=0;x[a+8>>2]=0;x[a+12>>2]=0}function af(a){var b=0;b=x[a>>2];if(b){Ka(b)}$e(a);return 0}function Ni(a,b,c){a=a|0;b=b|0;c=c|0;return Je(a,b,c,1)|0}function Mi(a,b,c){a=a|0;b=b|0;c=c|0;return Je(a,b,c,0)|0}function bc(a){v[a|0]=0;v[a+1|0]=0;v[a+2|0]=0;v[a+3|0]=0}function wi(a,b,c){a=a|0;b=b|0;c=c|0;return ye(a,b,c)|0}function si(a,b,c){a=a|0;b=b|0;c=c|0;return qd(a,b,c)|0}function me(a,b,c){a=a|0;b=b|0;c=c|0;return gd(a,b,c)|0}function jc(a,b,c){a=a|0;b=b|0;c=c|0;return Hb(a,b,c)|0}function Sc(a,b,c){a=a|0;b=b|0;c=c|0;return nc(a,b,c)|0}function Kc(a,b,c){a=a|0;b=b|0;c=c|0;return wc(a,b,c)|0}function Ie(a){v[a|0]=y[a|0]&248;v[a+31|0]=y[a+31|0]|64}function Ai(a,b,c){a=a|0;b=b|0;c=c|0;return Tc(a,b,c)|0}function oc(a,b){a=a|0;b=b|0;Pa(b,32);return vc(a,b)|0}function hi(a,b){a=a|0;b=b|0;Pa(b,32);return Lc(a,b)|0}function Cd(a){vb(a);Ea(a+40|0);Ea(a+80|0);vb(a+120|0)}function Aa(){var a=0;a=x[9433];if(a){Z[a|0]()}R();N()}function xj(a,b,c){a=a|0;b=b|0;c=c|0;Bb(a,b,0,1574,c)}function xd(a,b,c,d,e){return Z[x[9089]](a,b,c,d,e)|0}function vc(a,b){a=a|0;b=b|0;return Z[x[9088]](a,b)|0}function Zb(a,b,c,d,e){return Z[x[9083]](a,b,c,d,e)|0}function Sa(a,b){a=a|0;b=b|0;return Z[x[9084]](a,b)|0}function Ra(a,b){a=a|0;b=b|0;return Z[x[9086]](a,b)|0}function Jd(a,b,c,d,e){return Z[x[9082]](a,b,c,d,e)|0}function rd(a,b,c,d,e,f){return Qf(a,b,c,d,e,0,0,f)}function qf(a,b,c,d,e,f,g){return ac(a,b,c,d,e,f,g)}function of(a,b,c,d,e,f){pf(a,b,c,d,e,f,0);return 0}function ad(a,b,c,d,e,f,g){return dd(a,b,c,d,e,f,g)}function Pc(a,b,c,d,e,f,g){return Rc(a,b,c,d,e,f,g)}function Oc(a,b,c,d,e,f,g){return Qc(a,b,c,d,e,f,g)}function $c(a,b,c,d,e,f,g){return cd(a,b,c,d,e,f,g)}function ta(a,b,c,d){return Z[x[9085]](a,b,c,d)|0}function _b(a,b){a=a|0;b=b|0;return Cc(a,b,32)|0}function Od(a,b){a=a|0;b=b|0;return Cc(a,b,64)|0}function Gb(a,b){a=a|0;b=b|0;return Cc(a,b,16)|0}function $e(a){x[a+8>>2]=0;x[a>>2]=0;x[a+4>>2]=0}function Nf(a,b,c,d,e,f){return Pf(a,b,c,d,e,f)}function Mf(a,b,c,d,e,f){return Of(a,b,c,d,e,f)}function Li(a,b){a=a|0;b=b|0;return Ge(a,b,1)|0}function Ki(a,b){a=a|0;b=b|0;return Ge(a,b,0)|0}function hd(a,b){sb(a);if(b){Na(a,35872,34,0)}}function Xi(a,b,c){a=a|0;b=b|0;c=c|0;td(a,b,c)}function Wi(a,b,c){a=a|0;b=b|0;c=c|0;Vf(a,b,c)}function Uf(a,b,c){a=a|0;b=b|0;c=c|0;Ga(a,b,c)}function zi(a,b){a=a|0;b=b|0;return Fe(a,b)|0}function vg(a,b){a=a|0;b=b|0;Md(a,b);return 0}function ve(a,b){a=a|0;b=b|0;return oc(a,b)|0}function tg(a,b){a=a|0;b=b|0;Kd(a,b);return 0}function _i(a,b){a=a|0;b=b|0;return Xf(a,b)|0}function Lc(a,b){a=a|0;b=b|0;return vc(a,b)|0}function Ii(a,b){a=a|0;b=b|0;return Sa(a,b)|0}function Hi(a,b){a=a|0;b=b|0;return Ra(a,b)|0}function Ce(a,b,c,d,e){return De(a,b,c,d,e,0)}function Oa(a,b){return((a^b)&255)-1>>>31|0}function zf(a,b,c,d){return Af(a,b,c,d,2)}function fd(a,b,c,d){Na(a,b,c,d);return 0}function fc(a,b,c,d){qb(a,b,c,d);return 0}function Bf(a,b,c,d){return Af(a,b,c,d,1)}function le(a,b,c,d){return fd(a,b,c,d)}function gb(a,b,c,d){return Ja(a,b,c,d)}function Ja(a,b,c,d){return Jb(a,b,c,d)}function Ea(a){x[a>>2]=1;ya(a+4|0,0,36)}function pd(a){if((a&-7)!=1){Aa();N()}}function Zi(a,b){a=a|0;b=b|0;ud(a,b)}function Yi(a,b){a=a|0;b=b|0;Wf(a,b)}function Vi(a,b){a=a|0;b=b|0;sd(a,b)}function yi(a){a=a|0;return Ae(a)|0}function Ae(a){a=a|0;sb(a);return 0}function ng(a){return(a&128)>>>7|0}function la(a,b){return Gj(a,b)}function kd(){return-2147483648}function id(){return 1073741824}function yc(a,b){hg(a,b,nb(b))}function wf(){return 268435456}function gj(){return 134217728}function fj(){return 536870912}function xf(){return 67108864}function qi(a){a=a|0;Pa(a,16)}function pb(a,b){za(a,b,1024)}function _c(a){$e(a);return 0}function Zc(a){af(a);return 0}function Le(){return 16777216}function Ff(){return 33554432}function Fa(a){a=a|0;Pa(a,32)}function Oi(){return 524288}function $b(a){ya(a,0,1024)}function Pi(){return 32768}function Fb(a,b){Ga(a,b,b)}function $i(a){a=a|0;Yf(a)}function yf(){return 1559}function vb(a){ya(a,0,40)}function ti(){return 1478}function sf(){return 1321}function ri(){return 1523}function ld(){return 8192}function ji(){return 1438}function ij(){return 1549}function ej(){return 1157}function ei(){return 1315}function di(){return 1457}function bi(){return 1533}function ai(){return 1464}function Ui(){return 1540}function Qi(){return 1570}function Ji(){return 1488}function Gi(){return 1496}function Dj(){return 1089}function Bi(){return 1449}function rf(){return 384}function pi(){return 104}function nf(){return 416}function md(){return 128}function gc(){return 208}function Ri(){return 102}function Id(){return 256}function ua(){return 16}function pa(){return 32}function mi(){return 52}function li(){return 17}function ki(){return-18}function hb(){return-17}function ff(){return 48}function dg(){return 12}function ci(){return 10}function Ua(){return 24}function Ha(){return 64}function Be(){return-65}function zb(){return 2}function jd(){return 4}function hj(){return 6}function eb(){return 0}function Nb(){return 3}function Mb(){return 1}function Ia(){return-1}function $a(){return 8}function sg(){} +// EMSCRIPTEN_END_FUNCS +g=y;r(ga);var Z=e([null,Nd,wg,vg,ug,tg,Bj,Aj,zj,yj,vj,tj,sj,rj]);function _(){return u.byteLength/65536|0}function da(ea){ea=ea|0;var $=_()|0;var aa=$+ea|0;if($>0]=value;break;case"i8":HEAP8[ptr>>0]=value;break;case"i16":HEAP16[ptr>>1]=value;break;case"i32":HEAP32[ptr>>2]=value;break;case"i64":tempI64=[value>>>0,(tempDouble=value,+Math.abs(tempDouble)>=1?tempDouble>0?(Math.min(+Math.floor(tempDouble/4294967296),4294967295)|0)>>>0:~~+Math.ceil((tempDouble-+(~~tempDouble>>>0))/4294967296)>>>0:0)],HEAP32[ptr>>2]=tempI64[0],HEAP32[ptr+4>>2]=tempI64[1];break;case"float":HEAPF32[ptr>>2]=value;break;case"double":HEAPF64[ptr>>3]=value;break;default:abort("invalid type for setValue: "+type)}}function getValue(ptr,type,noSafe){type=type||"i8";if(type.charAt(type.length-1)==="*")type="i32";switch(type){case"i1":return HEAP8[ptr>>0];case"i8":return HEAP8[ptr>>0];case"i16":return HEAP16[ptr>>1];case"i32":return HEAP32[ptr>>2];case"i64":return HEAP32[ptr>>2];case"float":return HEAPF32[ptr>>2];case"double":return HEAPF64[ptr>>3];default:abort("invalid type for getValue: "+type)}return null}var wasmMemory;var ABORT=false;var EXITSTATUS;function assert(condition,text){if(!condition){abort("Assertion failed: "+text)}}var UTF8Decoder=typeof TextDecoder!=="undefined"?new TextDecoder("utf8"):undefined;function UTF8ArrayToString(heap,idx,maxBytesToRead){var endIdx=idx+maxBytesToRead;var endPtr=idx;while(heap[endPtr]&&!(endPtr>=endIdx))++endPtr;if(endPtr-idx>16&&heap.subarray&&UTF8Decoder){return UTF8Decoder.decode(heap.subarray(idx,endPtr))}else{var str="";while(idx>10,56320|ch&1023)}}}return str}function UTF8ToString(ptr,maxBytesToRead){return ptr?UTF8ArrayToString(HEAPU8,ptr,maxBytesToRead):""}function alignUp(x,multiple){if(x%multiple>0){x+=multiple-x%multiple}return x}var buffer,HEAP8,HEAPU8,HEAP16,HEAPU16,HEAP32,HEAPU32,HEAPF32,HEAPF64;function updateGlobalBufferAndViews(buf){buffer=buf;Module["HEAP8"]=HEAP8=new Int8Array(buf);Module["HEAP16"]=HEAP16=new Int16Array(buf);Module["HEAP32"]=HEAP32=new Int32Array(buf);Module["HEAPU8"]=HEAPU8=new Uint8Array(buf);Module["HEAPU16"]=HEAPU16=new Uint16Array(buf);Module["HEAPU32"]=HEAPU32=new Uint32Array(buf);Module["HEAPF32"]=HEAPF32=new Float32Array(buf);Module["HEAPF64"]=HEAPF64=new Float64Array(buf)}var INITIAL_MEMORY=Module["INITIAL_MEMORY"]||16777216;if(Module["wasmMemory"]){wasmMemory=Module["wasmMemory"]}else{wasmMemory=new WebAssembly.Memory({"initial":INITIAL_MEMORY/65536,"maximum":2147483648/65536})}if(wasmMemory){buffer=wasmMemory.buffer}INITIAL_MEMORY=buffer.byteLength;updateGlobalBufferAndViews(buffer);var wasmTable;var __ATPRERUN__=[];var __ATINIT__=[];var __ATPOSTRUN__=[];var runtimeInitialized=false;function preRun(){if(Module["preRun"]){if(typeof Module["preRun"]=="function")Module["preRun"]=[Module["preRun"]];while(Module["preRun"].length){addOnPreRun(Module["preRun"].shift())}}callRuntimeCallbacks(__ATPRERUN__)}function initRuntime(){runtimeInitialized=true;callRuntimeCallbacks(__ATINIT__)}function postRun(){if(Module["postRun"]){if(typeof Module["postRun"]=="function")Module["postRun"]=[Module["postRun"]];while(Module["postRun"].length){addOnPostRun(Module["postRun"].shift())}}callRuntimeCallbacks(__ATPOSTRUN__)}function addOnPreRun(cb){__ATPRERUN__.unshift(cb)}function addOnInit(cb){__ATINIT__.unshift(cb)}function addOnPostRun(cb){__ATPOSTRUN__.unshift(cb)}var runDependencies=0;var runDependencyWatcher=null;var dependenciesFulfilled=null;function addRunDependency(id){runDependencies++;if(Module["monitorRunDependencies"]){Module["monitorRunDependencies"](runDependencies)}}function removeRunDependency(id){runDependencies--;if(Module["monitorRunDependencies"]){Module["monitorRunDependencies"](runDependencies)}if(runDependencies==0){if(runDependencyWatcher!==null){clearInterval(runDependencyWatcher);runDependencyWatcher=null}if(dependenciesFulfilled){var callback=dependenciesFulfilled;dependenciesFulfilled=null;callback()}}}Module["preloadedImages"]={};Module["preloadedAudios"]={};function abort(what){if(Module["onAbort"]){Module["onAbort"](what)}what+="";err(what);ABORT=true;EXITSTATUS=1;what="abort("+what+"). Build with -s ASSERTIONS=1 for more info.";var e=new WebAssembly.RuntimeError(what);throw e}var dataURIPrefix="data:application/octet-stream;base64,";function isDataURI(filename){return filename.startsWith(dataURIPrefix)}function isFileURI(filename){return filename.startsWith("file://")}var wasmBinaryFile;wasmBinaryFile="<<< WASM_BINARY_FILE >>>";if(!isDataURI(wasmBinaryFile)){wasmBinaryFile=locateFile(wasmBinaryFile)}function getBinary(file){try{if(file==wasmBinaryFile&&wasmBinary){return new Uint8Array(wasmBinary)}var binary=tryParseAsDataURI(file);if(binary){return binary}if(readBinary){return readBinary(file)}else{throw"both async and sync fetching of the wasm failed"}}catch(err){abort(err)}}function getBinaryPromise(){if(!wasmBinary&&(ENVIRONMENT_IS_WEB||ENVIRONMENT_IS_WORKER)){if(typeof fetch==="function"&&!isFileURI(wasmBinaryFile)){return fetch(wasmBinaryFile,{credentials:"same-origin"}).then(function(response){if(!response["ok"]){throw"failed to load wasm binary file at '"+wasmBinaryFile+"'"}return response["arrayBuffer"]()}).catch(function(){return getBinary(wasmBinaryFile)})}else{if(readAsync){return new Promise(function(resolve,reject){readAsync(wasmBinaryFile,function(response){resolve(new Uint8Array(response))},reject)})}}}return Promise.resolve().then(function(){return getBinary(wasmBinaryFile)})}function createWasm(){var info={"a":asmLibraryArg};function receiveInstance(instance,module){var exports=instance.exports;Module["asm"]=exports;wasmTable=Module["asm"]["Bj"];addOnInit(Module["asm"]["g"]);removeRunDependency("wasm-instantiate")}addRunDependency("wasm-instantiate");function receiveInstantiationResult(result){receiveInstance(result["instance"])}function instantiateArrayBuffer(receiver){return getBinaryPromise().then(function(binary){var result=WebAssembly.instantiate(binary,info);return result}).then(receiver,function(reason){err("failed to asynchronously prepare wasm: "+reason);abort(reason)})}function instantiateAsync(){if(!wasmBinary&&typeof WebAssembly.instantiateStreaming==="function"&&!isDataURI(wasmBinaryFile)&&!isFileURI(wasmBinaryFile)&&typeof fetch==="function"){return fetch(wasmBinaryFile,{credentials:"same-origin"}).then(function(response){var result=WebAssembly.instantiateStreaming(response,info);return result.then(receiveInstantiationResult,function(reason){err("wasm streaming compile failed: "+reason);err("falling back to ArrayBuffer instantiation");return instantiateArrayBuffer(receiveInstantiationResult)})})}else{return instantiateArrayBuffer(receiveInstantiationResult)}}if(Module["instantiateWasm"]){try{var exports=Module["instantiateWasm"](info,receiveInstance);return exports}catch(e){err("Module.instantiateWasm callback failed with error: "+e);return false}}instantiateAsync();return{}}var tempDouble;var tempI64;var ASM_CONSTS={36380:function(){return Module.getRandomValue()},36416:function(){if(Module.getRandomValue===undefined){try{var window_="object"===typeof window?window:self;var crypto_=typeof window_.crypto!=="undefined"?window_.crypto:window_.msCrypto;var randomValuesStandard=function(){var buf=new Uint32Array(1);crypto_.getRandomValues(buf);return buf[0]>>>0};randomValuesStandard();Module.getRandomValue=randomValuesStandard}catch(e){try{var crypto=require("crypto");var randomValueNodeJS=function(){var buf=crypto["randomBytes"](4);return(buf[0]<<24|buf[1]<<16|buf[2]<<8|buf[3])>>>0};randomValueNodeJS();Module.getRandomValue=randomValueNodeJS}catch(e){throw"No secure random number generator found"}}}}};function callRuntimeCallbacks(callbacks){while(callbacks.length>0){var callback=callbacks.shift();if(typeof callback=="function"){callback(Module);continue}var func=callback.func;if(typeof func==="number"){if(callback.arg===undefined){wasmTable.get(func)()}else{wasmTable.get(func)(callback.arg)}}else{func(callback.arg===undefined?null:callback.arg)}}}function ___assert_fail(condition,filename,line,func){abort("Assertion failed: "+UTF8ToString(condition)+", at: "+[filename?UTF8ToString(filename):"unknown filename",line,func?UTF8ToString(func):"unknown function"])}function _abort(){abort()}var readAsmConstArgsArray=[];function readAsmConstArgs(sigPtr,buf){readAsmConstArgsArray.length=0;var ch;buf>>=2;while(ch=HEAPU8[sigPtr++]){var double=ch<105;if(double&&buf&1)buf++;readAsmConstArgsArray.push(double?HEAPF64[buf++>>1]:HEAP32[buf]);++buf}return readAsmConstArgsArray}function _emscripten_asm_const_int(code,sigPtr,argbuf){var args=readAsmConstArgs(sigPtr,argbuf);return ASM_CONSTS[code].apply(null,args)}function _emscripten_get_heap_max(){return 2147483648}function emscripten_realloc_buffer(size){try{wasmMemory.grow(size-buffer.byteLength+65535>>>16);updateGlobalBufferAndViews(wasmMemory.buffer);return 1}catch(e){}}function _emscripten_resize_heap(requestedSize){var oldSize=HEAPU8.length;requestedSize=requestedSize>>>0;var maxHeapSize=2147483648;if(requestedSize>maxHeapSize){return false}for(var cutDown=1;cutDown<=4;cutDown*=2){var overGrownHeapSize=oldSize*(1+.2/cutDown);overGrownHeapSize=Math.min(overGrownHeapSize,requestedSize+100663296);var newSize=Math.min(maxHeapSize,alignUp(Math.max(requestedSize,overGrownHeapSize),65536));var replacement=emscripten_realloc_buffer(newSize);if(replacement){return true}}return false}var ASSERTIONS=false;function intArrayToString(array){var ret=[];for(var i=0;i255){if(ASSERTIONS){assert(false,"Character code "+chr+" ("+String.fromCharCode(chr)+") at offset "+i+" not in 0x00-0xFF.")}chr&=255}ret.push(String.fromCharCode(chr))}return ret.join("")}var decodeBase64=typeof atob==="function"?atob:function(input){var keyStr="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";var output="";var chr1,chr2,chr3;var enc1,enc2,enc3,enc4;var i=0;input=input.replace(/[^A-Za-z0-9\+\/\=]/g,"");do{enc1=keyStr.indexOf(input.charAt(i++));enc2=keyStr.indexOf(input.charAt(i++));enc3=keyStr.indexOf(input.charAt(i++));enc4=keyStr.indexOf(input.charAt(i++));chr1=enc1<<2|enc2>>4;chr2=(enc2&15)<<4|enc3>>2;chr3=(enc3&3)<<6|enc4;output=output+String.fromCharCode(chr1);if(enc3!==64){output=output+String.fromCharCode(chr2)}if(enc4!==64){output=output+String.fromCharCode(chr3)}}while(i0){return}preRun();if(runDependencies>0){return}function doRun(){if(calledRun)return;calledRun=true;Module["calledRun"]=true;if(ABORT)return;initRuntime();if(Module["onRuntimeInitialized"])Module["onRuntimeInitialized"]();postRun()}if(Module["setStatus"]){Module["setStatus"]("Running...");setTimeout(function(){setTimeout(function(){Module["setStatus"]("")},1);doRun()},1)}else{doRun()}}Module["run"]=run;if(Module["preInit"]){if(typeof Module["preInit"]=="function")Module["preInit"]=[Module["preInit"]];while(Module["preInit"].length>0){Module["preInit"].pop()()}}run(); + }); + }; + var Module=typeof Module!=="undefined"?Module:{};var moduleOverrides={};var key;for(key in Module){if(Module.hasOwnProperty(key)){moduleOverrides[key]=Module[key]}}var arguments_=[];var thisProgram="./this.program";var quit_=function(status,toThrow){throw toThrow};var ENVIRONMENT_IS_WEB=false;var ENVIRONMENT_IS_WORKER=false;var ENVIRONMENT_IS_NODE=false;var ENVIRONMENT_IS_SHELL=false;ENVIRONMENT_IS_WEB=typeof window==="object";ENVIRONMENT_IS_WORKER=typeof importScripts==="function";ENVIRONMENT_IS_NODE=typeof process==="object"&&typeof process.versions==="object"&&typeof process.versions.node==="string";ENVIRONMENT_IS_SHELL=!ENVIRONMENT_IS_WEB&&!ENVIRONMENT_IS_NODE&&!ENVIRONMENT_IS_WORKER;var scriptDirectory="";function locateFile(path){if(Module["locateFile"]){return Module["locateFile"](path,scriptDirectory)}return scriptDirectory+path}var read_,readAsync,readBinary,setWindowTitle;var nodeFS;var nodePath;if(ENVIRONMENT_IS_NODE){if(ENVIRONMENT_IS_WORKER){scriptDirectory=require("path").dirname(scriptDirectory)+"/"}else{scriptDirectory=__dirname+"/"}read_=function shell_read(filename,binary){var ret=tryParseAsDataURI(filename);if(ret){return binary?ret:ret.toString()}if(!nodeFS)nodeFS=require("fs");if(!nodePath)nodePath=require("path");filename=nodePath["normalize"](filename);return nodeFS["readFileSync"](filename,binary?null:"utf8")};readBinary=function readBinary(filename){var ret=read_(filename,true);if(!ret.buffer){ret=new Uint8Array(ret)}assert(ret.buffer);return ret};if(process["argv"].length>1){thisProgram=process["argv"][1].replace(/\\/g,"/")}arguments_=process["argv"].slice(2);if(typeof module!=="undefined"){module["exports"]=Module}quit_=function(status){process["exit"](status)};Module["inspect"]=function(){return"[Emscripten Module object]"}}else if(ENVIRONMENT_IS_SHELL){if(typeof read!="undefined"){read_=function shell_read(f){var data=tryParseAsDataURI(f);if(data){return intArrayToString(data)}return read(f)}}readBinary=function readBinary(f){var data;data=tryParseAsDataURI(f);if(data){return data}if(typeof readbuffer==="function"){return new Uint8Array(readbuffer(f))}data=read(f,"binary");assert(typeof data==="object");return data};if(typeof scriptArgs!="undefined"){arguments_=scriptArgs}else if(typeof arguments!="undefined"){arguments_=arguments}if(typeof quit==="function"){quit_=function(status){quit(status)}}if(typeof print!=="undefined"){if(typeof console==="undefined")console={};console.log=print;console.warn=console.error=typeof printErr!=="undefined"?printErr:print}}else if(ENVIRONMENT_IS_WEB||ENVIRONMENT_IS_WORKER){if(ENVIRONMENT_IS_WORKER){scriptDirectory=self.location.href}else if(typeof document!=="undefined"&&document.currentScript){scriptDirectory=document.currentScript.src}if(scriptDirectory.indexOf("blob:")!==0){scriptDirectory=scriptDirectory.substr(0,scriptDirectory.lastIndexOf("/")+1)}else{scriptDirectory=""}{read_=function(url){try{var xhr=new XMLHttpRequest;xhr.open("GET",url,false);xhr.send(null);return xhr.responseText}catch(err){var data=tryParseAsDataURI(url);if(data){return intArrayToString(data)}throw err}};if(ENVIRONMENT_IS_WORKER){readBinary=function(url){try{var xhr=new XMLHttpRequest;xhr.open("GET",url,false);xhr.responseType="arraybuffer";xhr.send(null);return new Uint8Array(xhr.response)}catch(err){var data=tryParseAsDataURI(url);if(data){return data}throw err}}}readAsync=function(url,onload,onerror){var xhr=new XMLHttpRequest;xhr.open("GET",url,true);xhr.responseType="arraybuffer";xhr.onload=function(){if(xhr.status==200||xhr.status==0&&xhr.response){onload(xhr.response);return}var data=tryParseAsDataURI(url);if(data){onload(data.buffer);return}onerror()};xhr.onerror=onerror;xhr.send(null)}}setWindowTitle=function(title){document.title=title}}else{}var out=Module["print"]||console.log.bind(console);var err=Module["printErr"]||console.warn.bind(console);for(key in moduleOverrides){if(moduleOverrides.hasOwnProperty(key)){Module[key]=moduleOverrides[key]}}moduleOverrides=null;if(Module["arguments"])arguments_=Module["arguments"];if(Module["thisProgram"])thisProgram=Module["thisProgram"];if(Module["quit"])quit_=Module["quit"];var wasmBinary;if(Module["wasmBinary"])wasmBinary=Module["wasmBinary"];var noExitRuntime=Module["noExitRuntime"]||true;if(typeof WebAssembly!=="object"){abort("no native wasm support detected")}function setValue(ptr,value,type,noSafe){type=type||"i8";if(type.charAt(type.length-1)==="*")type="i32";switch(type){case"i1":HEAP8[ptr>>0]=value;break;case"i8":HEAP8[ptr>>0]=value;break;case"i16":HEAP16[ptr>>1]=value;break;case"i32":HEAP32[ptr>>2]=value;break;case"i64":tempI64=[value>>>0,(tempDouble=value,+Math.abs(tempDouble)>=1?tempDouble>0?(Math.min(+Math.floor(tempDouble/4294967296),4294967295)|0)>>>0:~~+Math.ceil((tempDouble-+(~~tempDouble>>>0))/4294967296)>>>0:0)],HEAP32[ptr>>2]=tempI64[0],HEAP32[ptr+4>>2]=tempI64[1];break;case"float":HEAPF32[ptr>>2]=value;break;case"double":HEAPF64[ptr>>3]=value;break;default:abort("invalid type for setValue: "+type)}}function getValue(ptr,type,noSafe){type=type||"i8";if(type.charAt(type.length-1)==="*")type="i32";switch(type){case"i1":return HEAP8[ptr>>0];case"i8":return HEAP8[ptr>>0];case"i16":return HEAP16[ptr>>1];case"i32":return HEAP32[ptr>>2];case"i64":return HEAP32[ptr>>2];case"float":return HEAPF32[ptr>>2];case"double":return HEAPF64[ptr>>3];default:abort("invalid type for getValue: "+type)}return null}var wasmMemory;var ABORT=false;var EXITSTATUS;function assert(condition,text){if(!condition){abort("Assertion failed: "+text)}}var UTF8Decoder=typeof TextDecoder!=="undefined"?new TextDecoder("utf8"):undefined;function UTF8ArrayToString(heap,idx,maxBytesToRead){var endIdx=idx+maxBytesToRead;var endPtr=idx;while(heap[endPtr]&&!(endPtr>=endIdx))++endPtr;if(endPtr-idx>16&&heap.subarray&&UTF8Decoder){return UTF8Decoder.decode(heap.subarray(idx,endPtr))}else{var str="";while(idx>10,56320|ch&1023)}}}return str}function UTF8ToString(ptr,maxBytesToRead){return ptr?UTF8ArrayToString(HEAPU8,ptr,maxBytesToRead):""}function alignUp(x,multiple){if(x%multiple>0){x+=multiple-x%multiple}return x}var buffer,HEAP8,HEAPU8,HEAP16,HEAPU16,HEAP32,HEAPU32,HEAPF32,HEAPF64;function updateGlobalBufferAndViews(buf){buffer=buf;Module["HEAP8"]=HEAP8=new Int8Array(buf);Module["HEAP16"]=HEAP16=new Int16Array(buf);Module["HEAP32"]=HEAP32=new Int32Array(buf);Module["HEAPU8"]=HEAPU8=new Uint8Array(buf);Module["HEAPU16"]=HEAPU16=new Uint16Array(buf);Module["HEAPU32"]=HEAPU32=new Uint32Array(buf);Module["HEAPF32"]=HEAPF32=new Float32Array(buf);Module["HEAPF64"]=HEAPF64=new Float64Array(buf)}var INITIAL_MEMORY=Module["INITIAL_MEMORY"]||16777216;var wasmTable;var __ATPRERUN__=[];var __ATINIT__=[];var __ATPOSTRUN__=[];var runtimeInitialized=false;function preRun(){if(Module["preRun"]){if(typeof Module["preRun"]=="function")Module["preRun"]=[Module["preRun"]];while(Module["preRun"].length){addOnPreRun(Module["preRun"].shift())}}callRuntimeCallbacks(__ATPRERUN__)}function initRuntime(){runtimeInitialized=true;callRuntimeCallbacks(__ATINIT__)}function postRun(){if(Module["postRun"]){if(typeof Module["postRun"]=="function")Module["postRun"]=[Module["postRun"]];while(Module["postRun"].length){addOnPostRun(Module["postRun"].shift())}}callRuntimeCallbacks(__ATPOSTRUN__)}function addOnPreRun(cb){__ATPRERUN__.unshift(cb)}function addOnInit(cb){__ATINIT__.unshift(cb)}function addOnPostRun(cb){__ATPOSTRUN__.unshift(cb)}var runDependencies=0;var runDependencyWatcher=null;var dependenciesFulfilled=null;function addRunDependency(id){runDependencies++;if(Module["monitorRunDependencies"]){Module["monitorRunDependencies"](runDependencies)}}function removeRunDependency(id){runDependencies--;if(Module["monitorRunDependencies"]){Module["monitorRunDependencies"](runDependencies)}if(runDependencies==0){if(runDependencyWatcher!==null){clearInterval(runDependencyWatcher);runDependencyWatcher=null}if(dependenciesFulfilled){var callback=dependenciesFulfilled;dependenciesFulfilled=null;callback()}}}Module["preloadedImages"]={};Module["preloadedAudios"]={};function abort(what){if(Module["onAbort"]){Module["onAbort"](what)}what+="";err(what);ABORT=true;EXITSTATUS=1;what="abort("+what+"). Build with -s ASSERTIONS=1 for more info.";var e=new WebAssembly.RuntimeError(what);throw e}var dataURIPrefix="data:application/octet-stream;base64,";function isDataURI(filename){return filename.startsWith(dataURIPrefix)}function isFileURI(filename){return filename.startsWith("file://")}var wasmBinaryFile;wasmBinaryFile="data:application/octet-stream;base64,AGFzbQEAAAABjAMtYAABf2ACf38Bf2ACf38AYAN/f38Bf2AEf39/fwF/YAN/f38AYAF/AX9gBn9/f39/fwF/YAV/f39/fwF/YAF/AGAHf39/f39/fwF/YAN/f34Bf2AEf35/fwF/YAR/f35/AX9gC39/f39/f39/f39/AX9gBn9/fn9/fwF/YAZ/f39+f38Bf2AGf39+f35/AX9gBX9/fn9/AX9gCH9/f39/f39/AX9gBH9/f38AYAAAYAx/f39/f39/f39/f38Bf2AHf39/fn9/fwF/YAp/f39/f39/f39/AX9gAn9+AGAIf39+f39+f38Bf2AJf39/f35/fn9/AX9gBX9/f35/AX9gAn5/AX5gA39/fgBgBX9/fn5/AX9gCH9+f35/fn9/AX9gA39+fwF/YAJ+fgF+YAF/AX5gBH9/f34AYAV+f39/fwBgBX9/f39/AGAIf39/fn9/f38Bf2AJf39/f35/f39/AX9gAn9/AX5gCn9/f39/fn9/f38Bf2AGf39/f39/AGAJf39/f39/f39/AX8CJQYBYQFhABQBYQFiABUBYQFjAAMBYQFkAAABYQFlAAMBYQFmAAYDjwSNBB0BIgEFHQIAAgIjCwAFAgUDAxUZAgUJCQUAAAsJAgULAQIFAQEGAAICBgMGAQACBAICAAELAAUFAgUCBgECCwMGBg8JAgIDAAQMEQEJAgEDBAsBBgAAFgELDAQEBAIGBgINAQkQCQICFAsAFAUDBAIBAwEUEiQCEhEBAwUCBQIeAwYFFAMHBxkDAQkJEBAQEAMDJQQCAQMGBhAQAxAQAQsDAgAAAAAAEwgJAxICBQIPDAwmAwYGCQAFFQEJAgANAh4CDQECAgcIBAgHBwcIJwoECAgHBAoKBwgIDQELAwQCAg8XAg8XAQQRAwQGAA0SAQEDBgkEBgAoAwgBAQQJAgUpBSorDQIJBgIBGhsACQ8XDxcNABwQEAAACx8gAAAAIQwhCx8gAAIEAwYGARISEhIRDBkFBQUCAQkBGhobGxIABQUCBQIFBhUFBgUFAgIBCwENBxMIBwgHCAgHCgcKBAQKGBgHCAoHEwoKBxMKBRMHEwgHCggHEwcIGBgHBwcKBwoEBBMOBA4EBAQKDgQEBAQsCgQKBwgKBxMKCgcTCgQICAQICAQODg4WDg4ODg4WDhYADQASAAAACAgBAwAAAAADAwAJAA0DAAEDAwQGAQMACwEBHAEBAAEBAAEBAwMAAAAABAgAAgUFAgIBCQkDAwYcAAAAAAABCgQPDwkBAwMGDxEMAAwABREMAQMGAAQEAXAADgUHAQGAAoCAAgYJAX8BQfCmwgILB+0XsgQBZwIAAWgAvwEBaQC2AwFqALUDAWsAtAMBbACzAwFtALIDAW4AsQMBbwCwAwFwAK8DAXEADQFyAMUCAXMAOAF0ABIBdQA7AXYAHQF3AA0BeAAzAXkAOAF6ABIBQQA7AUIAHQFDAK4DAUQArQMBRQCsAwFGAKsDAUcADQFIACwBSQA4AUoAEgFLADsBTAAdAU0ADQFOAA0BTwC3AwFQAN8BAVEA3gEBUgAdAVMADQFUAA0BVQBwAVYAHQFXAJwBAVgAqgMBWQCbAQFaAKkDAV8AqAMBJAAfAmFhAA0CYmEAmQICY2EAHQJkYQCmAQJlYQCnAwJmYQCkAQJnYQCmAwJoYQClAwJpYQANAmphAA0Ca2EAmQICbGEAHQJtYQDjAQJuYQCkAwJvYQDhAQJwYQDfAQJxYQDeAQJyYQANAnNhAA0CdGEADQJ1YQANAnZhACwCd2EADQJ4YQASAnlhABICemEAOwJBYQDNAwJCYQDMAwJDYQDsAQJEYQCWAQJFYQCMAQJGYQCLAQJHYQDcAQJIYQDbAQJJYQCjAwJKYQCiAwJLYQChAwJMYQCgAwJNYQCfAwJOYQCeAwJPYQCdAwJQYQCcAwJRYQCbAwJSYQCaAwJTYQCSAgJUYQCwAQJVYQB4AlZhAHcCV2EAjAECWGEAiwECWWEA3AECWmEA2wECX2EADQIkYQANAmFiAA0CYmIADQJjYgAsAmRiAA0CZWIAEgJmYgASAmdiADsCaGIANQJpYgANAmpiABICa2IADQJsYgASAm1iAE4CbmIADQJvYgASAnBiAA0CcWIAEgJyYgBiAnNiAB8CdGIAEgJ1YgANAnZiABICd2IAYQJ4YgAfAnliABICemIADQJBYgASAkJiAGACQ2IAHwJEYgASAkViAA0CRmIAEgJHYgASAkhiAB8CSWIADQJKYgASAktiAB8CTGIADQJNYgCeAgJOYgCdAgJPYgCZAwJQYgB0AlFiAJgDAlJiAHMCU2IAHQJUYgASAlViAB8CVmIADQJXYgASAlhiAB8CWWIADQJaYgASAl9iABICJGIAnQICYWMAHQJiYwCXAwJjYwCWAwJkYwBWAmVjAP0CAmZjAJUDAmdjAFUCaGMAHwJpYwDaAQJqYwC5AwJrYwANAmxjAMgDAm1jAFkCbmMAlAMCb2MAWAJwYwCTAwJxYwAfAnJjAHACc2MARgJ0YwCSAwJ1YwAyAnZjANoBAndjABICeGMAHwJ5YwAzAnpjAA0CQWMA2QECQmMAngICQ2MAEgJEYwAfAkVjADMCRmMADQJHYwDZAQJIYwAdAkljAMEDAkpjAMADAktjAL8DAkxjAL4DAk1jAA0CTmMADQJPYwANAlBjAA0CUWMAvQMCUmMAwwECU2MAEgJUYwANAlVjANgBAlZjANcBAldjAN4DAlhjANYBAlljAN0DAlpjANwDAl9jAB0CJGMA2AECYWQA1wECYmQAKgJjZADWAQJkZAApAmVkABICZmQADQJnZADDAQJoZAAdAmlkAFoCamQAEgJrZAAgAmxkADgCbWQAIAJuZAASAm9kAKwBAnBkAPsDAnFkAFsCcmQAIAJzZACrAQJ0ZACqAQJ1ZACpAQJ2ZACrAgJ3ZAD6AwJ4ZAD5AwJ5ZAAzAnpkAPgDAkFkAJEDAkJkAJADAkNkAI8DAkRkAI4DAkVkAI0DAkZkAE0CR2QAEgJIZAAgAklkADgCSmQAIAJLZAASAkxkAKwBAk1kAKQCAk5kAFoCT2QAIAJQZACrAQJRZACqAQJSZABNAlNkAKMCAlRkAFsCVWQAogICVmQAqQECV2QAqAECWGQAjAMCWWQA1QECWmQAiwMCX2QAWgIkZABNAmFlAE0CYmUAEgJjZQAgAmRlADgCZWUAIAJmZQASAmdlAKwBAmhlAKQCAmllAFoCamUAIAJrZQCrAQJsZQCqAQJtZQBNAm5lAKMCAm9lAFsCcGUAogICcWUAqQECcmUAqAECc2UAigMCdGUA1QECdWUAiQMCdmUAiAMCd2UAhwMCeGUA9wMCeWUAwgMCemUAjwECQWUAjgECQmUADQJDZQANAkRlAIABAkVlAH8CRmUADQJHZQANAkhlAA0CSWUALAJKZQANAktlABICTGUAEgJNZQA7Ak5lAN8DAk9lAIwBAlBlAIsBAlFlAB0CUmUAhgMCU2UAhQMCVGUAhAMCVWUAgwMCVmUAggMCV2UAgQMCWGUADQJZZQAsAlplAA0CX2UAEgIkZQASAmFmADsCYmYAHQJjZgAdAmRmAMcDAmVmAMYDAmZmAJABAmdmAIADAmhmAP8CAmpmAMUDAmtmAMQDAmxmACwCbWYADQJuZgDDAwJvZgA4AnBmAFoCcWYATQJyZgBbAnNmADMCdGYAEgJ1ZgDKAwJ2ZgDTAQJ3ZgDJAwJ4ZgAzAnlmABICemYA0wECQWYAcAJCZgAfAkNmAA0CRGYADQJFZgAfAkZmAPIBAkdmANUDAkhmANQDAklmANMDAkpmANIBAktmANEBAkxmANABAk1mAM8BAk5mANIDAk9mAM4BAlBmANEDAlFmANADAlJmAHACU2YAHwJUZgANAlVmAA0CVmYAHwJXZgDyAQJYZgDYAwJZZgDXAwJaZgDxAQJfZgDOAQIkZgDwAQJhZwDvAQJiZwCXAQJjZwD2AQJkZwDbAwJlZwDaAwJmZwDPAQJnZwDRAQJoZwDQAQJpZwDSAQJqZwANAmtnADMCbGcAIAJtZwANAm5nAMUCAm9nACACcGcA/gICcWcA/AICcmcA+wICc2cA+gICdGcA+QICdWcA+AICdmcAHQJ3ZwAdAnhnAA0CeWcALAJ6ZwAgAkFnAOoDAkJnAM0BAkNnAMwBAkRnAB0CRWcADQJGZwAzAkdnACACSGcA9wICSWcA9gICSmcA9QICS2cAHQJMZwDNAQJNZwD0AgJOZwDMAQJPZwANAlBnACwCUWcAIAJSZwAdAlNnABICVGcADQJVZwAfAlZnAFQCV2cAaAJYZwDJAQJZZwCSBAJaZwC9AQJfZwDNAgIkZwCRBAJhaAAnAmJoAIwEAmNoAA0CZGgAiQQCZWgA8wICZmgA/gMCZ2gA/QMCaGgA/AMCaWgArgECamgArQECa2gAiwQCbGgA6QMCbWgA6AMCbmgAvAMCb2gAuwMCcGgAWwJxaAA4AnJoALABAnNoAHgCdGgAoQECdWgA8gICdmgA8QICd2gA8AICeGgA7wICeWgA7gICemgA7QICQWgA7AICQmgA6wICQ2gADQJEaAANAkVoAA0CRmgADQJHaAAsAkhoABICSWgAOwJKaADqAgJLaADpAgJMaACSAgJNaACFBAJOaACEBAJPaACDBAJQaAC/AgJRaACCBAJSaACBBAJTaAC+AgJUaAC9AgJVaAC0AQJWaAC8AgJXaACzAQJYaACyAQJZaAC7AgJaaAC6AgJfaAANAiRoAB8CYWkADQJiaQAfAmNpAA0CZGkA9QMCZWkA9AMCZmkA8wMCZ2kAjwICaGkA8gMCaWkA8QMCamkA8AMCa2kA7wMCbGkA7gMCbWkA7QMCbmkA7AMCb2kAugICcGkA6wMCcWkADQJyaQAfAnNpAB8CdGkADQJ1aQDoAgJ2aQASAndpACACeGkAOAJ5aQAgAnppAA0CQWkA5wMCQmkA5gMCQ2kA5QMCRGkAIAJFaQD8AQJGaQAgAkdpAOQDAkhpAPwBAklpAKsCAkppAKgBAktpAOcCAkxpAOYCAk1pAOUCAk5pAOQCAk9pAOMDAlBpAOIDAlFpAOEDAlJpAOADAlNpAA0CVGkADQJVaQDPAwJWaQDOAwJXaQANAlhpAA0CWWkA4wICWmkA4gICX2kA4QICJGkA4AICYWoADQJiagAsAmNqABICZGoAOwJlagASAmZqABICZ2oA3wICaGoA3gICaWoA3QICamoADQJragAzAmxqACACbWoAHQJuagDcAgJvagDbAgJwagANAnFqADMCcmoAIAJzagAdAnRqAA0CdWoALAJ2agAgAndqANoCAnhqANkCAnlqANgCAnpqAB0CQWoAMQJCagAiAkNqAQAJIAEAQQELDcgB1wLWAtUC1AKQBI8EjgSNBIoEiASHBIYECqOIBo0ECAAgACABrYoLBwAgACABeAseACAAIAF8IABCAYZC/v///x+DIAFC/////w+DfnwLBwAgACABdwudCQInfgx/IAAgAigCBCIqrCILIAEoAhQiK0EBdKwiFH4gAjQCACIDIAE0AhgiBn58IAIoAggiLKwiDSABNAIQIgd+fCACKAIMIi2sIhAgASgCDCIuQQF0rCIVfnwgAigCECIvrCIRIAE0AggiCH58IAIoAhQiMKwiFiABKAIEIjFBAXSsIhd+fCACKAIYIjKsIiAgATQCACIJfnwgAigCHCIzQRNsrCIMIAEoAiQiNEEBdKwiGH58IAIoAiAiNUETbKwiBCABNAIgIgp+fCACKAIkIgJBE2ysIgUgASgCHCIBQQF0rCIZfnwgByALfiADICusIhp+fCANIC6sIht+fCAIIBB+fCARIDGsIhx+fCAJIBZ+fCAyQRNsrCIOIDSsIh1+fCAKIAx+fCAEIAGsIh5+fCAFIAZ+fCALIBV+IAMgB358IAggDX58IBAgF358IAkgEX58IDBBE2ysIh8gGH58IAogDn58IAwgGX58IAQgBn58IAUgFH58IiJCgICAEHwiI0Iah3wiJEKAgIAIfCIlQhmHfCISIBJCgICAEHwiE0KAgIDgD4N9PgIYIAAgCyAXfiADIAh+fCAJIA1+fCAtQRNsrCIPIBh+fCAKIC9BE2ysIhJ+fCAZIB9+fCAGIA5+fCAMIBR+fCAEIAd+fCAFIBV+fCAJIAt+IAMgHH58ICxBE2ysIiEgHX58IAogD358IBIgHn58IAYgH358IA4gGn58IAcgDH58IAQgG358IAUgCH58ICpBE2ysIBh+IAMgCX58IAogIX58IA8gGX58IAYgEn58IBQgH358IAcgDn58IAwgFX58IAQgCH58IAUgF358IiFCgICAEHwiJkIah3wiJ0KAgIAIfCIoQhmHfCIPIA9CgICAEHwiKUKAgIDgD4N9PgIIIAAgBiALfiADIB5+fCANIBp+fCAHIBB+fCARIBt+fCAIIBZ+fCAcICB+fCAJIDOsIg9+fCAEIB1+fCAFIAp+fCATQhqHfCITIBNCgICACHwiE0KAgIDwD4N9PgIcIAAgCCALfiADIBt+fCANIBx+fCAJIBB+fCASIB1+fCAKIB9+fCAOIB5+fCAGIAx+fCAEIBp+fCAFIAd+fCApQhqHfCIEIARCgICACHwiBEKAgIDwD4N9PgIMIAAgCyAZfiADIAp+fCAGIA1+fCAQIBR+fCAHIBF+fCAVIBZ+fCAIICB+fCAPIBd+fCAJIDWsIgx+fCAFIBh+fCATQhmHfCIFIAVCgICAEHwiBUKAgIDgD4N9PgIgIAAgJCAlQoCAgPAPg30gIiAjQoCAgGCDfSAEQhmHfCIEQoCAgBB8Ig5CGoh8PgIUIAAgBCAOQoCAgOAPg30+AhAgACAKIAt+IAMgHX58IA0gHn58IAYgEH58IBEgGn58IAcgFn58IBsgIH58IAggD358IAwgHH58IAkgAqx+fCAFQhqHfCIDIANCgICACHwiA0KAgIDwD4N9PgIkIAAgJyAoQoCAgPAPg30gISAmQoCAgGCDfSADQhmHQhN+fCIDQoCAgBB8IgZCGoh8PgIEIAAgAyAGQoCAgOAPg30+AgALCAAgACABrYkLNQEBfyMAQRBrIgIgADYCDCABBEBBACEAA0AgAigCDCAAakEAOgAAIABBAWoiACABRw0ACwsLBABBIAvLBgIbfgd/IAAgASgCDCIdQQF0rCIHIB2sIhN+IAEoAhAiIKwiBiABKAIIIiFBAXSsIgt+fCABKAIUIh1BAXSsIgggASgCBCIiQQF0rCICfnwgASgCGCIfrCIJIAEoAgAiI0EBdKwiBX58IAEoAiAiHkETbKwiAyAerCIQfnwgASgCJCIeQSZsrCIEIAEoAhwiAUEBdKwiFH58IAIgBn4gCyATfnwgHawiESAFfnwgAyAUfnwgBCAJfnwgAiAHfiAhrCIOIA5+fCAFIAZ+fCABQSZsrCIPIAGsIhV+fCADIB9BAXSsfnwgBCAIfnwiF0KAgIAQfCIYQhqHfCIZQoCAgAh8IhpCGYd8IgogCkKAgIAQfCIMQoCAgOAPg30+AhggACAFIA5+IAIgIqwiDX58IB9BE2ysIgogCX58IAggD358IAMgIEEBdKwiFn58IAQgB358IAggCn4gBSANfnwgBiAPfnwgAyAHfnwgBCAOfnwgHUEmbKwgEX4gI6wiDSANfnwgCiAWfnwgByAPfnwgAyALfnwgAiAEfnwiCkKAgIAQfCINQhqHfCIbQoCAgAh8IhxCGYd8IhIgEkKAgIAQfCISQoCAgOAPg30+AgggACALIBF+IAYgB358IAIgCX58IAUgFX58IAQgEH58IAxCGod8IgwgDEKAgIAIfCIMQoCAgPAPg30+AhwgACAFIBN+IAIgDn58IAkgD358IAMgCH58IAQgBn58IBJCGod8IgMgA0KAgIAIfCIDQoCAgPAPg30+AgwgACAJIAt+IAYgBn58IAcgCH58IAIgFH58IAUgEH58IAQgHqwiBn58IAxCGYd8IgQgBEKAgIAQfCIEQoCAgOAPg30+AiAgACAZIBpCgICA8A+DfSAXIBhCgICAYIN9IANCGYd8IgNCgICAEHwiCEIaiHw+AhQgACADIAhCgICA4A+DfT4CECAAIAcgCX4gESAWfnwgCyAVfnwgAiAQfnwgBSAGfnwgBEIah3wiAiACQoCAgAh8IgJCgICA8A+DfT4CJCAAIBsgHEKAgIDwD4N9IAogDUKAgIBgg30gAkIZh0ITfnwiAkKAgIAQfCIFQhqIfD4CBCAAIAIgBUKAgIDgD4N9PgIACwkAIAAgATYAAAsQACAAMwAAIAAxAAJCEIaECxIAIAAgASACQfSbAigCABELAAsEAEEQC+wBARJ/IAIoAgQhAyABKAIEIQQgAigCCCEFIAEoAgghBiACKAIMIQcgASgCDCEIIAIoAhAhCSABKAIQIQogAigCFCELIAEoAhQhDCACKAIYIQ0gASgCGCEOIAIoAhwhDyABKAIcIRAgAigCICERIAEoAiAhEiACKAIkIRMgASgCJCEUIAAgAigCACABKAIAajYCACAAIBMgFGo2AiQgACARIBJqNgIgIAAgDyAQajYCHCAAIA0gDmo2AhggACALIAxqNgIUIAAgCSAKajYCECAAIAcgCGo2AgwgACAFIAZqNgIIIAAgAyAEajYCBAtAAQN/IAAgASABQfgAaiICEAogAEEoaiABQShqIgMgAUHQAGoiBBAKIABB0ABqIAQgAhAKIABB+ABqIAEgAxAKC+wBARJ/IAIoAgQhAyABKAIEIQQgAigCCCEFIAEoAgghBiACKAIMIQcgASgCDCEIIAIoAhAhCSABKAIQIQogAigCFCELIAEoAhQhDCACKAIYIQ0gASgCGCEOIAIoAhwhDyABKAIcIRAgAigCICERIAEoAiAhEiACKAIkIRMgASgCJCEUIAAgASgCACACKAIAazYCACAAIBQgE2s2AiQgACASIBFrNgIgIAAgECAPazYCHCAAIA4gDWs2AhggACAMIAtrNgIUIAAgCiAJazYCECAAIAggB2s2AgwgACAGIAVrNgIIIAAgBCADazYCBAvyAgICfwF+AkAgAkUNACAAIAJqIgNBAWsgAToAACAAIAE6AAAgAkEDSQ0AIANBAmsgAToAACAAIAE6AAEgA0EDayABOgAAIAAgAToAAiACQQdJDQAgA0EEayABOgAAIAAgAToAAyACQQlJDQAgAEEAIABrQQNxIgRqIgMgAUH/AXFBgYKECGwiATYCACADIAIgBGtBfHEiBGoiAkEEayABNgIAIARBCUkNACADIAE2AgggAyABNgIEIAJBCGsgATYCACACQQxrIAE2AgAgBEEZSQ0AIAMgATYCGCADIAE2AhQgAyABNgIQIAMgATYCDCACQRBrIAE2AgAgAkEUayABNgIAIAJBGGsgATYCACACQRxrIAE2AgAgBCADQQRxQRhyIgRrIgJBIEkNACABrUKBgICAEH4hBSADIARqIQEDQCABIAU3AxggASAFNwMQIAEgBTcDCCABIAU3AwAgAUEgaiEBIAJBIGsiAkEfSw0ACwsgAAuDBAEDfyACQYAETwRAIAAgASACEAQaIAAPCyAAIAJqIQMCQCAAIAFzQQNxRQRAAkAgAEEDcUUEQCAAIQIMAQsgAkEBSARAIAAhAgwBCyAAIQIDQCACIAEtAAA6AAAgAUEBaiEBIAJBAWoiAkEDcUUNASACIANJDQALCwJAIANBfHEiBEHAAEkNACACIARBQGoiBUsNAANAIAIgASgCADYCACACIAEoAgQ2AgQgAiABKAIINgIIIAIgASgCDDYCDCACIAEoAhA2AhAgAiABKAIUNgIUIAIgASgCGDYCGCACIAEoAhw2AhwgAiABKAIgNgIgIAIgASgCJDYCJCACIAEoAig2AiggAiABKAIsNgIsIAIgASgCMDYCMCACIAEoAjQ2AjQgAiABKAI4NgI4IAIgASgCPDYCPCABQUBrIQEgAkFAayICIAVNDQALCyACIARPDQEDQCACIAEoAgA2AgAgAUEEaiEBIAJBBGoiAiAESQ0ACwwBCyADQQRJBEAgACECDAELIAAgA0EEayIESwRAIAAhAgwBCyAAIQIDQCACIAEtAAA6AAAgAiABLQABOgABIAIgAS0AAjoAAiACIAEtAAM6AAMgAUEEaiEBIAJBBGoiAiAETQ0ACwsgAiADSQRAA0AgAiABLQAAOgAAIAFBAWohASACQQFqIgIgA0cNAAsLIAALGAEBf0HkpgIoAgAiAARAIAARFQALEAEACwkAIAAgATcAAAs7AQF/IAAgAUEoaiICIAEQEyAAQShqIAIgARAVIABB0ABqIAFB0ABqECMgAEH4AGogAUH4AGpB4BEQCguVAQEEfyMAQTBrIgUkACAAIAFBKGoiAyABEBMgAEEoaiIEIAMgARAVIABB0ABqIgMgACACEAogBCAEIAJBKGoQCiAAQfgAaiIGIAJB+ABqIAFB+ABqEAogACABQdAAaiACQdAAahAKIAUgACAAEBMgACADIAQQFSAEIAMgBBATIAMgBSAGEBMgBiAFIAYQFSAFQTBqJAALFQAgAEEBNgIAIABBBGpBAEEkEBYaCwgAIABBIBAnC48dATZ+IAEQECETIAE1AAIhFCABQQVqEBAhFSABNQAHIRYgATUACiEXIAFBDWoQECERIAE1AA8hCyABQRJqEBAhCSABQRVqEBAhCCABNQAXIQcgAUEaahAQIQMgATUAHCEGIAIQECEOIAI1AAIhDyACQQVqEBAhDCACNQAHIQ0gAjUACiEQIAJBDWoQECESIAI1AA8hGCACQRJqEBAhGSACQRVqEBAhGiACNQAXIQogAkEaahAQIQQgACACNQAcQgeIIgUgA0ICiEL///8AgyIDfiAEQgKIQv///wCDIgQgBkIHiCIGfnwgAyAEfiAKQgWIQv///wCDIgogBn58IAUgB0IFiEL///8AgyIHfnwiIUKAgEB9Ih5CFYd8IiIgIkKAgEB9IiNCgICAf4N9IiJCk9gofiAPQgWIQv///wCDIg8gCEL///8AgyIIfiAOQv///wCDIg4gB358IAxCAohC////AIMiDCAJQgOIQv///wCDIgl+fCANQgeIQv///wCDIg0gC0IGiEL///8AgyILfnwgEEIEiEL///8AgyIQIBFCAYhC////AIMiEX58IBJCAYhC////AIMiEiAXQgSIQv///wCDIhd+fCAYQgaIQv///wCDIhggFkIHiEL///8AgyIWfnwgGkL///8AgyIaIBRCBYhC////AIMiFH58IBlCA4hC////AIMiGSAVQgKIQv///wCDIhV+fCAKIBNC////AIMiE358IAkgD34gCCAOfnwgCyAMfnwgDSARfnwgECAXfnwgEiAWfnwgFSAYfnwgFCAZfnwgEyAafnwiH0KAgEB9IhxCFYh8IiB8ICBCgIBAfSIdQoCAgH+DfSAhIB5CgICAf4N9IAMgCn4gBiAafnwgBCAHfnwgBSAIfnwgBiAZfiADIBp+fCAHIAp+fCAEIAh+fCAFIAl+fCIgQoCAQH0iG0IVh3wiHkKAgEB9IiRCFYd8IiFCmNocfnwgHiAkQoCAgH+DfSIeQuf2J358ICAgG0KAgIB/g30gByAafiAGIBh+fCADIBl+fCAIIAp+fCAEIAl+fCAFIAt+fCADIBh+IAYgEn58IAggGn58IAcgGX58IAkgCn58IAQgC358IAUgEX58IhtCgIBAfSIkQhWHfCIlQoCAQH0iJkIVh3wiIELTjEN+fCAfIBxCgICAf4N9IAsgD34gCSAOfnwgDCARfnwgDSAXfnwgECAWfnwgEiAVfnwgFCAYfnwgEyAZfnwgDyARfiALIA5+fCAMIBd+fCANIBZ+fCAQIBV+fCASIBR+fCATIBh+fCIoQoCAQH0iKUIViHwiKkKAgEB9IitCFYh8ICFCk9gofnwgHkKY2hx+fCAgQuf2J358IixCgIBAfSItQhWHfCIuQoCAQH0iL0IVhyAHIA9+IAMgDn58IAggDH58IAkgDX58IAsgEH58IBEgEn58IBcgGH58IBUgGn58IBYgGX58IAogFH58IAQgE358Ih8gIkKY2hx+IAUgBn4iHCAcQoCAQH0iHEKAgIB/g30gI0IVh3wiI0KT2Ch+fHwgHUIViHwgIULn9id+fCAeQtOMQ358IB9CgIBAfSIxQoCAgH+DfSAgQtGrCH58Ih18ICUgJkKAgIB/g30gGyAcQhWHIh9Cg6FWfnwgJEKAgIB/g30gAyASfiAGIBB+fCAHIBh+fCAJIBp+fCAIIBl+fCAKIAt+fCAEIBF+fCAFIBd+fCADIBB+IAYgDX58IAcgEn58IAggGH58IAsgGn58IAkgGX58IAogEX58IAQgF358IAUgFn58IhtCgIBAfSIkQhWHfCIlQoCAQH0iJkIVh3wiMEKAgEB9IidCFYd8IhxCg6FWfnwgHUKAgEB9IjJCgICAf4N9Ih0gHUKAgEB9IjNCgICAf4N9IC4gL0KAgIB/g30gHELRqwh+fCAwICdCgICAf4N9ICNCg6FWfiAfQtGrCH58ICV8ICZCgICAf4N9IBsgH0LTjEN+fCAjQtGrCH58ICJCg6FWfnwgJEKAgIB/g30gAyANfiAGIAx+fCAHIBB+fCAIIBJ+fCAJIBh+fCARIBp+fCALIBl+fCAKIBd+fCAEIBZ+fCAFIBV+fCADIAx+IAYgD358IAcgDX58IAggEH58IAkgEn58IAsgGH58IBcgGn58IBEgGX58IAogFn58IAQgFX58IAUgFH58IiRCgIBAfSIlQhWHfCImQoCAQH0iLkIVh3wiL0KAgEB9IjBCFYd8IhtCgIBAfSInQhWHfCIdQoOhVn58ICwgLUKAgIB/g30gKiArQoCAgH+DfSAeQpPYKH58ICBCmNocfnwgKCAPIBd+IA4gEX58IAwgFn58IA0gFX58IBAgFH58IBIgE358IA8gFn4gDiAXfnwgDCAVfnwgDSAUfnwgECATfnwiKkKAgEB9IitCFYh8IixCgIBAfSItQhWIfCApQoCAgH+DfSAgQpPYKH58IihCgIBAfSIpQhWHfCI0QoCAQH0iNUIVh3wgHELTjEN+fCAdQtGrCH58IBsgJ0KAgIB/g30iG0KDoVZ+fCInQoCAQH0iNkIVh3wiN0KAgEB9IjhCFYd8IDcgOEKAgIB/g30gJyA2QoCAgH+DfSA0IDVCgICAf4N9IBxC5/YnfnwgHULTjEN+fCAbQtGrCH58IC8gMEKAgIB/g30gI0LTjEN+IB9C5/YnfnwgIkLRqwh+fCAhQoOhVn58ICZ8IC5CgICAf4N9ICNC5/YnfiAfQpjaHH58ICJC04xDfnwgJHwgIULRqwh+fCAeQoOhVn58ICVCgICAf4N9IAMgD34gBiAOfnwgByAMfnwgCCANfnwgCSAQfnwgCyASfnwgESAYfnwgFiAafnwgFyAZfnwgCiAVfnwgBCAUfnwgBSATfnwgMUIViHwiBEKAgEB9IgZCFYd8IgpCgIBAfSIHQhWHfCIDQoCAQH0iCEIVh3wiBUKDoVZ+fCAoIClCgICAf4N9IBxCmNocfnwgHULn9id+fCAbQtOMQ358IAVC0asIfnwgAyAIQoCAgH+DfSIDQoOhVn58IghCgIBAfSIJQhWHfCILQoCAQH0iEEIVh3wgCyAQQoCAgH+DfSAIIAlCgICAf4N9ICwgLUKAgIB/g30gHEKT2Ch+fCAdQpjaHH58IBtC5/YnfnwgCiAHQoCAgH+DfSAjQpjaHH4gH0KT2Ch+fCAiQuf2J358ICFC04xDfnwgHkLRqwh+fCAEfCAgQoOhVn58IAZCgICAf4N9IDJCFYd8IgZCgIBAfSIKQhWHfCIEQoOhVn58IAVC04xDfnwgA0LRqwh+fCAPIBV+IA4gFn58IAwgFH58IA0gE358IA8gFH4gDiAVfnwgDCATfnwiB0KAgEB9IghCFYh8IgxCgIBAfSIJQhWIICp8ICtCgICAf4N9IB1Ck9gofnwgG0KY2hx+fCAEQtGrCH58IAVC5/YnfnwgA0LTjEN+fCINQoCAQH0iC0IVh3wiEEKAgEB9IhFCFYd8IBAgBiAKQoCAgH+DfSAzQhWHfCIKQoCAQH0iEkIVhyIGQoOhVn58IBFCgICAf4N9IA0gBkLRqwh+fCALQoCAgH+DfSAMIAlCgICAf4N9IBtCk9gofnwgBELTjEN+fCAFQpjaHH58IANC5/YnfnwgByAPIBN+IA4gFH58IA4gE34iD0KAgEB9Ig5CFYh8IgxCgIBAfSIJQhWIfCAIQoCAgP///weDfSAEQuf2J358IAVCk9gofnwgA0KY2hx+fCIFQoCAQH0iB0IVh3wiCEKAgEB9Ig1CFYd8IAggBkLTjEN+fCANQoCAgH+DfSAFIAZC5/YnfnwgB0KAgIB/g30gDCAJQoCAgP///weDfSAEQpjaHH58IANCk9gofnwgDyAOQoCAgP///wGDfSAEQpPYKH58IgVCgIBAfSIDQhWHfCIEQoCAQH0iB0IVh3wgBCAGQpjaHH58IAdCgICAf4N9IAUgA0KAgIB/g30gBkKT2Ch+fCIDQhWHfCIEQhWHfCIGQhWHfCIHQhWHfCIPQhWHfCIIQhWHfCIOQhWHfCIMQhWHfCIJQhWHfCINQhWHfCILQhWHIAogEkKAgIB/g318IgpCFYciBUKT2Ch+IANC////AIN8IgM8AAAgACADQgiIPAABIAAgBUKY2hx+IARC////AIN8IANCFYd8IgRCC4g8AAQgACAEQgOIPAADIAAgBULn9id+IAZC////AIN8IARCFYd8IgZCBog8AAYgACADQhCIQh+DIARC////AIMiBEIFhoQ8AAIgACAFQtOMQ34gB0L///8Ag3wgBkIVh3wiA0IJiDwACSAAIANCAYg8AAggACAGQv///wCDIgZCAoYgBEITiIQ8AAUgACAFQtGrCH4gD0L///8Ag3wgA0IVh3wiBEIMiDwADCAAIARCBIg8AAsgACADQv///wCDIgdCB4YgBkIOiIQ8AAcgACAFQoOhVn4gCEL///8Ag3wgBEIVh3wiA0IHiDwADiAAIARC////AIMiBEIEhiAHQhGIhDwACiAAIA5C////AIMgA0IVh3wiBUIKiDwAESAAIAVCAog8ABAgACADQv///wCDIgZCAYYgBEIUiIQ8AA0gACAMQv///wCDIAVCFYd8IgNCDYg8ABQgACADQgWIPAATIAAgBUL///8AgyIEQgaGIAZCD4iEPAAPIAAgCUL///8AgyADQhWHfCIFPAAVIAAgA0IDhiAEQhKIhDwAEiAAIAVCCIg8ABYgACANQv///wCDIAVCFYd8IgNCC4g8ABkgACADQgOIPAAYIAAgC0L///8AgyADQhWHfCIEQgaIPAAbIAAgBUIQiEIfgyADQv///wCDIgNCBYaEPAAXIAAgCkL///8AgyAEQhWHfCIFQhGIPAAfIAAgBUIJiDwAHiAAIAVCAYg8AB0gACAEQv///wCDIgRCAoYgA0ITiIQ8ABogACAFQgeGIARCDoiEPAAcCwUAQcAACwQAQX8LCgAgACABIAIQVwvMDAEHfwJAIABFDQAgAEEIayIDIABBBGsoAgAiAUF4cSIAaiEFAkAgAUEBcQ0AIAFBA3FFDQEgAyADKAIAIgFrIgNB6KICKAIASQ0BIAAgAWohACADQeyiAigCAEcEQCABQf8BTQRAIAMoAggiAiABQQN2IgRBA3RBgKMCakYaIAIgAygCDCIBRgRAQdiiAkHYogIoAgBBfiAEd3E2AgAMAwsgAiABNgIMIAEgAjYCCAwCCyADKAIYIQYCQCADIAMoAgwiAUcEQCADKAIIIgIgATYCDCABIAI2AggMAQsCQCADQRRqIgIoAgAiBA0AIANBEGoiAigCACIEDQBBACEBDAELA0AgAiEHIAQiAUEUaiICKAIAIgQNACABQRBqIQIgASgCECIEDQALIAdBADYCAAsgBkUNAQJAIAMgAygCHCICQQJ0QYilAmoiBCgCAEYEQCAEIAE2AgAgAQ0BQdyiAkHcogIoAgBBfiACd3E2AgAMAwsgBkEQQRQgBigCECADRhtqIAE2AgAgAUUNAgsgASAGNgIYIAMoAhAiAgRAIAEgAjYCECACIAE2AhgLIAMoAhQiAkUNASABIAI2AhQgAiABNgIYDAELIAUoAgQiAUEDcUEDRw0AQeCiAiAANgIAIAUgAUF+cTYCBCADIABBAXI2AgQgACADaiAANgIADwsgAyAFTw0AIAUoAgQiAUEBcUUNAAJAIAFBAnFFBEAgBUHwogIoAgBGBEBB8KICIAM2AgBB5KICQeSiAigCACAAaiIANgIAIAMgAEEBcjYCBCADQeyiAigCAEcNA0HgogJBADYCAEHsogJBADYCAA8LIAVB7KICKAIARgRAQeyiAiADNgIAQeCiAkHgogIoAgAgAGoiADYCACADIABBAXI2AgQgACADaiAANgIADwsgAUF4cSAAaiEAAkAgAUH/AU0EQCAFKAIIIgIgAUEDdiIEQQN0QYCjAmpGGiACIAUoAgwiAUYEQEHYogJB2KICKAIAQX4gBHdxNgIADAILIAIgATYCDCABIAI2AggMAQsgBSgCGCEGAkAgBSAFKAIMIgFHBEAgBSgCCCICQeiiAigCAEkaIAIgATYCDCABIAI2AggMAQsCQCAFQRRqIgIoAgAiBA0AIAVBEGoiAigCACIEDQBBACEBDAELA0AgAiEHIAQiAUEUaiICKAIAIgQNACABQRBqIQIgASgCECIEDQALIAdBADYCAAsgBkUNAAJAIAUgBSgCHCICQQJ0QYilAmoiBCgCAEYEQCAEIAE2AgAgAQ0BQdyiAkHcogIoAgBBfiACd3E2AgAMAgsgBkEQQRQgBigCECAFRhtqIAE2AgAgAUUNAQsgASAGNgIYIAUoAhAiAgRAIAEgAjYCECACIAE2AhgLIAUoAhQiAkUNACABIAI2AhQgAiABNgIYCyADIABBAXI2AgQgACADaiAANgIAIANB7KICKAIARw0BQeCiAiAANgIADwsgBSABQX5xNgIEIAMgAEEBcjYCBCAAIANqIAA2AgALIABB/wFNBEAgAEEDdiIBQQN0QYCjAmohAAJ/QdiiAigCACICQQEgAXQiAXFFBEBB2KICIAEgAnI2AgAgAAwBCyAAKAIICyECIAAgAzYCCCACIAM2AgwgAyAANgIMIAMgAjYCCA8LQR8hAiADQgA3AhAgAEH///8HTQRAIABBCHYiASABQYD+P2pBEHZBCHEiAXQiAiACQYDgH2pBEHZBBHEiAnQiBCAEQYCAD2pBEHZBAnEiBHRBD3YgASACciAEcmsiAUEBdCAAIAFBFWp2QQFxckEcaiECCyADIAI2AhwgAkECdEGIpQJqIQECQAJAAkBB3KICKAIAIgRBASACdCIHcUUEQEHcogIgBCAHcjYCACABIAM2AgAgAyABNgIYDAELIABBAEEZIAJBAXZrIAJBH0YbdCECIAEoAgAhAQNAIAEiBCgCBEF4cSAARg0CIAJBHXYhASACQQF0IQIgBCABQQRxaiIHQRBqKAIAIgENAAsgByADNgIQIAMgBDYCGAsgAyADNgIMIAMgAzYCCAwBCyAEKAIIIgAgAzYCDCAEIAM2AgggA0EANgIYIAMgBDYCDCADIAA2AggLQfiiAkH4ogIoAgBBAWsiAEF/IAAbNgIACwtGAQR+IAEpAgghAiABKQIQIQMgASkCGCEEIAEpAgAhBSAAIAEpAiA3AiAgACAENwIYIAAgAzcCECAAIAI3AgggACAFNwIAC68CARN/IAEoAgQhDCAAKAIEIQMgASgCCCENIAAoAgghBCABKAIMIQ4gACgCDCEFIAEoAhAhDyAAKAIQIQYgASgCFCEQIAAoAhQhByABKAIYIREgACgCGCEIIAEoAhwhEiAAKAIcIQkgASgCICETIAAoAiAhCiABKAIkIRQgACgCJCELIABBACACayICIAAoAgAiFSABKAIAc3EgFXM2AgAgACALIAsgFHMgAnFzNgIkIAAgCiAKIBNzIAJxczYCICAAIAkgCSAScyACcXM2AhwgACAIIAggEXMgAnFzNgIYIAAgByAHIBBzIAJxczYCFCAAIAYgBiAPcyACcXM2AhAgACAFIAUgDnMgAnFzNgIMIAAgBCAEIA1zIAJxczYCCCAAIAMgAyAMcyACcXM2AgQLxQICA34CfyMAQcAFayIHJAACQCACUA0AIAAgACkDSCIEIAJCA4Z8IgM3A0ggAEFAayIGIAYpAwAgAyAEVK18IAJCPYh8NwMAQgAhAyACQoABIARCA4hC/wCDIgV9IgRUBEADQCAAIAMgBXynaiABIAOnai0AADoAUCADQgF8IgMgAlINAAwCCwALA0AgACADIAV8p2ogASADp2otAAA6AFAgA0IBfCIDIARSDQALIAAgAEHQAGogByAHQYAFaiIGEHkgASAEp2ohASACIAR9IgJC/wBWBEADQCAAIAEgByAGEHkgAUGAAWohASACQoABfSICQv8AVg0ACwsCQCACUA0AQQAhBkIBIQMDQCAAIAZqIAEgBmotAAA6AFAgAiADUQ0BIAOnIQYgA0IBfCEDDAALAAsgB0HABRAMCyAHQcAFaiQAQQALEQAgACABc0H/AXFBAWtBH3YLIwEBfyABBEADQCAAIAJqEL0BOgAAIAJBAWoiAiABRw0ACwsLNAEBfwJAIAFBAUgNAEEBIQMDQCAAIAAQUyABIANGDQEgA0EBaiEDDAALAAsgACAAIAIQHgsQACAAIAFB+JsCKAIAEQEACxAAIAAgAUHwmwIoAgARAQALfwEDfyAAIQECQCAAQQNxBEADQCABLQAARQ0CIAFBAWoiAUEDcQ0ACwsDQCABIgJBBGohASACKAIAIgNBf3MgA0GBgoQIa3FBgIGChHhxRQ0ACyADQf8BcUUEQCACIABrDwsDQCACLQABIQMgAkEBaiIBIQIgAw0ACwsgASAAawsEAEEYC28BBX8jAEEwayIDJAAgACABEA4gAEHQAGoiAiABQShqIgYQDiAAQfgAaiIFIAFB0ABqENICIABBKGoiBCABIAYQEyADIAQQDiAEIAIgABATIAIgAiAAEBUgACADIAQQFSAFIAUgAhAVIANBMGokAAuqAQEJfyABKAIEIQIgASgCCCEDIAEoAgwhBCABKAIQIQUgASgCFCEGIAEoAhghByABKAIcIQggASgCICEJIAEoAiQhCiAAQQAgASgCAGs2AgAgAEEAIAprNgIkIABBACAJazYCICAAQQAgCGs2AhwgAEEAIAdrNgIYIABBACAGazYCFCAAQQAgBWs2AhAgAEEAIARrNgIMIABBACADazYCCCAAQQAgAms2AgQLJAEBfyMAQSBrIgEkACABIAAQNiABQSAQOSEAIAFBIGokACAAC2MBAn8gAkUEQEEADwsCfyAALQAAIgMEQANAAkACQCABLQAAIgRFDQAgAkEBayICRQ0AIAMgBEYNAQsgAwwDCyABQQFqIQEgAC0AASEDIABBAWohACADDQALC0EACyABLQAAawuZLgEMfyMAQRBrIgwkAAJAAkACQAJAAkACQAJAAkACQAJAAkACQCAAQfQBTQRAQdiiAigCACIFQRAgAEELakF4cSAAQQtJGyIIQQN2IgJ2IgFBA3EEQCABQX9zQQFxIAJqIgNBA3QiAUGIowJqKAIAIgRBCGohAAJAIAQoAggiAiABQYCjAmoiAUYEQEHYogIgBUF+IAN3cTYCAAwBCyACIAE2AgwgASACNgIICyAEIANBA3QiAUEDcjYCBCABIARqIgEgASgCBEEBcjYCBAwNCyAIQeCiAigCACIKTQ0BIAEEQAJAQQIgAnQiAEEAIABrciABIAJ0cSIAQQAgAGtxQQFrIgAgAEEMdkEQcSICdiIBQQV2QQhxIgAgAnIgASAAdiIBQQJ2QQRxIgByIAEgAHYiAUEBdkECcSIAciABIAB2IgFBAXZBAXEiAHIgASAAdmoiA0EDdCIAQYijAmooAgAiBCgCCCIBIABBgKMCaiIARgRAQdiiAiAFQX4gA3dxIgU2AgAMAQsgASAANgIMIAAgATYCCAsgBEEIaiEAIAQgCEEDcjYCBCAEIAhqIgIgA0EDdCIBIAhrIgNBAXI2AgQgASAEaiADNgIAIAoEQCAKQQN2IgFBA3RBgKMCaiEHQeyiAigCACEEAn8gBUEBIAF0IgFxRQRAQdiiAiABIAVyNgIAIAcMAQsgBygCCAshASAHIAQ2AgggASAENgIMIAQgBzYCDCAEIAE2AggLQeyiAiACNgIAQeCiAiADNgIADA0LQdyiAigCACIGRQ0BIAZBACAGa3FBAWsiACAAQQx2QRBxIgJ2IgFBBXZBCHEiACACciABIAB2IgFBAnZBBHEiAHIgASAAdiIBQQF2QQJxIgByIAEgAHYiAUEBdkEBcSIAciABIAB2akECdEGIpQJqKAIAIgEoAgRBeHEgCGshAyABIQIDQAJAIAIoAhAiAEUEQCACKAIUIgBFDQELIAAoAgRBeHEgCGsiAiADIAIgA0kiAhshAyAAIAEgAhshASAAIQIMAQsLIAEgCGoiCSABTQ0CIAEoAhghCyABIAEoAgwiBEcEQCABKAIIIgBB6KICKAIASRogACAENgIMIAQgADYCCAwMCyABQRRqIgIoAgAiAEUEQCABKAIQIgBFDQQgAUEQaiECCwNAIAIhByAAIgRBFGoiAigCACIADQAgBEEQaiECIAQoAhAiAA0ACyAHQQA2AgAMCwtBfyEIIABBv39LDQAgAEELaiIAQXhxIQhB3KICKAIAIglFDQBBACAIayEDAkACQAJAAn9BACAIQYACSQ0AGkEfIAhB////B0sNABogAEEIdiIAIABBgP4/akEQdkEIcSICdCIAIABBgOAfakEQdkEEcSIBdCIAIABBgIAPakEQdkECcSIAdEEPdiABIAJyIAByayIAQQF0IAggAEEVanZBAXFyQRxqCyIFQQJ0QYilAmooAgAiAkUEQEEAIQAMAQtBACEAIAhBAEEZIAVBAXZrIAVBH0YbdCEBA0ACQCACKAIEQXhxIAhrIgcgA08NACACIQQgByIDDQBBACEDIAIhAAwDCyAAIAIoAhQiByAHIAIgAUEddkEEcWooAhAiAkYbIAAgBxshACABQQF0IQEgAg0ACwsgACAEckUEQEEAIQRBAiAFdCIAQQAgAGtyIAlxIgBFDQMgAEEAIABrcUEBayIAIABBDHZBEHEiAnYiAUEFdkEIcSIAIAJyIAEgAHYiAUECdkEEcSIAciABIAB2IgFBAXZBAnEiAHIgASAAdiIBQQF2QQFxIgByIAEgAHZqQQJ0QYilAmooAgAhAAsgAEUNAQsDQCAAKAIEQXhxIAhrIgEgA0khAiABIAMgAhshAyAAIAQgAhshBCAAKAIQIgEEfyABBSAAKAIUCyIADQALCyAERQ0AIANB4KICKAIAIAhrTw0AIAQgCGoiBiAETQ0BIAQoAhghBSAEIAQoAgwiAUcEQCAEKAIIIgBB6KICKAIASRogACABNgIMIAEgADYCCAwKCyAEQRRqIgIoAgAiAEUEQCAEKAIQIgBFDQQgBEEQaiECCwNAIAIhByAAIgFBFGoiAigCACIADQAgAUEQaiECIAEoAhAiAA0ACyAHQQA2AgAMCQsgCEHgogIoAgAiAk0EQEHsogIoAgAhAwJAIAIgCGsiAUEQTwRAQeCiAiABNgIAQeyiAiADIAhqIgA2AgAgACABQQFyNgIEIAIgA2ogATYCACADIAhBA3I2AgQMAQtB7KICQQA2AgBB4KICQQA2AgAgAyACQQNyNgIEIAIgA2oiACAAKAIEQQFyNgIECyADQQhqIQAMCwsgCEHkogIoAgAiBkkEQEHkogIgBiAIayIBNgIAQfCiAkHwogIoAgAiAiAIaiIANgIAIAAgAUEBcjYCBCACIAhBA3I2AgQgAkEIaiEADAsLQQAhACAIQS9qIgkCf0GwpgIoAgAEQEG4pgIoAgAMAQtBvKYCQn83AgBBtKYCQoCggICAgAQ3AgBBsKYCIAxBDGpBcHFB2KrVqgVzNgIAQcSmAkEANgIAQZSmAkEANgIAQYAgCyIBaiIFQQAgAWsiB3EiAiAITQ0KQZCmAigCACIEBEBBiKYCKAIAIgMgAmoiASADTSABIARLcg0LC0GUpgItAABBBHENBQJAAkBB8KICKAIAIgMEQEGYpgIhAANAIAMgACgCACIBTwRAIAEgACgCBGogA0sNAwsgACgCCCIADQALC0EAEEciAUF/Rg0GIAIhBUG0pgIoAgAiA0EBayIAIAFxBEAgAiABayAAIAFqQQAgA2txaiEFCyAFIAhNIAVB/v///wdLcg0GQZCmAigCACIEBEBBiKYCKAIAIgMgBWoiACADTSAAIARLcg0HCyAFEEciACABRw0BDAgLIAUgBmsgB3EiBUH+////B0sNBSAFEEciASAAKAIAIAAoAgRqRg0EIAEhAAsgAEF/RiAIQTBqIAVNckUEQEG4pgIoAgAiASAJIAVrakEAIAFrcSIBQf7///8HSwRAIAAhAQwICyABEEdBf0cEQCABIAVqIQUgACEBDAgLQQAgBWsQRxoMBQsgACIBQX9HDQYMBAsAC0EAIQQMBwtBACEBDAULIAFBf0cNAgtBlKYCQZSmAigCAEEEcjYCAAsgAkH+////B0sNASACEEciAUF/RkEAEEciAEF/RnIgACABTXINASAAIAFrIgUgCEEoak0NAQtBiKYCQYimAigCACAFaiIANgIAQYymAigCACAASQRAQYymAiAANgIACwJAAkACQEHwogIoAgAiBwRAQZimAiEAA0AgASAAKAIAIgMgACgCBCICakYNAiAAKAIIIgANAAsMAgtB6KICKAIAIgBBACAAIAFNG0UEQEHoogIgATYCAAtBACEAQZymAiAFNgIAQZimAiABNgIAQfiiAkF/NgIAQfyiAkGwpgIoAgA2AgBBpKYCQQA2AgADQCAAQQN0IgNBiKMCaiADQYCjAmoiAjYCACADQYyjAmogAjYCACAAQQFqIgBBIEcNAAtB5KICIAVBKGsiA0F4IAFrQQdxQQAgAUEIakEHcRsiAGsiAjYCAEHwogIgACABaiIANgIAIAAgAkEBcjYCBCABIANqQSg2AgRB9KICQcCmAigCADYCAAwCCyAALQAMQQhxIAMgB0tyIAEgB01yDQAgACACIAVqNgIEQfCiAiAHQXggB2tBB3FBACAHQQhqQQdxGyIAaiICNgIAQeSiAkHkogIoAgAgBWoiASAAayIANgIAIAIgAEEBcjYCBCABIAdqQSg2AgRB9KICQcCmAigCADYCAAwBC0HoogIoAgAgAUsEQEHoogIgATYCAAsgASAFaiECQZimAiEAAkACQAJAAkACQAJAA0AgAiAAKAIARwRAIAAoAggiAA0BDAILCyAALQAMQQhxRQ0BC0GYpgIhAANAIAcgACgCACICTwRAIAIgACgCBGoiBCAHSw0DCyAAKAIIIQAMAAsACyAAIAE2AgAgACAAKAIEIAVqNgIEIAFBeCABa0EHcUEAIAFBCGpBB3EbaiIJIAhBA3I2AgQgAkF4IAJrQQdxQQAgAkEIakEHcRtqIgUgCCAJaiIGayECIAUgB0YEQEHwogIgBjYCAEHkogJB5KICKAIAIAJqIgA2AgAgBiAAQQFyNgIEDAMLIAVB7KICKAIARgRAQeyiAiAGNgIAQeCiAkHgogIoAgAgAmoiADYCACAGIABBAXI2AgQgACAGaiAANgIADAMLIAUoAgQiAEEDcUEBRgRAIABBeHEhBwJAIABB/wFNBEAgBSgCCCIDIABBA3YiAEEDdEGAowJqRhogAyAFKAIMIgFGBEBB2KICQdiiAigCAEF+IAB3cTYCAAwCCyADIAE2AgwgASADNgIIDAELIAUoAhghCAJAIAUgBSgCDCIBRwRAIAUoAggiACABNgIMIAEgADYCCAwBCwJAIAVBFGoiACgCACIDDQAgBUEQaiIAKAIAIgMNAEEAIQEMAQsDQCAAIQQgAyIBQRRqIgAoAgAiAw0AIAFBEGohACABKAIQIgMNAAsgBEEANgIACyAIRQ0AAkAgBSAFKAIcIgNBAnRBiKUCaiIAKAIARgRAIAAgATYCACABDQFB3KICQdyiAigCAEF+IAN3cTYCAAwCCyAIQRBBFCAIKAIQIAVGG2ogATYCACABRQ0BCyABIAg2AhggBSgCECIABEAgASAANgIQIAAgATYCGAsgBSgCFCIARQ0AIAEgADYCFCAAIAE2AhgLIAUgB2ohBSACIAdqIQILIAUgBSgCBEF+cTYCBCAGIAJBAXI2AgQgAiAGaiACNgIAIAJB/wFNBEAgAkEDdiIAQQN0QYCjAmohAgJ/QdiiAigCACIBQQEgAHQiAHFFBEBB2KICIAAgAXI2AgAgAgwBCyACKAIICyEAIAIgBjYCCCAAIAY2AgwgBiACNgIMIAYgADYCCAwDC0EfIQAgAkH///8HTQRAIAJBCHYiACAAQYD+P2pBEHZBCHEiA3QiACAAQYDgH2pBEHZBBHEiAXQiACAAQYCAD2pBEHZBAnEiAHRBD3YgASADciAAcmsiAEEBdCACIABBFWp2QQFxckEcaiEACyAGIAA2AhwgBkIANwIQIABBAnRBiKUCaiEEAkBB3KICKAIAIgNBASAAdCIBcUUEQEHcogIgASADcjYCACAEIAY2AgAgBiAENgIYDAELIAJBAEEZIABBAXZrIABBH0YbdCEAIAQoAgAhAQNAIAEiAygCBEF4cSACRg0DIABBHXYhASAAQQF0IQAgAyABQQRxaiIEKAIQIgENAAsgBCAGNgIQIAYgAzYCGAsgBiAGNgIMIAYgBjYCCAwCC0HkogIgBUEoayIDQXggAWtBB3FBACABQQhqQQdxGyIAayICNgIAQfCiAiAAIAFqIgA2AgAgACACQQFyNgIEIAEgA2pBKDYCBEH0ogJBwKYCKAIANgIAIAcgBEEnIARrQQdxQQAgBEEna0EHcRtqQS9rIgAgACAHQRBqSRsiAkEbNgIEIAJBoKYCKQIANwIQIAJBmKYCKQIANwIIQaCmAiACQQhqNgIAQZymAiAFNgIAQZimAiABNgIAQaSmAkEANgIAIAJBGGohAANAIABBBzYCBCAAQQhqIQEgAEEEaiEAIAEgBEkNAAsgAiAHRg0DIAIgAigCBEF+cTYCBCAHIAIgB2siBEEBcjYCBCACIAQ2AgAgBEH/AU0EQCAEQQN2IgBBA3RBgKMCaiECAn9B2KICKAIAIgFBASAAdCIAcUUEQEHYogIgACABcjYCACACDAELIAIoAggLIQAgAiAHNgIIIAAgBzYCDCAHIAI2AgwgByAANgIIDAQLQR8hACAHQgA3AhAgBEH///8HTQRAIARBCHYiACAAQYD+P2pBEHZBCHEiAnQiACAAQYDgH2pBEHZBBHEiAXQiACAAQYCAD2pBEHZBAnEiAHRBD3YgASACciAAcmsiAEEBdCAEIABBFWp2QQFxckEcaiEACyAHIAA2AhwgAEECdEGIpQJqIQMCQEHcogIoAgAiAkEBIAB0IgFxRQRAQdyiAiABIAJyNgIAIAMgBzYCACAHIAM2AhgMAQsgBEEAQRkgAEEBdmsgAEEfRht0IQAgAygCACEBA0AgASICKAIEQXhxIARGDQQgAEEddiEBIABBAXQhACACIAFBBHFqIgMoAhAiAQ0ACyADIAc2AhAgByACNgIYCyAHIAc2AgwgByAHNgIIDAMLIAMoAggiACAGNgIMIAMgBjYCCCAGQQA2AhggBiADNgIMIAYgADYCCAsgCUEIaiEADAULIAIoAggiACAHNgIMIAIgBzYCCCAHQQA2AhggByACNgIMIAcgADYCCAtB5KICKAIAIgAgCE0NAEHkogIgACAIayIBNgIAQfCiAkHwogIoAgAiAiAIaiIANgIAIAAgAUEBcjYCBCACIAhBA3I2AgQgAkEIaiEADAMLQdSiAkEwNgIAQQAhAAwCCwJAIAVFDQACQCAEKAIcIgJBAnRBiKUCaiIAKAIAIARGBEAgACABNgIAIAENAUHcogIgCUF+IAJ3cSIJNgIADAILIAVBEEEUIAUoAhAgBEYbaiABNgIAIAFFDQELIAEgBTYCGCAEKAIQIgAEQCABIAA2AhAgACABNgIYCyAEKAIUIgBFDQAgASAANgIUIAAgATYCGAsCQCADQQ9NBEAgBCADIAhqIgBBA3I2AgQgACAEaiIAIAAoAgRBAXI2AgQMAQsgBCAIQQNyNgIEIAYgA0EBcjYCBCADIAZqIAM2AgAgA0H/AU0EQCADQQN2IgBBA3RBgKMCaiECAn9B2KICKAIAIgFBASAAdCIAcUUEQEHYogIgACABcjYCACACDAELIAIoAggLIQAgAiAGNgIIIAAgBjYCDCAGIAI2AgwgBiAANgIIDAELQR8hACADQf///wdNBEAgA0EIdiIAIABBgP4/akEQdkEIcSICdCIAIABBgOAfakEQdkEEcSIBdCIAIABBgIAPakEQdkECcSIAdEEPdiABIAJyIAByayIAQQF0IAMgAEEVanZBAXFyQRxqIQALIAYgADYCHCAGQgA3AhAgAEECdEGIpQJqIQICQAJAIAlBASAAdCIBcUUEQEHcogIgASAJcjYCACACIAY2AgAgBiACNgIYDAELIANBAEEZIABBAXZrIABBH0YbdCEAIAIoAgAhCANAIAgiASgCBEF4cSADRg0CIABBHXYhAiAAQQF0IQAgASACQQRxaiICKAIQIggNAAsgAiAGNgIQIAYgATYCGAsgBiAGNgIMIAYgBjYCCAwBCyABKAIIIgAgBjYCDCABIAY2AgggBkEANgIYIAYgATYCDCAGIAA2AggLIARBCGohAAwBCwJAIAtFDQACQCABKAIcIgJBAnRBiKUCaiIAKAIAIAFGBEAgACAENgIAIAQNAUHcogIgBkF+IAJ3cTYCAAwCCyALQRBBFCALKAIQIAFGG2ogBDYCACAERQ0BCyAEIAs2AhggASgCECIABEAgBCAANgIQIAAgBDYCGAsgASgCFCIARQ0AIAQgADYCFCAAIAQ2AhgLAkAgA0EPTQRAIAEgAyAIaiIAQQNyNgIEIAAgAWoiACAAKAIEQQFyNgIEDAELIAEgCEEDcjYCBCAJIANBAXI2AgQgAyAJaiADNgIAIAoEQCAKQQN2IgBBA3RBgKMCaiEEQeyiAigCACECAn9BASAAdCIAIAVxRQRAQdiiAiAAIAVyNgIAIAQMAQsgBCgCCAshACAEIAI2AgggACACNgIMIAIgBDYCDCACIAA2AggLQeyiAiAJNgIAQeCiAiADNgIACyABQQhqIQALIAxBEGokACAAC7gBAQV/IwBBwAVrIgUkACAFIQMCQCAAIgIoAkhBA3ZB/wBxIgRB7wBNBEAgAiAEakHQAGpBkJcCQfAAIARrEBcaDAELIAJB0ABqIgYgBGpBkJcCQYABIARrEBcaIAIgBiADIANBgAVqEHkgBkEAQfAAEBYaCyACQcABaiACQUBrQRAQuQIgAiACQdAAaiADIANBgAVqEHkgASAAQcAAELkCIAVBwAUQDCAAQdABEAwgBUHABWokAEEACwQAQQgLMgEBfyAAIAEgAUH4AGoiAhAKIABBKGogAUEoaiABQdAAaiIBEAogAEHQAGogASACEAoL3AUBEX8CfyADRQRAQbLaiMsHIQRB7siBmQMhBUHl8MGLBiELQfTKgdkGDAELIAMoAAAhCyADKAAEIQUgAygACCEEIAMoAAwLIQYgAigAACEDIAIoAAQhCCACKAAIIQcgAigADCEJIAIoABAhDCACKAAUIQ0gAigAGCEQIAIoABwhEiABKAAAIQ4gASgABCEPIAEoAAghCiABKAAMIQFBASECA0AgDiADIAtqIgtzQRAQCSIOIAxqIgwgA3NBDBAJIQMgAyAOIAMgC2oiC3NBCBAJIg4gDGoiDHNBBxAJIQMgCCANIA8gBSAIaiINc0EQEAkiD2oiEXNBDBAJIQUgBSARIA8gBSANaiINc0EIEAkiD2oiEXNBBxAJIQUgByAKIAQgB2oiCHNBEBAJIgogEGoiEHNBDBAJIQQgBCAQIAogBCAIaiITc0EIEAkiCmoiCHNBBxAJIQQgCSABIAYgCWoiBnNBEBAJIgcgEmoiEHNBDBAJIQEgASAHIAEgBmoiFHNBCBAJIgcgEGoiCXNBBxAJIQYgBSAIIAcgBSALaiIBc0EQEAkiB2oiCHNBDBAJIQUgBSAIIAcgASAFaiILc0EIEAkiAWoiEHNBBxAJIQggBCAOIAQgDWoiBXNBEBAJIgcgCWoiCXNBDBAJIQQgBCAHIAQgBWoiBXNBCBAJIg4gCWoiEnNBBxAJIQcgBiAPIAYgE2oiBHNBEBAJIgkgDGoiDHNBDBAJIQYgBiAMIAkgBCAGaiIEc0EIEAkiD2oiDHNBBxAJIQkgAyAKIAMgFGoiBnNBEBAJIgogEWoiDXNBDBAJIQMgAyAKIAMgBmoiBnNBCBAJIgogDWoiDXNBBxAJIQMgAkEKRwRAIAJBAWohAgwBCwsgACALEA8gAEEEaiAFEA8gAEEIaiAEEA8gAEEMaiAGEA8gAEEQaiAOEA8gAEEUaiAPEA8gAEEYaiAKEA8gAEEcaiABEA9BAAu3AwECfyMAQTBrIgMkACADIAEQwgEgACADKAIAIgE6AAAgACABQRB2OgACIAAgAUEIdjoAASAAIAMoAgQiAkEOdjoABSAAIAJBBnY6AAQgACACQQJ0IAFBGHZyOgADIAAgAygCCCIBQQ12OgAIIAAgAUEFdjoAByAAIAFBA3QgAkEWdnI6AAYgACADKAIMIgJBC3Y6AAsgACACQQN2OgAKIAAgAkEFdCABQRV2cjoACSAAIAMoAhAiAUESdjoADyAAIAFBCnY6AA4gACABQQJ2OgANIAAgAUEGdCACQRN2cjoADCAAIAMoAhQiAToAECAAIAFBEHY6ABIgACABQQh2OgARIAAgAygCGCICQQ92OgAVIAAgAkEHdjoAFCAAIAJBAXQgAUEYdnI6ABMgACADKAIcIgFBDXY6ABggACABQQV2OgAXIAAgAUEDdCACQRd2cjoAFiAAIAMoAiAiAkEMdjoAGyAAIAJBBHY6ABogACACQQR0IAFBFXZyOgAZIAAgAygCJCIBQRJ2OgAfIAAgAUEKdjoAHiAAIAFBAnY6AB0gACABQQZ0IAJBFHZyOgAcIANBMGokAAvCAwEMfiABNQAAIQQgAUEEahAQIQUgAUEHahAQIQYgAUEKahAQIQIgAUENahAQIQcgATUAECEDIAFBFGoQECEIIAFBF2oQECEJIAFBGmoQECEKIAFBHWoQECELIAAgAkIDhiICIAJCgICACHwiAkKAgIDwD4N9IAZCBYYgBUIGhiIFQoCAgAh8IgZCGYd8IgxCgICAEHwiDUIaiHw+AgwgACAMIA1CgICA4A+DfT4CCCAAIAMgA0KAgIAIfCIDQoCAgPAPg30gB0IChiACQhmHfCICQoCAgBB8IgdCGoh8PgIUIAAgAiAHQoCAgOAPg30+AhAgACAIQgeGIANCGYd8IgMgA0KAgIAQfCIDQoCAgOAPg30+AhggACAJQgWGIgIgAkKAgIAIfCICQoCAgPAPg30gA0IaiHw+AhwgACAKQgSGIAJCGYd8IgMgA0KAgIAQfCIDQoCAgOAPg30+AiAgACALQgKGQvz//w+DIgIgAkKAgIAIfCICQoCAgBCDfSADQhqIfD4CJCAAIAUgBkKAgIDwD4N9IAQgAkIZiEITfnwiA0KAgIAQfCIEQhqIfD4CBCAAIAMgBEKAgIDgD4N9PgIACwQAQQALRQECfyMAQRBrIgNBADoADyABBEADQCADIAAgAmotAAAgAy0AD3I6AA8gAkEBaiICIAFHDQALCyADLQAPQQFrQQh2QQFxCwoAIAAgASACECELBABBbwsoACAAIAEgAhAkIABBKGogAUEoaiACECQgAEHQAGogAUHQAGogAhAkCzgAIAAgASACECQgAEEoaiABQShqIAIQJCAAQdAAaiABQdAAaiACECQgAEH4AGogAUH4AGogAhAkC0QBAn8jAEGAAWsiAiQAIAJBCGoiAyABECMgA0EoaiABQShqECMgA0HQAGogAUHQAGoQIyAAIAJBCGoQLSACQYABaiQACzQBAX8CQCABQQFIDQBBASEDA0AgACAAEA4gASADRg0BIANBAWohAwwACwALIAAgACACEAoLXQEBfyMAQZABayICJAAgAkHgAGogAUHQAGoQSiACQTBqIAEgAkHgAGoQCiACIAFBKGogAkHgAGoQCiAAIAIQNiAAIAJBMGoQQUEHdCAALQAfczoAHyACQZABaiQACyYBAX8jAEEgayIBJAAgASAAEDYgAS0AACEAIAFBIGokACAAQQFxC/ACAQV/IwBBgANrIgIkACAAQShqIgQgARA3IABB0ABqIgMQHCACQdACaiAEEA4gAkGgAmogAkHQAmpBAEGAEWoQCiACQdACaiACQdACaiADEBUgAkGgAmogAkGgAmogAxATIAJB8AFqIAJBoAJqEA4gAkHwAWogAkHwAWogAkGgAmoQCiAAIAJB8AFqEA4gACAAIAJBoAJqEAogACAAIAJB0AJqEAogACAAEIQBIAAgACACQfABahAKIAAgACACQdACahAKIAJBwAFqIAAQDiACQcABaiACQcABaiACQaACahAKIAJBkAFqIAJBwAFqIAJB0AJqEBUgAkHgAGogAkHAAWogAkHQAmoQEyACQZABahAvIQMgAkHgAGoQLyEGIAIgACAFQbARahAKIAAgAkEBIANrECQgAkEwaiAAEC4gACACQTBqIAAQQSABLQAfQQd2cxAkIABB+ABqIAAgBBAKIAJBgANqJAAgAyAGckEBawsMACAAIAFBgAgQFxoLnQICA34CfyMAQaACayIGJAACQCACUA0AIAAgACkDICIEIAJCA4Z8NwMgIAJCwAAgBEIDiEI/gyIFfSIEVARAA0AgACADIAV8p2ogASADp2otAAA6ACggA0IBfCIDIAJSDQAMAgsACwNAIAAgAyAFfKdqIAEgA6dqLQAAOgAoIANCAXwiAyAEUg0ACyAAIABBKGogBiAGQYACaiIHEHEgASAEp2ohASACIAR9IgJCP1YEQANAIAAgASAGIAcQcSABQUBrIQEgAkJAfCICQj9WDQALCwJAIAJQDQBBACEHQgEhAwNAIAAgB2ogASAHai0AADoAKCACIANRDQEgA6chByADQgF8IQMMAAsACyAGQaACEAwLIAZBoAJqJABBAAtpAQF/IwBBEGsiAyAANgIMIAMgATYCCEEAIQEgA0EAOgAHIAIEQANAIAMgAy0AByADKAIIIAFqLQAAIAMoAgwgAWotAABzcjoAByABQQFqIgEgAkcNAAsLIAMtAAdBAWtBCHZBAXFBAWsLHgAgAEIANwNAIABCADcDSCAAQdCRAkHAABAXGkEAC1IBAn9B4JsCKAIAIgEgAEEDakF8cSICaiEAAkAgAkEAIAAgAU0bDQAgAD8AQRB0SwRAIAAQBUUNAQtB4JsCIAA2AgAgAQ8LQdSiAkEwNgIAQX8LKgAgBK1CgICAgBAgAkI/fEIGiH1WBEAQGAALIAAgASACIAMgBCAFELUBCwsAIABBAEEoEBYaC+EEAQF/IwBBwAFrIgIkACACQZABaiABEA4gAkHgAGogAkGQAWoQDiACQeAAaiACQeAAahAOIAJB4ABqIAEgAkHgAGoQCiACQZABaiACQZABaiACQeAAahAKIAJBMGogAkGQAWoQDiACQeAAaiACQeAAaiACQTBqEAogAkEwaiACQeAAahAOQQIhAQNAIAJBMGogAkEwahAOIAFBBUZFBEAgAUEBaiEBDAELCyACQeAAaiACQTBqIAJB4ABqEAogAkEwaiACQeAAahAOQQIhAQNAIAJBMGogAkEwahAOIAFBCkZFBEAgAUEBaiEBDAELCyACQTBqIAJBMGogAkHgAGoQCiACIAJBMGoQDkECIQEDQCACIAIQDiABQRRGRQRAIAFBAWohAQwBCwsgAkEwaiACIAJBMGoQCkECIQEDQCACQTBqIAJBMGoQDiABQQtGRQRAIAFBAWohAQwBCwsgAkHgAGogAkEwaiACQeAAahAKIAJBMGogAkHgAGoQDkECIQEDQCACQTBqIAJBMGoQDiABQTJGRQRAIAFBAWohAQwBCwsgAkEwaiACQTBqIAJB4ABqEAogAiACQTBqEA5BAiEBA0AgAiACEA4gAUHkAEZFBEAgAUEBaiEBDAELCyACQTBqIAIgAkEwahAKQQIhAQNAIAJBMGogAkEwahAOIAFBM0ZFBEAgAUEBaiEBDAELCyACQeAAaiACQTBqIAJB4ABqEApBAiEBA0AgAkHgAGogAkHgAGoQDiABQQZGRQRAIAFBAWohAQwBCwsgACACQeAAaiACQZABahAKIAJBwAFqJAALMQEDfwNAIAAgAkEDdCIDaiIEIAQpAwAgASADaikDAIU3AwAgAkEBaiICQYABRw0ACwvoAgECfwJAIAAgAUYNACABIAAgAmoiBGtBACACQQF0a00EQCAAIAEgAhAXDwsgACABc0EDcSEDAkACQCAAIAFJBEAgAwRAIAAhAwwDCyAAQQNxRQRAIAAhAwwCCyAAIQMDQCACRQ0EIAMgAS0AADoAACABQQFqIQEgAkEBayECIANBAWoiA0EDcQ0ACwwBCwJAIAMNACAEQQNxBEADQCACRQ0FIAAgAkEBayICaiIDIAEgAmotAAA6AAAgA0EDcQ0ACwsgAkEDTQ0AA0AgACACQQRrIgJqIAEgAmooAgA2AgAgAkEDSw0ACwsgAkUNAgNAIAAgAkEBayICaiABIAJqLQAAOgAAIAINAAsMAgsgAkEDTQ0AA0AgAyABKAIANgIAIAFBBGohASADQQRqIQMgAkEEayICQQNLDQALCyACRQ0AA0AgAyABLQAAOgAAIANBAWohAyABQQFqIQEgAkEBayICDQALCyAACwQAQQILlQUBFH8CfyADRQRAQbLaiMsHIQRB7siBmQMhBUHl8MGLBiEGQfTKgdkGDAELIAMoAAAhBiADKAAEIQUgAygACCEEIAMoAAwLIQNBFCEPIAIoAAAhCiACKAAEIRAgAigACCESIAIoAAwhCyACKAAQIQwgAigAFCEHIAIoABghDSACKAAcIQ4gASgAACECIAEoAAQhCCABKAAIIQkgASgADCEBA0AgBiAHakEHEAkgC3MiCyAGakEJEAkgCXMiCSALakENEAkgB3MiESAJakESEAkhEyAFIApqQQcQCSABcyIBIAVqQQkQCSANcyINIAFqQQ0QCSAKcyIKIA1qQRIQCSEUIAIgBGpBBxAJIA5zIg4gBGpBCRAJIBBzIgcgDmpBDRAJIAJzIhUgB2pBEhAJIRYgAyAMakEHEAkgEnMiAiADakEJEAkgCHMiCCACakENEAkgDHMiDCAIakESEAkhFyACIAYgE3MiBmpBBxAJIApzIgogBmpBCRAJIAdzIhAgCmpBDRAJIAJzIhIgEGpBEhAJIAZzIQYgBSAUcyIFIAtqQQcQCSAVcyICIAVqQQkQCSAIcyIIIAJqQQ0QCSALcyILIAhqQRIQCSAFcyEFIAQgFnMiBCABakEHEAkgDHMiDCAEakEJEAkgCXMiCSAMakENEAkgAXMiASAJakESEAkgBHMhBCADIBdzIgMgDmpBBxAJIBFzIgcgA2pBCRAJIA1zIg0gB2pBDRAJIA5zIg4gDWpBEhAJIANzIQMgD0ECSyERIA9BAmshDyARDQALIAAgBhAPIABBBGogBRAPIABBCGogBBAPIABBDGogAxAPIABBEGogAhAPIABBFGogCBAPIABBGGogCRAPIABBHGogARAPQQALHAAgAUKAgICAEFoEQBAYAAsgACABIAIgAxC2AQsnACACQoCAgIAQWgRAEBgACyAAIAEgAiADIAQgBUGUnAIoAgAREQALvwMBBn8jAEHgA2siAiQAAn8gASIDLQAfIgZBf3NB/wBxIQRBHiEFA0AgBCADIAVqLQAAQX9zciEEIAVBAWsiByEFIAcNAAsgBEH/AXFBAWtB7AEgAy0AACIDa3FBCHYgAyAGQQd2cnJBf3NBAXELBH8gAkHQAmogARA3IAJBoAJqIAJB0AJqEA4gAkHwAWoQHCACQfABaiACQfABaiACQaACahAVIAJBkAFqIAJB8AFqEA4gAkHAAWoQHCACQcABaiACQcABaiACQaACahATIAJB4ABqIAJBwAFqEA4gAkEwakGAESACQZABahAKIAJBMGogAkEwahAuIAJBMGogAkEwaiACQeAAahAVIAIgAkEwaiACQeAAahAKIAJBgANqEBwgAkGwA2ogAkGAA2ogAhC5ASEDIAAgAkGwA2ogAkHAAWoQCiAAQShqIgEgAkGwA2ogABAKIAEgASACQTBqEAogACAAIAJB0AJqEAogACAAIAAQEyAAIAAQggEgASACQfABaiABEAogAEHQAGoQHCAAQfgAaiIEIAAgARAKQQAgBBBBQQEgA2tyIAEQL3JrBUF/CyEAIAJB4ANqJAAgAAuVEgEefiAAEBAhECAANQACIREgAEEFahAQIRIgADUAByEZIAA1AAohGiAAQQ1qEBAhGyAANQAPIQsgAEESahAQIQogAEEVahAQIQggADUAFyEFIABBGmoQECEBIAA1ABwhHCAANQAfIRMgAEEiahAQIRQgADUAJCEMIABBJ2oQECEPIABBKmoQECEJIAA1ACwhBiAAIABBL2oQEEICiEL///8AgyICQtGrCH4gAUICiEL///8Ag3wgADUAMUIHiEL///8AgyIBQtOMQ358IAA1ADRCBIhC////AIMiA0Ln9id+fCAAQTdqEBBCAYhC////AIMiBEKY2hx+fCAANQA5QgaIQv///wCDIgdCk9gofnwiFSAGQgWIQv///wCDIAA1ADxCA4giBkKDoVZ+IAlC////AIN8Ig1CgIBAfSIOQhWHfCIJQoOhVn58IAJC04xDfiAFQgWIQv///wCDfCABQuf2J358IANCmNocfnwgBEKT2Ch+fCACQuf2J34gCEL///8Ag3wgAUKY2hx+fCADQpPYKH58IgVCgIBAfSIWQhWIfCIIQoCAQH0iF0IVh3wgFUKAgEB9IhVCgICAf4N9IhggGEKAgEB9IhhCgICAf4N9IAlC0asIfiAIfCAXQoCAgH+DfSANIA5CgICAf4N9IAZC0asIfiAPQgOIQv///wCDfCAHQoOhVn58IARCg6FWfiAMQgaIQv///wCDfCAGQtOMQ358IAdC0asIfnwiDEKAgEB9Ig9CFYd8Ig1CgIBAfSIOQhWHfCIIQoOhVn58IAUgAkKY2hx+IApCA4hC////AIN8IAFCk9gofnwgAkKT2Ch+IAtCBohC////AIN8IhdCgIBAfSIdQhWIfCIKQoCAQH0iHkIViHwgFkKAgID///8Hg30gCULTjEN+fCAIQtGrCH58IA0gDkKAgIB/g30iC0KDoVZ+fCIFQoCAQH0iDUIVh3wiDkKAgEB9IhZCFYd8IA4gFkKAgIB/g30gBSANQoCAgH+DfSAKIB5CgICA////B4N9IAlC5/YnfnwgCELTjEN+fCALQtGrCH58IAwgD0KAgIB/g30gA0KDoVZ+IBRCAYhC////AIN8IARC0asIfnwgBkLn9id+fCAHQtOMQ358IAFCg6FWfiATQgSIQv///wCDfCADQtGrCH58IARC04xDfnwgBkKY2hx+fCAHQuf2J358IhNCgIBAfSIUQhWHfCIFQoCAQH0iDEIVh3wiCkKDoVZ+fCAXIB1CgICA////AYN9IAlCmNocfnwgCELn9id+fCALQtOMQ358IApC0asIfnwgBSAMQoCAgH+DfSIFQoOhVn58IgxCgIBAfSIPQhWHfCINQoCAQH0iDkIVh3wgDSAOQoCAgH+DfSAMIA9CgICAf4N9IAlCk9gofiAbQgGIQv///wCDfCAIQpjaHH58IAtC5/YnfnwgCkLTjEN+fCAFQtGrCH58IBMgFEKAgIB/g30gAkKDoVZ+IBxCB4hC////AIN8IAFC0asIfnwgA0LTjEN+fCAEQuf2J358IAZCk9gofnwgB0KY2hx+fCAVQhWHfCIBQoCAQH0iA0IVh3wiAkKDoVZ+fCAIQpPYKH4gGkIEiEL///8Ag3wgC0KY2hx+fCAKQuf2J358IAVC04xDfnwgAkLRqwh+fCIEQoCAQH0iB0IVh3wiBkKAgEB9IglCFYd8IAYgASADQoCAgH+DfSAYQhWHfCIDQoCAQH0iCEIVhyIBQoOhVn58IAlCgICAf4N9IAFC0asIfiAEfCAHQoCAgH+DfSALQpPYKH4gGUIHiEL///8Ag3wgCkKY2hx+fCAFQuf2J358IAJC04xDfnwgCkKT2Ch+IBJCAohC////AIN8IAVCmNocfnwgAkLn9id+fCIEQoCAQH0iB0IVh3wiBkKAgEB9IglCFYd8IAYgAULTjEN+fCAJQoCAgH+DfSABQuf2J34gBHwgB0KAgIB/g30gBUKT2Ch+IBFCBYhC////AIN8IAJCmNocfnwgAkKT2Ch+IBBC////AIN8IgJCgIBAfSIEQhWHfCIHQoCAQH0iBkIVh3wgAUKY2hx+IAd8IAZCgICAf4N9IAIgBEKAgIB/g30gAUKT2Ch+fCIBQhWHfCIEQhWHfCIHQhWHfCIGQhWHfCIJQhWHfCILQhWHfCIKQhWHfCIFQhWHfCIQQhWHfCIRQhWHfCISQhWHIAMgCEKAgIB/g318IghCFYciAkKT2Ch+IAFC////AIN8IgE8AAAgACABQgiIPAABIAAgAkKY2hx+IARC////AIN8IAFCFYd8IgNCC4g8AAQgACADQgOIPAADIAAgAkLn9id+IAdC////AIN8IANCFYd8IgRCBog8AAYgACABQhCIQh+DIANC////AIMiA0IFhoQ8AAIgACACQtOMQ34gBkL///8Ag3wgBEIVh3wiAUIJiDwACSAAIAFCAYg8AAggACAEQv///wCDIgRCAoYgA0ITiIQ8AAUgACACQtGrCH4gCUL///8Ag3wgAUIVh3wiA0IMiDwADCAAIANCBIg8AAsgACABQv///wCDIgdCB4YgBEIOiIQ8AAcgACACQoOhVn4gC0L///8Ag3wgA0IVh3wiAUIHiDwADiAAIANC////AIMiA0IEhiAHQhGIhDwACiAAIApC////AIMgAUIVh3wiAkIKiDwAESAAIAJCAog8ABAgACABQv///wCDIgRCAYYgA0IUiIQ8AA0gACAFQv///wCDIAJCFYd8IgFCDYg8ABQgACABQgWIPAATIAAgAkL///8AgyIDQgaGIARCD4iEPAAPIAAgEEL///8AgyABQhWHfCICPAAVIAAgAUIDhiADQhKIhDwAEiAAIAJCCIg8ABYgACARQv///wCDIAJCFYd8IgFCC4g8ABkgACABQgOIPAAYIAAgEkL///8AgyABQhWHfCIDQgaIPAAbIAAgAkIQiEIfgyABQv///wCDIgFCBYaEPAAXIAAgCEL///8AgyADQhWHfCICQhGIPAAfIAAgAkIJiDwAHiAAIAJCAYg8AB0gACADQv///wCDIgNCAoYgAUITiIQ8ABogACACQgeGIANCDoiEPAAcCwoAIAAgASABEB4LCwAgACABQRAQhgELMgAgAkGAAk8EQEEAIgBBxQpqIABB7glqQesAIABB4whqEAAACyAAIAEgAkH/AXEQigELVQEBf0F/IQQCQCADQQFrQT9LIAJBwABLcg0AAkAgAUEAIAIbRQRAIAAgA0H/AXEQ9QFFDQEMAgsgACADQf8BcSABIAJB/wFxEOQBDQELQQAhBAsgBAu6AQIFfwF+AkAgAlANACAAQeABaiEHIABB4ABqIQUgACgA4AIhAwNAIAAgA2pB4ABqIQZBgAIgA2siBK0iCCACWgRAIAYgASACpyIBEBcaIAAgACgA4AIgAWo2AOACDAILIAYgASAEEBcaIAAgACgA4AIgBGo2AOACIABCgAEQjQEgACAFEJoBIAUgB0GAARAXGiAAIAAoAOACQYABayIDNgDgAiABIARqIQEgAiAIfSICQgBSDQALC0EAC9YBAgV/AX4jAEGgAmsiBSQAIAUhAwJAIAAiAikDICIHp0EDdkE/cSIEQTdNBEAgAiAEakEoakGQmwJBOCAEaxAXGgwBCyACQShqIgYgBGpBkJsCQcAAIARrEBcaIAIgBiADIANBgAJqEHEgBkEAQTgQFhogAikDICEHCyACQeAAaiAHELgCIAIgAkEoaiADIANBgAJqEHFBACEDA0AgASADQQJ0IgRqIAIgBGooAgAQiwIgA0EBaiIDQQhHDQALIAVBoAIQDCAAQegAEAwgBUGgAmokAEEACzkBAX8gAEIANwMgIABB8JgCIgEpAwA3AwAgACABKQMINwMIIAAgASkDEDcDECAAIAEpAxg3AxhBAAsEAEEBCwQAQQML0yUCHX8QfiMAQUBqIg8kAAJAIAgQMSIVRQRAQWohAgwBCyAPQgA3AyAgD0IANwMYIA8gBjYCFCAPIAU2AhAgDyAENgIMIA8gAzYCCCAPIAg2AgQgDyAVNgIAIA9BADYCOCAPIAI2AjQgDyACNgIwIA8gATYCLCAPIAA2AigCQAJ/IAshASMAQTBrIgAkAAJAIA8iAxCHASIGDQBBZiEGIAFBAWtBAUsNACADKAIsIQQgAygCMCECIABBADYCACADKAIoIQUgACACNgIcIABBfzYCDCAAIAU2AgggACACQQN0IgUgBCAEIAVJGyACQQJ0IgRuIgI2AhQgACACQQJ0NgIYIAAgAiAEbDYCECADKAI0IQIgACABNgIkIAAgAjYCICMAQdAAayICJABBZyEFAkAgACIBRSADIgRFcg0AIAEgASgCFEEDdBAxIgU2AgQgBUUEQEFqIQUMAQsCfyABKAIQIQ0jAEEQayIMJABBaiEFAkAgASIGRSANRXINACANQQp0Ig4gDW5BgAhHDQAgBkEMEDEiDTYCACANRQ0AIA1CADcDAEHUogIgDEEMaiAOELECIg02AgACQAJAIA0EQCAMQQA2AgwMAQsgDCgCDCINDQELIAYoAgAQIiAGQQA2AgAMAQsgBigCACANNgIAIAYoAgAgDTYCBCAGKAIAIA42AghBACEFCyAMQRBqJAAgBQsEQCABIAQoAjgQywEMAQsgASgCJCEMIwAiBSENIAVBwANrQUBxIgYkACAERSACIgVFckUEQCAGQUBrQQBBAEHAABBWGiAGQTxqIAQoAjAQDyAGQUBrIAZBPGpCBBAhGiAGQTxqIAQoAgQQDyAGQUBrIAZBPGpCBBAhGiAGQTxqIAQoAiwQDyAGQUBrIAZBPGpCBBAhGiAGQTxqIAQoAigQDyAGQUBrIAZBPGpCBBAhGiAGQTxqQRMQDyAGQUBrIAZBPGpCBBAhGiAGQTxqIAwQDyAGQUBrIAZBPGpCBBAhGiAGQTxqIAQoAgwQDyAGQUBrIAZBPGpCBBAhGgJAIAQoAggiDEUNACAGQUBrIAwgBDUCDBAhGiAELQA4QQFxRQ0AIAQoAgggBCgCDBAMIARBADYCDAsgBkE8aiAEKAIUEA8gBkFAayAGQTxqQgQQIRogBCgCECIMBEAgBkFAayAMIAQ1AhQQIRoLIAZBPGogBCgCHBAPIAZBQGsgBkE8akIEECEaAkAgBCgCGCIMRQ0AIAZBQGsgDCAENQIcECEaIAQtADhBAnFFDQAgBCgCGCAEKAIcEAwgBEEANgIcCyAGQTxqIAQoAiQQDyAGQUBrIAZBPGpCBBAhGiAEKAIgIgwEQCAGQUBrIAwgBDUCJBAhGgsgBkFAayAFQcAAEFUaCyANJAAgAkFAa0EIEAwgAiEEQQAhBSMAQYAIayIGJAAgASgCHARAIARBxABqIQ0gBEFAayEMA0AgDEEAEA8gDSAFEA8gBkGACCAEQcgAEIkBIAEoAgAoAgQgASgCGCAFbEEKdGogBhDKASAMQQEQDyAGQYAIIARByAAQiQEgASgCACgCBCABKAIYIAVsQQp0akGACGogBhDKASAFQQFqIgUgASgCHEkNAAsLIAZBgAgQDCAGQYAIaiQAIAJByAAQDEEAIQULIAJB0ABqJAAgBSIGDQAgACgCCARAA0AgEiEBQQAhF0EAIQIjAEEgayIFJAACQCAAIgRFDQAgBCgCHEUNACAFIAE2AhADQCAFIBc6ABhBACEGQQAhASACRQRAA0AgBUEANgIcIAUgBSkDGDcDCCAFIAY2AhQgBSAFKQMQNwMAIAUhAgJAIAQiAUUNAAJ/AkAgASgCJEECRw0AIAIoAgAiEUUEQCACLQAIQQJJDQELIAEoAgQhG0EBDAELIAEoAgQiGyERIwBBgCBrIg4kACAOQYAYahBpIA5BgBBqEGkCQCABIgxFIAIiDUVyDQAgDiANNQIANwOAECAOIA01AgQ3A4gQIA4gDTEACDcDkBAgDiAMNQIQNwOYECAOIAw1Agg3A6AQIA4gDDUCJDcDqBAgDCgCFEUNAEEAIQ0DQCANQf8AcSIURQRAIA4gDikDsBBCAXw3A7AQIA4QaSAOQYAIahBpIA5BgBhqIA5BgBBqIA4QiAEgDkGAGGogDiAOQYAIahCIAQsgESANQQN0aiAOQYAIaiAUQQN0aikDADcDACANQQFqIg0gDCgCFEkNAAsLIA5BgCBqJAAgAigCACERQQALIRwgESACLQAIIgxyRUEBdCIUIAEoAhQiDU8NAEF/IAEoAhgiDkEBayAUIA4gAigCBGxqIAwgDWxqIhEgDnAbIBFqIQ0DQCARQQFrIA0gESAOcEEBRhshGCABKAIcIQwCfyAcRQRAIAEoAgAhDSAbIBRBA3RqDAELIAEoAgAiDSgCBCAYQQp0agspAwAhLSACIBQ2AgwgDSgCBCIWIA4gLUIgiKcgDHCtIikgKSACNQIEIikgAi0ACBsgAigCACIZGyIqp2xBCnRqAn8gASENIC2nIRogKSAqUSEOAn4gAiIMKAIARQRAIAwtAAgiEEUEQCAMKAIMQQFrIQ5CAAwCCyANKAIUIBBsIRAgDCgCDCEMIA4EQCAMIBBqQQFrIQ5CAAwCCyAQIAxFayEOQgAMAQsgDSgCFCEQIA0oAhghEwJ/IA4EQCAMKAIMIBMgEEF/c2pqDAELIBMgEGsgDCgCDEVrCyEOQgAgDC0ACCIMQQNGDQAaIBAgDEEBamytCyEtIC0gDkEBa618IA6tIBqtIi0gLX5CIIh+QiCIfSANNQIYgqdBCnQLaiEMIBYgGEEKdGohEyAWIBFBCnRqIQ4CQCAZBEAgEyAMIA4QiAEMAQtBACEQIwBBgBBrIg0kACANQYAIaiAMEEMgDUGACGogExBLIA0gDUGACGoQQ0EAIRYDQCANQYAIaiAQQQd0IgxBwAByaiITKQMAIA1BgAhqIAxB4AByaiIZKQMAIA1BgAhqIAxqIhopAwAgDUGACGogDEEgcmoiHSkDACItEAgiKYVBIBAGIioQCCIrIC2FQRgQBiEtIC0gKyAqICkgLRAIIiyFQRAQBiIvEAgiNoVBPxAGIS0gDUGACGogDEHIAHJqIh4pAwAgDUGACGogDEHoAHJqIh8pAwAgDUGACGogDEEIcmoiICkDACANQYAIaiAMQShyaiIhKQMAIikQCCIqhUEgEAYiKxAIIjAgKYVBGBAGISkgKSAwICsgKiApEAgiMIVBEBAGIjcQCCI4hUE/EAYhKSANQYAIaiAMQdAAcmoiIikDACANQYAIaiAMQfAAcmoiIykDACANQYAIaiAMQRByaiIkKQMAIA1BgAhqIAxBMHJqIiUpAwAiKhAIIiuFQSAQBiIxEAgiMiAqhUEYEAYhKiAqIDIgMSArICoQCCIyhUEQEAYiMRAIIjOFQT8QBiEqIA1BgAhqIAxB2AByaiImKQMAIA1BgAhqIAxB+AByaiInKQMAIA1BgAhqIAxBGHJqIigpAwAgDUGACGogDEE4cmoiDCkDACIrEAgiNIVBIBAGIi4QCCI1ICuFQRgQBiErICsgNSAuIDQgKxAIIjSFQRAQBiIuEAgiNYVBPxAGISsgGiAsICkQCCIsICkgMyAsIC6FQSAQBiIsEAgiM4VBGBAGIikQCCIuNwMAICcgLCAuhUEQEAYiLDcDACAiIDMgLBAIIiw3AwAgISApICyFQT8QBjcDACAgIDAgKhAIIikgKiA1ICkgL4VBIBAGIikQCCIshUEYEAYiKhAIIi83AwAgGSApIC+FQRAQBiIpNwMAICYgLCApEAgiKTcDACAlICkgKoVBPxAGNwMAICQgMiArEAgiKSArIDYgKSA3hUEgEAYiKRAIIiqFQRgQBiIrEAgiLDcDACAfICkgLIVBEBAGIik3AwAgEyAqICkQCCIpNwMAIAwgKSArhUE/EAY3AwAgKCA0IC0QCCIpIC0gOCApIDGFQSAQBiIpEAgiKoVBGBAGIi0QCCIrNwMAICMgKSArhUEQEAYiKTcDACAeICogKRAIIik3AwAgHSApIC2FQT8QBjcDACAQQQFqIhBBCEcNAAsDQCAWQQR0IhAgDUGACGpqIgwiEykDgAQgDCkDgAYgDCkDACAMKQOAAiItEAgiKYVBIBAGIioQCCIrIC2FQRgQBiEtIC0gKyAqICkgLRAIIiyFQRAQBiIvEAgiNoVBPxAGIS0gDCkDiAQgDCkDiAYgDUGACGogEEEIcmoiECkDACAMKQOIAiIpEAgiKoVBIBAGIisQCCIwICmFQRgQBiEpICkgMCArICogKRAIIjCFQRAQBiI3EAgiOIVBPxAGISkgDCkDgAUgDCkDgAcgDCkDgAEgDCkDgAMiKhAIIiuFQSAQBiIxEAgiMiAqhUEYEAYhKiAqIDIgMSArICoQCCIyhUEQEAYiMRAIIjOFQT8QBiEqIAwpA4gFIAwpA4gHIAwpA4gBIAwpA4gDIisQCCI0hUEgEAYiLhAIIjUgK4VBGBAGISsgKyA1IC4gNCArEAgiNIVBEBAGIi4QCCI1hUE/EAYhKyAMICwgKRAIIiwgKSAzICwgLoVBIBAGIiwQCCIzhUEYEAYiKRAIIi43AwAgDCAsIC6FQRAQBiIsNwOIByAMIDMgLBAIIiw3A4AFIAwgKSAshUE/EAY3A4gCIBAgMCAqEAgiKSAqIDUgKSAvhUEgEAYiKRAIIiyFQRgQBiIqEAgiLzcDACAMICkgL4VBEBAGIik3A4AGIAwgLCApEAgiKTcDiAUgDCApICqFQT8QBjcDgAMgDCAyICsQCCIpICsgNiApIDeFQSAQBiIpEAgiKoVBGBAGIisQCCIsNwOAASAMICkgLIVBEBAGIik3A4gGIBMgKiApEAgiKTcDgAQgDCApICuFQT8QBjcDiAMgDCA0IC0QCCIpIC0gOCApIDGFQSAQBiIpEAgiKoVBGBAGIi0QCCIrNwOIASAMICkgK4VBEBAGIik3A4AHIAwgKiApEAgiKTcDiAQgDCApIC2FQT8QBjcDgAIgFkEBaiIWQQhHDQALIA4gDRBDIA4gDUGACGoQSyANQYAQaiQACyAUQQFqIhQgASgCFE8NASARQQFqIREgGEEBaiENIAEoAhghDgwACwALIAZBAWoiBiAEKAIcIgFJDQALCyAXQQFqIhdBBEYNASABRSECDAALAAsgBUEgaiQAIBJBAWoiEiAAKAIISQ0ACwtBACEFIwBBgBBrIgEkACADRSAAIgJFckUEQCABQYAIaiACKAIAKAIEIAIoAhhBCnRqQYAIaxBDIAIoAhxBAk8EQEEBIRIDQCABQYAIaiACKAIAKAIEIAIoAhgiBCAEIBJsakEKdGpBgAhrEEsgEkEBaiISIAIoAhxJDQALCyABIgRBgAhqIQYDQCAEIAVBA3QiEmogBiASaikDABAZIAVBAWoiBUGAAUcNAAsgAygCACADKAIEIAFBgAgQiQEgAUGACGpBgAgQDCABQYAIEAwgAiADKAI4EMsBCyABQYAQaiQAQQAhBgsgAEEwaiQAIAYiAgsEQCAVIAgQDAwBCwJAIAlFIApFcg0AAn8gCSEBIAohAiAPIQAjAEEQayIDJABBYSEEAkACQAJ/AkACQCALQQFrDgIBAAQLIAJBDUkNAiABQYULKQAANwAAIAFBigspAAA3AAUgAkEMayECIAFBDGoMAQsgAkEMSQ0BIAFB+QopAAA3AAAgAUGBCygAADYACCACQQtrIQIgAUELagshBSAAEIcBIgQNASADQQVqQRMQdSACIANBBWoQKyIBTQ0AIAUgA0EFaiABQQFqEBchBCACIAFrIgJBBEkNACABIARqIgRBpNr1ATYAACADQQVqIAAoAiwQdSACQQNrIgIgA0EFahArIgFNDQAgBEEDaiADQQVqIAFBAWoQFyEEIAIgAWsiAkEESQ0AIAEgBGoiBEGs6PUBNgAAIANBBWogACgCKBB1IAJBA2siAiADQQVqECsiAU0NACAEQQNqIANBBWogAUEBahAXIQQgAiABayICQQRJDQAgASAEaiIEQazg9QE2AAAgA0EFaiAAKAIwEHUgAkEDayICIANBBWoQKyIBTQ0AIARBA2ogA0EFaiABQQFqEBchBCACIAFrIgJBAkkNACABIARqIgFBJDsAACABQQFqIgEgAkEBayICIAAoAhAgACgCFEEDEK4BRQ0AQWEhBCACIAEQKyICayIFQQJJDQEgASACaiIBQSQ7AAAgAUEBaiAFQQFrIAAoAgAgACgCBEEDEK4BIQAgA0EQaiQAQQBBYSAAGwwCC0FhIQQLIANBEGokACAEC0UNACAVIAgQDCAJIAoQDEFhIQIMAQsgBwRAIAcgFSAIEBcaCyAVIAgQDEEAIQILIBUQIgsgD0FAayQAIAIL8QEBA38CfwJAIAEiBEH/AXEiAwRAIABBA3EEQANAIAAtAAAiAkUgAiAEQf8BcUZyDQMgAEEBaiIAQQNxDQALCwJAIAAoAgAiAkF/cyACQYGChAhrcUGAgYKEeHENACADQYGChAhsIQMDQCACIANzIgJBf3MgAkGBgoQIa3FBgIGChHhxDQEgACgCBCECIABBBGohACACQYGChAhrIAJBf3NxQYCBgoR4cUUNAAsLA0AgACICLQAAIgMEQCACQQFqIQAgAyAEQf8BcUcNAQsLIAIMAgsgABArIABqDAELIAALIgBBACAALQAAIAFB/wFxRhsLLQEBfyMAQdABayIDJAAgAxBGGiADIAEgAhAlGiADIAAQMhogA0HQAWokAEEACyMAIAFCgICAgBBaBEAQGAALIAAgASACIANBjJwCKAIAEQwACxEAIAAgASACIANBCBC4AUEACxEAIAAgASACIANBDBC4AUEACxEAIAAgASACIANBFBC4AUEAC+QDAQZ/IwBB4AZrIgIkACACQdACaiABQdAAaiIFIAFBKGoiBBATIAIgBSAEEBUgAkHQAmogAkHQAmogAhAKIAJBoAJqIAEgBBAKIAJB8AFqIAJBoAJqEA4gAkHwAWogAkHQAmogAkHwAWoQCiACQeADahAcIAJB8ARqIAJB4ANqIAJB8AFqELkBGiACQbAGaiACQfAEaiACQdACahAKIAJBgAZqIAJB8ARqIAJBoAJqEAogAkEwaiACQbAGaiACQYAGahAKIAJBMGogAkEwaiABQfgAaiIDEAogAkHABGogAUEAQbARaiIHEAogAkGQBGogBCAHEAogAkGgBWogAkGwBmogBkHQG2oQCiACQYADaiADIAJBMGoQCiACQYADahBBIQMgAkHAAWogARAjIAJBkAFqIAQQIyACQdAFaiACQYAGahAjIAJBwAFqIAJBkARqIAMQJCACQZABaiACQcAEaiADECQgAkHQBWogAkGgBWogAxAkIAJB4ABqIAJBwAFqIAJBMGoQCiACQZABaiACQZABaiACQeAAahBBEMkCIAJBsANqIAUgAkGQAWoQFSACQbADaiACQdAFaiACQbADahAKIAJBsANqIAJBsANqEIIBIAAgAkGwA2oQNiACQeAGaiQAC9oBAQV/IwBBEGsiA0EANgALIANBADYCCANAIAAgAmotAAAhBEEAIQEDQCADQQhqIAFqIgUgBS0AACABQQV0QdAZaiACai0AACAEc3I6AAAgAUEBaiIBQQdHDQALIAJBAWoiAkEfRw0ACyAALQAfQf8AcSECQQAhAEEAIQEDQCADQQhqIAFqIgQgBC0AACACIAFBBXRB7xlqLQAAc3I6AAAgAUEBaiIBQQdHDQALQQAhAQNAIANBCGogAGotAABBAWsgAXIhASAAQQFqIgBBB0cNAAsgAUEIdkEBcQusAQEBfyMAQaACayIBJAAgAUHwAWogABAOIAFBwAFqIABBKGoQDiABQZABaiAAQdAAahAOIAFBMGogAUHAAWogAUHwAWoQFSABQTBqIAFBMGogAUGQAWoQCiABIAFB8AFqIAFBwAFqEAogASABQYAREAogAUHgAGogAUGQAWoQDiABIAEgAUHgAGoQEyABQTBqIAFBMGogARAVIAFBMGoQLyEAIAFBoAJqJAAgAAumAwEFfyMAQdADayICJAADQCADQQF0IgUgAkGQA2pqIAEgA2otAAAiBkEPcToAACACQZADaiAFQQFyaiAGQQR2OgAAIANBAWoiA0EgRw0AC0EAIQMDQCACQZADaiAEaiIBIAEtAAAgA2oiASABQRh0QYCAgEBrIgFBGHVB8AFxazoAACABQRx1IQMgBEEBaiIEQT9HDQALIAIgAi0AzwMgA2o6AM8DIAAQvAFBASEDA0AgAiADQQF2IAJBkANqIANqLAAAEM4CIAJB8AFqIAAgAhC+ASAAIAJB8AFqEBQgA0E+SSEBIANBAmohAyABDQALIAJB8AFqIAAQPiACQfgAaiACQfABahA0IAJB8AFqIAJB+ABqEC0gAkH4AGogAkHwAWoQNCACQfABaiACQfgAahAtIAJB+ABqIAJB8AFqEDQgAkHwAWogAkH4AGoQLSAAIAJB8AFqEBRBACEDA0AgAiADQQF2IAJBkANqIANqLAAAEM4CIAJB8AFqIAAgAhC+ASAAIAJB8AFqEBQgA0E+SSEBIANBAmohAyABDQALIAJB0ANqJAALFAAgACABIAIgA0HsmwIoAgARDQALCwAgACABQSAQhgELDAAgAEEAQYAIEBYaC6YBAQJ/IAFBAWtBP0sgBUHAAEtyBH9BfwUCfyMAIgYhByAGQYADa0FAcSIGJABBASACIANQG0UgAEUgAUH/AXEiAUEBa0H/AXFBwABPcnIgBEEBIAVB/wFxIgUbRSAFQcEAT3JyRQRAAkAgBQRAIAYgASAEIAUQ5AEaDAELIAYgARD1ARoLIAYgAiADEFcaIAYgACABEIoBGiAHJABBAAwBCxAYAAsLCwkAIABBADYAAAtFAQN/IABBwBBBwAAQF0FAa0EAQaUCEBYaA0AgACACQQN0IgNqIgQgASADaikAACAEKQAAhTcAACACQQFqIgJBCEcNAAsLKAECfwNAIAAgAkECdCIDaiABIANqKAIANgIAIAJBAWoiAkEQRw0ACwt8AQN/IAIgA0EHdCAAakFAahBtIANBAXQiBARAIANBBHQhBUEAIQMDQCACIAAgA0EGdCIGahCEAiACEIMCIAEgA0EFdGogAhBtIAIgACAGQcAAcmoQhAIgAhCDAiABIANBA3QgBWpBAnRqIAIQbSADQQJqIgMgBEkNAAsLCw0AIAAgASACEEQaQQALBQBB0AEL1RcBGX8gAiEMA0AgDCAEQQJ0IgZqIAEgBmooAAAiBkEYdCAGQQh0QYCA/AdxciAGQQh2QYD+A3EgBkEYdnJyNgIAIARBAWoiBEEQRw0ACyADIAApAhg3AhggAyAAKQIQNwIQIAMgACkCCDcCCCADIAApAgA3AgADQCADIAIgFEECdCIBaiIMKAIAIAMoAhAiC0EGEAcgC0ELEAdzIAtBGRAHc2ogAUGQmQJqKAIAaiALIAMoAhgiBCADKAIUIgdzcSAEc2ogAygCHGoiBiADKAIMaiIINgIMIAMgAygCACIJQQIQByAJQQ0QB3MgCUEWEAdzIAZqIAMoAggiCiADKAIEIgVyIAlxIAUgCnFyaiIGNgIcIAMgCiAEIAcgCCAHIAtzcXNqIAhBBhAHIAhBCxAHcyAIQRkQB3NqIAIgAUEEciIEaiIRKAIAaiAEQZCZAmooAgBqIgRqIgo2AgggAyAEIAYgBSAJcnEgBSAJcXJqIAZBAhAHIAZBDRAHcyAGQRYQB3NqIgQ2AhggAyAFIAcgCyAKIAggC3Nxc2ogCkEGEAcgCkELEAdzIApBGRAHc2ogAiABQQhyIgdqIhMoAgBqIAdBkJkCaigCAGoiDWoiBzYCBCADIA0gBCAGIAlycSAGIAlxcmogBEECEAcgBEENEAdzIARBFhAHc2oiBTYCFCADIAkgCyAHIAggCnNxIAhzaiAHQQYQByAHQQsQB3MgB0EZEAdzaiACIAFBDHIiC2oiDSgCAGogC0GQmQJqKAIAaiIOaiILNgIAIAMgDiAFIAQgBnJxIAQgBnFyaiAFQQIQByAFQQ0QB3MgBUEWEAdzaiIJNgIQIAMgBiALIAcgCnNxIApzIAhqIAtBBhAHIAtBCxAHcyALQRkQB3NqIAIgAUEQciIIaiIOKAIAaiAIQZCZAmooAgBqIg9qIgg2AhwgAyAPIAkgBCAFcnEgBCAFcXJqIAlBAhAHIAlBDRAHcyAJQRYQB3NqIgY2AgwgAyAEIAggByALc3EgB3MgCmogCEEGEAcgCEELEAdzIAhBGRAHc2ogAiABQRRyIgpqIg8oAgBqIApBkJkCaigCAGoiEGoiCjYCGCADIBAgBiAFIAlycSAFIAlxcmogBkECEAcgBkENEAdzIAZBFhAHc2oiBDYCCCADIAUgCiAIIAtzcSALcyAHaiAKQQYQByAKQQsQB3MgCkEZEAdzaiACIAFBGHIiB2oiECgCAGogB0GQmQJqKAIAaiISaiIHNgIUIAMgEiAEIAYgCXJxIAYgCXFyaiAEQQIQByAEQQ0QB3MgBEEWEAdzaiIFNgIEIAMgCSAHIAggCnNxIAhzIAtqIAdBBhAHIAdBCxAHcyAHQRkQB3NqIAIgAUEcciILaiISKAIAaiALQZCZAmooAgBqIhVqIgs2AhAgAyAVIAUgBCAGcnEgBCAGcXJqIAVBAhAHIAVBDRAHcyAFQRYQB3NqIgk2AgAgAyAGIAsgByAKc3EgCnMgCGogC0EGEAcgC0ELEAdzIAtBGRAHc2ogAiABQSByIghqIhUoAgBqIAhBkJkCaigCAGoiFmoiCDYCDCADIBYgCSAEIAVycSAEIAVxcmogCUECEAcgCUENEAdzIAlBFhAHc2oiBjYCHCADIAQgCCAHIAtzcSAHcyAKaiAIQQYQByAIQQsQB3MgCEEZEAdzaiACIAFBJHIiCmoiFigCAGogCkGQmQJqKAIAaiIXaiIKNgIIIAMgFyAGIAUgCXJxIAUgCXFyaiAGQQIQByAGQQ0QB3MgBkEWEAdzaiIENgIYIAMgBSAKIAggC3NxIAtzIAdqIApBBhAHIApBCxAHcyAKQRkQB3NqIAIgAUEociIHaiIXKAIAaiAHQZCZAmooAgBqIhhqIgc2AgQgAyAYIAQgBiAJcnEgBiAJcXJqIARBAhAHIARBDRAHcyAEQRYQB3NqIgU2AhQgAyAJIAcgCCAKc3EgCHMgC2ogB0EGEAcgB0ELEAdzIAdBGRAHc2ogAiABQSxyIgtqIhgoAgBqIAtBkJkCaigCAGoiGWoiCzYCACADIBkgBSAEIAZycSAEIAZxcmogBUECEAcgBUENEAdzIAVBFhAHc2oiCTYCECADIAYgCyAHIApzcSAKcyAIaiALQQYQByALQQsQB3MgC0EZEAdzaiACIAFBMHIiCGoiGSgCAGogCEGQmQJqKAIAaiIaaiIINgIcIAMgGiAJIAQgBXJxIAQgBXFyaiAJQQIQByAJQQ0QB3MgCUEWEAdzaiIGNgIMIAMgBCAIIAcgC3NxIAdzIApqIAhBBhAHIAhBCxAHcyAIQRkQB3NqIAIgAUE0ciIKaiIaKAIAaiAKQZCZAmooAgBqIhtqIgo2AhggAyAbIAYgBSAJcnEgBSAJcXJqIAZBAhAHIAZBDRAHcyAGQRYQB3NqIgQ2AgggAyAFIAogCCALc3EgC3MgB2ogCkEGEAcgCkELEAdzIApBGRAHc2ogAiABQThyIgdqIhsoAgBqIAdBkJkCaigCAGoiB2oiBTYCFCADIAcgBCAGIAlycSAGIAlxcmogBEECEAcgBEENEAdzIARBFhAHc2oiBzYCBCADIAkgBSAIIApzcSAIcyALaiAFQQYQByAFQQsQB3MgBUEZEAdzaiACIAFBPHIiAWoiCCgCAGogAUGQmQJqKAIAaiIBajYCECADIAEgByAEIAZycSAEIAZxcmogB0ECEAcgB0ENEAdzIAdBFhAHc2o2AgAgFEEwRgRAA0AgACAcQQJ0IgFqIgIgAigCACABIANqKAIAajYCACAcQQFqIhxBCEcNAAsFIAIgFEEQaiIUQQJ0aiAbKAIAIgFBCnYgAUEREAdzIAFBExAHcyAWKAIAIgVqIAwoAgBqIBEoAgAiBEEDdiAEQQcQB3MgBEESEAdzaiIGNgIAIAwgBCAXKAIAIglqIAgoAgAiBEEKdiAEQREQB3MgBEETEAdzaiATKAIAIgdBA3YgB0EHEAdzIAdBEhAHc2oiCDYCRCAMIAcgGCgCACIKaiAGQREQByAGQQp2cyAGQRMQB3NqIA0oAgAiEUEDdiARQQcQB3MgEUESEAdzaiIHNgJIIAwgESAZKAIAIgtqIAhBERAHIAhBCnZzIAhBExAHc2ogDigCACINQQN2IA1BBxAHcyANQRIQB3NqIhE2AkwgDCANIBooAgAiE2ogB0EREAcgB0EKdnMgB0ETEAdzaiAPKAIAIg5BA3YgDkEHEAdzIA5BEhAHc2oiDTYCUCAMIAEgDmogEUEREAcgEUEKdnMgEUETEAdzaiAQKAIAIg9BA3YgD0EHEAdzIA9BEhAHc2oiDjYCVCAMIAQgD2ogDUEREAcgDUEKdnMgDUETEAdzaiASKAIAIhBBA3YgEEEHEAdzIBBBEhAHc2oiDzYCWCAMIAYgEGogDkEREAcgDkEKdnMgDkETEAdzaiAVKAIAIhJBA3YgEkEHEAdzIBJBEhAHc2oiEDYCXCAMIAggEmogD0EREAcgD0EKdnMgD0ETEAdzaiAFQQcQByAFQQN2cyAFQRIQB3NqIgg2AmAgDCAFIAdqIBBBERAHIBBBCnZzIBBBExAHc2ogCUEHEAcgCUEDdnMgCUESEAdzaiIFNgJkIAwgCSARaiAIQREQByAIQQp2cyAIQRMQB3NqIApBBxAHIApBA3ZzIApBEhAHc2oiCTYCaCAMIAogDWogBUEREAcgBUEKdnMgBUETEAdzaiALQQcQByALQQN2cyALQRIQB3NqIgU2AmwgDCALIA5qIAlBERAHIAlBCnZzIAlBExAHc2ogE0EHEAcgE0EDdnMgE0ESEAdzaiIJNgJwIAwgDyATaiAFQREQByAFQQp2cyAFQRMQB3NqIAFBBxAHIAFBA3ZzIAFBEhAHc2oiBTYCdCAMIAEgEGogCUEREAcgCUEKdnMgCUETEAdzaiAEQQcQByAEQQN2cyAEQRIQB3NqNgJ4IAwgBCAIaiAFQREQByAFQQp2cyAFQRMQB3NqIAZBBxAHIAZBA3ZzIAZBEhAHc2o2AnwMAQsLCz0BAn8jACIEQYADa0FAcSIDJAAgA0EAQQBBGBB0GiADIAFCIBA6GiADIAJCIBA6GiADIABBGBBzGiAEJAALCgAgACABIAIQVQsMACAAIAEgAiADEFYLZgEFfyMAQRBrIgMkAEEKIQIDQAJAIAIiBEEBayICIANBBmpqIgUgASABQQpuIgZBCmxrQTByOgAAIAFBCkkNACAGIQEgAg0BCwsgACAFQQsgBGsiABAXIABqQQA6AAAgA0EQaiQAC40BAQZ/AkAgAC0AACIGQTBrQf8BcUEJSw0AIAYhAyAAIQIDQCACIQcgBEGZs+bMAUsNASADQf8BcUEwayICIARBCmwiA0F/c0sNASACIANqIQQgB0EBaiICLQAAIgNBMGtB/wFxQQpJDQALIAAgAkYgBkEwRkEAIAAgB0cbcg0AIAEgBDYCACACIQULIAULNQECfyMAQSBrIgMkAEF/IQQgAyACIAEQgAFFBEAgAEGQmAIgA0EAEE4hBAsgA0EgaiQAIAQLDgAgAUEgECcgACABEH8LjRgCEH4SfyACIRUDQCAVIBRBA3QiFmogASAWaikAACIEQjiGIARCKIZCgICAgICAwP8Ag4QgBEIYhkKAgICAgOA/gyAEQgiGQoCAgIDwH4OEhCAEQgiIQoCAgPgPgyAEQhiIQoCA/AeDhCAEQiiIQoD+A4MgBEI4iISEhDcDACAUQQFqIhRBEEcNAAsgAyAAQcAAEBchAQNAIAEgAiAXQQN0IgNqIhUpAwAgASkDICIKQQ4QBiAKQRIQBoUgCkEpEAaFfCADQZCSAmopAwB8IAogASkDMCIHIAEpAygiC4WDIAeFfCABKQM4fCIEIAEpAxh8Igg3AxggASABKQMAIgVBHBAGIAVBIhAGhSAFQScQBoUgBHwgASkDECIJIAEpAwgiBoQgBYMgBiAJg4R8IgQ3AzggASAJIAcgCyAIIAogC4WDhXwgCEEOEAYgCEESEAaFIAhBKRAGhXwgAiADQQhyIhRqIhYpAwB8IBRBkJICaikDAHwiB3wiCTcDECABIAcgBCAFIAaEgyAFIAaDhHwgBEEcEAYgBEEiEAaFIARBJxAGhXwiBzcDMCABIAYgCyAKIAkgCCAKhYOFfCAJQQ4QBiAJQRIQBoUgCUEpEAaFfCACIANBEHIiFGoiGSkDAHwgFEGQkgJqKQMAfCIMfCILNwMIIAEgDCAHIAQgBYSDIAQgBYOEfCAHQRwQBiAHQSIQBoUgB0EnEAaFfCIGNwMoIAEgBSAKIAsgCCAJhYMgCIV8IAtBDhAGIAtBEhAGhSALQSkQBoV8IAIgA0EYciIUaiIaKQMAfCAUQZCSAmopAwB8Igx8Igo3AwAgASAMIAYgBCAHhIMgBCAHg4R8IAZBHBAGIAZBIhAGhSAGQScQBoV8IgU3AyAgASAEIAogCSALhYMgCYUgCHwgCkEOEAYgCkESEAaFIApBKRAGhXwgAiADQSByIhRqIhspAwB8IBRBkJICaikDAHwiDHwiCDcDOCABIAwgBSAGIAeEgyAGIAeDhHwgBUEcEAYgBUEiEAaFIAVBJxAGhXwiBDcDGCABIAcgCCAKIAuFgyALhSAJfCAIQQ4QBiAIQRIQBoUgCEEpEAaFfCACIANBKHIiFGoiHCkDAHwgFEGQkgJqKQMAfCIMfCIJNwMwIAEgDCAEIAUgBoSDIAUgBoOEfCAEQRwQBiAEQSIQBoUgBEEnEAaFfCIHNwMQIAEgBiAJIAggCoWDIAqFIAt8IAlBDhAGIAlBEhAGhSAJQSkQBoV8IAIgA0EwciIUaiIdKQMAfCAUQZCSAmopAwB8Igx8Igs3AyggASAMIAcgBCAFhIMgBCAFg4R8IAdBHBAGIAdBIhAGhSAHQScQBoV8IgY3AwggASAFIAsgCCAJhYMgCIUgCnwgC0EOEAYgC0ESEAaFIAtBKRAGhXwgAiADQThyIhRqIh4pAwB8IBRBkJICaikDAHwiDHwiCjcDICABIAwgBiAEIAeEgyAEIAeDhHwgBkEcEAYgBkEiEAaFIAZBJxAGhXwiBTcDACABIAQgCiAJIAuFgyAJhSAIfCAKQQ4QBiAKQRIQBoUgCkEpEAaFfCACIANBwAByIhRqIh8pAwB8IBRBkJICaikDAHwiDHwiCDcDGCABIAwgBSAGIAeEgyAGIAeDhHwgBUEcEAYgBUEiEAaFIAVBJxAGhXwiBDcDOCABIAcgCCAKIAuFgyALhSAJfCAIQQ4QBiAIQRIQBoUgCEEpEAaFfCACIANByAByIhRqIiApAwB8IBRBkJICaikDAHwiDHwiCTcDECABIAwgBCAFIAaEgyAFIAaDhHwgBEEcEAYgBEEiEAaFIARBJxAGhXwiBzcDMCABIAYgCSAIIAqFgyAKhSALfCAJQQ4QBiAJQRIQBoUgCUEpEAaFfCACIANB0AByIhRqIiEpAwB8IBRBkJICaikDAHwiDHwiCzcDCCABIAwgByAEIAWEgyAEIAWDhHwgB0EcEAYgB0EiEAaFIAdBJxAGhXwiBjcDKCABIAUgCyAIIAmFgyAIhSAKfCALQQ4QBiALQRIQBoUgC0EpEAaFfCACIANB2AByIhRqIiIpAwB8IBRBkJICaikDAHwiDHwiCjcDACABIAwgBiAEIAeEgyAEIAeDhHwgBkEcEAYgBkEiEAaFIAZBJxAGhXwiBTcDICABIAQgCiAJIAuFgyAJhSAIfCAKQQ4QBiAKQRIQBoUgCkEpEAaFfCACIANB4AByIhRqIiMpAwB8IBRBkJICaikDAHwiDHwiCDcDOCABIAwgBSAGIAeEgyAGIAeDhHwgBUEcEAYgBUEiEAaFIAVBJxAGhXwiBDcDGCABIAcgCCAKIAuFgyALhSAJfCAIQQ4QBiAIQRIQBoUgCEEpEAaFfCACIANB6AByIhRqIiQpAwB8IBRBkJICaikDAHwiDHwiCTcDMCABIAwgBCAFIAaEgyAFIAaDhHwgBEEcEAYgBEEiEAaFIARBJxAGhXwiBzcDECABIAkgCCAKhYMgCoUgC3wgCUEOEAYgCUESEAaFIAlBKRAGhXwgAiADQfAAciIUaiIlKQMAfCAUQZCSAmopAwB8IgsgBnwiBjcDKCABIAsgByAEIAWEgyAEIAWDhHwgB0EcEAYgB0EiEAaFIAdBJxAGhXwiCzcDCCABIAYgCCAJhYMgCIUgCnwgBkEOEAYgBkESEAaFIAZBKRAGhXwgAiADQfgAciIDaiIUKQMAfCADQZCSAmopAwB8IgYgBXw3AyAgASAGIAsgBCAHhIMgBCAHg4R8IAtBHBAGIAtBIhAGhSALQScQBoV8NwMAIBdBwABGBEADQCAAIBhBA3QiAmoiAyADKQMAIAEgAmopAwB8NwMAIBhBAWoiGEEIRw0ACwUgAiAXQRBqIhdBA3RqICUpAwAiBEIGiCAEQRMQBoUgBEE9EAaFICApAwAiBXwgFSkDAHwgFikDACIGQgeIIAZBARAGhSAGQQgQBoV8Igc3AwAgFSAGICEpAwAiCHwgFCkDACIGQgaIIAZBExAGhSAGQT0QBoV8IBkpAwAiCkIHiCAKQQEQBoUgCkEIEAaFfCIJNwOIASAVIAogIikDACILfCAHQRMQBiAHQgaIhSAHQT0QBoV8IBopAwAiDUIHiCANQQEQBoUgDUEIEAaFfCIKNwOQASAVIA0gIykDACIMfCAJQRMQBiAJQgaIhSAJQT0QBoV8IBspAwAiDkIHiCAOQQEQBoUgDkEIEAaFfCINNwOYASAVIA4gJCkDACISfCAKQRMQBiAKQgaIhSAKQT0QBoV8IBwpAwAiD0IHiCAPQQEQBoUgD0EIEAaFfCIONwOgASAVIAQgD3wgDUETEAYgDUIGiIUgDUE9EAaFfCAdKQMAIhBCB4ggEEEBEAaFIBBBCBAGhXwiDzcDqAEgFSAGIBB8IA5BExAGIA5CBoiFIA5BPRAGhXwgHikDACIRQgeIIBFBARAGhSARQQgQBoV8IhA3A7ABIBUgByARfCAPQRMQBiAPQgaIhSAPQT0QBoV8IB8pAwAiE0IHiCATQQEQBoUgE0EIEAaFfCIRNwO4ASAVIAkgE3wgEEETEAYgEEIGiIUgEEE9EAaFfCAFQQEQBiAFQgeIhSAFQQgQBoV8Igk3A8ABIBUgBSAKfCARQRMQBiARQgaIhSARQT0QBoV8IAhBARAGIAhCB4iFIAhBCBAGhXwiBTcDyAEgFSAIIA18IAlBExAGIAlCBoiFIAlBPRAGhXwgC0EBEAYgC0IHiIUgC0EIEAaFfCIINwPQASAVIAsgDnwgBUETEAYgBUIGiIUgBUE9EAaFfCAMQQEQBiAMQgeIhSAMQQgQBoV8IgU3A9gBIBUgDCAPfCAIQRMQBiAIQgaIhSAIQT0QBoV8IBJBARAGIBJCB4iFIBJBCBAGhXwiCDcD4AEgFSAQIBJ8IAVBExAGIAVCBoiFIAVBPRAGhXwgBEEBEAYgBEIHiIUgBEEIEAaFfCIFNwPoASAVIAQgEXwgCEETEAYgCEIGiIUgCEE9EAaFfCAGQQEQBiAGQgeIhSAGQQgQBoV8NwPwASAVIAYgCXwgBUETEAYgBUIGiIUgBUE9EAaFfCAHQQEQBiAHQgeIhSAHQQgQBoV8NwP4AQwBCwsLJwAgAkKAgICAEFoEQBAYAAsgACABIAIgA0IAIARBlJwCKAIAEREAC9kJATF/IwBBQGoiHSQAIAAoAjwhHiAAKAI4IR8gACgCNCETIAAoAjAhECAAKAIsISAgACgCKCEhIAAoAiQhIiAAKAIgISMgACgCHCEkIAAoAhghJSAAKAIUISYgACgCECEnIAAoAgwhKCAAKAIIISkgACgCBCEqIAAoAgAhKwNAAkAgA0I/VgRAIAIhBQwBC0EAIQQgHUEAQcAAEBYiGCEFIANQRQRAA0AgBCAYaiABIARqLQAAOgAAIAMgBEEBaiIErVYNAAsLIAUhASACIRgLQRIhFCArIQwgKiEVICkhESAoIQ0gJyEEICYhDiAlIQIgJCEPICMhCiAiIQkgISEZIB4hEiAfIQcgEyEIIBAhBiAgIQsDQCAEIAogBCAMaiIMIAZzQRAQCSIEaiIGc0EMEAkhCiAKIAQgCiAMaiIMc0EIEAkiGiAGaiIbc0EHEAkhFiAJIA4gFWoiCiAIc0EQEAkiCGoiBiAOc0EMEAkhCSAJIAggCSAKaiIVc0EIEAkiCiAGaiIcc0EHEAkhDiACIAcgAiARaiIHc0EQEAkiCCAZaiIGc0EMEAkhAiACIAggAiAHaiIJc0EIEAkiBCAGaiIHc0EHEAkhFyALIA0gD2oiBiASc0EQEAkiAmoiCyAPc0EMEAkhEiASIAsgAiAGIBJqIg1zQQgQCSICaiIIc0EHEAkhESAOIAIgDCAOaiIGc0EQEAkiCyAHaiICc0EMEAkhByAHIAsgBiAHaiIMc0EIEAkiEiACaiIZc0EHEAkhDiAXIBogFSAXaiIGc0EQEAkiCyAIaiICc0EMEAkhCCAIIAsgBiAIaiIVc0EIEAkiBiACaiILc0EHEAkhAiARIAogCSARaiIJc0EQEAkiCCAbaiIHc0EMEAkhDyAPIAcgCCAJIA9qIhFzQQgQCSIIaiIKc0EHEAkhDyAWIAQgDSAWaiINc0EQEAkiByAcaiIJc0EMEAkhBCAEIAkgByAEIA1qIg1zQQgQCSIHaiIJc0EHEAkhBCAUBEAgFEECayEUDAELCyABKAAEISwgASgACCEtIAEoAAwhLiABKAAQIS8gASgAFCEwIAEoABghMSABKAAcITIgASgAICEzIAEoACQhNCABKAAoIRQgASgALCEWIAEoADAhFyABKAA0IRogASgAOCEbIAEoADwhHCAFIAEoAAAgDCAranMQDyAFQQRqICwgFSAqanMQDyAFQQhqIC0gESApanMQDyAFQQxqIC4gDSAoanMQDyAFQRBqIC8gBCAnanMQDyAFQRRqIDAgDiAmanMQDyAFQRhqIDEgAiAlanMQDyAFQRxqIDIgDyAkanMQDyAFQSBqIDMgCiAjanMQDyAFQSRqIDQgCSAianMQDyAFQShqIBQgGSAhanMQDyAFQSxqIBYgCyAganMQDyAFQTBqIBcgBiAQanMQDyAFQTRqIBogCCATanMQDyAFQThqIBsgByAfanMQDyAFQTxqIBwgEiAeanMQDyATIBAgEEEBaiIQS2ohEyADQsAAWARAAkAgA0I/Vg0AIAOnIgFFDQBBACEEA0AgBCAYaiAEIAVqLQAAOgAAIARBAWoiBCABRw0ACwsgACATNgI0IAAgEDYCMCAdQUBrJAAFIAFBQGshASAFQUBrIQIgA0JAfCEDDAELCwtxACAAQuXwwYvmjZmQMzcCACAAQrLaiMvHrpmQ6wA3AgggACABKAAANgIQIAAgASgABDYCFCAAIAEoAAg2AhggACABKAAMNgIcIAAgASgAEDYCICAAIAEoABQ2AiQgACABKAAYNgIoIAAgASgAHDYCLAsYACAAIAEgAiADQgAgBEGInAIoAgAREQALGAAgACABIAIgAyAEIAVBiJwCKAIAEREACxAAIAAgAUGAnAIoAgARAQALagEDfyMAQRBrIgMkACADQQA6AA9BfyEFIAAgASACQfybAigCABEDAEUEQANAIAMgACAEai0AACADLQAPcjoADyAEQQFqIgRBIEcNAAtBACADLQAPQQFrQQh2QQFxayEFCyADQRBqJAAgBQupAwEVfyABKAIEIQsgACgCBCEMIAEoAgghDSAAKAIIIQ4gASgCDCEPIAAoAgwhAyABKAIQIRAgACgCECEEIAEoAhQhESAAKAIUIQUgASgCGCESIAAoAhghBiABKAIcIRMgACgCHCEHIAEoAiAhFCAAKAIgIQggASgCJCEVIAAoAiQhCSAAQQAgAmsiAiABKAIAIhYgACgCACIKc3EiFyAKczYCACAAIAkgCSAVcyACcSIKczYCJCAAIAggCCAUcyACcSIJczYCICAAIAcgByATcyACcSIIczYCHCAAIAYgBiAScyACcSIHczYCGCAAIAUgBSARcyACcSIGczYCFCAAIAQgBCAQcyACcSIFczYCECAAIAMgAyAPcyACcSIEczYCDCAAIA4gDSAOcyACcSIDczYCCCAAIAwgCyAMcyACcSIAczYCBCABIAogFXM2AiQgASAJIBRzNgIgIAEgCCATczYCHCABIAcgEnM2AhggASAGIBFzNgIUIAEgBSAQczYCECABIAQgD3M2AgwgASADIA1zNgIIIAEgACALczYCBCABIBYgF3M2AgALDQAgACABIAEQQRDJAguVAQEEfyMAQTBrIgUkACAAIAFBKGoiAyABEBMgAEEoaiIEIAMgARAVIABB0ABqIgMgACACQShqEAogBCAEIAIQCiAAQfgAaiIGIAJB+ABqIAFB+ABqEAogACABQdAAaiACQdAAahAKIAUgACAAEBMgACADIAQQFSAEIAMgBBATIAMgBSAGEBUgBiAFIAYQEyAFQTBqJAALzQQBAn8jAEGQAWsiAiQAIAJB4ABqIAEQDiACQTBqIAJB4ABqEA4gAkEwaiACQTBqEA4gAkEwaiABIAJBMGoQCiACQeAAaiACQeAAaiACQTBqEAogAkHgAGogAkHgAGoQDiACQeAAaiACQTBqIAJB4ABqEAogAkEwaiACQeAAahAOQQIhAwNAIAJBMGogAkEwahAOIANBBUZFBEAgA0EBaiEDDAELCyACQeAAaiACQTBqIAJB4ABqEAogAkEwaiACQeAAahAOQQIhAwNAIAJBMGogAkEwahAOIANBCkZFBEAgA0EBaiEDDAELCyACQTBqIAJBMGogAkHgAGoQCiACIAJBMGoQDkECIQMDQCACIAIQDiADQRRGRQRAIANBAWohAwwBCwsgAkEwaiACIAJBMGoQCkECIQMDQCACQTBqIAJBMGoQDiADQQtGRQRAIANBAWohAwwBCwsgAkHgAGogAkEwaiACQeAAahAKIAJBMGogAkHgAGoQDkECIQMDQCACQTBqIAJBMGoQDiADQTJGRQRAIANBAWohAwwBCwsgAkEwaiACQTBqIAJB4ABqEAogAiACQTBqEA5BAiEDA0AgAiACEA4gA0HkAEZFBEAgA0EBaiEDDAELCyACQTBqIAIgAkEwahAKQQIhAwNAIAJBMGogAkEwahAOIANBM0ZFBEAgA0EBaiEDDAELCyACQeAAaiACQTBqIAJB4ABqEAogAkHgAGogAkHgAGoQDiACQeAAaiACQeAAahAOIAAgAkHgAGogARAKIAJBkAFqJAALpgQCDn4KfyAAKAIkIRIgACgCICETIAAoAhwhFCAAKAIYIRUgACgCFCERIAJCEFoEQCAALQBQRUEYdCEWIAAoAhAiF60hDyAAKAIMIhitIQ0gACgCCCIZrSELIAAoAgQiGq0hCSAaQQVsrSEQIBlBBWytIQ4gGEEFbK0hDCAXQQVsrSEKIAA1AgAhCANAIAEoAANBAnZB////H3EgFWqtIgMgDX4gASgAAEH///8fcSARaq0iBCAPfnwgASgABkEEdkH///8fcSAUaq0iBSALfnwgASgACUEGdiATaq0iBiAJfnwgEiAWaiABKAAMQQh2aq0iByAIfnwgAyALfiAEIA1+fCAFIAl+fCAGIAh+fCAHIAp+fCADIAl+IAQgC358IAUgCH58IAYgCn58IAcgDH58IAMgCH4gBCAJfnwgBSAKfnwgBiAMfnwgByAOfnwgAyAKfiAEIAh+fCAFIAx+fCAGIA5+fCAHIBB+fCIDQhqIQv////8Pg3wiBEIaiEL/////D4N8IgVCGohC/////w+DfCIGQhqIQv////8Pg3wiB0IaiKdBBWwgA6dB////H3FqIhFBGnYgBKdB////H3FqIRUgBadB////H3EhFCAGp0H///8fcSETIAenQf///x9xIRIgEUH///8fcSERIAFBEGohASACQhB9IgJCD1YNAAsLIAAgETYCFCAAIBI2AiQgACATNgIgIAAgFDYCHCAAIBU2AhgLbAEBfyMAQRBrIgMgADYCDCADIAE2AghBACEBIANBADYCBCACQQFOBEADQCADIAMoAgQgAygCCCABai0AACADKAIMIAFqLQAAc3I2AgQgAUEBaiIBIAJHDQALCyADKAIEQQFrQQh2QQFxQQFrC/EBAQJ/IABFBEBBZw8LIAAoAgBFBEBBfw8LAkACf0F+IAAoAgRBEEkNABogACgCCEUEQEFuIAAoAgwNARoLIAAoAhQhASAAKAIQRQ0BQXogAUEISQ0AGiAAKAIYRQRAQWwgACgCHA0BGgsgACgCIEUEQEFrIAAoAiQNARoLIAAoAjAiAUUEQEFwDwtBbyABQf///wdLDQAaQXIgACgCLCICQQhJDQAaQXEgAkGAgIABSw0AGkFyIAIgAUEDdEkNABogACgCKEUEQEF0DwsgACgCNCIARQRAQWQPC0FjQQAgAEH///8HSxsLDwtBbUF6IAEbC5MNAhB+EX8jAEGAEGsiEyQAIBNBgAhqIAEQQyATQYAIaiAAEEsgEyATQYAIahBDIBMgAhBLQQAhAQNAIBNBgAhqIBRBB3QiAEHAAHJqIhUpAwAgE0GACGogAEHgAHJqIhYpAwAgE0GACGogAGoiFykDACATQYAIaiAAQSByaiIYKQMAIgcQCCIDhUEgEAYiBBAIIgUgB4VBGBAGIQcgByAFIAQgAyAHEAgiBoVBEBAGIgkQCCIQhUE/EAYhByATQYAIaiAAQcgAcmoiGSkDACATQYAIaiAAQegAcmoiGikDACATQYAIaiAAQQhyaiIbKQMAIBNBgAhqIABBKHJqIhwpAwAiAxAIIgSFQSAQBiIFEAgiCiADhUEYEAYhAyADIAogBSAEIAMQCCIKhUEQEAYiERAIIhKFQT8QBiEDIBNBgAhqIABB0AByaiIdKQMAIBNBgAhqIABB8AByaiIeKQMAIBNBgAhqIABBEHJqIh8pAwAgE0GACGogAEEwcmoiICkDACIEEAgiBYVBIBAGIgsQCCIMIASFQRgQBiEEIAQgDCALIAUgBBAIIgyFQRAQBiILEAgiDYVBPxAGIQQgE0GACGogAEHYAHJqIiEpAwAgE0GACGogAEH4AHJqIiIpAwAgE0GACGogAEEYcmoiIykDACATQYAIaiAAQThyaiIAKQMAIgUQCCIOhUEgEAYiCBAIIg8gBYVBGBAGIQUgBSAPIAggDiAFEAgiDoVBEBAGIggQCCIPhUE/EAYhBSAXIAYgAxAIIgYgAyANIAYgCIVBIBAGIgYQCCINhUEYEAYiAxAIIgg3AwAgIiAGIAiFQRAQBiIGNwMAIB0gDSAGEAgiBjcDACAcIAMgBoVBPxAGNwMAIBsgCiAEEAgiAyAEIA8gAyAJhUEgEAYiAxAIIgaFQRgQBiIEEAgiCTcDACAWIAMgCYVBEBAGIgM3AwAgISAGIAMQCCIDNwMAICAgAyAEhUE/EAY3AwAgHyAMIAUQCCIDIAUgECADIBGFQSAQBiIDEAgiBIVBGBAGIgUQCCIGNwMAIBogAyAGhUEQEAYiAzcDACAVIAQgAxAIIgM3AwAgACADIAWFQT8QBjcDACAjIA4gBxAIIgMgByASIAMgC4VBIBAGIgMQCCIEhUEYEAYiBxAIIgU3AwAgHiADIAWFQRAQBiIDNwMAIBkgBCADEAgiAzcDACAYIAMgB4VBPxAGNwMAIBRBAWoiFEEIRw0ACwNAIAFBBHQiFCATQYAIamoiACIVQYAEaikDACAAKQOABiAAKQMAIAApA4ACIgcQCCIDhUEgEAYiBBAIIgUgB4VBGBAGIQcgByAFIAQgAyAHEAgiBoVBEBAGIgkQCCIQhUE/EAYhByAAKQOIBCAAKQOIBiATQYAIaiAUQQhyaiIUKQMAIAApA4gCIgMQCCIEhUEgEAYiBRAIIgogA4VBGBAGIQMgAyAKIAUgBCADEAgiCoVBEBAGIhEQCCIShUE/EAYhAyAAKQOABSAAKQOAByAAKQOAASAAKQOAAyIEEAgiBYVBIBAGIgsQCCIMIASFQRgQBiEEIAQgDCALIAUgBBAIIgyFQRAQBiILEAgiDYVBPxAGIQQgACkDiAUgACkDiAcgACkDiAEgACkDiAMiBRAIIg6FQSAQBiIIEAgiDyAFhUEYEAYhBSAFIA8gCCAOIAUQCCIOhUEQEAYiCBAIIg+FQT8QBiEFIAAgBiADEAgiBiADIA0gBiAIhUEgEAYiBhAIIg2FQRgQBiIDEAgiCDcDACAAIAYgCIVBEBAGIgY3A4gHIAAgDSAGEAgiBjcDgAUgACADIAaFQT8QBjcDiAIgFCAKIAQQCCIDIAQgDyADIAmFQSAQBiIDEAgiBoVBGBAGIgQQCCIJNwMAIAAgAyAJhUEQEAYiAzcDgAYgACAGIAMQCCIDNwOIBSAAIAMgBIVBPxAGNwOAAyAAIAwgBRAIIgMgBSAQIAMgEYVBIBAGIgMQCCIEhUEYEAYiBRAIIgY3A4ABIAAgAyAGhUEQEAYiAzcDiAYgFSAEIAMQCCIDNwOABCAAIAMgBYVBPxAGNwOIAyAAIA4gBxAIIgMgByASIAMgC4VBIBAGIgMQCCIEhUEYEAYiBxAIIgU3A4gBIAAgAyAFhUEQEAYiAzcDgAcgACAEIAMQCCIDNwOIBCAAIAMgB4VBPxAGNwOAAiABQQFqIgFBCEcNAAsgAiATEEMgAiATQYAIahBLIBNBgBBqJAALxAMBAn8jACIEIQUgBEHABGtBQHEiBCQAIARBADYCvAEgBEG8AWogARAPAkAgAUHAAE0EQCAEQcABakEAQQAgARBWQQBIDQEgBEHAAWogBEG8AWpCBBAhQQBIDQEgBEHAAWogAiADrRAhQQBIDQEgBEHAAWogACABEFUaDAELIARBwAFqQQBBAEHAABBWQQBIDQAgBEHAAWogBEG8AWpCBBAhQQBIDQAgBEHAAWogAiADrRAhQQBIDQAgBEHAAWogBEHwAGpBwAAQVUEASA0AIAAgBCkDcDcAACAAIAQpA3g3AAggACAEKQOIATcAGCAAIAQpA4ABNwAQIABBIGohACABQSBrIgFBwQBPBEADQCAEQTBqIARB8ABqQcAAEBcaIARB8ABqQcAAIARBMGpCwABBAEEAEGpBAEgNAiAAIAQpA3A3AAAgACAEKQN4NwAIIAAgBCkDiAE3ABggACAEKQOAATcAECAAQSBqIQAgAUEgayIBQcAASw0ACwsgBEEwaiAEQfAAakHAABAXGiAEQfAAaiABIARBMGpCwABBAEEAEGpBAEgNACAAIARB8ABqIAEQFxoLIARBwAFqQYADEAwgBSQAC9cCAQN/IwBBQGoiBCQAQX8hAwJAIAJBAWtB/wFxQcAASQRAIAApAFBQBEAgACAAKADgAiIDQYEBTwR/IABCgAEQjQEgACAAQeAAaiIFEJoBIAAgACgA4AJBgAFrIgM2AOACIANBgQFPDQMgBSAAQeABaiADEBcaIAAoAOACBSADC60QjQEgACIDLQDkAgRAIANCfzcAWAsgA0J/NwBQIABB4ABqIgMgACgA4AIiBWpBAEGAAiAFaxAWGiAAIAMQmgEgBCAAKQAAEBkgBEEIciAAKQAIEBkgBEEQaiAAKQAQEBkgBEEYaiAAKQAYEBkgBEEgaiAAKQAgEBkgBEEoaiAAKQAoEBkgBEEwaiAAKQAwEBkgBEE4aiAAKQA4EBkgASAEIAIQFxogAEHAABAMIANBgAIQDEEAIQMLIARBQGskACADDwsQGAALQdkKQcEJQbICQfYIEAAACxcAIAAgASACrSADrUIghoQgBCAFELICCxcAIAAgASACrSADrUIghoQgBCAFELMCCy0CAX8BfiAAQUBrIgIgASACKQAAIgF8IgM3AAAgACAAKQBIIAEgA1atfDcASAsLACAAIAEgAhCAAQsIACAAIAEQfwuOAQEBfyMAQTBrIgEkACABIAApABg3AxggASAAKQAQNwMQIAEgACkAADcDACABIAApAAg3AwggASAAKQAkNwMgIAEgAUIoIABBIGogABDEAhogACABKQMYNwAYIAAgASkDEDcAECAAIAEpAwg3AAggACABKQMANwAAIAAgASkDIDcAJCAAEJEBIAFBMGokAAsJACAAQQE2ACALEQAgACABIAIgAyAEIAUQlAELEQAgACABIAIgAyAEIAUQlQELkgICAX8BfiMAQeAAayIGJAAgBiAEIAVBABBOGiAGQSBqQiAgBEEQaiIFIAYQtwEaQX8hBAJAAkAgAiABIAMgBkEgahBnDQBBACEEIABFDQEgACABSUEAIAEgAGutIANUG0EBIAAgAU0gACABa60gA1pyGwRAIAAgASADpxBMIQELAkBCICADIANCIFYbIgdQBEAgBkEgaiAGQSBqIAdCIHwgBSAGEH0aDAELIAZBQGsgASAHpyICEBchBCAGQSBqIAZBIGogB0IgfCAFIAYQfRogACAEIAIQFxoLQQAhBCADQiFUDQAgACAHpyICaiABIAJqIAMgB30gBUIBIAYQfhoLIAZBIBAMCyAGQeAAaiQAIAQLpAICAX8BfiMAQeACayIGJAAgBiAEIAVBABBOGiAAIAJLQQAgACACa60gA1QbQQEgACACTyACIABrrSADWnIbBEAgACACIAOnEEwhAgsgBkIANwM4IAZCADcDMCAGQgA3AyggBkIANwMgQiAgAyADQiBWGyIHUCIFRQRAIAZBQGsgAiAHpxAXGgsgBkEgaiAGQSBqIAdCIHwgBEEQaiIEIAYQfRogBkHgAGogBkEgahAqGiAFRQRAIAAgBkFAayAHpxAXGgsgBkEgakHAABAMIANCIVoEQCAAIAenIgVqIAIgBWogAyAHfSAEQgEgBhB+GgsgBkEgEAwgBkHgAGogACADEBEaIAZB4ABqIAEQKRogBkHgAGpBgAIQDCAGQeACaiQAQQALCgAgACABIAIQdwu2AQIBfwN+IwBBoAFrIgMkACABIAJCIBBeGiABIAEtAABB+AFxOgAAIAEgAS0AH0E/cUHAAHI6AB8gAyABEGYgACADEEAgAikACCEEIAIpABAhBSACKQAAIQYgASACKQAYNwAYIAEgBTcAECABIAQ3AAggASAGNwAAIAApAAghBCAAKQAQIQUgACkAACEGIAEgACkAGDcAOCABIAU3ADAgASAENwAoIAEgBjcAICADQaABaiQAQQALyQEBAn4gBEEINgIAIAICfwJAIAICfwJAIABCgIACIABCgIACVhsiBSABQQV2rVoEQCABQQt2rSEGQgEhAANAIAYgAIhQDQIgAEIBfCIAQj9SDQALQT8MAgsgA0EBNgIAIAUgBCgCAEECdK2AQgGIIQVCASEAA0AgBSAAiFANAyAAQgF8IgBCP1INAAtBPwwDCyAApwsiATYCACADIAVCAoggAa2IIgBC/////wMgAEL/////A1QbpyAEKAIAbjYCAA8LIACnCzYCAAtJAQF/IAMEQANAIAFFBEBBAA8LIAAgAkE/cUGACGotAAA6AAAgAkEGdiECIAFBAWshASAAQQFqIQAgBEEGaiIEIANJDQALCyAAC+42Ah5+A38jAEGAAmsiICQAA0AgIUEDdCIiICBBgAFqaiABICJqKQAANwMAICFBAWoiIUEQRw0ACyAgIABBwAAQFyIBKQMAIAEpAyAiHiABKQOAAXx8IhkgAEFAaykAAIVC0YWa7/rPlIfRAIVBIBAGIhdCiJLznf/M+YTqAHwiEyAehUEYEAYhFiAWIBcgASkDiAEiHiAWIBl8fCIOhUEQEAYiAyATfCIHhUE/EAYhHCABKQMIIAEpA5ABIg0gASkDKCIWfHwiGSAAKQBIhUKf2PnZwpHagpt/hUEgEAYiF0LFsdXZp6+UzMQAfSITIBaFQRgQBiEWIBYgFyABKQOYASAWIBl8fCIGhUEQEAYiECATfCIPhUE/EAYhEyABKQMQIAEpA6ABIgsgASkDMCIWfHwiFyAAKQBQhULr+obav7X2wR+FQSAQBiIaQqvw0/Sv7ry3PHwiEiAWhUEYEAYhGSAZIBogASkDqAEiFiAXIBl8fCIJhUEQEAYiCCASfCIEhUE/EAYhGiABKQMYIAEpA7ABIhkgASkDOCIXfHwiAiAAKQBYhUL5wvibkaOz8NsAhUEgEAYiBUKPkouH2tiC2NoAfSIKIBeFQRgQBiESIBIgCiAFIAEpA7gBIhcgAiASfHwiEYVBEBAGIgx8IgqFQT8QBiECIBMgBCAMIAEpA8ABIgUgDiATfHwiEoVBIBAGIg58IgSFQRgQBiETIBMgDiABKQPIASIMIBIgE3x8IhSFQRAQBiIVIAR8Ih2FQT8QBiEEIBogAyABKQPQASISIAYgGnx8IgaFQSAQBiIDIAp8IgqFQRgQBiETIBMgCiADIAEpA9gBIg4gBiATfHwiGIVBEBAGIht8IgqFQT8QBiEDIAIgByAQIAEpA+ABIhMgAiAJfHwiBoVBIBAGIhB8IgeFQRgQBiEaIBogByAQIAEpA+gBIgIgBiAafHwiCYVBEBAGIhB8Ih+FQT8QBiEHIBwgDyAIIAEpA/ABIhogESAcfHwiEYVBIBAGIgh8Ig+FQRgQBiEGIBsgBiAPIAggASkD+AEiHCAGIBF8fCIRhUEQEAYiCHwiD4VBPxAGIgYgFCAafHwiFIVBIBAGIhsgH3wiHyAGhUEYEAYhBiAGIBsgBiASIBR8fCIUhUEQEAYiGyAffCIfhUE/EAYhBiAEIA8gECAEIAt8IBh8Ig+FQSAQBiIQfCILhUEYEAYhBCAEIBAgBCAFIA98fCIPhUEQEAYiECALfCILhUE/EAYhBCADIAggAyAMfCAJfCIJhUEgEAYiCCAdfCIMhUEYEAYhAyADIAggAyAJIBx8fCIJhUEQEAYiCCAMfCIMhUE/EAYhAyAHIAogFSACIAd8IBF8IhGFQSAQBiIVfCIKhUEYEAYhByAHIAogFSAHIBEgGXx8IgqFQRAQBiIRfCIVhUE/EAYhByAEIAwgESAEIBQgHnx8IhSFQSAQBiIRfCIMhUEYEAYhBCAEIAwgESAEIBMgFHx8IhSFQRAQBiIRfCIMhUE/EAYhBCADIBUgGyABKQOAASIdIAMgD3x8Ig+FQSAQBiIYfCIVhUEYEAYhAyADIBUgGCADIA0gD3x8Ig+FQRAQBiIYfCIVhUE/EAYhAyAHIBAgByAJIA58fCIJhUEgEAYiECAffCIbhUEYEAYhByAHIBsgECAHIAkgF3x8IgmFQRAQBiIffCIbhUE/EAYhByAGIAsgCCAGIBZ8IAp8IguFQSAQBiIIfCIKhUEYEAYhBiAbIBggBiAKIAggASkDmAEiECAGIAt8fCILhUEQEAYiCHwiCoVBPxAGIgYgDiAUfHwiFIVBIBAGIhh8IhsgBoVBGBAGIQYgBiAYIAYgBSAUfHwiFIVBEBAGIhggG3wiG4VBPxAGIQUgBCAfIAQgE3wgD3wiBoVBIBAGIg8gCnwiCoVBGBAGIQQgBCAPIAQgBiAdfHwiBoVBEBAGIg8gCnwiCoVBPxAGIQQgAyAIIAMgFnwgCXwiCYVBIBAGIgggDHwiDIVBGBAGIQMgAyAIIAMgCSANfHwiCYVBEBAGIgggDHwiDIVBPxAGIQMgByARIAcgHHwgC3wiC4VBIBAGIhEgFXwiFYVBGBAGIQcgByARIAcgAiALfHwiC4VBEBAGIhEgFXwiFYVBPxAGIQcgBCAMIBEgBCASIBR8fCIMhUEgEAYiEXwiFIVBGBAGIQQgBCARIAQgDCAafHwiDIVBEBAGIhEgFHwiFIVBPxAGIQQgAyAVIBggAyAGIBB8fCIGhUEgEAYiHXwiFYVBGBAGIQMgAyAVIB0gAyAGIBl8fCIYhUEQEAYiHXwiFYVBPxAGIQMgByAPIAcgCSAXfHwiBoVBIBAGIg8gG3wiCYVBGBAGIQcgByAJIA8gByAGIB58fCIbhUEQEAYiH3wiCYVBPxAGIQcgBSAKIAggASkDyAEiBiAFIAt8fCILhUEgEAYiCHwiCoVBGBAGIQUgCSAdIAUgCiAIIAEpA6ABIg8gBSALfHwiC4VBEBAGIgh8IgqFQT8QBiIFIAwgF3x8IgyFQSAQBiIdfCIJIAWFQRgQBiEFIAUgCSAdIAUgBiAMfHwiDIVBEBAGIh18IgmFQT8QBiEFIAQgCiAfIAQgEHwgGHwiEIVBIBAGIgp8IhiFQRgQBiEEIAQgCiAEIBAgHnx8IhCFQRAQBiIKIBh8IhiFQT8QBiEEIAMgFCAIIAIgA3wgG3wiG4VBIBAGIgh8IhSFQRgQBiECIAIgFCAIIAIgEyAbfHwiFIVBEBAGIgh8IhuFQT8QBiECIAcgFSARIAcgDnwgC3wiC4VBIBAGIhF8IhWFQRgQBiEDIAMgESADIAsgGnx8IguFQRAQBiIHIBV8IhGFQT8QBiEDIAQgGyAHIAQgDCANfHwiDIVBIBAGIgd8IhWFQRgQBiEEIAQgFSAHIAQgDCAZfHwiDIVBEBAGIht8IhWFQT8QBiEEIAIgHSACIBAgFnx8IgeFQSAQBiIQIBF8IhGFQRgQBiECIAIgESAQIAIgByASfHwiHYVBEBAGIh98IhGFQT8QBiECIAMgCSAKIAMgDyAUfHwiEIVBIBAGIgl8IgqFQRgQBiEDIAMgCiAJIAEpA4ABIgcgAyAQfHwiFIVBEBAGIgl8IgqFQT8QBiEDIAUgGCAIIAUgHHwgC3wiC4VBIBAGIgh8IhCFQRgQBiEFIAogHyAFIBAgCCABKQPAASIQIAUgC3x8IguFQRAQBiIIfCIYhUE/EAYiBSAGIAx8fCIGhUEgEAYiDHwiCiAFhUEYEAYhBSAFIAogDCAFIAYgB3x8IgaFQRAQBiIKfCIMhUE/EAYhBSAEIBggCSAEIBZ8IB18Ih2FQSAQBiIJfCIYhUEYEAYhBCAEIAkgBCAXIB18fCIdhUEQEAYiCSAYfCIYhUE/EAYhBCACIAggAiANfCAUfCIUhUEgEAYiCCAVfCIVhUEYEAYhAiACIAggAiAPIBR8fCIPhUEQEAYiCCAVfCIUhUE/EAYhAiADIBEgGyADIBJ8IAt8IguFQSAQBiIVfCIRhUEYEAYhAyADIBEgFSADIAsgHHx8IguFQRAQBiIVfCIRhUE/EAYhAyAEIBQgFSAEIAYgGnx8IgaFQSAQBiIVfCIUhUEYEAYhBCAEIBQgFSAEIAYgHnx8IgaFQRAQBiIUfCIVhUE/EAYhBCACIBEgCiACIA4gHXx8IhGFQSAQBiIKfCIdhUEYEAYhAiACIAogAiARIBN8fCIRhUEQEAYiCiAdfCIdhUE/EAYhAiADIAkgAyAPIBl8fCIPhUEgEAYiCSAMfCIMhUEYEAYhAyADIAkgAyAPIBB8fCIPhUEQEAYiCSAMfCIMhUE/EAYhAyAFIBggCCABKQOYASIbIAUgC3x8IguFQSAQBiIIfCIYhUEYEAYhBSAMIAogBSAYIAggASkD6AEiHyAFIAt8fCILhUEQEAYiCHwiGIVBPxAGIgUgBiANfHwiBoVBIBAGIgp8IgwgBYVBGBAGIQ0gDSAMIAogDSAGIBN8fCIGhUEQEAYiCnwiDIVBPxAGIQ0gBCAJIAQgGXwgEXwiEYVBIBAGIgkgGHwiGIVBGBAGIQUgBSAJIAUgESASfHwiBIVBEBAGIgkgGHwiEYVBPxAGIQUgAiAIIAIgB3wgD3wiB4VBIBAGIg8gFXwiCIVBGBAGIQIgAiAPIAIgByAOfHwiB4VBEBAGIg8gCHwiCIVBPxAGIQ4gAyAUIAMgEHwgC3wiEIVBIBAGIgsgHXwiFIVBGBAGIQIgAiALIAIgECAbfHwiA4VBEBAGIhAgFHwiC4VBPxAGIQIgBSAIIBAgASkDoAEgBSAGfHwiBoVBIBAGIhB8IgiFQRgQBiEFIAUgECAFIAYgH3x8IgaFQRAQBiIQIAh8IgiFQT8QBiEFIA4gCyAKIA4gBCAXfHwiBIVBIBAGIgt8IgqFQRgQBiEOIA4gCyAOIAQgFnx8IgSFQRAQBiILIAp8IgqFQT8QBiEOIAIgCSACIAcgHHx8IgeFQSAQBiIJIAx8IgyFQRgQBiECIAIgCSACIAcgGnx8IgeFQRAQBiIJIAx8IgyFQT8QBiECIA0gDyANIB58IAN8IgOFQSAQBiIPIBF8IhGFQRgQBiENIAwgCyANIA8gASkDyAEgAyANfHwiA4VBEBAGIg8gEXwiEYVBPxAGIg0gBiATfHwiBoVBIBAGIgt8IgwgDYVBGBAGIQ0gDSALIA0gBiAWfHwiBoVBEBAGIgsgDHwiDIVBPxAGIQ0gBSAJIAUgHnwgBHwiBIVBIBAGIgkgEXwiEYVBGBAGIQUgBSAJIAUgBCAcfHwiBIVBEBAGIgkgEXwiEYVBPxAGIQUgDiAPIA4gGnwgB3wiB4VBIBAGIg8gCHwiCIVBGBAGIQ4gDiAPIAEpA+gBIAcgDnx8IgeFQRAQBiIPIAh8IgiFQT8QBiEOIAIgECABKQOgASACIAN8fCIDhUEgEAYiECAKfCIKhUEYEAYhAiACIBAgAiADIBJ8fCIDhUEQEAYiECAKfCIKhUE/EAYhAiAFIAggECABKQOAASAFIAZ8fCIGhUEgEAYiEHwiCIVBGBAGIQUgBSAQIAUgBiAXfHwiBoVBEBAGIhAgCHwiCIVBPxAGIQUgDiALIA4gBCAZfHwiBIVBIBAGIgsgCnwiCoVBGBAGIQ4gDiALIAEpA5gBIAQgDnx8IgSFQRAQBiILIAp8IgqFQT8QBiEOIAIgCSABKQPIASACIAd8fCIHhUEgEAYiCSAMfCIMhUEYEAYhAiACIAkgASkDkAEgAiAHfHwiB4VBEBAGIgkgDHwiDIVBPxAGIQIgDSAPIAEpA8ABIAMgDXx8IgOFQSAQBiIPIBF8IhGFQRgQBiENIA0gESAPIAEpA9gBIhQgAyANfHwiA4VBEBAGIg98IhGFQT8QBiENIA0gCyABKQPoASAGIA18fCIGhUEgEAYiCyAMfCIMhUEYEAYhDSANIAsgBiANfCAUfCIGhUEQEAYiCyAMfCIMhUE/EAYhDSAFIAkgBSAXfCAEfCIEhUEgEAYiCSARfCIRhUEYEAYhBSAFIAkgBSAEIBp8fCIEhUEQEAYiCSARfCIRhUE/EAYhBSAOIA8gDiATfCAHfCIHhUEgEAYiDyAIfCIIhUEYEAYhDiAOIA8gDiAHIB58fCIHhUEQEAYiDyAIfCIIhUE/EAYhDiACIBAgASkDmAEgAiADfHwiA4VBIBAGIhAgCnwiCoVBGBAGIQIgAiAQIAEpA8gBIAIgA3x8IgOFQRAQBiIQIAp8IgqFQT8QBiECIAUgECAFIAYgFnx8IgaFQSAQBiIQIAh8IgiFQRgQBiEFIAUgECABKQOAASAFIAZ8fCIGhUEQEAYiECAIfCIIhUE/EAYhBSAOIAsgDiAEIBx8fCIEhUEgEAYiCyAKfCIKhUEYEAYhDiAOIAsgASkDoAEgBCAOfHwiBIVBEBAGIgsgCnwiCoVBPxAGIQ4gAiAJIAEpA8ABIAIgB3x8IgeFQSAQBiIJIAx8IgyFQRgQBiECIAIgCSACIAcgGXx8IgeFQRAQBiIJIAx8IgyFQT8QBiECIA0gDyABKQOQASADIA18fCIDhUEgEAYiDyARfCIRhUEYEAYhDSAMIAsgDSAPIA0gAyASfHwiA4VBEBAGIg8gEXwiEYVBPxAGIg0gBiAZfHwiBoVBIBAGIgt8IgwgDYVBGBAGIQ0gDSALIA0gBiAcfHwiBoVBEBAGIgsgDHwiDIVBPxAGIQ0gBSAJIAUgGnwgBHwiBIVBIBAGIgkgEXwiEYVBGBAGIQUgBSAJIAEpA8gBIAQgBXx8IgSFQRAQBiIJIBF8IhGFQT8QBiEFIA4gDyABKQPYASAHIA58fCIHhUEgEAYiDyAIfCIIhUEYEAYhDiAOIA8gASkDmAEgByAOfHwiB4VBEBAGIg8gCHwiCIVBPxAGIQ4gAiAQIAEpA4ABIAIgA3x8IgOFQSAQBiIQIAp8IgqFQRgQBiECIAIgECABKQPAASACIAN8fCIDhUEQEAYiECAKfCIKhUE/EAYhAiAFIBAgBSAGIBN8fCIGhUEgEAYiECAIfCIIhUEYEAYhBSAFIAggECABKQOQASIUIAUgBnx8IgaFQRAQBiIQfCIIhUE/EAYhBSAOIAsgASkD6AEgBCAOfHwiBIVBIBAGIgsgCnwiCoVBGBAGIQ4gDiALIA4gBCAXfHwiBIVBEBAGIgsgCnwiCoVBPxAGIQ4gAiAJIAIgByAefHwiB4VBIBAGIgkgDHwiDIVBGBAGIQIgAiAMIAkgASkDoAEiFSACIAd8fCIHhUEQEAYiCXwiDIVBPxAGIQIgDSAPIA0gEnwgA3wiA4VBIBAGIg8gEXwiEYVBGBAGIQ0gCyANIA8gDSADIBZ8fCIDhUEQEAYiDyARfCIRhUE/EAYiDSAGIBJ8fCIGhUEgEAYiCyAMfCIMIA2FQRgQBiESIBIgDCALIAYgEnwgFHwiBoVBEBAGIgt8IgyFQT8QBiESIAUgCSABKQPAASAEIAV8fCIEhUEgEAYiCSARfCIRhUEYEAYhDSANIAkgBCANfCAVfCIFhUEQEAYiBCARfCIJhUE/EAYhDSAOIA8gDiAXfCAHfCIHhUEgEAYiDyAIfCIIhUEYEAYhDiAOIA8gDiAHIBl8fCIHhUEQEAYiDyAIfCIIhUE/EAYhDiACIBAgAiAefCADfCIDhUEgEAYiECAKfCIKhUEYEAYhAiACIBAgAiADIBZ8fCIDhUEQEAYiECAKfCIKhUE/EAYhAiANIAggECANIAYgHHx8IgaFQSAQBiIQfCIIhUEYEAYhDSANIBAgASkD2AEgBiANfHwiBoVBEBAGIhAgCHwiCIVBPxAGIQ0gDiALIAEpA8gBIAUgDnx8IgWFQSAQBiILIAp8IgqFQRgQBiEOIA4gCyAOIAUgGnx8IgWFQRAQBiILIAp8IgqFQT8QBiEOIAIgDCAEIAEpA5gBIhEgAiAHfHwiB4VBIBAGIgR8IgyFQRgQBiECIAIgBCACIAcgE3x8IgeFQRAQBiIEIAx8IgyFQT8QBiECIBIgDyABKQPoASADIBJ8fCIDhUEgEAYiDyAJfCIJhUEYEAYhEiASIAkgDyABKQOAASIUIAMgEnx8IgOFQRAQBiIPfCIJhUE/EAYhEiASIAsgBiASfCAUfCIGhUEgEAYiCyAMfCIMhUEYEAYhEiASIAsgEiAGIB58fCIGhUEQEAYiCyAMfCIMhUE/EAYhEiANIAQgASkDkAEgBSANfHwiBYVBIBAGIgQgCXwiCYVBGBAGIQ0gDSAEIAUgDXwgEXwiBYVBEBAGIgQgCXwiCYVBPxAGIQ0gDiAPIAEpA6ABIAcgDnx8IgeFQSAQBiIPIAh8IgiFQRgQBiEOIA4gDyAOIAcgFnx8IgeFQRAQBiIPIAh8IgiFQT8QBiEOIAIgECACIBl8IAN8IgOFQSAQBiIQIAp8IgqFQRgQBiECIAIgECACIAMgF3x8IgOFQRAQBiIQIAp8IgqFQT8QBiECIA0gECABKQPAASAGIA18fCIGhUEgEAYiECAIfCIIhUEYEAYhDSANIBAgASkDyAEgBiANfHwiBoVBEBAGIhAgCHwiCIVBPxAGIQ0gDiAKIAsgASkD0AEiESAFIA58fCIFhUEgEAYiC3wiCoVBGBAGIQ4gDiALIAEpA9gBIAUgDnx8IgWFQRAQBiILIAp8IgqFQT8QBiEOIAIgBCACIAcgE3x8IgeFQSAQBiIEIAx8IgyFQRgQBiECIAIgBCABKQPoASACIAd8fCIHhUEQEAYiBCAMfCIMhUE/EAYhAiASIA8gEiAafCADfCIDhUEgEAYiDyAJfCIJhUEYEAYhEiALIBIgDyASIAMgHHx8IgOFQRAQBiIPIAl8IgmFQT8QBiISIAYgGnx8IgaFQSAQBiILIAx8IgwgEoVBGBAGIRogGiALIAYgGnwgEXwiBoVBEBAGIgsgDHwiEYVBPxAGIRogDSAEIAEpA6ABIAUgDXx8IgWFQSAQBiIEIAl8IgmFQRgQBiESIBIgBCABKQPAASAFIBJ8fCIFhUEQEAYiBCAJfCIJhUE/EAYhEiAOIA8gASkDyAEgByAOfHwiB4VBIBAGIg8gCHwiCIVBGBAGIQ0gDSAPIA0gByAcfHwiDoVBEBAGIgcgCHwiD4VBPxAGIRwgAiAQIAEpA+gBIAIgA3x8IgOFQSAQBiIQIAp8IgiFQRgQBiENIA0gECANIAMgGXx8IgKFQRAQBiIDIAh8IhCFQT8QBiEZIAEgEiAGIB58fCIeIBN8IBIgAyAehUEgEAYiEyAPfCINhUEYEAYiEnwiHjcDACABIBMgHoVBEBAGIhM3A3ggASANIBN8IhM3A1AgASASIBOFQT8QBjcDKCABIBwgCyABKQOAASAFIBx8fCIThUEgEAYiEiAQfCINhUEYEAYiHCATfCABKQOQAXwiEzcDCCABIBIgE4VBEBAGIhM3A2AgASANIBN8IhM3A1ggASATIByFQT8QBjcDMCABIBcgASkD2AEgDiAZfHwiE3wgGSAEIBOFQSAQBiIXIBF8IhOFQRgQBiIZfCIcNwMQIAEgFyAchUEQEAYiFzcDaCABIBMgF3wiFzcDQCABIBcgGYVBPxAGNwM4IAEgGiAHIBYgGnwgAnwiFoVBIBAGIhkgCXwiF4VBGBAGIhMgFnwgASkDmAF8IhY3AxggASAWIBmFQRAQBiIWNwNwIAEgFiAXfCIWNwNIIAEgEyAWhUE/EAY3AyAgACABKQNAIB4gACkAAIWFNwAAQQEhIQNAIAAgIUEDdCIgaiIiIAEgIGoiICkDACAiKQAAhSAgQUBrKQMAhTcAACAhQQFqIiFBCEcNAAsgAUGAAmokAAs5AQF/IwBBIGsiAiQAIAAgAhBYGiAAQegAaiIAIAJCIBBEGiAAIAEQWBogAkEgEAwgAkEgaiQAQQALqQIBA38jAEHgAGsiAyQAIAJBwQBPBEAgABBZGiAAIAEgAq0QRBogACADEFgaQSAhAiADIQELIAAQWRogA0EgakE2QcAAEBYaAkAgAkUNACADIAEtAABBNnM6ACBBASEEIAJBAUYNAANAIANBIGogBGoiBSAFLQAAIAEgBGotAABzOgAAIARBAWoiBCACRw0ACwsgACADQSBqQsAAEEQaIABB6ABqIgAQWRogA0EgakHcAEHAABAWGgJAIAJFDQAgAyABLQAAQdwAczoAIEEBIQQgAkEBRg0AA0AgA0EgaiAEaiIFIAUtAAAgASAEai0AAHM6AAAgBEEBaiIEIAJHDQALCyAAIANBIGpCwAAQRBogA0EgakHAABAMIANBIBAMIANB4ABqJABBAAsKACAAEI0CGkEACwkAIAAQjAJBAAsRACAAIAEgAiADIAQgBRCiAQsRACAAIAEgAiADIAQgBRCjAQs1AQJ/IwBBIGsiAyQAQX8hBCADIAIgARCAAUUEQCAAQdCYAiADQQAQNSEECyADQSBqJAAgBAuRAgIBfwF+IwBB4ABrIgYkACAGIAQgBUEAEDUaIAZBIGpCICAEQRBqIgUgBhBfGkF/IQQCQAJAIAIgASADIAZBIGoQZw0AQQAhBCAARQ0BIAAgAUlBACABIABrrSADVBtBASAAIAFNIAAgAWutIANachsEQCAAIAEgA6cQTCEBCwJAQiAgAyADQiBWGyIHUARAIAZBIGogBkEgaiAHQiB8IAUgBhB6GgwBCyAGQUBrIAEgB6ciAhAXIQQgBkEgaiAGQSBqIAdCIHwgBSAGEHoaIAAgBCACEBcaC0EAIQQgA0IhVA0AIAAgB6ciAmogASACaiADIAd9IAVCASAGEFAaCyAGQSAQDAsgBkHgAGokACAEC6QCAgF/AX4jAEHgAmsiBiQAIAYgBCAFQQAQNRogACACS0EAIAAgAmutIANUG0EBIAAgAk8gAiAAa60gA1pyGwRAIAAgAiADpxBMIQILIAZCADcDOCAGQgA3AzAgBkIANwMoIAZCADcDIEIgIAMgA0IgVhsiB1AiBUUEQCAGQUBrIAIgB6cQFxoLIAZBIGogBkEgaiAHQiB8IARBEGoiBCAGEHoaIAZB4ABqIAZBIGoQKhogBUUEQCAAIAZBQGsgB6cQFxoLIAZBIGpBwAAQDCADQiFaBEAgACAHpyIFaiACIAVqIAMgB30gBEIBIAYQUBoLIAZBIBAMIAZB4ABqIAAgAxARGiAGQeAAaiABECkaIAZB4ABqQYACEAwgBkHgAmokAEEACzsBAX8jAEFAaiICJAAgACACEDIaIABB0AFqIgAgAkLAABAlGiAAIAEQMhogAkHAABAMIAJBQGskAEEACw0AIAAgASACECUaQQALqwIBA38jAEHAAWsiAyQAIAJBgQFPBEAgABBGGiAAIAEgAq0QJRogACADEDIaQcAAIQIgAyEBCyAAEEYaIANBQGtBNkGAARAWGgJAIAJFDQAgAyABLQAAQTZzOgBAQQEhBCACQQFGDQADQCADQUBrIARqIgUgBS0AACABIARqLQAAczoAACAEQQFqIgQgAkcNAAsLIAAgA0FAa0KAARAlGiAAQdABaiIAEEYaIANBQGtB3ABBgAEQFhoCQCACRQ0AIAMgAS0AAEHcAHM6AEBBASEEIAJBAUYNAANAIANBQGsgBGoiBSAFLQAAIAEgBGotAABzOgAAIARBAWoiBCACRw0ACwsgACADQUBrQoABECUaIANBQGtBgAEQDCADQcAAEAwgA0HAAWokAEEACxcAIAAQRhogAQRAIABBoJgCQiIQJRoLCwgAQYCAgIAECwQAQQQLCABBgICAgHgLBgBBgMAACwUAQYABC70HAQt/IwBBEGsiDCQAIAcQrwECQAJAIANFDQAgB0EEcSERA0AgCSEKA0AgAiAKaiwAACENAkACfyARBEBBACANIghBBGogCEHQ/wNqQQh2QX9zcUE5IAhrQQh2QX9zcUH/AXEgCEHBAGsiDiAOQQh2QX9zcUHaACAIa0EIdkF/c3FB/wFxIAhBuQFqIAhBn/8DakEIdkF/c3FB+gAgCGtBCHZBf3NxQf8BcSAIQaD/AHNBAWpBCHZBf3NBP3EgCEHS/wBzQQFqQQh2QX9zQT5xcnJyciIOa0EIdkF/cyAIQb7/A3NBAWpBCHZxQf8BcSAOcgwBC0EAIA0iCEEEaiAIQdD/A2pBCHZBf3NxQTkgCGtBCHZBf3NxQf8BcSAIQcEAayIOIA5BCHZBf3NxQdoAIAhrQQh2QX9zcUH/AXEgCEG5AWogCEGf/wNqQQh2QX9zcUH6ACAIa0EIdkF/c3FB/wFxIAhB0P8Ac0EBakEIdkF/c0E/cSAIQdT/AHNBAWpBCHZBf3NBPnFycnJyIg5rQQh2QX9zIAhBvv8Dc0EBakEIdnFB/wFxIA5yCyIIQf8BRgRAIARFDQQgBCANEF0NASAKIQkMBAsgCCAQQQZ0aiEQAkAgC0EGaiIJQQhJBEAgCSELDAELIAtBAmshCyABIA9NBEAgDCAKNgIMQdSiAkHEADYCAEEBIRIgCiEJDAYLIAAgD2ogECALdjoAACAPQQFqIQ8LIApBAWoiCSADSQ0CDAMLIApBAWoiCiADSQ0ACwsgAyAJQQFqIgAgACADSRshCQsgDCAJNgIMCwJAIAtBBEsEQEEAIQBBfyEKDAELQX8hCkEAIQAgEiAQQX8gC3RBf3Nxcg0AIAdBAnFFBEACfyACIQcgAyEJIAQhAQJAIAtBAXYiDQRAIAwoAgwhCgNAIAkgCk0EQEHEACEIDAMLAkAgByAKaiwAACILQT1GBEAgDUEBayENDAELQRwhCCABRQ0DIAEgCxBdRQ0DCyAMIApBAWoiCjYCDCANDQALC0EADAELQdSiAiAINgIAQX8LIgoNASAMKAIMIQkLQQAhCiAERSADIAlNckUEQAJAIAQgAiAJaiwAABBdRQ0AIANBAWshAANAIAAgCUcEQCAEIAIgCUEBaiIJaiwAABBdDQEMAgsLIAMhCQsgDCAJNgIMCyAPIQALIAwoAgwhAQJAIAYEQCAGIAEgAmo2AgAMAQsgASADRg0AQdSiAkEcNgIAQX8hCgsgBQRAIAUgADYCAAsgDEEQaiQAIAoL2wMBBn8gBBCvASADQQNuIgVBAnQhBgJAIAVBfWwgA2oiBUUNACAEQQJxRQRAIAZBBGohBgwBCyAGQQJyIAVBAXZqIQYLAkACQAJ/AkAgASAGSwRAAkAgBEEEcQRAIANFDQVBCCEFQQAhBAwBCyADRQ0EQQghBUEAIQQMAgsDQCAHIAIgCGotAAAiCnIhCQNAIAAgBGogCSAFIgdBBmsiBXZBP3EQsAI6AAAgBEEBaiEEIAVBBUsNAAsgAyAIQQFqIghHBEAgBUEIaiEFIAlBCHQhBwwBCwsgBUUNBCAKQQwgB2t0QT9xELACDAILEBgACwNAIAcgAiAIai0AACIKciEJA0AgACAEaiAJIAUiB0EGayIFdkE/cRCvAjoAACAEQQFqIQQgBUEFSw0ACyADIAhBAWoiCEcEQCAFQQhqIQUgCUEIdCEHDAELCyAFRQ0CIApBDCAHa3RBP3EQrwILIQUgACAEaiAFOgAAIARBAWohBAwBC0EAIQQLAkACQCAEIAZNBEAgBCAGSQ0BIAQhBgwCC0EAIgBB0AhqIABBsQlqQeYBIABB4QtqEAAACyAAIARqQT0gBiAEaxAWGgsgACAGakEAIAEgBkEBaiICIAEgAksbIAZrEBYaIAALEAAgAEF5cUEBRwRAEBgACwtWAQF/IwBBQGoiAyQAIAMgAkIgEF4aIAEgAykDGDcAGCABIAMpAxA3ABAgASADKQMINwAIIAEgAykDADcAACADQcAAEAwgACABEH8hACADQUBrJAAgAAsRACAAIAEgAiADQgAgBBC2AgtQAQF/IwBBQGoiAiQAIAIgAUHAABAXIgEQUiAAIAEpAxg3ABggACABKQMQNwAQIAAgASkDCDcACCAAIAEpAwA3AAAgAUHAABAMIAFBQGskAAv0AQIEfwJ+IwBBgAFrIgMkACADQgA3A2ggA0IANwNwIANCADcDeCADQgA3A2AgAyABKQAQNwNQIAMgASkAGDcDWCABKQAIIQcgASkAACEIIANCADcDKCADQgA3AzAgA0IANwM4IAMgCDcDQCADIAc3A0ggA0IANwMgIAMgAikAEDcDECADIAIpABg3AxggAyACKQAANwMAIAMgAikACDcDCCADQUBrIQUgAyEBQQAhAgNAIAIgBWoiBiABIAJqLQAAIAQgBi0AAGpqIgQ6AAAgBEEIdiEEIAJBAWoiAkEgRw0ACyAAIANBQGsQsgEgA0GAAWokAAvbAQECfyMAQYABayICJAAgAkIANwNQIAJCADcDWCACQgA3AyggAkIANwMwIAJCADcDOCACQbCRAiIDKQMINwNoIAIgAykDEDcDcCACIAMpAxg3A3ggAkIANwNAIAJCADcDSCACQgA3AyAgAiADKQMANwNgIAIgASkAEDcDECACIAEpABg3AxggAiABKQAANwMAIAIgASkACDcDCCACQUBrIAIQjgIgAkFAaxBSIAAgAikDWDcAGCAAIAIpA1A3ABAgACACKQNINwAIIAAgAikDQDcAACACQYABaiQACycAIAJCgICAgBBaBEAQGAALIAAgASACIAMgBCAFQZicAigCABEPAAsjACABQoCAgIAQWgRAEBgACyAAIAEgAiADQZCcAigCABEMAAsUACAAIAEgAiADQYScAigCABEMAAvMBgEkfyACKAAAIRkgAigABCEaIAIoAAghGyACKAAMIRwgAigAECEdIAIoABghHiACKAAcIR8gAigAFCIjIQIgHiEFIB8hDAJ/IANFBEBB5fDBiwYhEkGy2ojLByETQe7IgZkDIRRB9MqB2QYMAQsgAygAACESIAMoAAQhFCADKAAIIRMgAygADAsiJCEDIB0hDSATIQ4gASgADCIgIQogASgACCIlIQsgASgABCImIQcgASgAACInIQEgFCEPIBwhECAbIQggGiEJIBkhESASIQYCQCAEQQFIDQBBAiEVICAhCgNAIAIgBmpBBxAJIBBzIhYgBmpBCRAJIAtzIiEgFmpBDRAJIAJzIiggIWpBEhAJIQsgDyARakEHEAkgCnMiFyAPakEJEAkgBXMiIiAXakENEAkgEXMiBSAiakESEAkhECABIA5qQQcQCSAMcyIYIA5qQQkQCSAJcyIJIBhqQQ0QCSABcyIBIAlqQRIQCSEKIAMgDWpBBxAJIAhzIgggA2pBCRAJIAdzIgcgCGpBDRAJIA1zIgwgB2pBEhAJIQIgCCAGIAtzIgZqQQcQCSAFcyIRIAZqQQkQCSAJcyIJIBFqQQ0QCSAIcyIIIAlqQRIQCSAGcyEGIA8gEHMiBSAWakEHEAkgAXMiASAFakEJEAkgB3MiByABakENEAkgFnMiECAHakESEAkgBXMhDyAKIA5zIgUgF2pBBxAJIAxzIg0gBWpBCRAJICFzIgsgDWpBDRAJIBdzIgogC2pBEhAJIAVzIQ4gAiADcyIDIBhqQQcQCSAocyICIANqQQkQCSAicyIFIAJqQQ0QCSAYcyIMIAVqQRIQCSADcyEDIAQgFUwNASAVQQJqIRUMAAsACyAAIAYgEmoQDyAAQQRqIBEgGWoQDyAAQQhqIAkgGmoQDyAAQQxqIAggG2oQDyAAQRBqIBAgHGoQDyAAQRRqIA8gFGoQDyAAQRhqIAEgJ2oQDyAAQRxqIAcgJmoQDyAAQSBqIAsgJWoQDyAAQSRqIAogIGoQDyAAQShqIA4gE2oQDyAAQSxqIA0gHWoQDyAAQTBqIAIgI2oQDyAAQTRqIAUgHmoQDyAAQThqIAwgH2oQDyAAQTxqIAMgJGoQDwv7AQEDfyMAQaACayIDJAAgA0HwAWogAhAOIANB8AFqIANB8AFqIAIQCiAAIANB8AFqEA4gACAAIAIQCiAAIAAgARAKIAAgABCEASAAIAAgA0HwAWoQCiAAIAAgARAKIANBwAFqIAAQDiADQcABaiADQcABaiACEAogA0GQAWogA0HAAWogARAVIANB4ABqIANBwAFqIAEQEyADQTBqIAFBsBEiAhAKIANBMGogA0HAAWogA0EwahATIANBkAFqEC8hBCADQeAAahAvIQEgA0EwahAvIQUgAyAAIAIQCiAAIAMgASAFchAkIAAgABCCASADQaACaiQAIAEgBHILUgEDfyAALQAfQX9zQf8AcSEBQR4hAgNAIAEgACACai0AAEF/c3IhASACQQFrIgMhAiADDQALIAFB/wFxQQFrQewBIAAtAABrcUEIdkF/c0EBcQuoBAEEfyMAQaABayIDJAAjAEHgDWsiASQAIAFB4ANqIAAQGiABQcACaiAAED4gASABQcACahAUIAFBwAJqIAEgAUHgA2oQGyABQaABaiABQcACahAUIAFBgAVqIgAgAUGgAWoQGiABQcACaiABIAAQGyABQaABaiABQcACahAUIAFBoAZqIgAgAUGgAWoQGiABQcACaiABIAAQGyABQaABaiABQcACahAUIAFBwAdqIgAgAUGgAWoQGiABQcACaiABIAAQGyABQaABaiABQcACahAUIAFB4AhqIgAgAUGgAWoQGiABQcACaiABIAAQGyABQaABaiABQcACahAUIAFBgApqIgAgAUGgAWoQGiABQcACaiABIAAQGyABQaABaiABQcACahAUIAFBoAtqIgAgAUGgAWoQGiABQcACaiABIAAQGyABQaABaiABQcACahAUIAFBwAxqIAFBoAFqEBogAyIEELwBQfwBIQIDQCABQcACaiAEED4CQCACIgBBgIwCaiwAACICQQFOBEAgAUGgAWogAUHAAmoQFCABQcACaiABQaABaiABQeADaiACQf4BcUEBdkGgAWxqEBsMAQsgAkF/Sg0AIAFBoAFqIAFBwAJqEBQgAUHAAmogAUGgAWogAUHgA2pBACACa0H+AXFBAXZBoAFsahCDAQsgBCABQcACahAUIABBAWshAiAADQALIAFB4A1qJAAgAxAvIQAgA0GgAWokACAACx0AIAAQSSAAQShqEBwgAEHQAGoQHCAAQfgAahBJCywBAn8jAEEQayIAJAAgAEEAOgAPQZycAiAAQQ9qQQAQAiEBIABBEGokACABC4sBAQR/IwBBMGsiBSQAIAAgAUEoaiIDIAEQEyAAQShqIgQgAyABEBUgAEHQAGoiAyAAIAIQCiAEIAQgAkEoahAKIABB+ABqIgYgAkHQAGogAUH4AGoQCiAFIAFB0ABqIgEgARATIAAgAyAEEBUgBCADIAQQEyADIAUgBhATIAYgBSAGEBUgBUEwaiQACwMAAQvTAgEDfyMAQaACayICJAAgAEEoaiIDIAEQNyAAQdAAaiIEEBwgAkHwAWogAxAOIAJBwAFqIAJB8AFqQYAREAogAkHwAWogAkHwAWogBBAVIAJBwAFqIAJBwAFqIAQQEyACQZABaiACQcABahAOIAJBkAFqIAJBkAFqIAJBwAFqEAogACACQZABahAOIAAgACACQcABahAKIAAgACACQfABahAKIAAgABCEASAAIAAgAkGQAWoQCiAAIAAgAkHwAWoQCiACQeAAaiAAEA4gAkHgAGogAkHgAGogAkHAAWoQCiACQTBqIAJB4ABqIAJB8AFqEBUCfyACQTBqEC9FBEAgAiACQeAAaiACQfABahATQX8gAhAvRQ0BGiAAIABBsBEQCgsgABBBIAEtAB9BB3ZGBEAgACAAEC4LIABB+ABqIAAgAxAKQQALIQAgAkGgAmokACAACxAAIABCADcCACAAQgA3AggLzgIBCX8gACABKAIgIgIgASgCHCIDIAEoAhgiBCABKAIUIgUgASgCECIGIAEoAgwiByABKAIIIgggASgCBCIJIAEoAgAiCiABKAIkIgFBE2xBgICACGpBGXZqQRp1akEZdWpBGnVqQRl1akEadWpBGXVqQRp1akEZdWpBGnUgAWpBGXVBE2wgCmoiCkH///8fcTYCACAAIAkgCkEadWoiCUH///8PcTYCBCAAIAggCUEZdWoiCEH///8fcTYCCCAAIAcgCEEadWoiB0H///8PcTYCDCAAIAYgB0EZdWoiBkH///8fcTYCECAAIAUgBkEadWoiBUH///8PcTYCFCAAIAQgBUEZdWoiBEH///8fcTYCGCAAIAMgBEEadWoiA0H///8PcTYCHCAAIAIgA0EZdWoiAkH///8fcTYCICAAIAEgAkEadWpB////D3E2AiQLBQBBgAILFAAgACABIAIgA0HomwIoAgARDQALrAMCDH8EfiAAKQM4Ig5QRQRAIAAgDqciA2oiAkFAa0EBOgAAIA5CAXxCD1gEQCACQcEAakEAQQ8gA2sQFhoLIABBAToAUCAAIABBQGtCEBCFAQsgADUCNCEOIAA1AjAhDyAANQIsIRAgASAANQIoIAAoAiQgACgCICAAKAIcIAAoAhgiA0EadmoiAkEadmoiBEEadmoiB0GAgIBgciAEQf///x9xIgggAkH///8fcSIFIAAoAhQgB0EadkEFbGoiAkH///8fcSIJQQVqIgpBGnYgA0H///8fcSACQRp2aiICaiIGQRp2aiILQRp2aiIMQRp2aiIEQR91IgMgAnEgBiAEQR92QQFrIgZB////H3EiAnFyIg1BGnQgAiAKcSADIAlxcnKtfCIRpxAPIAFBBGogECADIAVxIAIgC3FyIgVBFHQgDUEGdnKtfCARQiCIfCIQpxAPIAFBCGogDyADIAhxIAIgDHFyIgJBDnQgBUEMdnKtfCAQQiCIfCIPpxAPIAFBDGogDiAEIAZxIAMgB3FyQQh0IAJBEnZyrXwgD0IgiHynEA8gAEHYABAMC/UBAQN+AkAgACkDOCIEUEUEQCACQhAgBH0iAyACIANUGyIFUEUEQEIAIQMDQCAAIAMgBHynakFAayABIAOnai0AADoAACAAKQM4IQQgA0IBfCIDIAVSDQALCyAAIAQgBXwiAzcDOCADQhBUDQEgACAAQUBrQhAQhQEgAEIANwM4IAIgBX0hAiABIAWnaiEBCyACQhBaBEAgACABIAJCcIMiAxCFASACQg+DIQIgASADp2ohAQsgAlANAEIAIQMDQCAAIAApAzggA3ynakFAayABIAOnai0AADoAACADQgF8IgMgAlINAAsgACAAKQM4IAJ8NwM4CwuyAQEBfyAAIAEoAABB////H3E2AgAgACABKAADQQJ2QYP+/x9xNgIEIAAgASgABkEEdkH/gf8fcTYCCCAAIAEoAAlBBnZB///AH3E2AgwgASgADCECIABCADcCFCAAQgA3AhwgAEEANgIkIAAgAkEIdkH//z9xNgIQIAAgASgAEDYCKCAAIAEoABQ2AiwgACABKAAYNgIwIAEoABwhASAAQQA6AFAgAEIANwM4IAAgATYCNAswAQJ/IwAiBUGAAWtBQHEiBCQAIAQgAxDHASAEIAEgAhDGASAEIAAQxQEgBSQAQQALDAAgACABQcAAEIYBCykBAn8DQCAAIAJBA3QiA2ogASADaikAADcDACACQQFqIgJBgAFHDQALC3YBAX8gACECAkAgAUEEcUUNACACKAIAIgEEQCABKAIEIAIoAhBBCnQQDAsgAigCBCIBRQ0AIAEgAigCFEEDdBAMCyAAKAIEECIgAEEANgIEAkAgACgCACIBRQ0AIAEoAgAiAkUNACACECILIAEQIiAAQQA2AgALFwAgACABIAKtIAOtQiCGhCAEIAUQsQELFQAgACABrSACrUIghoQgAyAEELcCCxMAIAAgASACrSADrUIghoQQ1gMLFQAgACABIAKtIAOtQiCGhCAEEPMBCxcAIAAgASACIAOtIAStQiCGhCAFEJoCCxcAIAAgASACIAOtIAStQiCGhCAFENkDCxcAIAAgASACIAOtIAStQiCGhCAFEPYDCxUAIAAgASACrSADrUIghoQgBBDLAwuuAQECfyABQQFrQT9LIAVBwABLcgR/QX8FAn8jACIIIQkgCEGAA2tBQHEiCCQAQQEgAiADUBtFIABFIAFB/wFxIgFBAWtB/wFxQcAAT3JyIARBASAFQf8BcSIFG0UgBUHBAE9yckUEQAJAIAUEQCAIIAEgBCAFIAYgBxDdARoMAQsgCCABIAYgBxDtARoLIAggAiADEFcaIAggACABEIoBGiAJJABBAAwBCxAYAAsLCx8AIAAgASACrSADrUIghoQgBK0gBa1CIIaEIAYQoAILEgAgACABIAKtIAOtQiCGhBARCxQAIAAgASACrSADrUIghoQgBBBnCxUAIAAgASACrSADrUIghoQgBBDEAQsXACAAIAEgAq0gA61CIIaEIAQgBRC6AwsSACAAIAEgAq0gA61CIIaEEF4LGQAgACABIAKtIAOtQiCGhCAEIAUgBhD/AwsZACAAIAEgAq0gA61CIIaEIAQgBSAGEIAEC4gCAQF/IwBBwAFrIgYkACACRSABQQFrQf8BcUHAAE9yIANFIANBwQBPcnJFBEAgBkGBAjsBggEgBiADOgCBASAGIAE6AIABIAZBgAFqQQRyEGsgBkGAAWpBCHJCABAZIAZCADcDmAEgBkIANwOQAQJAIAQEQCAGQYABaiAEEOkBDAELIAZCADcDqAEgBkIANwOgAQsCQCAFBEAgBkGAAWogBRDmAQwBCyAGQgA3A7gBIAZCADcDsAELIAAgBkGAAWoQbCADIAZqQQBBAEGAASADayADQRh0QRh1QQBIGxAWGiAAIAYgAiADEBciAEKAARBXGiAAQYABEAwgAEHAAWokAEEADwsQGAALFQAgACABIAKtIAOtQiCGhCAEELgDCxUAIAAgASACrSADrUIghoQgBBDgAQs0AQF/IwBBoANrIgQkACAEIANBIBDjARogBCABIAIQ4gEaIAQgABDhARogBEGgA2okAEEAC0YBAX8jAEFAaiICJAAgACACEKQBGiABIAIpAxg3ABggASACKQMQNwAQIAEgAikDCDcACCABIAIpAwA3AAAgAkFAayQAQQALCwAgACABIAIQpQELCwAgACABIAIQpgELrQEBAX8jAEHAAWsiBCQAIAJFIAFBAWtB/wFxQcAAT3IgA0UgA0HBAE9yckUEQCAEQYECOwGCASAEIAM6AIEBIAQgAToAgAEgBEGAAWpBBHIQayAEQYABakEIckIAEBkgBEGQAWpBAEEwEBYaIAAgBEGAAWoQbCADIARqQQBBgAEgA2sQFhogACAEIAIgAxAXIgBCgAEQVxogAEGAARAMIABBwAFqJABBAA8LEBgACysBAn8DQCAAIAJqIgMgAy0AACABIAJqLQAAczoAACACQQFqIgJBCEcNAAsLFgAgACABKQAANwAwIAAgASkACDcAOAsqAQF/QX8hBiACQhBaBH8gACABQRBqIAEgAkIQfSADIAQgBRDoAQUgBgsLPgECfyMAQSBrIgckAEF/IQggByAFIAYQlgFFBEAgACABIAIgAyAEIAcQkgEhCCAHQSAQDAsgB0EgaiQAIAgLFgAgACABKQAANwAgIAAgASkACDcAKAslACACQvD///8PWgRAEBgACyAAQRBqIAAgASACIAMgBCAFEOsBCz4BAn8jAEEgayIHJABBfyEIIAcgBSAGEJYBRQRAIAAgASACIAMgBCAHEJMBIQggB0EgEAwLIAdBIGokACAICwgAIAAgARB4C6IBAQF/IwBBQGoiBCQAIAFBAWtB/wFxQcAASQRAIARBAToAAyAEQYACOwABIAQgAToAACAEQQRyEGsgBEEIckIAEBkgBEIANwMYIARCADcDEAJAIAIEQCAEIAIQ6QEMAQsgBEIANwMoIARCADcDIAsCQCADBEAgBCADEOYBDAELIARCADcDOCAEQgA3AzALIAAgBBBsIARBQGskAEEADwsQGAALNAEBfyMAQSBrIgYkACAGIAMgBUEAEDUaIAAgASACIANBEGogBCAGEFAhACAGQSBqJAAgAAstAQF/IwBBQGoiAyQAIAAgAxAyGiABIANCwAAgAkEBEPQBIQAgA0FAayQAIAALLwEBfyMAQUBqIgQkACAAIAQQMhogASACIARCwAAgA0EBEJsCIQAgBEFAayQAIAALCQAgABBGGkEACwUAQb9/Cw8AIAAgASACIANBABD0AQvGCAEIfyMAQdAEayIFJABBfyEGAkAgAEEgaiIIEMwCRQ0AIAAQZA0AIAMQugFFDQAgAxBkDQAgBUGAAWogAxDAAQ0AIAVBgANqIAQQpwEgBUGAA2ogAEIgECUaIAVBgANqIANCIBAlGiAFQYADaiABIAIQJRogBUGAA2ogBUHAAmoQMhogBUHAAmoQUiMAQeARayIEJAAgBEHgD2ogBUHAAmoQ0wIgBEHgDWogCBDTAiAEQeADaiAFQYABaiIBEBogBEHAAmogARA+IAQgBEHAAmoQFCAEQcACaiAEIARB4ANqEBsgBEGgAWogBEHAAmoQFCAEQYAFaiIBIARBoAFqEBogBEHAAmogBCABEBsgBEGgAWogBEHAAmoQFCAEQaAGaiIBIARBoAFqEBogBEHAAmogBCABEBsgBEGgAWogBEHAAmoQFCAEQcAHaiIBIARBoAFqEBogBEHAAmogBCABEBsgBEGgAWogBEHAAmoQFCAEQeAIaiIBIARBoAFqEBogBEHAAmogBCABEBsgBEGgAWogBEHAAmoQFCAEQYAKaiIBIARBoAFqEBogBEHAAmogBCABEBsgBEGgAWogBEHAAmoQFCAEQaALaiIBIARBoAFqEBogBEHAAmogBCABEBsgBEGgAWogBEHAAmoQFCAEQcAMaiAEQaABahAaIAVBCGoiCBBJIAhBKGoQHCAIQdAAahAcQf8BIQMCQANAAkAgAyIBIARB4A9qai0AAA0AIARB4A1qIAFqLQAADQAgAUEBayEDIAENAQwCCwsgAUEASA0AA0AgBEHAAmogCBAtAkAgASIDIARB4A9qaiwAACIBQQFOBEAgBEGgAWogBEHAAmoQFCAEQcACaiAEQaABaiAEQeADaiABQf4BcUEBdkGgAWxqEBsMAQsgAUF/Sg0AIARBoAFqIARBwAJqEBQgBEHAAmogBEGgAWogBEHgA2pBACABa0H+AXFBAXZBoAFsahCDAQsCQCAEQeANaiADaiwAACIHQQFOBEAgBEGgAWogBEHAAmoQFCAEQcACaiAEQaABaiAHQf4BcUEBdkH4AGxBkBJqEL4BDAELIAdBf0oNACAEQaABaiAEQcACahAUIwBBMGsiCyQAIARBwAJqIgEgBEGgAWoiCUEoaiIKIAkQEyABQShqIgYgCiAJEBUgAUHQAGoiCiABQQAgB2tB/gFxQQF2QfgAbEGQEmoiDEEoahAKIAYgBiAMEAogAUH4AGoiByAMQdAAaiAJQfgAahAKIAsgCUHQAGoiCSAJEBMgASAKIAYQFSAGIAogBhATIAogCyAHEBUgByALIAcQEyALQTBqJAALIAggBEHAAmoQNCADQQFrIQEgA0EASg0ACwsgBEHgEWokACAFQaACaiAFQQhqEEBBfyAFQaACaiAAEGggBUGgAmogAEYbIAAgBUGgAmpBIBBFciEGCyAFQdAEaiQAIAYLYQEBfyMAQUBqIgIkACABQQFrQf8BcUHAAE8EQBAYAAsgAkEBOgADIAJBgAI7AAEgAiABOgAAIAJBBHIQayACQQhyQgAQGSACQRBqQQBBMBAWGiAAIAIQbCACQUBrJABBAAssAQF/IwBBIGsiAiQAIAJBIBAnIAAgASACEJcBGiACQSAQDCACQSBqJABBAAt1AQJ/IwBBoAFrIgQkAANAIAAgA2ogASADai0AADoAACADQQFqIgNBIEcNAAsgAgRAIAAQ+QELIAAgAC0AH0H/AHE6AB8gBCAAEGYgACAEEEBBfyEDIAAQ+AFFBEBBf0EAIAFBIBA5GyEDCyAEQaABaiQAIAMLRwECfyAALQAAQQFzIQFBASECA0AgACACai0AACABciEBIAJBAWoiAkEfRw0ACyAALQAfQf8AcSABQf8BcXJBAWtBCHZBAXELHgAgACAALQAAQfgBcToAACAAIAAtAB9BwAByOgAfC6MBAQJ/IwBBwAJrIgQkAEF/IQUCQCACELoBRQ0AIAIQZA0AIAQgAhBCDQAgBBC7AUUNAEEAIQIDQCAAIAJqIAEgAmotAAA6AAAgAkEBaiICQSBHDQALIAMEQCAAEPkBCyAAIAAtAB9B/wBxOgAfIARBoAFqIAAgBBDRAiAAIARBoAFqEEAgABD4AQ0AQX9BACABQSAQORshBQsgBEHAAmokACAFCyYBAX8DQCAAIAFqLQAARQRAIAEPCyABQQFqIgFB5gBHDQALQeYACwcAQYCAgAgLRAECfyMAQRBrIgkkAEF/IQogCRCeAUUEQEF/IAkgACABIAIgAyAEIAUgBiAHIAgQiAIgCRCdARshCgsgCUEQaiQAIAoLdAEFfwJAA0BBACEFQQAhAyAEQSBPDQEDQAJAIANBCGohBiAEQQFqIQcgAiAEai0AACADdCAFciEFIANBD0sNACAGIQMgByIEQSBJDQELCyAAIAFqIAAgASAFIAYQmQEiAGshASAHIQQgAA0AC0EAIQALIAALkgICB38BfiMAQTBrIgUkAAJAIAMgBUEMaiAFQQhqIAVBBGoQggIiBkUNACAGIANrIQkgBTUCDCEMIAkCfwJ/IAYhByAGECtBAWohCANAQQAgCEUNARogByAIQQFrIghqIgotAABBJEcNAAsgCgsiBwRAIAcgBmsMAQsgBhArCyIHaiIIQS1qIglB5gBLIAcgCUtyDQAgACABIAIgBiAHQgEgDIYgBSgCCCAFKAIEIAVBEGpBIBCIAg0AIAQgAyAIEBciACAIaiIBQSQ6AAAgAUEBaiIBIABB5gBqIgIgAWsgBUEQahD+ASEBIAVBEGpBIBAMIAFFIAEgAk9yDQAgAUEAOgAAIAAhCwsgBUEwaiQAIAsLZgEEfyMAQRBrIgMkAAJAA0AgA0EMaiABLQAAEIECBEBBACEBIABBADYCAAwCCyABQQFqIQEgAygCDCACdCAEciEEIAJBGEkhBSACQQZqIQIgBQ0ACyAAIAQ2AgALIANBEGokACABC6wBAQN/IAACf0GACCEAQcEAIQICQEGACC0AACABQf8BcUYNACABQf8BcUGBgoQIbCEDA0AgACgCACADcyIEQX9zIARBgYKECGtxQYCBgoR4cQ0BIABBBGohACACQQRrIgJBA0sNAAsLIAIEQCABQf8BcSEBA0AgACABIAAtAABGDQIaIABBAWohACACQQFrIgINAAsLQQALIgBBgAhrQQAgABs2AgBBAEF/IAAbC0sBAX8CQCAALQAAQSRHDQAgAC0AAUE3Rw0AIAAtAAJBJEcNACABIAAtAAMQgQINACACIABBBGoQgAIiAEUNACADIAAQgAIhBAsgBAu0BQEXfyMAQUBqIgEkACABIAAQbSABKAIcIQcgASgCDCEIIAEoAiwhAyABKAI8IQQgASgCCCEJIAEoAjghEiABKAIYIQUgASgCKCENIAEoAjQhECABKAIkIRMgASgCBCEGIAEoAhQhDiABKAIgIQwgASgCECEKIAEoAjAhDyABKAIAIQIDQCAGIA5qQQd3IBNzIgsgDmpBCXcgEHMiFCACIA9qQQd3IApzIgogAmpBCXcgDHMiFSAKakENdyAPcyIWIAMgBGpBB3cgCHMiCCAEakEJdyAHcyIHIAhqQQ13IANzIgwgB2pBEncgBHMiBCAFIA1qQQd3IBJzIgNqQQd3cyIPIARqQQl3cyIQIA9qQQ13IANzIhIgEGpBEncgBHMhBCAMIAMgAyANakEJdyAJcyIJakENdyAFcyIXIAlqQRJ3IA1zIgUgC2pBB3dzIgMgBWpBCXcgFXMiDCADakENdyALcyITIAxqQRJ3IAVzIQ0gByAXIBQgCyAUakENdyAGcyILakESdyAOcyIGIApqQQd3cyIFIAZqQQl3cyIHIAVqQQ13IApzIgogB2pBEncgBnMhDiAIIBUgFmpBEncgAnMiAmpBB3cgC3MiBiACakEJdyAJcyIJIAZqQQ13IAhzIgggCWpBEncgAnMhAiARQQZJIQsgEUECaiERIAsNAAsgASAPNgIwIAEgDDYCICABIAo2AhAgASAONgIUIAEgEDYCNCABIBM2AiQgASAGNgIEIAEgDTYCKCABIBI2AjggASAFNgIYIAEgBDYCPCABIAk2AgggASADNgIsIAEgBzYCHCABIAg2AgwgASACNgIAIAAgACgCACACajYCAEEBIQIDQCAAIAJBAnQiA2oiBCAEKAIAIAEgA2ooAgBqNgIAIAJBAWoiAkEQRw0ACyABQUBrJAALMAEDfwNAIAAgAkECdCIDaiIEIAQoAgAgASADaigCAHM2AgAgAkEBaiICQRBHDQALC0MBA38gAkEETwRAIAJBAnYhA0EAIQIDQCAAIAJBAnQiBGoiBSAFKAIAIAEgBGooAgBzNgIAIAJBAWoiAiADRw0ACwsLEAAgAUEHdCAAakFAaikCAAs7AQJ/IAJBBE8EQCACQQJ2IQNBACECA0AgACACQQJ0IgRqIAEgBGooAgA2AgAgAkEBaiICIANHDQALCwvdBQIMfwN+IAetIAatfkKAgICABFoEQEHUogJBFjYCAEF/DwsgBUKAgICAEFoEQEHUogJBFjYCAEF/DwsgBUICWkEAIAV7QgJUG0UEQEHUogJBHDYCAEF/DwsgBkEAIAcbRQRAQdSiAkEcNgIAQX8PCwJAAkBB////DyAHbiAGSSAGQf///wdLckUEQEH///8PIAZurSAFWg0BCwwBCyAGQQd0IhQgB2wiDyAUIAWnbCILaiINIA9JDQAgDSANIAZBCHRBwAByaiIKSw0AAkAgCiAAKAIISwRAQX8hDCAAEI0CDQEjAEEQayINJABB1KICIA1BDGogChCxAiIONgIAIABBACANKAIMIA4bIg42AgQgACAONgIAIAAgCkEAIA4bNgIIIA1BEGokACAORQ0BCyABIAIgAyAEIAAoAgQiEiAPEIkCIA8gEmoiDSALaiEOQQAhAANAIBIgACAUbGohFSAOIQNBACEKQQAhEyAGIgRBBXQiDARAA0AgAyAKQQJ0IgtqIAsgFWooAAA2AgAgCkEBaiIKIAxHDQALCyANIQoCQCAFIhdQDQAgAyAEQQh0aiEQIAMgBEEHdCIRaiELQgIhFgNAIAogDCATbEECdGogAyAREIcCIAMgCyAQIAQQbiAKIBNBAXIgDGxBAnRqIAsgERCHAiALIAMgECAEEG4gFiAXVARAIBanIRMgFkICfCEWDAELCyAXQgF9IRhCAiEWA0AgAyAKIAwgAyAEEIYCIBiDp2xBAnRqIBEQhQIgAyALIBAgBBBuIAsgCiAMIAsgBBCGAiAYg6dsQQJ0aiAREIUCIAsgAyAQIAQQbiAWIBdaDQEgFkICfCEWDAALAAsgDARAQQAhCgNAIBUgCkECdCIEaiADIARqKAIAEA8gCkEBaiIKIAxHDQALCyAAQQFqIgAgB0cNAAsgASACIBIgDyAIIAkQiQJBACEMCyAMDwtB1KICQTA2AgBBfwvgAQECfyMAQfADayIGJAAgBkGgAmogACABEJwBGiAGQaACaiACIAOtEG8aAkAgBUUNAEEBIQMDQCAGQcwAaiADEIsCIAZB0ABqIAZBoAJqQdABEBcaIAZB0ABqIAZBzABqQgQQbxogBkHQAGogBkEgahCbARogBiAGKQM4NwMYIAYgBikDMDcDECAGIAYpAyg3AwggBiAGKQMgNwMAIAQgB2ogBiAFIAdrIgBBICAAQSBJGxAXGiADQQV0IgcgBU8NASADQQFqIQMMAAsACyAGQaACakHQARAMIAZB8ANqJAALMwEBfyMAQdABayIEJAAgBCADQSAQnAEaIAQgASACEG8aIAQgABCbARogBEHQAWokAEEACykAIAAgAUEIdEGAgPwHcSABQRh0ciABQQh2QYD+A3EgAUEYdnJyNgAACxAAIABBADYCCCAAQgA3AgALGQEBfyAAKAIAIgEEQCABECILIAAQjAJBAAs7AQN/A0AgACACaiIDIAMtAAAgBCABIAJqLQAAamsiAzoAACADQQh2QQFxIQQgAkEBaiICQcAARw0ACwt/AQF/IwBBgAdrIgIkACACQdAGaiABEDcgAkGgBmogAUEgahA3IAJBwAJqIAJB0AZqEMgCIAJBoAFqIAJBoAZqEMgCIAJBgAVqIAJBoAFqEBogAkHgA2ogAkHAAmogAkGABWoQGyACIAJB4ANqEBQgACACEGMgAkGAB2okAEEAC9UCAQJ/IwBBMGsiCCQAIAhBADYCCCAIQgA3AwAgCEEQaiAGIAdBABA1GiAIIAYpABA3AgQjAEHgAmsiByQAIAdBIGpCwAAgCCIGIAhBEGoiCRC2ARogB0HgAGogB0EgahAqGiAHQSBqQcAAEAwgB0HgAGogBCAFEBEaIAdB4ABqQeCYAkIAIAV9Qg+DEBEaIAdB4ABqIAEgAhARGiAHQeAAakHgmAJCACACfUIPgxARGiAHQRhqIAUQGSAHQeAAaiAHQRhqQggQERogB0EYaiACEBkgB0HgAGogB0EYakIIEBEaIAdB4ABqIAcQKRogB0HgAGpBgAIQDCAHIAMQVCEDIAdBEBAMAkAgAEUNACADBEAgAEEAIAKnEBYaQX8hAwwBCyAAIAEgAiAGQQEgCRC1ARpBACEDCyAHQeACaiQAIAMhACAIQRBqQSAQDCAIQTBqJAAgAAusAgEBfyMAQTBrIgkkACAJQQA2AgggCUIANwMAIAlBEGogByAIQQAQNRogCSAHKQAQNwIEIwBB0AJrIgckACAHQRBqQsAAIAkgCUEQaiIIELYBGiAHQdAAaiAHQRBqECoaIAdBEGpBwAAQDCAHQdAAaiAFIAYQERogB0HQAGpB4JgCQgAgBn1CD4MQERogACADIAQgCUEBIAgQtQEaIAdB0ABqIAAgBBARGiAHQdAAakHgmAJCACAEfUIPgxARGiAHQQhqIAYQGSAHQdAAaiAHQQhqQggQERogB0EIaiAEEBkgB0HQAGogB0EIakIIEBEaIAdB0ABqIAEQKRogB0HQAGpBgAIQDCACBEAgAkIQNwMACyAHQdACaiQAIAlBEGpBIBAMIAlBMGokAEEACwQAQTALMgEDf0EBIQEDQCAAIAJqIgMgASADLQAAaiIBOgAAIAFBCHYhASACQQFqIgJBBEcNAAsLKgEBf0F/IQYgAkIQWgR/IAAgAUEQaiABIAJCEH0gAyAEIAUQlQIFIAYLCz4BAn8jAEEgayIHJABBfyEIIAcgBSAGEKEBRQRAIAAgASACIAMgBCAHEJ8BIQggB0EgEAwLIAdBIGokACAICyUAIAJC8P///w9aBEAQGAALIABBEGogACABIAIgAyAEIAUQlwILPgECfyMAQSBrIgckAEF/IQggByAFIAYQoQFFBEAgACABIAIgAyAEIAcQoAEhCCAHQSAQDAsgB0EgaiQAIAgLNAEBfyMAQaADayIEJAAgBCADQSAQpgEaIAQgASACEKUBGiAEIAAQpAEaIARBoANqJABBAAsFAEGgAwsUACAAIAEgAiADIARBABCbAhpBAAupIQI8fgF/IwBBsARrIkIkACBCQeACaiAFEKcBIEJBoAJqIARCIBBeGiBCQeACaiBCQcACakIgECUaIEJB4AJqIAIgAxAlGiBCQeACaiBCQeABahAyGiAEKQAgIQggBCkAKCEHIAQpADAhBiAAIAQpADg3ADggACAGNwAwIAAgBzcAKCAAQSBqIgQgCDcAACBCQeABahBSIEIgQkHgAWoQZiAAIEIQQCBCQeACaiAFEKcBIEJB4AJqIABCwAAQJRogQkHgAmogAiADECUaIEJB4AJqIEJBoAFqEDIaIEJBoAFqEFIgQiBCLQCgAkH4AXE6AKACIEIgQi0AvwJBP3FBwAByOgC/AiBCQaABaiIAEBAhECAANQACIS0gAEEFahAQIS4gADUAByEvIAA1AAohMCAAQQ1qEBAhNiAANQAPITcgAEESahAQITggAEEVahAQITkgADUAFyEPIABBGmoQECEJIAA1ABwhDCBCQaACaiIAEBAhMSAANQACITogAEEFahAQITsgADUAByEqIAA1AAohKyAAQQ1qEBAhPCAANQAPIQ4gAEESahAQIQ0gAEEVahAQIQggADUAFyEHIABBGmoQECEGIAA1ABwhAyBCQeABaiIAEBAhPiAANQACIT8gAEEFahAQIUAgADUAByFBIAA1AAohPSAAQQ1qEBAhESAANQAPISwgAEESahAQIQogAEEVahAQIQsgBCADQgeIIhIgCUICiEL///8AgyITfiAGQgKIQv///wCDIhQgDEIHiCIVfnwgEyAUfiAHQgWIQv///wCDIhYgFX58IBIgD0IFiEL///8AgyIXfnwiGEKAgEB9Ig9CFYd8IglCgIBAfSIMQhWHIBIgFX4iAyADQoCAQH0iA0KAgIB/g318IjJCg6FWfiADQhWHIjNC0asIfnwgPEIBiEL///8AgyIZIBN+ICtCBIhC////AIMiGiAVfnwgDkIGiEL///8AgyIbIBd+fCAIQv///wCDIhwgOEIDiEL///8AgyIdfnwgDUIDiEL///8AgyIeIDlC////AIMiH358IBYgN0IGiEL///8AgyIgfnwgFCA2QgGIQv///wCDIiF+fCASIDBCBIhC////AIMiIn58IBMgGn4gKkIHiEL///8AgyIjIBV+fCAXIBl+fCAbIB9+fCAcICB+fCAdIB5+fCAWICF+fCAUICJ+fCASIC9CB4hC////AIMiJH58IghCgIBAfSIHQhWHfCIDfCADQoCAQH0iBkKAgIB/g30gCCAzQtOMQ358IDJC0asIfnwgCSAMQoCAgH+DfSI0QoOhVn58IAdCgICAf4N9IBMgI34gO0ICiEL///8AgyIlIBV+fCAXIBp+fCAZIB9+fCAbIB1+fCAcICF+fCAeICB+fCAWICJ+fCAUICR+fCASIC5CAohC////AIMiJn58IBMgJX4gOkIFiEL///8AgyInIBV+fCAXICN+fCAaIB9+fCAZIB1+fCAbICB+fCAcICJ+fCAeICF+fCAWICR+fCAUICZ+fCASIC1CBYhC////AIMiKH58IjZCgIBAfSI3QhWHfCI4QoCAQH0iOUIVh3wiOkKAgEB9IjtCFYd8IipCgIBAfSIrQhWHIBMgG34gFSAZfnwgHCAffnwgFyAefnwgFiAdfnwgFCAgfnwgEiAhfnwiAyAzQoOhVn58IANCgIBAfSIHQoCAgH+DfSAGQhWHfCIDIANCgIBAfSIGQoCAgH+DfXwiNUKDoVZ+IBcgHH4gFSAbfnwgEyAefnwgFiAffnwgFCAdfnwgEiAgfnwgB0IVh3wiAyADQoCAQH0iDUKAgIB/g30gBkIVh3wiLULRqwh+fCAfICd+IDFC////AIMiKSAXfnwgHSAlfnwgICAjfnwgGiAhfnwgGSAifnwgGyAkfnwgHCAofnwgHiAmfnwgFiAQQv///wCDIhB+fCAANQAXQgWIQv///wCDfCAdICd+IB8gKX58ICAgJX58ICEgI358IBogIn58IBkgJH58IBsgJn58IBAgHH58IB4gKH58IAtC////AIN8IgtCgIBAfSIJQhWIfCIMIBggD0KAgIB/g30gEyAWfiAVIBx+fCAUIBd+fCASIB9+fCAVIB5+IBMgHH58IBYgF358IBQgH358IBIgHX58IghCgIBAfSIHQhWHfCIGQoCAQH0iA0IVh3wiLkKY2hx+IDRCk9gofnwgBiADQoCAgH+DfSIvQuf2J358IAggB0KAgIB/g30gDUIVh3wiMELTjEN+fHwgDEKAgEB9Ig5CgICAf4N9IC9CmNocfiAuQpPYKH58IDBC5/YnfnwgC3wgCUKAgIB/g30gICAnfiAdICl+fCAhICV+fCAiICN+fCAaICR+fCAZICZ+fCAbICh+fCAQIB5+fCAKQgOIQv///wCDfCAhICd+ICAgKX58ICIgJX58ICMgJH58IBogJn58IBkgKH58IBAgG358ICxCBohC////AIN8IgtCgIBAfSIJQhWIfCIMQoCAQH0iCEIViHwiB0KAgEB9IgZCFYd8IgN8IANCgIBAfSIPQoCAgH+DfSAHIC1C04xDfnwgMEKY2hx+IC9Ck9gofnwgDHwgCEKAgIB/g30gCyAwQpPYKH58ICIgJ34gISApfnwgJCAlfnwgIyAmfnwgGiAofnwgECAZfnwgEUIBiEL///8Ag3wgJCAnfiAiICl+fCAlICZ+fCAjICh+fCAQIBp+fCA9QgSIQv///wCDfCI8QoCAQH0iPUIViHwiEUKAgEB9IixCFYh8IAlCgICAf4N9IgpCgIBAfSIYQhWHfCINQoCAQH0iC0IVh3wgBkKAgIB/g30gNULRqwh+fCAqICtCgICAf4N9IjFCg6FWfnwiCUKAgEB9IgxCFYd8IghCgIBAfSIHQhWHIBcgJ34gEyApfnwgHyAlfnwgHSAjfnwgGiAgfnwgGSAhfnwgGyAifnwgHCAmfnwgHiAkfnwgFiAofnwgECAUfnwgAEEaahAQQgKIQv///wCDfCIDIDRCmNocfiAyQpPYKH58IC5C5/YnfnwgL0LTjEN+fCAwQtGrCH58fCAOQhWIfCADQoCAQH0iBkKAgIB/g30iAyAtQoOhVn58IA9CFYd8IANCgIBAfSIPQoCAgH+DfSIDfCADQoCAQH0iDkKAgIB/g30gCCAHQoCAgH+DfSAJIAxCgICAf4N9IA0gLULn9id+fCALQoCAgH+DfSA1QtOMQ358IDFC0asIfnwgOiA7QoCAgH+DfSAyQtOMQ34gM0Ln9id+fCA0QtGrCH58IC5Cg6FWfnwgOHwgOUKAgIB/g30gMkLn9id+IDNCmNocfnwgNELTjEN+fCA2fCAuQtGrCH58IC9Cg6FWfnwgN0KAgIB/g30gEyAnfiAVICl+fCAXICV+fCAfICN+fCAaIB1+fCAZICB+fCAbICF+fCAcICR+fCAeICJ+fCAWICZ+fCAQIBJ+fCAUICh+fCAANQAcQgeIfCAGQhWIfCINQoCAQH0iC0IVh3wiCUKAgEB9IgxCFYd8IgZCgIBAfSIDQhWHfCIqQoOhVn58IC1CmNocfiAKfCAYQoCAgH+DfSA1Quf2J358IDFC04xDfnwgKkLRqwh+fCAGIANCgICAf4N9IitCg6FWfnwiCEKAgEB9IgdCFYd8IgZCgIBAfSIDQhWHfCAGIANCgICAf4N9IAggB0KAgIB/g30gESAsQoCAgH+DfSAtQpPYKH58IDVCmNocfnwgMULn9id+fCAJIAxCgICAf4N9IDJCmNocfiAzQpPYKH58IDRC5/YnfnwgLkLTjEN+fCAvQtGrCH58IDBCg6FWfnwgDXwgC0KAgIB/g30gD0IVh3wiDUKAgEB9IgtCFYd8IgpCg6FWfnwgKkLTjEN+fCArQtGrCH58ICYgJ34gJCApfnwgJSAofnwgECAjfnwgQUIHiEL///8Ag3wgJyAofiAmICl+fCAQICV+fCBAQgKIQv///wCDfCIYQoCAQH0iD0IViHwiCUKAgEB9IgxCFYggPHwgPUKAgIB/g30gNUKT2Ch+fCAxQpjaHH58IApC0asIfnwgKkLn9id+fCArQtOMQ358IghCgIBAfSIHQhWHfCIGQoCAQH0iA0IVh3wgBiANIAtCgICAf4N9IA5CFYd8IhFCgIBAfSIsQhWHIg5Cg6FWfnwgA0KAgIB/g30gCCAOQtGrCH58IAdCgICAf4N9IAkgDEKAgIB/g30gMUKT2Ch+fCAKQtOMQ358ICpCmNocfnwgK0Ln9id+fCAYIBAgJ34gKCApfnwgP0IFiEL///8Ag3wgECApfiA+Qv///wCDfCINQoCAQH0iC0IViHwiCUKAgEB9IgxCFYh8IA9CgICA////D4N9IApC5/YnfnwgKkKT2Ch+fCArQpjaHH58IghCgIBAfSIHQhWHfCIGQoCAQH0iA0IVh3wgBiAOQtOMQ358IANCgICAf4N9IAggDkLn9id+fCAHQoCAgH+DfSAJIAxCgICA////D4N9IApCmNocfnwgK0KT2Ch+fCANIAtCgICA////A4N9IApCk9gofnwiCEKAgEB9IgdCFYd8IgZCgIBAfSIDQhWHfCAGIA5CmNocfnwgA0KAgIB/g30gCCAHQoCAgH+DfSAOQpPYKH58IgpCFYd8Ig5CFYd8IgZCFYd8IgNCFYd8IhhCFYd8Ig9CFYd8Ig1CFYd8IgtCFYd8IglCFYd8IgxCFYd8IghCFYcgESAsQoCAgH+DfXwiB0IVhyIRQpPYKH4gCkL///8Ag3wiLDwAACAEICxCCIg8AAEgBCARQpjaHH4gDkL///8Ag3wgLEIVh3wiCkILiDwABCAEIApCA4g8AAMgBCARQuf2J34gBkL///8Ag3wgCkIVh3wiDkIGiDwABiAEICxCEIhCH4MgCkL///8AgyIGQgWGhDwAAiAEIBFC04xDfiADQv///wCDfCAOQhWHfCIKQgmIPAAJIAQgCkIBiDwACCAEIA5C////AIMiA0IChiAGQhOIhDwABSAEIBFC0asIfiAYQv///wCDfCAKQhWHfCIYQgyIPAAMIAQgGEIEiDwACyAEIApC////AIMiBkIHhiADQg6IhDwAByAEIBFCg6FWfiAPQv///wCDfCAYQhWHfCIPQgeIPAAOIAQgGEL///8AgyIDQgSGIAZCEYiEPAAKIAQgDUL///8AgyAPQhWHfCINQgqIPAARIAQgDUICiDwAECAEIA9C////AIMiBkIBhiADQhSIhDwADSAEIAtC////AIMgDUIVh3wiC0INiDwAFCAEIAtCBYg8ABMgBCANQv///wCDIgNCBoYgBkIPiIQ8AA8gBCAJQv///wCDIAtCFYd8Igk8ABUgBCALQgOGIANCEoiEPAASIAQgCUIIiDwAFiAEIAxC////AIMgCUIVh3wiBkILiDwAGSAEIAZCA4g8ABggBCAIQv///wCDIAZCFYd8IgNCBog8ABsgBCAJQhCIQh+DIAZC////AIMiBkIFhoQ8ABcgBCAHQv///wCDIANCFYd8IgdCEYg8AB8gBCAHQgmIPAAeIAQgB0IBiDwAHSAEIANC////AIMiA0IChiAGQhOIhDwAGiAEIAdCB4YgA0IOiIQ8ABwgQkGgAmpBwAAQDCBCQeABakHAABAMIAEEQCABQsAANwMACyBCQbAEaiQAQQALEAAgACABIAIgAyAEIAUQagsFAEGAAwsFAEGpCgtGAAJAAkAgAkKAgICAEFoEQEHUogJBFjYCAAwBCyAAIAEgAqdBAhCtAiIARQ0BIABBXUcNAEHUogJBHDYCAAtBfyEACyAAC5wBAQF/IwBBEGsiBSQAIABBAEGAARAWIQACfyACQv////8PViADQv////8PVnJBASAEQYGAgIB4SRsEQEHUogJBFjYCAEF/DAELIANCACAEQf8/SxtQBEBB1KICQRw2AgBBfwwBCyAFQRAQJ0F/QQAgA6cgBEEKdkEBIAEgAqcgBUEQQQBBICAAQYABQQIQXBsLIQAgBUEQaiQAIAAL0AEBAX8gAEEAIAGnIggQFiEAAkAgAUKAgICAEFoEQEHUogJBFjYCAAwBCyABQg9YBEBB1KICQRw2AgAMAQsgA0L/////D1YgBUL/////D1ZyQQEgBkGBgICAeEkbBEBB1KICQRY2AgAMAQsgBUIAIAZB/z9LG1AEQEHUogJBHDYCAAwBCyAAIAJGBEBB1KICQRw2AgAMAQsgB0ECRgRAQX9BACAFpyAGQQp2QQEgAiADpyAEQRAgACAIQQBBAEECEFwbDwtB1KICQRw2AgALQX8LCABBgICAgAELBwBBgICAIAsFAEGXDAsNACAAIAEgAkECEKYCC6gCAgR/AX4jAEFAaiIEJAACQAJAAkAgAUL/////D1hBACAAECsiBkGAAUkbRQRAQdSiAkEcNgIADAELIARBADYCOCAEQgA3AzAgBEIANwMoAkACf0EAIAYiBUUNABogBa0iCKciByAFQQFyQYCABEkNABpBfyAHIAhCIIinGwsiBxAxIgVFDQAgBUEEay0AAEEDcUUNACAFQQAgBxAWGgsgBQ0BC0F/IQAMAQsgBEIANwMgIAQgBTYCCCAEIAU2AhAgBCAGNgIUIAQgBTYCACAEIAY2AgwgBEIANwMYIAQgBjYCBAJ/IAQgACADEK4CBEBB1KICQRw2AgBBfwwBC0EBIAQoAiggAadHDQAaIAQoAiwgAkEKdkcLIQAgBRAiCyAEQUBrJAAgAAsNACAAIAEgAkEBEKYCC0YAAkACQCACQoCAgIAQWgRAQdSiAkEWNgIADAELIAAgASACp0EBEK0CIgBFDQEgAEFdRw0AQdSiAkEcNgIAC0F/IQALIAALnwEBAX8jAEEQayIFJAAgAEEAQYABEBYhAAJ/IAJC/////w9WIANC/////w9WckEBIARBgYCAgHhJGwRAQdSiAkEWNgIAQX8MAQsgA0IDWkEAIARB/z9LG0UEQEHUogJBHDYCAEF/DAELIAVBEBAnQX9BACADpyAEQQp2QQEgASACpyAFQRBBAEEgIABBgAFBARBcGwshACAFQRBqJAAgAAvTAQEBfyAAQQAgAaciCBAWIQACQCABQoCAgIAQWgRAQdSiAkEWNgIADAELIAFCD1gEQEHUogJBHDYCAAwBCyADQv////8PViAFQv////8PVnJBASAGQYGAgIB4SRsEQEHUogJBFjYCAAwBCyAFQgNaQQAgBkH/P0sbRQRAQdSiAkEcNgIADAELIAAgAkYEQEHUogJBHDYCAAwBCyAHQQFGBEBBf0EAIAWnIAZBCnZBASACIAOnIARBECAAIAhBAEEAQQEQXBsPC0HUogJBHDYCAAtBfwsHAEGAgIAQC4sMAQZ/IAAgAWohBQJAAkAgACgCBCICQQFxDQAgAkEDcUUNASAAKAIAIgIgAWohAQJAIAAgAmsiAEHsogIoAgBHBEAgAkH/AU0EQCAAKAIIIgQgAkEDdiICQQN0QYCjAmpGGiAAKAIMIgMgBEcNAkHYogJB2KICKAIAQX4gAndxNgIADAMLIAAoAhghBgJAIAAgACgCDCIDRwRAIAAoAggiAkHoogIoAgBJGiACIAM2AgwgAyACNgIIDAELAkAgAEEUaiICKAIAIgQNACAAQRBqIgIoAgAiBA0AQQAhAwwBCwNAIAIhByAEIgNBFGoiAigCACIEDQAgA0EQaiECIAMoAhAiBA0ACyAHQQA2AgALIAZFDQICQCAAIAAoAhwiBEECdEGIpQJqIgIoAgBGBEAgAiADNgIAIAMNAUHcogJB3KICKAIAQX4gBHdxNgIADAQLIAZBEEEUIAYoAhAgAEYbaiADNgIAIANFDQMLIAMgBjYCGCAAKAIQIgIEQCADIAI2AhAgAiADNgIYCyAAKAIUIgJFDQIgAyACNgIUIAIgAzYCGAwCCyAFKAIEIgJBA3FBA0cNAUHgogIgATYCACAFIAJBfnE2AgQgACABQQFyNgIEIAUgATYCAA8LIAQgAzYCDCADIAQ2AggLAkAgBSgCBCICQQJxRQRAIAVB8KICKAIARgRAQfCiAiAANgIAQeSiAkHkogIoAgAgAWoiATYCACAAIAFBAXI2AgQgAEHsogIoAgBHDQNB4KICQQA2AgBB7KICQQA2AgAPCyAFQeyiAigCAEYEQEHsogIgADYCAEHgogJB4KICKAIAIAFqIgE2AgAgACABQQFyNgIEIAAgAWogATYCAA8LIAJBeHEgAWohAQJAIAJB/wFNBEAgBSgCCCIEIAJBA3YiAkEDdEGAowJqRhogBCAFKAIMIgNGBEBB2KICQdiiAigCAEF+IAJ3cTYCAAwCCyAEIAM2AgwgAyAENgIIDAELIAUoAhghBgJAIAUgBSgCDCIDRwRAIAUoAggiAkHoogIoAgBJGiACIAM2AgwgAyACNgIIDAELAkAgBUEUaiIEKAIAIgINACAFQRBqIgQoAgAiAg0AQQAhAwwBCwNAIAQhByACIgNBFGoiBCgCACICDQAgA0EQaiEEIAMoAhAiAg0ACyAHQQA2AgALIAZFDQACQCAFIAUoAhwiBEECdEGIpQJqIgIoAgBGBEAgAiADNgIAIAMNAUHcogJB3KICKAIAQX4gBHdxNgIADAILIAZBEEEUIAYoAhAgBUYbaiADNgIAIANFDQELIAMgBjYCGCAFKAIQIgIEQCADIAI2AhAgAiADNgIYCyAFKAIUIgJFDQAgAyACNgIUIAIgAzYCGAsgACABQQFyNgIEIAAgAWogATYCACAAQeyiAigCAEcNAUHgogIgATYCAA8LIAUgAkF+cTYCBCAAIAFBAXI2AgQgACABaiABNgIACyABQf8BTQRAIAFBA3YiAkEDdEGAowJqIQECf0HYogIoAgAiA0EBIAJ0IgJxRQRAQdiiAiACIANyNgIAIAEMAQsgASgCCAshAiABIAA2AgggAiAANgIMIAAgATYCDCAAIAI2AggPC0EfIQIgAEIANwIQIAFB////B00EQCABQQh2IgIgAkGA/j9qQRB2QQhxIgR0IgIgAkGA4B9qQRB2QQRxIgN0IgIgAkGAgA9qQRB2QQJxIgJ0QQ92IAMgBHIgAnJrIgJBAXQgASACQRVqdkEBcXJBHGohAgsgACACNgIcIAJBAnRBiKUCaiEHAkACQEHcogIoAgAiBEEBIAJ0IgNxRQRAQdyiAiADIARyNgIAIAcgADYCACAAIAc2AhgMAQsgAUEAQRkgAkEBdmsgAkEfRht0IQIgBygCACEDA0AgAyIEKAIEQXhxIAFGDQIgAkEddiEDIAJBAXQhAiAEIANBBHFqIgdBEGooAgAiAw0ACyAHIAA2AhAgACAENgIYCyAAIAA2AgwgACAANgIIDwsgBCgCCCIBIAA2AgwgBCAANgIIIABBADYCGCAAIAQ2AgwgACABNgIICwucAgEFfyMAQUBqIgQkACAEQQhqQQBBNBAWGiAEIAAQKyIFNgIUIAQgBTYCJCAEIAU2AgQgBCAFEDEiBjYCICAEIAUQMSIHNgIQIAQgBRAxIgg2AgACQAJAIAhFIAZFIAdFcnINACAFEDEiBUUNACAEIAAgAxCuAiIABEAgBCgCIBAiIAQoAhAQIiAEKAIAECIgBRAiDAILQQAhACAEKAIoIAQoAiwgBCgCNCABIAIgBCgCECAEKAIUIAUgBCgCBEEAQQAgAxBcIQEgBCgCIBAiIAQoAhAQIgJAIAFFBEAgBSAEKAIAIAQoAgQQRUUNAQtBXSEACyAFECIgBCgCABAiDAELIAYQIiAHECIgCBAiQWohAAsgBEFAayQAIAAL2QMBBH8jAEEQayIDJAAgACgCFCEFIABBADYCFCAAKAIEIQYgAEEANgIEQWYhBAJAAkACfwJAAkAgAkEBaw4CAQAEC0FgIQQgAUGNCUEJEDANAyABQQlqDAELQWAhBCABQYQJQQgQMA0CIAFBCGoLIgRBjgtBAxAwDQAgBEEDaiADQQxqEHYiAUUNAEFmIQQgAygCDEETRw0BIAFBmgtBAxAwDQAgAUEDaiADQQxqEHYiAUUNACAAIAMoAgw2AiwgAUGSC0EDEDANACABQQNqIANBDGoQdiIBRQ0AIAAgAygCDDYCKCABQZYLQQMQMA0AIAFBA2ogA0EMahB2IgFFDQAgACADKAIMIgI2AjAgACACNgI0IAEtAAAiAkEkRw0AIAMgBTYCDCAAKAIQIAUgAUEBaiABIAJBJEYbIgEgARArQQAgA0EMaiADQQhqQQMQrQENACAAIAMoAgw2AhQgAygCCCIBLQAAIgJBJEcNACADIAY2AgwgACgCACAGIAFBAWogASACQSRGGyIBIAEQK0EAIANBDGogA0EIakEDEK0BDQAgACADKAIMNgIEIAMoAgghASAAEIcBIgQNAUFgQQAgAS0AABshBAwBC0FgIQQLIANBEGokACAEC3oBAn8gAEHA/wBzQQFqQQh2QX9zQS9xIABBwf8Ac0EBakEIdkF/c0ErcSAAQeb/A2pBCHZB/wFxIgEgAEHBAGpxcnIgAEHM/wNqQQh2IgIgAEHHAGpxIAFB/wFzcXIgAEH8AWogAEHC/wNqQQh2cSACQX9zcUH/AXFyC3sBAn8gAEHA/wFzQQFqQQh2QX9zQd8AcSAAQcH/AHNBAWpBCHZBf3NBLXEgAEHm/wNqQQh2Qf8BcSIBIABBwQBqcXJyIABBzP8DakEIdiICIABBxwBqcSABQf8Bc3FyIABB/AFqIABBwv8DakEIdnEgAkF/c3FB/wFxcguCAwEGfwJ/An9BMCABQYB/Sw0BGgJ/IAFBgH9PBEBB1KICQTA2AgBBAAwBC0EAQRAgAUELakF4cSABQQtJGyIFQcwAahAxIgFFDQAaIAFBCGshAgJAIAFBP3FFBEAgAiEBDAELIAFBBGsiBigCACIHQXhxIAFBP2pBQHFBCGsiASABQUBrIAEgAmtBD0sbIgEgAmsiA2shBCAHQQNxRQRAIAIoAgAhAiABIAQ2AgQgASACIANqNgIADAELIAEgBCABKAIEQQFxckECcjYCBCABIARqIgQgBCgCBEEBcjYCBCAGIAMgBigCAEEBcXJBAnI2AgAgAiADaiIEIAQoAgRBAXI2AgQgAiADEKwCCwJAIAEoAgQiAkEDcUUNACACQXhxIgMgBUEQak0NACABIAUgAkEBcXJBAnI2AgQgASAFaiICIAMgBWsiBUEDcjYCBCABIANqIgMgAygCBEEBcjYCBCACIAUQrAILIAFBCGoLIgFFCwRAQTAPCyAAIAE2AgBBAAsLDwAgACABIAIgAyAEELQCCw8AIAAgASACIAMgBBC1AgtzAQJ/IwBBIGsiBSQAQX8hBgJAIAJCIFQNACAFQiAgAyAEELcCGiABQRBqIAFBIGogAkIgfSAFEGcNACAAIAEgAiADIAQQsQEaIABCADcAGCAAQgA3ABAgAEIANwAIIABCADcAAEEAIQYLIAVBIGokACAGC0YBAX9BfyEFIAJCIFoEfyAAIAEgAiADIAQQsQEaIABBEGogAEEgaiACQiB9IAAQxAEaIABCADcACCAAQgA3AABBAAUgBQsLOgEBfyMAQSBrIgYkACAGIAMgBUEAEE4aIAAgASACIANBEGogBCAGEH4hACAGQSAQDCAGQSBqJAAgAAs3AQF/IwBBIGsiBCQAIAQgAiADQQAQThogACABIAJBEGogBBC3ASEAIARBIBAMIARBIGokACAAC2QAIAAgAUIohkKAgICAgIDA/wCDIAFCOIaEIAFCGIZCgICAgIDgP4MgAUIIhkKAgICA8B+DhIQgAUIIiEKAgID4D4MgAUIYiEKAgPwHg4QgAUIoiEKA/gODIAFCOIiEhIQ3AAALOwECfyACQQhPBEAgAkEDdiEDQQAhAgNAIAAgAkEDdCIEaiABIARqKQMAELgCIAJBAWoiAiADRw0ACwsLCgAgACABIAIQHgskAQF/IwBBIGsiAyQAIAMgAhC0ASAAIAEgAxCzASADQSBqJAAL4gEBAn8jAEGAAWsiAiQAIAJCADcDUCACQgA3A1ggAkIANwMoIAJCADcDMCACQgA3AzggAkGwkQIiAykDCDcDaCACIAMpAxA3A3AgAiADKQMYNwN4IAJCADcDQCACQgA3A0ggAkEBOgBAIAJCADcDICACIAMpAwA3A2AgAiABKQAYNwMYIAIgASkAEDcDECACIAEpAAg3AwggAiABKQAANwMAIAJBQGsgAhCOAiACQUBrEFIgACACKQNYNwAYIAAgAikDUDcAECAAIAIpA0g3AAggACACKQNANwAAIAJBgAFqJAAL6AQBAX8jAEHgBWsiAiQAIAJBwAVqIAEQUyACQeABaiABIAJBwAVqEB4gAkGgBWogASACQeABahAeIAJBgAVqIAJBoAVqEFMgAkGgA2ogAkHABWogAkGABWoQHiACQcACaiABIAJBoANqEB4gAkHgBGogAkGABWoQUyACQaACaiACQcACahBTIAJBwARqIAJBoANqIAJBoAJqEB4gAkHAA2ogAkHgBGogAkGgAmoQHiACQaAEaiACQcAEahBTIAJBgANqIAJB4ARqIAJBoARqEB4gAkHgAmogAkHgAWogAkGAA2oQHiACQcABaiACQeAEaiACQeACahAeIAJBoAFqIAJBoAVqIAJBwAFqEB4gAkHgAGogAkGgBWogAkGgAWoQHiACQYAEaiACQaAEaiACQeACahAeIAJB4ANqIAJBoAVqIAJBgARqEB4gAkGAAmogAkHAA2ogAkHgA2oQHiACQYABaiACQaACaiACQYACahAeIAJBQGsgAkGAA2ogAkHgA2oQHiACQSBqIAJBoAVqIAJBQGsQHiACIAJBoANqIAJBIGoQHiAAIAJBwAJqIAIQHiAAQf4AIAJB4AJqECggAEEJIAJBwAVqECggACAAIAIQHiAAQQcgAkGgAWoQKCAAQQkgAhAoIABBCyACQYACahAoIABBCCACQUBrECggAEEJIAJB4ABqECggAEEGIAJBwAJqECggAEEOIAJBgARqECggAEEKIAJBwAFqECggAEEJIAJB4ANqECggAEEKIAIQKCAAQQggAkGAAWoQKCAAQQggAkEgahAoIAJB4AVqJABBACABQSAQOWsLKAADQCAAQSAQJyAAIAAtAB9BH3E6AB8gABDMAkUNACAAQSAQOQ0ACwthAQF/IwBBMGsiAiQAIAAgASkAGDcAGCAAIAEpAAA3AAAgACABKQAQNwAQIAAgASkACDcACCAAIAAtAB8iAUH/AHE6AB8gAiAAEDcgACACIAFBgAFxEMsCIAJBMGokAEEAC4kCAQF/IwBB4AJrIggkACAIQSBqQsAAIAYgBxBPGiAIQeAAaiAIQSBqECoaIAhBIGpBwAAQDCAIQeAAaiAEIAUQERogCEHgAGpBoJECQgAgBX1CD4MQERogCEHgAGogASACEBEaIAhB4ABqQaCRAkIAIAJ9Qg+DEBEaIAhBGGogBRAZIAhB4ABqIAhBGGpCCBARGiAIQRhqIAIQGSAIQeAAaiAIQRhqQggQERogCEHgAGogCBApGiAIQeAAakGAAhAMIAggAxBUIQMgCEEQEAwCQCAARQ0AIAMEQCAAQQAgAqcQFhpBfyEDDAELIAAgASACIAZBASAHEEgaQQAhAwsgCEHgAmokACADC98BAQF/IwBB4AJrIggkACAIQSBqQsAAIAYgBxBfGiAIQeAAaiAIQSBqECoaIAhBIGpBwAAQDCAIQeAAaiAEIAUQERogCEEYaiAFEBkgCEHgAGogCEEYakIIEBEaIAhB4ABqIAEgAhARGiAIQRhqIAIQGSAIQeAAaiAIQRhqQggQERogCEHgAGogCBApGiAIQeAAakGAAhAMIAggAxBUIQMgCEEQEAwCQCAARQ0AIAMEQCAAQQAgAqcQFhpBfyEDDAELIAAgASACIAZCASAHEFAaQQAhAwsgCEHgAmokACADC+YBAQF/IwBB0AJrIgkkACAJQRBqQsAAIAcgCBBPGiAJQdAAaiAJQRBqECoaIAlBEGpBwAAQDCAJQdAAaiAFIAYQERogCUHQAGpBoJECQgAgBn1CD4MQERogACADIAQgB0EBIAgQSBogCUHQAGogACAEEBEaIAlB0ABqQaCRAkIAIAR9Qg+DEBEaIAlBCGogBhAZIAlB0ABqIAlBCGpCCBARGiAJQQhqIAQQGSAJQdAAaiAJQQhqQggQERogCUHQAGogARApGiAJQdAAakGAAhAMIAIEQCACQhA3AwALIAlB0AJqJABBAAu8AQEBfyMAQdACayIJJAAgCUEQakLAACAHIAgQXxogCUHQAGogCUEQahAqGiAJQRBqQcAAEAwgCUHQAGogBSAGEBEaIAlBCGogBhAZIAlB0ABqIAlBCGpCCBARGiAAIAMgBCAHQgEgCBBQGiAJQdAAaiAAIAQQERogCUEIaiAEEBkgCUHQAGogCUEIakIIEBEaIAlB0ABqIAEQKRogCUHQAGpBgAIQDCACBEAgAkIQNwMACyAJQdACaiQAQQALJwAgAkKAgICAEFoEQBAYAAsgACABIAIgA0EAIARBmJwCKAIAEQ8ACwQAQQwLMgAgACACBH8gAigAAAVBAAs2AjAgACABKAAANgI0IAAgASgABDYCOCAAIAEoAAg2AjwLPQAgAAJ/IAIEQCAAIAIoAAA2AjAgAigABAwBCyAAQQA2AjBBAAs2AjQgACABKAAANgI4IAAgASgABDYCPAuyBAEDfyMAQaAFayICJAAgAkGQBGoQHCACQeADaiABEA4gAkHgA2pBAEGwEWogAkHgA2oQCiACQfABaiACQeADaiACQZAEahATIAJB8AFqIAJB8AFqIANBsI4CahAKIAJB8ARqEBwgAkHwBGogAkHwBGoQLiACQbADaiACQeADaiADQYARaiIEEBMgAkHAAWogAkHgA2ogBBAKIAJBwAFqIAJB8ARqIAJBwAFqEBUgAkHAAWogAkHAAWogAkGwA2oQCiACQYADaiACQfABaiACQcABahC5ASEEIAJB0AJqIAJBgANqIAEQCiACQdACaiACQdACahCCASACQdACaiACQdACahAuIAJBgANqIAJB0AJqQQEgBGsiARAkIAJB8ARqIAJB4ANqIAEQJCACQcAEaiACQeADaiACQZAEahAVIAJBwARqIAJBwARqIAJB8ARqEAogAkHABGogAkHABGogA0HgjgJqEAogAkHABGogAkHABGogAkHAAWoQFSACQZABaiACQYADaiACQYADahATIAJBkAFqIAJBkAFqIAJBwAFqEAogAkHgAGogAkHABGogA0GQjwJqEAogAkGgAmogAkGAA2oQDiACQTBqIAJBkARqIAJBoAJqEBUgAiACQZAEaiACQaACahATIAAgAkGQAWogAhAKIABBKGogAkEwaiACQeAAahAKIABB0ABqIAJB4ABqIAIQCiAAQfgAaiACQZABaiACQTBqEAogAkGgBWokAAsoAQF/IwBBMGsiAyQAIAMgARAuIAAgARAjIAAgAyACECQgA0EwaiQAC70DAQx+IAE0AgQhAiABNAIIIQMgATQCDCEEIAE0AhAhBSABNAIUIQYgATQCGCEHIAE0AgAhCyAAIAE0AiRChtodfiIIIAhCgICACHwiCEKAgIDwD4N9IAE0AiBChtodfiABNAIcQobaHX4iCUKAgIAIfCIKQhmHfCIMQoCAgBB8Ig1CGoh8PgIkIAAgDCANQoCAgOAPg30+AiAgACAJIApCgICA8A+DfSAHQobaHX4gBkKG2h1+IgZCgICACHwiB0IZh3wiCUKAgIAQfCIKQhqIfD4CHCAAIAkgCkKAgIDgD4N9PgIYIAAgBiAHQoCAgPAPg30gBUKG2h1+IARChtodfiIEQoCAgAh8IgVCGYd8IgZCgICAEHwiB0IaiHw+AhQgACAGIAdCgICA4A+DfT4CECAAIAQgBUKAgIDwD4N9IANChtodfiACQobaHX4iAkKAgIAIfCIDQhmHfCIEQoCAgBB8IgVCGoh8PgIMIAAgBCAFQoCAgOAPg30+AgggACACIANCgICA8A+DfSAIQhmHQhN+IAtChtodfnwiAkKAgIAQfCIDQhqIfD4CBCAAIAIgA0KAgIDgD4N9PgIAC+AGAQJ/IwBBwAZrIgMkACADQbAFaiABENICIAMgAygCsAVBAWo2ArAFIANBsAVqIANBsAVqEEogA0GABWogA0GwBWoQygIgA0GABWogA0GABWoQLiADQdAEaiADQYAFahAOIANBoARqIANBgAVqIANB0ARqEAogA0GQBmogA0GgBGogA0GABWoQEyADQdAEaiADQdAEahDKAiADQZAGaiADQdAEaiADQZAGahATIwBB0ANrIgEkACABQaADaiADQZAGaiIEIAQQCiABQfACaiAEIAFBoANqEAogAUHAAmogAUHwAmoQDiABQcACaiABQcACahAOIAFBkAJqIAFB8AJqIAFBwAJqEAogAUHgAWogAUGQAmoQDiABQeABaiABQeABahAOIAFB4AFqIAFB4AFqEA4gAUHgAWogAUHgAWoQDiABQbABaiABQZACaiABQeABahAKIAFBgAFqIAFBsAFqECMgAUGAAWpBAiABQfACahA/IAFB0ABqIAFBgAFqECMgAUGAAWpBCiABQdAAahA/IAFBgAFqQQogAUHQAGoQPyABQSBqIAFBgAFqECMgAUGAAWpBHiABQSBqED8gAUEgaiABQYABahAjIAFBgAFqQTwgAUEgahA/IAFBIGogAUGAAWoQIyABQYABakH4ACABQSBqED8gAUGAAWpBCiABQdAAahA/IAFBgAFqQQMgAUHwAmoQPyABQYABaiABQYABahAOIAEgAUGAAWoQNiABLQABIQQgAUHQA2okACAEQQFxIQEgA0HgBWogA0GABWoQLiADQYAFaiADQeAFaiABECQgA0HQBGoQSSADQdAEakGAjgIgARAkIANBgAVqIANBgAVqIANB0ARqEBUgA0GAA2oQHCADQeABaiADQYAFaiADQYADahATIANBMGogA0GABWogA0GAA2oQFSADQeAAaiADQeABahBKIAMgA0EwaiADQeAAahAKIAAgAxA2IAAgAC0AHyACcjoAHyADQYADaiAAEEIEQBABAAsgA0HgAWogA0GAA2oQPiADQeAAaiADQeABahA0IANB4AFqIANB4ABqEC0gA0HgAGogA0HgAWoQNCADQeABaiADQeAAahAtIANBgANqIANB4AFqEBQgACADQYADahBAIANBwAZqJAALXQEFf0EBIQNBHyEBA0AgACABai0AACIEIAFBsBtqLQAAIgVrQQh1IANxIAJyIQIgAQRAIAQgBXNB//8DakEIdiADcSEDIAFBAWshASACQf8BcSECDAELCyACQQBHCykBAX8jAEEQayIAJAAgAEEAOgAPQcCcAiAAQQ9qQQAQAhogAEEQaiQAC/gBAQJ/IwBBgAFrIgMkACACEM8CIQQgABAcIABBKGoQHCAAQdAAahBJIAAgAUHAB2xBgBxqIgEgAkEAIARrIAJxQQF0a0EYdEEYdSICQQEQJhA8IAAgAUH4AGogAkECECYQPCAAIAFB8AFqIAJBAxAmEDwgACABQegCaiACQQQQJhA8IAAgAUHgA2ogAkEFECYQPCAAIAFB2ARqIAJBBhAmEDwgACABQdAFaiACQQcQJhA8IAAgAUHIBmogAkEIECYQPCADQQhqIABBKGoQIyADQTBqIAAQIyADQdgAaiAAQdAAahAuIAAgA0EIaiAEEDwgA0GAAWokAAsLACAAQYABcUEHdgv+AQECfyMAQaABayIDJAAgAhDPAiEEIAAQHCAAQShqEBwgAEHQAGoQHCAAQfgAahBJIAAgASACQQAgBGsgAnFBAXRrQRh0QRh1IgJBARAmED0gACABQaABaiACQQIQJhA9IAAgAUHAAmogAkEDECYQPSAAIAFB4ANqIAJBBBAmED0gACABQYAFaiACQQUQJhA9IAAgAUGgBmogAkEGECYQPSAAIAFBwAdqIAJBBxAmED0gACABQeAIaiACQQgQJhA9IAMgAEEoahAjIANBKGogABAjIANB0ABqIABB0ABqECMgA0H4AGogAEH4AGoQLiAAIAMgBBA9IANBoAFqJAALywUBBH8jAEHAH2siAyQAIANBoAFqIAIQGiADQcgbaiACED4gA0HoEmogA0HIG2oQFCADQcACaiIEIANB6BJqEBogA0GoGmogAiAEEBsgA0HIEWogA0GoGmoQFCADQeADaiADQcgRahAaIANBiBlqIANB6BJqED4gA0GoEGogA0GIGWoQFCADQYAFaiIEIANBqBBqEBogA0HoF2ogAiAEEBsgA0GID2ogA0HoF2oQFCADQaAGaiADQYgPahAaIANByBZqIANByBFqED4gA0HoDWogA0HIFmoQFCADQcAHaiIEIANB6A1qEBogA0GoFWogAiAEEBsgA0HIDGogA0GoFWoQFCADQeAIaiADQcgMahAaIANBiBRqIANBqBBqED4gA0GoC2ogA0GIFGoQFCADQYAKaiADQagLahAaQQAhBEEAIQIDQCACQQF0IgUgA0GAH2pqIAEgAmotAAAiBkEPcToAACADQYAfaiAFQQFyaiAGQQR2OgAAIAJBAWoiAkEgRw0AC0EAIQIDQCADQYAfaiAEaiIBIAEtAAAgAmoiASABQRh0QYCAgEBrIgFBGHVB8AFxazoAACABQRx1IQIgBEEBaiIEQT9HDQALIAMgAy0Avx8gAmoiBDoAvx8gABC8AUE+IQIDQCADIANBoAFqIARBGHRBGHUQ0AIgA0HgHWogACADEBsgA0HoHGogA0HgHWoQNCADQeAdaiADQegcahAtIANB6BxqIANB4B1qEDQgA0HgHWogA0HoHGoQLSADQegcaiADQeAdahA0IANB4B1qIANB6BxqEC0gA0HoHGogA0HgHWoQNCADQeAdaiADQegcahAtIAAgA0HgHWoQFCACBEAgA0GAH2ogAmotAAAhBCACQQFrIQIMAQsLIAMgA0GgAWogAywAgB8Q0AIgA0HgHWogACADEBsgACADQeAdahAUIANBwB9qJAAL6QYCHH4JfyAAIAEoAgwiIEEBdKwiCCABKAIEIiFBAXSsIgJ+IAEoAggiIqwiDSANfnwgASgCECIjrCIHIAEoAgAiJEEBdKwiBX58IAEoAhwiHkEmbKwiDiAerCIRfnwgASgCICIlQRNsrCIDIAEoAhgiH0EBdKx+fCABKAIkIiZBJmysIgQgASgCFCIBQQF0rCIJfnxCAYYiFUKAgIAQfCIWQhqHIAIgB34gIkEBdKwiCyAgrCISfnwgAawiDyAFfnwgAyAeQQF0rCITfnwgBCAfrCIKfnxCAYZ8IhdCgICACHwiGEIZhyAIIBJ+IAcgC358IAIgCX58IAUgCn58IAMgJawiEH58IAQgE358QgGGfCIGIAZCgICAEHwiDEKAgIDgD4N9PgIYIAAgAUEmbKwgD34gJKwiBiAGfnwgH0ETbKwiBiAjQQF0rCIUfnwgCCAOfnwgAyALfnwgAiAEfnxCAYYiGUKAgIAQfCIaQhqHIAYgCX4gBSAhrCIbfnwgByAOfnwgAyAIfnwgBCANfnxCAYZ8IhxCgICACHwiHUIZhyAFIA1+IAIgG358IAYgCn58IAkgDn58IAMgFH58IAQgCH58QgGGfCIGIAZCgICAEHwiBkKAgIDgD4N9PgIIIAAgCyAPfiAHIAh+fCACIAp+fCAFIBF+fCAEIBB+fEIBhiAMQhqHfCIMIAxCgICACHwiDEKAgIDwD4N9PgIcIAAgBSASfiACIA1+fCAKIA5+fCADIAl+fCAEIAd+fEIBhiAGQhqHfCIDIANCgICACHwiA0KAgIDwD4N9PgIMIAAgCiALfiAHIAd+fCAIIAl+fCACIBN+fCAFIBB+fCAEICasIgd+fEIBhiAMQhmHfCIEIARCgICAEHwiBEKAgIDgD4N9PgIgIAAgFyAYQoCAgPAPg30gFSAWQoCAgGCDfSADQhmHfCIDQoCAgBB8IglCGoh8PgIUIAAgAyAJQoCAgOAPg30+AhAgACAIIAp+IA8gFH58IAsgEX58IAIgEH58IAUgB358QgGGIARCGod8IgIgAkKAgIAIfCICQoCAgPAPg30+AiQgACAcIB1CgICA8A+DfSAZIBpCgICAYIN9IAJCGYdCE358IgJCgICAEHwiBUIaiHw+AgQgACACIAVCgICA4A+DfT4CAAuAAgEIfwNAIAAgAmogASACQQN2ai0AACACQQdxdkEBcToAACACQQFqIgJBgAJHDQALA0AgBCIBQQFqIQQCQCAAIAFqIgYtAABFDQAgBCECQQEhBSABQf4BSw0AA0ACQCAAIAJqIgMsAAAiB0UNACAHIAV0IgcgBiwAACIIaiIJQQ9MBEAgBiAJOgAAIANBADoAAAwBCyAIIAdrIgNBcUgNAiAGIAM6AAADQCAAIAJqIgMtAABFBEAgA0EBOgAADAILIANBADoAACACQf8BSSEDIAJBAWohAiADDQALCyAFQQVLDQEgBUEBaiIFIAFqIgJBgAJJDQALCyAEQYACRw0ACwsLACAAIAEQxQFBAAsNACAAIAEgAhDGAUEACwsAIAAgARDHAUEACyoBAX8jAEEQayIEJAAgBCABIAIgAxDIARogACAEEFQhACAEQRBqJAAgAAsZACAAIAEgAq0gA61CIIaEIARCACAFEO4BCyEAIAAgASACrSADrUIghoQgBCAFrSAGrUIghoQgBxDuAQs4AQF/IwBBIGsiBSQAIAUgAyAEQQAQNRogACABrSACrUIghoQgA0EQaiAFEF8hACAFQSBqJAAgAAvkAgIBfwJ+IwBB8ABrIgYkACACrSADrUIghoQiB1BFBEAgBiAFKQAYNwMYIAYgBSkAEDcDECAGIAUpAAA3AwAgBiAFKQAINwMIIAQpAAAhCCAGQgA3A2ggBiAINwNgAkAgB0LAAFoEQANAQQAhAiAGQSBqIAZB4ABqIAZBABBgGgNAIAAgAmogBkEgaiACai0AACABIAJqLQAAczoAAEEBIQMgAkEBaiICQcAARw0AC0EIIQIDQCAGQeAAaiACaiIEIAMgBC0AAGoiAzoAACADQQh2IQMgAkEBaiICQRBHDQALIAFBQGshASAAQUBrIQAgB0JAfCIHQj9WDQALIAdQDQELQQAhAiAGQSBqIAZB4ABqIAZBABBgGiAHpyEDA0AgACACaiAGQSBqIAJqLQAAIAEgAmotAABzOgAAIAJBAWoiAiADRw0ACwsgBkEgakHAABAMIAZBIBAMCyAGQfAAaiQAQQALoQICAX8CfiMAQfAAayIFJAAgAa0gAq1CIIaEIgZQRQRAIAUgBCkAGDcDGCAFIAQpABA3AxAgBSAEKQAANwMAIAUgBCkACDcDCCADKQAAIQcgBUIANwNoIAUgBzcDYAJAIAZCwABaBEADQCAAIAVB4ABqIAVBABBgGkEIIQFBASECA0AgBUHgAGogAWoiAyACIAMtAABqIgI6AAAgAkEIdiECIAFBAWoiAUEQRw0ACyAAQUBrIQAgBkJAfCIGQj9WDQALIAZQDQELQQAhASAFQSBqIAVB4ABqIAVBABBgGiAGpyECA0AgACABaiAFQSBqIAFqLQAAOgAAIAFBAWoiASACRw0ACwsgBUEgakHAABAMIAVBIBAMCyAFQfAAaiQAQQAL5AICAX8CfiMAQfAAayIGJAAgAq0gA61CIIaEIgdQRQRAIAYgBSkAGDcDGCAGIAUpABA3AxAgBiAFKQAANwMAIAYgBSkACDcDCCAEKQAAIQggBkIANwNoIAYgCDcDYAJAIAdCwABaBEADQEEAIQIgBkEgaiAGQeAAaiAGQQAQYRoDQCAAIAJqIAZBIGogAmotAAAgASACai0AAHM6AABBASEDIAJBAWoiAkHAAEcNAAtBCCECA0AgBkHgAGogAmoiBCADIAQtAABqIgM6AAAgA0EIdiEDIAJBAWoiAkEQRw0ACyABQUBrIQEgAEFAayEAIAdCQHwiB0I/Vg0ACyAHUA0BC0EAIQIgBkEgaiAGQeAAaiAGQQAQYRogB6chAwNAIAAgAmogBkEgaiACai0AACABIAJqLQAAczoAACACQQFqIgIgA0cNAAsLIAZBIGpBwAAQDCAGQSAQDAsgBkHwAGokAEEAC6ECAgF/An4jAEHwAGsiBSQAIAGtIAKtQiCGhCIGUEUEQCAFIAQpABg3AxggBSAEKQAQNwMQIAUgBCkAADcDACAFIAQpAAg3AwggAykAACEHIAVCADcDaCAFIAc3A2ACQCAGQsAAWgRAA0AgACAFQeAAaiAFQQAQYRpBCCEBQQEhAgNAIAVB4ABqIAFqIgMgAiADLQAAaiICOgAAIAJBCHYhAiABQQFqIgFBEEcNAAsgAEFAayEAIAZCQHwiBkI/Vg0ACyAGUA0BC0EAIQEgBUEgaiAFQeAAaiAFQQAQYRogBqchAgNAIAAgAWogBUEgaiABai0AADoAACABQQFqIgEgAkcNAAsLIAVBIGpBwAAQDCAFQSAQDAsgBUHwAGokAEEAC4wKAQh+IAQpAAAiBUL1ys2D16zbt/MAhSEHIAVC4eSV89bs2bzsAIUhCCAEKQAIIgVCg9+R85bM3LfkAIUhBiAFQvPK0cunjNmy9ACFIQkgASABIAKtIAOtQiCGhCIKpyICaiACQQdxIgNrIgJHBEADQCABKQAAIQUgBkENEAshCyAGIAd8IgZBIBALIQcgBSAJhSIJQRAQCyAIIAl8IgiFIglBFRALIQwgBiALhSIGQREQCyELIAYgCHwiBkEgEAshCCAGIAuFIgZBDRALIQsgBiAHIAl8Igd8IgZBIBALIAcgDIUiB0EQEAsgByAIfCIHhSIIfCIMIAhBFRALhSEJIAYgC4UiBkEREAsgBiAHfCIIhSEGIAUgDIUhByAIQSAQCyEIIAFBCGoiASACRw0ACyACIQELIApCOIYhBQJAAkACQAJAAkACQAJAAkAgA0EBaw4HBgUEAwIBAAcLIAExAAZCMIYgBYQhBQsgATEABUIohiAFhCEFCyABMQAEQiCGIAWEIQULIAExAANCGIYgBYQhBQsgATEAAkIQhiAFhCEFCyABMQABQgiGIAWEIQULIAUgATEAAIQhBQsgBkENEAshCiAGIAd8IgZBIBALIQcgBSAJhSIJQRAQCyAIIAl8IgiFIglBFRALIQsgBiAKhSIGQREQCyEKIAYgCHwiBkEgEAshCCAGIAqFIgZBDRALIQogBiAHIAl8Igd8IgZBIBALIQkgByALhSIHQRAQCyAHIAh8IgeFIghBFRALIQsgBiAKhSIGQREQCyEKIAYgB3wiBkEgEAshByAGIAqFIgZBDRALIQogBiAFIAggCXwiCIV8IgVBIBALIQYgCCALhSIIQRAQCyAHQu4BhSAIfCIHhSIIQRUQCyEJIAUgCoUiBUEREAshCiAFIAd8IgVBIBALIQcgBSAKhSIFQQ0QCyEKIAUgBiAIfCIGfCIFQSAQCyEIIAYgCYUiBkEQEAsgBiAHfCIGhSIHQRUQCyEJIAUgCoUiBUEREAshCiAFIAZ8IgVBIBALIQYgBSAKhSIFQQ0QCyEKIAUgByAIfCIHfCIFQSAQCyEIIAcgCYUiB0EQEAsgBiAHfCIGhSIHQRUQCyEJIAUgCoUiBUEREAshCiAFIAZ8IgVBIBALIQYgBSAKhSIFQQ0QCyEKIAUgByAIfCIHfCIFQSAQCyEIIAcgCYUiB0EQEAsgBiAHfCIGhSIHQRUQCyEJIAAgBSAKhSIFQREQCyAFIAZ8IgaFIgogByAIfCIFhSAGQSAQCyIHhSAFIAmFIgaFEBkgCkLdAYUiCEENEAshCSAFIAh8IgVBIBALIQggBkEQEAsgBiAHfCIGhSIHQRUQCyEKIAUgCYUiBUEREAshCSAFIAZ8IgVBIBALIQYgBSAJhSIFQQ0QCyEJIAUgByAIfCIHfCIFQSAQCyEIIAcgCoUiB0EQEAsgBiAHfCIGhSIHQRUQCyEKIAUgCYUiBUEREAshCSAFIAZ8IgVBIBALIQYgBSAJhSIFQQ0QCyEJIAUgByAIfCIHfCIFQSAQCyEIIAcgCoUiB0EQEAsgBiAHfCIGhSIHQRUQCyEKIAUgCYUiBUEREAshCSAFIAZ8IgVBIBALIQYgBSAJhSIFQQ0QCyEJIABBCGogCiAHIAh8IgeFIghBEBALIAYgCHwiBoVBFRALIAkgBSAHfIUiBSAGfCIGhSAFQREQC4UgBkEgEAuFEBlBAAsuAQF+IAKtIAOtQiCGhCIGQhBaBH8gACABQRBqIAEgBkIQfSAEIAUQogEFQX8LCxkAIAAgASACIAOtIAStQiCGhCAFIAYQogELMgEBfiACrSADrUIghoQiBkLw////D1oEQBAYAAsgAEEQaiAAIAEgBiAEIAUQowEaQQALGQAgACABIAIgA60gBK1CIIaEIAUgBhCjAQukAQEBfyMAQSBrIgQkACABrSACrUIghoQgAyAEQRxqIARBFGogBEEMahCYAQJAIAAQ+wFB5QBHBEBB1KICQRw2AgBBfyEADAELIAAgBEEYaiAEQQhqIARBEGoQggJFBEBB1KICQRw2AgBBfyEADAELQQEhACAEKAIcIAQoAhhHDQAgBCgCDCAEKAIIRw0AIAQoAhQgBCgCEEchAAsgBEEgaiQAIAALgAEBAX4gAq0gA61CIIaEIQQjAEGAAWsiAiQAQX8hAwJAIAAQ+wFB5QBHDQAgAhCeAQ0AIAJBEGpBAEHmABAWGiACIAEgBKcgACACQRBqEP8BIQEgAhCdARogAUUNACACQRBqIABB5gAQRSEDIAJBEGpB5gAQDAsgAkGAAWokACADC/ICAgJ/An4gBK0gBa1CIIaEIQkjAEGAAWsiByQAIABBAEHmABAWIQgCfwJAIAKtIAOtQiCGhCIKQoCAgIAQWgRAQdSiAkEWNgIADAELIAkgBiAHQQxqIAdBCGogB0EEahCYASAHQeAAakEgECcCfyAHQeAAaiEGIAdBIGohAkEAIQACQCAHKAIMIgVBP0sgBygCCCIErSAHKAIEIgOtfkL/////A1ZyDQAgAkGk7gA7AAAgAkEkOgACIAIgBUGACGotAAA6AAMgAkEEakE2IANBHhCZASIDRQ0AIAMgAkE6aiIFIANrIARBHhCZASIDRQ0AIAMgBSADayAGEP4BIgNFIAMgBU9yDQAgA0EAOgAAIAIhAAsgAEULBEBB1KICQRw2AgAMAQtBfyAHQRBqEJ4BDQEaIAdBEGogASAKpyAHQSBqIAgQ/wEhACAHQRBqEJ0BGkEAIAANARpB1KICQRw2AgALQX8LIQAgB0GAAWokACAAC9ABAQN+IAetIAitQiCGhCELIwBBEGsiByQAIABBACABrSACrUIghoQiCqciARAWIQACfyAErSAFrUIghoQiDEL/////D1hBACAKQoCAgIAQVBtFBEBB1KICQRY2AgBBfwwBCyAKQhBaBEAgCyAJIAdBDGogB0EIaiAHQQRqEJgBIAAgA0YEQEHUogJBHDYCAEF/DAILIAMgDKcgBkEgQgEgBzUCDIYgBygCBCAHKAIIIAAgARD9AQwBC0HUogJBHDYCAEF/CyEAIAdBEGokACAACx8AIAAgASACIAMgBK0gBa1CIIaEIAYgByAIIAkQ/QELTQICfwF+IwBBIGsiBiQAQX8hByACrSADrUIghoQiCEIwWgRAIAYgASAEEHIgACABQSBqIAhCIH0gBiABIAUQlAIhBwsgBkEgaiQAIAcLmgEBAX4gAq0gA61CIIaEIQUjAEHgAGsiAiQAQX8hAyACQSBqIAIQeEUEQCACQUBrIAJBIGogBBByIABBIGogASAFIAJBQGsgBCACEJYCIQMgACACKQM4NwAYIAAgAikDMDcAECAAIAIpAyg3AAggACACKQMgNwAAIAJBIBAMIAJBIGpBIBAMIAJBQGtBGBAMCyACQeAAaiQAIAMLGQAgACABIAKtIAOtQiCGhCAEIAUgBhCUAgsuAQF+IAKtIAOtQiCGhCIGQhBaBH8gACABQRBqIAEgBkIQfSAEIAUQnwEFQX8LCxsAIAAgASACIAOtIAStQiCGhCAFIAYgBxCVAgsZACAAIAEgAiADrSAErUIghoQgBSAGEJ8BCxkAIAAgASACrSADrUIghoQgBCAFIAYQlgILLwEBfiACrSADrUIghoQiBkLw////D1oEQBAYAAsgAEEQaiAAIAEgBiAEIAUQoAELGwAgACABIAIgA60gBK1CIIaEIAUgBiAHEJcCCxkAIAAgASACIAOtIAStQiCGhCAFIAYQoAELMAEBfiABrSACrUIghoQiA0KAgICAEFoEQEGxCkGXCUHFAUHECBAAAAsgACADpxAnCyEAIAAgASACrSADrUIghoQgBCAFrSAGrUIghoQgBxC2AgsWACAAIAEgAq0gA61CIIaEIAQgBRB9CyAAIAAgASACrSADrUIghoQgBCAFrSAGrUIghoQgBxB+CxUAIAAgAa0gAq1CIIaEIAMgBBC3AQsXACAAIAEgAq0gA61CIIaEIAQgBRDEAgsYACAAIAEgAq0gA61CIIaEIAQgBSAGEEgLFAAgACABrSACrUIghoQgAyAEEE8LFgAgACABIAKtIAOtQiCGhCAEIAUQegsgACAAIAEgAq0gA61CIIaEIAQgBa0gBq1CIIaEIAcQUAtdAQF/QX8hBgJAIANBAWtBP0sgAkHAAEtyDQACQCABQQAgAhtFBEAgACADQf8BcSAEIAUQ7QFFDQEMAgsgACADQf8BcSABIAJB/wFxIAQgBRDdAQ0BC0EAIQYLIAYLFAAgACABrSACrUIghoQgAyAEEF8L7AMBA34CfyAFrSAGrUIghoQhCiAIrSAJrUIghoQhDCMAQeACayIFJAAgAgRAIAJCADcDAAsgAwRAIANB/wE6AAALQX8hCAJAAkAgCkIRVA0AIApCEX0iC0Lv////D1oNASAFQSBqQsAAIABBIGoiBiAAEE8aIAVB4ABqIAVBIGoQKhogBUEgakHAABAMIAVB4ABqIAcgDBARGiAFQeAAakHQmwJCACAMfUIPgxARGiAFQSBqQQBBwAAQFhogBSAELQAAOgAgIAVBIGogBUEgakLAACAGQQEgABBIGiAFLQAgIQcgBSAELQAAOgAgIAVB4ABqIAVBIGpCwAAQERogBUHgAGogBEEBaiIEIAsQERogBUHgAGpB0JsCIApCAX1CD4MQERogBUEYaiAMEBkgBUHgAGogBUEYakIIEBEaIAVBGGogCkIvfBAZIAVB4ABqIAVBGGpCCBARGiAFQeAAaiAFECkaIAVB4ABqQYACEAwgBSAEIAunakEQEEUEQCAFQRAQDAwBCyABIAQgCyAGQQIgABBIGiAAQSRqIAUQ5QEgBhCTAgJAIAdBAnFFBEAgBkEEEDlFDQELIAAQkAELIAIEQCACIAs3AwALQQAhCCADRQ0AIAMgBzoAAAsgBUHgAmokACAIDAELEBgACwufAwECfgJ/IAStIAWtQiCGhCEKIAetIAitQiCGhCELIwBB0AJrIgQkACACBEAgAkIANwMACyAKQu////8PVARAIARBEGpCwAAgAEEgaiIFIAAQTxogBEHQAGogBEEQahAqGiAEQRBqQcAAEAwgBEHQAGogBiALEBEaIARB0ABqQdCbAkIAIAt9Qg+DEBEaIARBEGpBAEHAABAWGiAEIAk6ABAgBEEQaiAEQRBqQsAAIAVBASAAEEgaIARB0ABqIARBEGpCwAAQERogASAELQAQOgAAIAFBAWoiASADIAogBUECIAAQSBogBEHQAGogASAKEBEaIARB0ABqQdCbAiAKQg+DEBEaIARBCGogCxAZIARB0ABqIARBCGpCCBARGiAEQQhqIApCQH0QGSAEQdAAaiAEQQhqQggQERogBEHQAGogASAKp2oiARApGiAEQdAAakGAAhAMIABBJGogARDlASAFEJMCAkAgCUECcUUEQCAFQQQQOUUNAQsgABCQAQsgAgRAIAIgCkIRfDcDAAsgBEHQAmokAEEADAELEBgACwsXACAAIAEgAq0gA61CIIaEIAQgBRC0AgsXACAAIAEgAq0gA61CIIaEIAQgBRC1AgsuAQF+IAKtIAOtQiCGhCIGQhBaBH8gACABQRBqIAEgBkIQfSAEIAUQlAEFQX8LCxkAIAAgASACIAOtIAStQiCGhCAFIAYQlAELMgEBfiACrSADrUIghoQiBkLw////D1oEQBAYAAsgAEEQaiAAIAEgBiAEIAUQlQEaQQALGQAgACABIAIgA60gBK1CIIaEIAUgBhCVAQtOAQF+An8gAa0gAq1CIIaEIQQgAEGXDEEKEDBFBEAgACAEIAMQpQIMAQsgAEGNDEEJEDBFBEAgACAEIAMQpwIMAQtB1KICQRw2AgBBfwsLTgEBfgJ/IAKtIAOtQiCGhCEEIABBlwxBChAwRQRAIAAgASAEEJ8CDAELIABBjQxBCRAwRQRAIAAgASAEEKgCDAELQdSiAkEcNgIAQX8LC1EBAn4CfyACrSADrUIghoQhCCAErSAFrUIghoQhCQJAAkACQCAHQQFrDgICAAELIAAgASAIIAkgBhCgAgwCCxAYAAsgACABIAggCSAGEKkCCwtzAQN+An8gAa0gAq1CIIaEIQsgBK0gBa1CIIaEIQwgB60gCK1CIIaEIQ0CQAJAAkAgCkEBaw4CAAECCyAAIAsgAyAMIAYgDSAJQQEQqgIMAgsgACALIAMgDCAGIA0gCUECEKECDAELQdSiAkEcNgIAQX8LCxMAIAAgASACrSADrUIghoQQnwILLQAgACABrSACrUIghoQgAyAErSAFrUIghoQgBiAHrSAIrUIghoQgCSAKEKECCxMAIAAgAa0gAq1CIIaEIAMQpQILEwAgACABrSACrUIghoQgAxCnAgsTACAAIAEgAq0gA61CIIaEEKgCCx8AIAAgASACrSADrUIghoQgBK0gBa1CIIaEIAYQqQILLQAgACABrSACrUIghoQgAyAErSAFrUIghoQgBiAHrSAIrUIghoQgCSAKEKoCCxIAIAAgASACrSADrUIghoQQJQs+AQF/IwBB8ABrIgQkACAEQQhqEFkaIARBCGogASACrSADrUIghoQQRBogBEEIaiAAEFgaIARB8ABqJABBAAsSACAAIAEgAq0gA61CIIaEEEQLEgAgACABIAKtIAOtQiCGhBAhCx0AIAAgASACIAOtIAStQiCGhCAFIAYgByAIENQBCxgAIAAgASACIAOtIAStQiCGhCAFIAYQagsSACAAIAEgAq0gA61CIIaEEDoLGQAgACABIAIgA60gBK1CIIaEIAUgBhCcAgtNAgJ/AX4jAEEgayIGJABBfyEHIAKtIAOtQiCGhCIIQjBaBEAgBiABIAQQciAAIAFBIGogCEIgfSAGIAEgBRDnASEHCyAGQSBqJAAgBwubAQEBfiACrSADrUIghoQhBSMAQeAAayICJABBfyEDIAJBIGogAhDsAUUEQCACQUBrIAJBIGogBBByIABBIGogASAFIAJBQGsgBCACEOoBIQMgACACKQM4NwAYIAAgAikDMDcAECAAIAIpAyg3AAggACACKQMgNwAAIAJBIBAMIAJBIGpBIBAMIAJBQGtBGBAMCyACQeAAaiQAIAMLGQAgACABIAKtIAOtQiCGhCAEIAUgBhDnAQsuAQF+IAKtIAOtQiCGhCIGQhBaBH8gACABQRBqIAEgBkIQfSAEIAUQkgEFQX8LCxsAIAAgASACIAOtIAStQiCGhCAFIAYgBxDoAQsZACAAIAEgAiADrSAErUIghoQgBSAGEJIBCxkAIAAgASACrSADrUIghoQgBCAFIAYQ6gELLwEBfiACrSADrUIghoQiBkLw////D1oEQBAYAAsgAEEQaiAAIAEgBiAEIAUQkwELGwAgACABIAIgA60gBK1CIIaEIAUgBiAHEOsBCxkAIAAgASACIAOtIAStQiCGhCAFIAYQkwELEwAgACABIAKtIAOtQiCGhBDiAQtJAQF/IwBBQGoiBSQAIAUgASACrSADrUIghoQgBBCYAhogACAFEMkBIQEgBSAAQcAAEEUhAiAFQUBrJAAgAkF/IAEgACAFRhtyCxUAIAAgASACrSADrUIghoQgBBCYAgsTACAAIAEgAq0gA61CIIaEEKUBC0cBAX8jAEEgayIFJAAgBSABIAKtIAOtQiCGhCAEEIoCGiAAIAUQaCEBIAUgAEEgEEUhAiAFQSBqJAAgAkF/IAEgACAFRhtyCxUAIAAgASACrSADrUIghoQgBBCKAgsSACAAIAEgAq0gA61CIIaEEG8LWwECfiAHrSAIrUIghoQhDEF/IQIgBK0gBa1CIIaEIgtCEFoEQCAAIAMgC0IQfSADIAunakEQayAGIAwgCSAKEJACIQILIAEEQCABQgAgC0IQfSACGzcDAAsgAgslACAAIAIgA60gBK1CIIaEIAUgBiAHrSAIrUIghoQgCSAKEJACC1kBAn4CfyAGrSAHrUIghoQhDCADrSAErUIghoQiC0Lw////D1QEQCAAIAAgC6dqQQAgAiALIAUgDCAJIAoQkQIaIAEEQCABIAtCEHw3AwALQQAMAQsQGAALCycAIAAgASACIAMgBK0gBa1CIIaEIAYgB60gCK1CIIaEIAogCxCRAgtbAQJ+IAetIAitQiCGhCEMQX8hAiAErSAFrUIghoQiC0IQWgRAIAAgAyALQhB9IAMgC6dqQRBrIAYgDCAJIAoQwAIhAgsgAQRAIAFCACALQhB9IAIbNwMACyACCyUAIAAgAiADrSAErUIghoQgBSAGIAetIAitQiCGhCAJIAoQwAILWwECfiAHrSAIrUIghoQhDEF/IQIgBK0gBa1CIIaEIgtCEFoEQCAAIAMgC0IQfSADIAunakEQayAGIAwgCSAKEMECIQILIAEEQCABQgAgC0IQfSACGzcDAAsgAgslACAAIAIgA60gBK1CIIaEIAUgBiAHrSAIrUIghoQgCSAKEMECC1kBAn4CfyAGrSAHrUIghoQhDCADrSAErUIghoQiC0Lw////D1QEQCAAIAAgC6dqQQAgAiALIAUgDCAJIAoQwgIaIAEEQCABIAtCEHw3AwALQQAMAQsQGAALCycAIAAgASACIAMgBK0gBa1CIIaEIAYgB60gCK1CIIaEIAogCxDCAgtZAQJ+An8gBq0gB61CIIaEIQwgA60gBK1CIIaEIgtC8P///w9UBEAgACAAIAunakEAIAIgCyAFIAwgCSAKEMMCGiABBEAgASALQhB8NwMAC0EADAELEBgACwsnACAAIAEgAiADIAStIAWtQiCGhCAGIAetIAitQiCGhCAKIAsQwwILBQBBuAsLPwEBfyMAQSBrIgQkACAEIAEgAiADEOABGiAAIAQQaCEBIAQgAEEgEEUhAyAEQSBqJAAgA0F/IAEgACAERhtyCwUAQf0LC20CAX8BfiMAQSBrIgUkACADKQAAIQYgBUIANwMYIAUgBjcDECAFIAIQGSAFQgA3AwgCfyABQRBrQTFPBEBB1KICQRw2AgBBfwwBCyAAIAFBAEIAIARBICAFIAVBEGoQ1AELIQAgBUEgaiQAIAALBABBCgsFAEGxCwsFAEGjCgvvAQEEfyMAIgUhByAFQYAEa0FAcSIFJAAgACABIAAbIggEQEF/IQYgBUHgAGogAyAEEI4BRQRAIAEgACABGyEBQQAhACAFQYABakEAQQBBwAAQdBogBUGAAWogBUHgAGpCIBA6GiAFQeAAakEgEAwgBUGAAWogBEIgEDoaIAVBgAFqIAJCIBA6GiAFQYABaiAFQSBqQcAAEHMaIAVBgAFqQYADEAwDQCAAIAFqIAVBIGogAGoiAi0AADoAACAAIAhqIAItACA6AAAgAEEBaiIAQSBHDQALIAVBIGpBwAAQDEEAIQYLIAckACAGDwsQGAAL7wEBBH8jACIFIQcgBUGABGtBQHEiBSQAIAAgASAAGyIIBEBBfyEGIAVB4ABqIAMgBBCOAUUEQCABIAAgARshAUEAIQAgBUGAAWpBAEEAQcAAEHQaIAVBgAFqIAVB4ABqQiAQOhogBUHgAGpBIBAMIAVBgAFqIAJCIBA6GiAFQYABaiAEQiAQOhogBUGAAWogBUEgakHAABBzGiAFQYABakGAAxAMA0AgACAIaiAFQSBqIABqIgItAAA6AAAgACABaiACLQAgOgAAIABBAWoiAEEgRw0ACyAFQSBqQcAAEAxBACEGCyAHJAAgBg8LEBgACw8AIAFBIBAnIAAgARCPAQsZACABQSAgAkIgQQBBABCcAhogACABEI8BCwUAQZ4LCwQAQW4LBABBEQsEAEE0CysBAX4gACABIAJBABA1GiAAEJEBIAEpABAhAyAAQgA3ACwgACADNwAkQQALMQEBfiABQRgQJyAAIAEgAkEAEDUaIAAQkQEgASkAECEDIABCADcALCAAIAM3ACRBAAsFAEHoAAsIACAAQRAQJwsFAEHzCwuiBwIHfgF/IAMpAAAiBEL1ys2D16zbt/MAhSEFIARC4eSV89bs2bzsAIUhBiADKQAIIghC7d6R85bM3LfkAIUhBCAIQvPK0cunjNmy9ACFIQggASABIAKnIgNqIANBB3EiC2siA0cEQANAIAEpAAAhByAEQQ0QCyEJIAQgBXwiBEEgEAshBSAHIAiFIghBEBALIAYgCHwiBoUiCEEVEAshCiAEIAmFIgRBERALIQkgBCAGfCIEQSAQCyEGIAQgCYUiBEENEAshCSAEIAUgCHwiBXwiBEEgEAsgBSAKhSIFQRAQCyAFIAZ8IgWFIgZ8IgogBkEVEAuFIQggBCAJhSIEQREQCyAEIAV8IgaFIQQgByAKhSEFIAZBIBALIQYgAUEIaiIBIANHDQALIAMhAQsgAkI4hiECAkACQAJAAkACQAJAAkACQCALQQFrDgcGBQQDAgEABwsgATEABkIwhiAChCECCyABMQAFQiiGIAKEIQILIAExAARCIIYgAoQhAgsgATEAA0IYhiAChCECCyABMQACQhCGIAKEIQILIAExAAFCCIYgAoQhAgsgAiABMQAAhCECCyAEQQ0QCyEHIAQgBXwiBEEgEAshBSACIAiFIghBEBALIAYgCHwiBoUiCEEVEAshCSAEIAeFIgRBERALIQcgBCAGfCIEQSAQCyEGIAQgB4UiBEENEAshByAEIAUgCHwiBXwiBEEgEAshCCAFIAmFIgVBEBALIAUgBnwiBYUiBkEVEAshCSAEIAeFIgRBERALIQcgBCAFfCIEQSAQCyEFIAQgB4UiBEENEAshByAEIAIgBiAIfCIEhXwiAkEgEAshBiAEIAmFIgRBEBALIAVC/wGFIAR8IgSFIgVBFRALIQggAiAHhSICQREQCyEHIAIgBHwiAkEgEAshBCACIAeFIgJBDRALIQcgAiAFIAZ8IgV8IgJBIBALIQYgBSAIhSIFQRAQCyAEIAV8IgSFIgVBFRALIQggAiAHhSICQREQCyEHIAIgBHwiAkEgEAshBCACIAeFIgJBDRALIQcgAiAFIAZ8IgV8IgJBIBALIQYgBSAIhSIFQRAQCyAEIAV8IgSFIgVBFRALIQggAiAHhSICQREQCyEHIAIgBHwiAkEgEAshBCACIAeFIgJBDRALIQcgACAIIAUgBnwiBYUiBkEQEAsgBCAGfCIEhUEVEAsgByACIAV8hSICIAR8IgSFIAJBERALhSAEQSAQC4UQGUEACwsAIAAgASACELABCwUAQcYLC14BAn8jAEGgAWsiAyQAA0AgACACaiABIAJqLQAAOgAAIAJBAWoiAkEgRw0ACyAAIAAtAB9B/wBxOgAfIAMgABBmIAAgAxBjIABBIBA5IQAgA0GgAWokAEF/QQAgABsLewECfyMAQcACayIEJABBfyEDIAQgAhBRRQRAQQAhAwNAIAAgA2ogASADai0AADoAACADQQFqIgNBIEcNAAsgACAALQAfQf8AcToAHyAEQaABaiAAIAQQ0QIgACAEQaABahBjQX9BACAAQSAQORshAwsgBEHAAmokACADCwsAIAAgASACEO8BCw0AIAAgASACIAMQ8AELBwAgABDxAQsJACAAIAEQ9gELCwAgACABIAIQlwELBQBBqQsLCgAgACABIAIQJQs6AQN+IAEpACAhAiABKQAoIQMgASkAMCEEIAAgASkAODcAGCAAIAQ3ABAgACADNwAIIAAgAjcAAEEACzoBA34gASkACCECIAEpABAhAyABKQAAIQQgACABKQAYNwAYIAAgAzcAECAAIAI3AAggACAENwAAQQALewEBfwJAAkACQCADQsAAVA0AIANCQHwiA0K/////D1YNACACIAJBQGsiBSADIAQQ8wFFDQEgAEUNACAAQQAgA6cQFhoLQX8hAiABRQ0BIAFCADcDAEF/DwsgAQRAIAEgAzcDAAtBACECIABFDQAgACAFIAOnEEwaCyACC20BAX8jAEFAaiICJAAgAiABQiAQXhogAiACLQAAQfgBcToAACACIAItAB9BP3FBwAByOgAfIAAgAikDEDcAECAAIAIpAwg3AAggACACKQMANwAAIAAgAikDGDcAGCACQcAAEAwgAkFAayQAQQALhgEBAn8jAEGAAmsiAiQAQX8hAwJAIAEQZA0AIAJB4ABqIAEQwAENACACQeAAahC7AUUNACACEBwgAiACIAJBiAFqIgEQFSACQTBqEBwgAkEwaiACQTBqIAEQEyACIAIQSiACQTBqIAJBMGogAhAKIAAgAkEwahA2QQAhAwsgAkGAAmokACADCwUAQdgLCwgAIAAgARApCwgAIAAgARAqCwUAQdALCwsAIAAgAUEAEPcBCwsAIAAgAUEBEPcBCw0AIAAgASACQQAQ+gELDQAgACABIAJBARD6AQsGAEGAgCALBgBBgIACCwUAQaIMCwUAQeYAC6IBAQZ/IwBBEGsiBUEANgIMQX8hBCACIANBAWtLBH8gASACQQFrIgZqIQdBACECQQAhAUEAIQQDQCAFIAUoAgwgAkEAIAcgAmstAAAiCEGAAXNBAWsgBSgCDEEBayAEQQFrcXFBCHZBAXEiCWtxcjYCDCABIAlyIQEgBCAIciEEIAJBAWoiAiADRw0ACyAAIAYgBSgCDGs2AgAgAUEBawUgBAsL0gEBBH8jAEEQayIFJAACQAJAIANFBEBBfyEHDAELAn8gAyADQQFrIgZxRQRAIAIgBnEMAQsgAiADcAshCEF/IQcgBiAIayIGIAJBf3NPDQEgAiAGaiICIARPDQAgAARAIAAgAkEBajYCAAsgASACaiEAQQAhByAFQQA6AA9BACECA0AgACACayIBIAEtAAAgBS0AD3EgAiAGc0EBa0EYdiIBQYABcXI6AAAgBSAFLQAPIAFyOgAPIAJBAWoiAiADRw0ACwsgBUEQaiQAIAcPCxAYAAsFAEGEDAsJACAAIAEQsgELCwAgACABIAIQuwILCwAgACABIAIQswELCQAgACABELwCCwkAIAAgARC0AQsJACAAIAEQvQILBwAgABC+AgsjAQF/IwBBQGoiASQAIAFBwAAQJyAAIAEQjwIaIAFBQGskAAtuAQJ/IwBBoAZrIgMkAEF/IQQCQCADQYAFaiABEFENACADQeADaiACEFENACADIANB4ANqEBogA0GgAWogA0GABWogAxCDASADQcACaiADQaABahAUIAAgA0HAAmoQY0EAIQQLIANBoAZqJAAgBAttAQJ/IwBBoAZrIgMkAEF/IQQCQCADQYAFaiABEFENACADQeADaiACEFENACADIANB4ANqEBogA0GgAWogA0GABWogAxAbIANBwAJqIANBoAFqEBQgACADQcACahBjQQAhBAsgA0GgBmokACAECyEBAX8jAEGgAWsiASQAIAEgABBRIQAgAUGgAWokACAARQtzAQF/IwBBEGsiBSQAIAAgBUEIaiAAQUBrIAIgA6ciAhBMIAMgBBCaAhoCQCAFKQMIQsAAUgRAIAEEQCABQgA3AwALIABBACACQUBrEBYaQX8hAAwBC0EAIQAgAUUNACABIANCQH03AwALIAVBEGokACAACwUAQYUJCwgAQYCAgIACCwgAQYCAgMAACwQAQQYLBQBBjQwLPwEBfyABEK8BIABBA24iAkECdEEBciACQX1sIABqIgBBAXYgAHJBAXFBBEEDIABrQQAgAUEBdkEBcWtxa2xqC/kCAQp/An8CQCADRQ0AAkACQANAIAchCANAAkAgAiAIai0AACIMQd8BcUE3a0H/AXEiDUH2/wNqIA1B8P8DanNBCHYiDiAMQTBzIg9B9v8DakEIdiIKckH/AXFFBEBBASEKIARFIAtB/wFxcg0EIAQgDBBdDQEgCCEHDAYLIAEgCU0EQEHUogJBxAA2AgBBACEKDAQLIA0gDnEgCiAPcXIhBwJAIAtB/wFxRQRAIAdBBHQhEAwBCyAAIAlqIAcgEHI6AAAgCUEBaiEJCyALQX9zIQtBASEKIAhBAWoiByADSQ0CDAQLQQAhCyAIQQFqIgggA0kNAAsLIAMgB0EBaiIAIAAgA0kbIQcMAgsgCCEHCyALQf8BcQRAQdSiAkEcNgIAIAdBAWshB0EAIQlBfwwCCyAKDQBBACEJQX8MAQtBAAshCAJAIAYEQCAGIAIgB2o2AgAMAQsgAyAHRg0AQdSiAkEcNgIAQX8hCAsgBQRAIAUgCTYCAAsgCAusAQEDfwJAIANB/v///wdLIANBAXQgAU9yRQRAIAMEQEEAIQEDQCAAIAFBAXQiBGogASACai0AACIFQQR2IgYgBkH2/wNqQQh2QdkBcWpB1wBqOgAAIAAgBEEBcmogBUEPcSIEQQh0IARB9v8DakGAsgNxakGArgFqQQh2OgAAIAFBAWoiASADRw0ACyAAIANBAXRqIQEMAgsgACEBDAELEBgACyABQQA6AAAgAAs7AQJ/IwBBIGsiBiQAQX8hByAGIAQgBRB3RQRAIAAgASACIAMgBhCyAiEHIAZBIBAMCyAGQSBqJAAgBws7AQJ/IwBBIGsiBiQAQX8hByAGIAQgBRB3RQRAIAAgASACIAMgBhCzAiEHIAZBIBAMCyAGQSBqJAAgBwsiAQF/IwBBIGsiASQAIAFBIBAnIAAgARC/AhogAUEgaiQAC/wBAQR/IwBBoAFrIgIkACABLQAAIQUDQCACQYABaiADaiABIANrIgQtAD86AAAgAkHgAGogA2ogBC0AHzoAACADQQFqIgNBIEcNAAsgAiACLQCfAUH/AHE6AJ8BIAIgAi0Af0H/AHE6AH8gAkEwaiACQYABahA3IAIgAkHgAGoQNyACIAIoAjAgASwAIEEHdkETcWogAigCAEEmbGo2AjBBASEDA0AgA0ECdCIBIAJBMGpqIgQgBCgCACABIAJqKAIAQSZsajYCACADQQFqIgNBCkcNAAsgAkEwaiACQTBqEMIBIAAgAkEwaiAFQYABcRDLAiACQaABaiQAQQALhAEBAn8jAEGgBmsiAyQAQX8hBAJAIANBgAVqIAEQQg0AIANBgAVqEGVFDQAgA0HgA2ogAhBCDQAgA0HgA2oQZUUNACADIANB4ANqEBogA0GgAWogA0GABWogAxCDASADQcACaiADQaABahAUIAAgA0HAAmoQQEEAIQQLIANBoAZqJAAgBAuDAQECfyMAQaAGayIDJABBfyEEAkAgA0GABWogARBCDQAgA0GABWoQZUUNACADQeADaiACEEINACADQeADahBlRQ0AIAMgA0HgA2oQGiADQaABaiADQYAFaiADEBsgA0HAAmogA0GgAWoQFCAAIANBwAJqEEBBACEECyADQaAGaiQAIAQLQgECfyMAQaABayIBJAACQCAAELoBRQ0AIAAQZA0AIAEgABBCDQAgARBlRQ0AIAEQuwFBAEchAgsgAUGgAWokACACC1cBAX8jAEHQAGsiBiQAIAJQRQRAIAZBDGogBBAPIAZBEGogBRB8IAZBEGogAyAGQQxqEMYCIAZBEGogASAAIAIQeyAGQRBqQcAAEAwLIAZB0ABqJABBAAtlAQF/IwBB0ABrIgYkACACUEUEQCAGQQhqIASnEA8gBkEMaiAEQiCIpxAPIAZBEGogBRB8IAZBEGogAyAGQQhqEMcCIAZBEGogASAAIAIQeyAGQRBqQcAAEAwLIAZB0ABqJABBAAtGAQF/IwBBQGoiBCQAIAFQRQRAIAQgAxB8IAQgAkEAEMYCIAQgAEEAIAGnEBYiACAAIAEQeyAEQcAAEAwLIARBQGskAEEACyYBAn8CQEHQogIoAgAiAEUNACAAKAIUIgBFDQAgABEAACEBCyABC0YBAX8jAEFAaiIEJAAgAVBFBEAgBCADEHwgBCACQQAQxwIgBCAAQQAgAacQFiIAIAAgARB7IARBwAAQDAsgBEFAayQAQQALnwIBAn9B4KYCKAIABH9BAQVBpKICQQA2AgAjAEEQayIAJAAgABDBASAAKAIABH8gABDBAUGoogJBAEEoEBYaQQAFQX8LGiAAQRBqJABBoKICQQE2AgAQzQICQAJ/QfwMLgEAIgBFBEBB1KICQRw2AgBBfwwBCwJAAkAgAEF+Sg0AQemgDCEBAkACQAJAAkACQAJAAkAgAEH/AXFBAWsOCggAAQIDBAQFBQYHC0GAgAgMCAtBgIACDAcLQYCABAwGC0H/////BwwFC0EBDAQLEANBEHYMAwtBAAwCCyAAIQELIAELIgBBAU4EQEHkmwIgADYCAAwBC0HkmwIoAgAhAAsgAEEPTQRAEBgAC0HQpgJBEBAnQeCmAkEBNgIAQQALCw8AIAAgAa1BpgwgAhBPGgvzAgECfyMAQfAAayIHJAAgAlBFBEAgByAFKQAYNwMYIAcgBSkAEDcDECAHIAUpAAA3AwBBCCEGIAcgBSkACDcDCCAHIAMpAAA3A2ADQCAHQeAAaiAGaiAEPAAAIARCCIghBCAGQQFqIgZBEEcNAAsgAkI/VgRAA0BBACEGIAdBIGogB0HgAGogB0EAEGIaA0AgACAGaiAHQSBqIAZqLQAAIAEgBmotAABzOgAAQQEhBSAGQQFqIgZBwABHDQALQQghBgNAIAdB4ABqIAZqIgMgBSADLQAAaiIDOgAAIANBCHYhBSAGQQFqIgZBEEcNAAsgAUFAayEBIABBQGshACACQkB8IgJCP1YNAAsLIAJQRQRAQQAhBiAHQSBqIAdB4ABqIAdBABBiGiACpyEDA0AgACAGaiAHQSBqIAZqLQAAIAEgBmotAABzOgAAIAZBAWoiBiADRw0ACwsgB0EgakHAABAMIAdBIBAMCyAHQfAAaiQAQQALlwICAn8BfiMAQfAAayIEJAAgAVBFBEAgBCADKQAYNwMYIAQgAykAEDcDECAEIAMpAAA3AwAgBCADKQAINwMIIAIpAAAhBiAEQgA3A2ggBCAGNwNgAkAgAULAAFoEQANAIAAgBEHgAGogBEEAEGIaQQghA0EBIQIDQCAEQeAAaiADaiIFIAIgBS0AAGoiAjoAACACQQh2IQIgA0EBaiIDQRBHDQALIABBQGshACABQkB8IgFCP1YNAAsgAVANAQtBACEDIARBIGogBEHgAGogBEEAEGIaIAGnIQIDQCAAIANqIARBIGogA2otAAA6AAAgA0EBaiIDIAJHDQALCyAEQSBqQcAAEAwgBEEgEAwLIARB8ABqJABBAAunAQEDfyMAQdABayICJAADQCAAIANqIAEgA2otAAA6AAAgA0EBaiIDQSBHDQALIAAgAC0AAEH4AXE6AAAgACAALQAfQT9xQcAAcjoAHyACQTBqIAAQZiMAQeAAayIBJAAgAUEwaiACQYABaiIDIAJB2ABqIgQQEyABIAMgBBAVIAEgARBKIAIgAUEwaiABEAogAUHgAGokACAAIAIQNiACQdABaiQAQQAL7AkCCH8MfiMAQdACayIDJABBfyEEAn8gAiEGIwBBEGsiCEEANgALIAhBADYCCANAIAYgB2otAAAhCUEAIQUDQCAIQQhqIAVqIgogCi0AACAFQQV0QcCPAmogB2otAAAgCXNyOgAAIAVBAWoiBUEHRw0ACyAHQQFqIgdBH0cNAAsgBi0AH0H/AHEhB0EAIQZBACEFA0AgCEEIaiAFaiIJIAktAAAgByAFQQV0Qd+PAmotAABzcjoAACAFQQFqIgVBB0cNAAtBACEFA0AgCEEIaiAGai0AAEEBayAFciEFIAZBAWoiBkEHRw0ACyAFQQh2QQFxRQsEQEEAIQQDQCAAIARqIAEgBGotAAA6AAAgBEEBaiIEQSBHDQALIAAgAC0AAEH4AXE6AAAgACAALQAfQT9xQcAAcjoAHyADQaACaiACEDcgA0HwAWoQHCADQcABahBJIANBkAFqIANBoAJqECMgA0HgAGoQHEH+ASECQQAhBANAIANB8AFqIANBkAFqIAAgAiIGQQN2ai0AACAGQQdxdkEBcSIBIARzIgQQgQEgA0HAAWogA0HgAGogBBCBASAGQQFrIQIgA0EwaiADQZABaiADQeAAahAVIAMgA0HwAWogA0HAAWoQFSADQfABaiADQfABaiADQcABahATIANBwAFqIANBkAFqIANB4ABqEBMgA0HgAGogA0EwaiADQfABahAKIANBwAFqIANBwAFqIAMQCiADQTBqIAMQDiADIANB8AFqEA4gA0GQAWogA0HgAGogA0HAAWoQEyADQcABaiADQeAAaiADQcABahAVIANB8AFqIAMgA0EwahAKIAMgAyADQTBqEBUgA0HAAWogA0HAAWoQDiADNAIEIQsgAzQCCCEMIAM0AgwhDSADNAIQIQ4gAzQCFCEPIAM0AhghECADNAIAIRQgAyADNAIkQsK2B34iESARQoCAgAh8IhFCgICA8A+DfSADNAIgQsK2B34gAzQCHELCtgd+IhJCgICACHwiE0IZh3wiFUKAgIAQfCIWQhqIfD4ChAEgAyAVIBZCgICA4A+DfT4CgAEgAyASIBNCgICA8A+DfSAQQsK2B34gD0LCtgd+Ig9CgICACHwiEEIZh3wiEkKAgIAQfCITQhqIfD4CfCADIBIgE0KAgIDgD4N9PgJ4IAMgDyAQQoCAgPAPg30gDkLCtgd+IA1CwrYHfiINQoCAgAh8Ig5CGYd8Ig9CgICAEHwiEEIaiHw+AnQgAyAPIBBCgICA4A+DfT4CcCADIA0gDkKAgIDwD4N9IAxCwrYHfiALQsK2B34iC0KAgIAIfCIMQhmHfCINQoCAgBB8Ig5CGoh8PgJsIAMgDSAOQoCAgOAPg30+AmggAyALIAxCgICA8A+DfSARQhmHQhN+IBRCwrYHfnwiC0KAgIAQfCIMQhqIfD4CZCADIAsgDEKAgIDgD4N9PgJgIANBkAFqIANBkAFqEA4gA0EwaiADQTBqIANB4ABqEBMgA0HgAGogA0GgAmogA0HAAWoQCiADQcABaiADIANBMGoQCiABIQQgBg0ACyADQfABaiADQZABaiABEIEBIANBwAFqIANB4ABqIAEQgQEgA0HAAWogA0HAAWoQSiADQfABaiADQfABaiADQcABahAKIAAgA0HwAWoQNkEAIQQLIANB0AJqJAAgBAsrAQJ/IABBAk8Ef0EAIABrIABwIQEDQBC9ASICIAFJDQALIAIgAHAFIAELCwUAQcEICwvWjgIYAEGACAuyBC4vMDEyMzQ1Njc4OUFCQ0RFRkdISUpLTE1OT1BRUlNUVVZXWFlaYWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXoAanMAcmFuZG9tYnl0ZXMAYjY0X3BvcyA8PSBiNjRfbGVuAGNyeXB0b19nZW5lcmljaGFzaF9ibGFrZTJiX2ZpbmFsACRhcmdvbjJpACRhcmdvbjJpZAByYW5kb21ieXRlcy9yYW5kb21ieXRlcy5jAHNvZGl1bS9jb2RlY3MuYwBjcnlwdG9fZ2VuZXJpY2hhc2gvYmxha2UyYi9yZWYvYmxha2UyYi1yZWYuYwBjcnlwdG9fZ2VuZXJpY2hhc2gvYmxha2UyYi9yZWYvZ2VuZXJpY2hhc2hfYmxha2UyYi5jAHgyNTUxOWJsYWtlMmIAYnVmX2xlbiA8PSBTSVpFX01BWABvdXRsZW4gPD0gVUlOVDhfTUFYAFMtPmJ1ZmxlbiA8PSBCTEFLRTJCX0JMT0NLQllURVMAJGFyZ29uMmkkdj0AJGFyZ29uMmlkJHY9ACx0PQAscD0AJG09AGN1cnZlMjU1MTkAZWQyNTUxOQAxLjAuMTgAaG1hY3NoYTUxMjI1NgBjdXJ2ZTI1NTE5eHNhbHNhMjBwb2x5MTMwNQBzb2RpdW1fYmluMmJhc2U2NABzaXBoYXNoMjQAc2hhNTEyAHhzYWxzYTIwACRhcmdvbjJpJAAkYXJnb24yaWQkACQ3JABMaWJzb2RpdW1EUkcAQcAMC2oC/wAEZAAgAAAE//8GAAEAAQABAP//Af8B//////8B/wH/Af8B/wH/Af8B/wH//////wr/IAD//wP/Af8E/x4AAAEF//////9jAAAIYwDoAwIAAAD//////wAAAAH/Af//////////////AEG5DQsBBABBxg0LRAH/Af//////AAEgAAQAgAAACP//Af8B/////////wH/Bv8H/wj/Cf//////vAK8AgEA//8BAAEA//8AAP//////////AEGaDgsBFABBug4LHv//AQAK////////////Af8B/wAAAAAAAAH/Af8B/wBB6g4LSAH/AAAAAAAAAf8B/wEAAAABAAAAAf//////AAAAAAH///8AAAAA/////////////ygACv//////AQAK/////wD//////////wBBlhALHAH/Af///wEACv////////////////8K//////8AQcAQC5cBCMm882fmCWo7p8qEha5nuyv4lP5y82488TYdXzr1T6XRguatf1IOUR9sPiuMaAWba71B+6vZgx95IX4TGc3gW7Z4Wf+FctMAvW4V/w8KagApwAEAmOh5/7w8oP+Zcc7/ALfi/rQNSP8AAAAAAAAAALCgDv7TyYb/nhiPAH9pNQBgDL0Ap9f7/59MgP5qZeH/HvwEAJIMrgBB4BELJ1nxsv4K5ab/e90q/h4U1ABSgAMAMNHzAHd5QP8y45z/AG7FAWcbkABBkBILwAeFO4wBvfEk//glwwFg3DcAt0w+/8NCPQAyTKQB4aRM/0w9o/91Ph8AUZFA/3ZBDgCic9b/BoouAHzm9P8Kio8ANBrCALj0TACBjykBvvQT/3uqev9igUQAedWTAFZlHv+hZ5sAjFlD/+/lvgFDC7UAxvCJ/u5FvP9Dl+4AEyps/+VVcQEyRIf/EWoJADJnAf9QAagBI5ge/xCouQE4Wej/ZdL8ACn6RwDMqk//Di7v/1BN7wC91kv/EY35ACZQTP++VXUAVuSqAJzY0AHDz6T/lkJM/6/hEP+NUGIBTNvyAMaicgAu2pgAmyvx/pugaP8zu6UAAhGvAEJUoAH3Oh4AI0E1/kXsvwAthvUBo3vdACBuFP80F6UAutZHAOmwYADy7zYBOVmKAFMAVP+IoGQAXI54/mh8vgC1sT7/+ilVAJiCKgFg/PYAl5c//u+FPgAgOJwALae9/46FswGDVtMAu7OW/vqqDv/So04AJTSXAGNNGgDunNX/1cDRAUkuVAAUQSkBNs5PAMmDkv6qbxj/sSEy/qsmy/9O93QA0d2ZAIWAsgE6LBkAySc7Ab0T/AAx5dIBdbt1ALWzuAEActsAMF6TAPUpOAB9Dcz+9K13ACzdIP5U6hQA+aDGAex+6v8vY6j+quKZ/2az2ADijXr/ekKZ/rb1hgDj5BkB1jnr/9itOP+159IAd4Cd/4FfiP9ufjMAAqm3/weCYv5FsF7/dATjAdnykf/KrR8BaQEn/y6vRQDkLzr/1+BF/s84Rf8Q/ov/F8/U/8oUfv9f1WD/CbAhAMgFz//xKoD+IyHA//jlxAGBEXgA+2eX/wc0cP+MOEL/KOL1/9lGJf6s1gn/SEOGAZLA1v8sJnAARLhL/85a+wCV640Atao6AHT07wBcnQIAZq1iAOmJYAF/McsABZuUABeUCf/TegwAIoYa/9vMiACGCCn/4FMr/lUZ9wBtfwD+qYgwAO532//nrdUAzhL+/gi6B/9+CQcBbypIAG807P5gP40Ak79//s1OwP8Oau0Bu9tMAK/zu/5pWa0AVRlZAaLzlAACdtH+IZ4JAIujLv9dRigAbCqO/m/8jv+b35AAM+Wn/0n8m/9edAz/mKDa/5zuJf+z6s//xQCz/5qkjQDhxGgACiMZ/tHU8v9h/d7+uGXlAN4SfwGkiIf/Hs+M/pJh8wCBwBr+yVQh/28KTv+TUbL/BAQYAKHu1/8GjSEANdcO/ym10P/ni50As8vd//+5cQC94qz/cULW/8o+Lf9mQAj/Tq4Q/oV1RP8AQfAZCwEBAEGQGguwASbolY/CsiewRcP0ifLvmPDV36wF08YzObE4AohtU/wFxxdqcD1N2E+6PAt2DRBnDyogU/osOczGTsf9d5KsA3rs////////////////////////////////////////f+3///////////////////////////////////////9/7v///////////////////////////////////////3/t0/VcGmMSWNac96Le+d4UAEHPGwus8QEQ/UBdAKBqPwA501f+DNK6AFi8dP5B2AEA/8g9AdhClP8A+1wAJLLh/wAAAAAAAAAAhTuMAb3xJP/4JcMBYNw3ALdMPv/DQj0AMkykAeGkTP9MPaP/dT4fAFGRQP92QQ4AonPW/waKLgB85vT/CoqPADQawgC49EwAgY8pAb70E/97qnr/YoFEAHnVkwBWZR7/oWebAIxZQ//v5b4BQwu1AMbwif7uRbz/6nE8/yX/Of9Fsrb+gNCzAHYaff4DB9b/8TJN/1XLxf/Th/r/GTBk/7vVtP4RWGkAU9GeAQVzYgAErjz+qzdu/9m1Ef8UvKoAkpxm/lfWrv9yepsB6SyqAH8I7wHW7OoArwXbADFqPf8GQtD/Ampu/1HqE//Xa8D/Q5fuABMqbP/lVXEBMkSH/xFqCQAyZwH/UAGoASOYHv8QqLkBOFno/2XS/AAp+kcAzKpP/w4u7/9QTe8AvdZL/xGN+QAmUEz/vlV1AFbkqgCc2NABw8+k/5ZCTP+v4RD/jVBiAUzb8gDGonIALtqYAJsr8f6boGj/sgn8/mRu1AAOBacA6e+j/xyXnQFlkgr//p5G/kf55ABYHjIARDqg/78YaAGBQoH/wDJV/wiziv8m+skAc1CgAIPmcQB9WJMAWkTHAP1MngAc/3YAcfr+AEJLLgDm2isA5Xi6AZREKwCIfO4Bu2vF/1Q19v8zdP7/M7ulAAIRrwBCVKAB9zoeACNBNf5F7L8ALYb1AaN73QAgbhT/NBelALrWRwDpsGAA8u82ATlZigBTAFT/iKBkAFyOeP5ofL4AtbE+//opVQCYgioBYPz2AJeXP/7vhT4AIDicAC2nvf+OhbMBg1bTALuzlv76qg7/RHEV/966O/9CB/EBRQZIAFacbP43p1kAbTTb/g2wF//ELGr/75VH/6SMff+frQEAMynnAJE+IQCKb10BuVNFAJBzLgBhlxD/GOQaADHZ4gBxS+r+wZkM/7YwYP8ODRoAgMP5/kXBOwCEJVH+fWo8ANbwqQGk40IA0qNOACU0lwBjTRoA7pzV/9XA0QFJLlQAFEEpATbOTwDJg5L+qm8Y/7EhMv6rJsv/Tvd0ANHdmQCFgLIBOiwZAMknOwG9E/wAMeXSAXW7dQC1s7gBAHLbADBekwD1KTgAfQ3M/vStdwAs3SD+VOoUAPmgxgHsfur/jz7dAIFZ1v83iwX+RBS//w7MsgEjw9kALzPOASb2pQDOGwb+nlckANk0kv99e9f/VTwf/6sNBwDa9Vj+/CM8ADfWoP+FZTgA4CAT/pNA6gAakaIBcnZ9APj8+gBlXsT/xo3i/jMqtgCHDAn+bazS/8XswgHxQZoAMJwv/5lDN//apSL+SrSzANpCRwFYemMA1LXb/1wq5//vAJoA9U23/15RqgES1dgAq11HADRe+AASl6H+xdFC/670D/6iMLcAMT3w/rZdwwDH5AYByAUR/4kt7f9slAQAWk/t/yc/Tf81Us8BjhZ2/2XoEgFcGkMABchY/yGoiv+V4UgAAtEb/yz1qAHc7RH/HtNp/o3u3QCAUPX+b/4OAN5fvgHfCfEAkkzU/2zNaP8/dZkAkEUwACPkbwDAIcH/cNa+/nOYlwAXZlgAM0r4AOLHj/7MomX/0GG9AfVoEgDm9h7/F5RFAG5YNP7itVn/0C9a/nKhUP8hdPgAs5hX/0WQsQFY7hr/OiBxAQFNRQA7eTT/mO5TADQIwQDnJ+n/xyKKAN5ErQBbOfL+3NJ//8AH9v6XI7sAw+ylAG9dzgDU94UBmoXR/5vnCgBATiYAevlkAR4TYf8+W/kB+IVNAMU/qP50ClIAuOxx/tTLwv89ZPz+JAXK/3dbmf+BTx0AZ2er/u3Xb//YNUUA7/AXAMKV3f8m4d4A6P+0/nZShf850bEBi+iFAJ6wLv7Ccy4AWPflARxnvwDd3q/+lessAJfkGf7aaWcAjlXSAJWBvv/VQV7+dYbg/1LGdQCd3dwAo2UkAMVyJQBorKb+C7YAAFFIvP9hvBD/RQYKAMeTkf8ICXMBQdav/9mt0QBQf6YA9+UE/qe3fP9aHMz+rzvw/wsp+AFsKDP/kLHD/pb6fgCKW0EBeDze//XB7wAd1r3/gAIZAFCaogBN3GsB6s1K/zamZ/90SAkA5F4v/x7IGf8j1ln/PbCM/1Pio/9LgqwAgCYRAF+JmP/XfJ8BT10AAJRSnf7Dgvv/KMpM//t+4ACdYz7+zwfh/2BEwwCMup3/gxPn/yqA/gA02z3+ZstIAI0HC/+6pNUAH3p3AIXykQDQ/Oj/W9W2/48E+v7510oApR5vAasJ3wDleyIBXIIa/02bLQHDixz/O+BOAIgR9wBseSAAT/q9/2Dj/P4m8T4APq59/5tvXf8K5s4BYcUo/wAxOf5B+g0AEvuW/9xt0v8Frqb+LIG9AOsjk/8l943/SI0E/2dr/wD3WgQANSwqAAIe8AAEOz8AWE4kAHGntAC+R8H/x56k/zoIrABNIQwAQT8DAJlNIf+s/mYB5N0E/1ce/gGSKVb/iszv/myNEf+78ocA0tB/AEQtDv5JYD4AUTwY/6oGJP8D+RoAI9VtABaBNv8VI+H/6j04/zrZBgCPfFgA7H5CANEmt/8i7gb/rpFmAF8W0wDED5n+LlTo/3UikgHn+kr/G4ZkAVy7w/+qxnAAeBwqANFGQwAdUR8AHahkAamtoABrI3UAPmA7/1EMRQGH777/3PwSAKPcOv+Jibz/U2ZtAGAGTADq3tL/ua7NATye1f8N8dYArIGMAF1o8gDAnPsAK3UeAOFRngB/6NoA4hzLAOkbl/91KwX/8g4v/yEUBgCJ+yz+Gx/1/7fWff4oeZUAup7V/1kI4wBFWAD+y4fhAMmuywCTR7gAEnkp/l4FTgDg1vD+JAW0APuH5wGjitQA0vl0/liBuwATCDH+Pg6Q/59M0wDWM1IAbXXk/mffy/9L/A8Bmkfc/xcNWwGNqGD/tbaFAPozNwDq6tT+rz+eACfwNAGevST/1ShVASC09/8TZhoBVBhh/0UV3gCUi3r/3NXrAejL/wB5OZMA4weaADUWkwFIAeEAUoYw/lM8nf+RSKkAImfvAMbpLwB0EwT/uGoJ/7eBUwAksOYBImdIANuihgD1Kp4AIJVg/qUskADK70j+15YFACpCJAGE168AVq5W/xrFnP8x6If+Z7ZSAP2AsAGZsnoA9foKAOwYsgCJaoQAKB0pADIemP98aSYA5r9LAI8rqgAsgxT/LA0X/+3/mwGfbWT/cLUY/2jcbAA304MAYwzV/5iXkf/uBZ8AYZsIACFsUQABA2cAPm0i//qbtAAgR8P/JkaRAZ9f9QBF5WUBiBzwAE/gGQBObnn/+Kh8ALuA9wACk+v+TwuEAEY6DAG1CKP/T4mF/yWqC/+N81X/sOfX/8yWpP/v1yf/Llec/gijWP+sIugAQixm/xs2Kf7sY1f/KXupATRyKwB1higAm4YaAOfPW/4jhCb/E2Z9/iTjhf92A3H/HQ18AJhgSgFYks7/p7/c/qISWP+2ZBcAH3U0AFEuagEMAgcARVDJAdH2rAAMMI0B4NNYAHTinwB6YoIAQezqAeHiCf/P4nsBWdY7AHCHWAFa9Mv/MQsmAYFsugBZcA8BZS7M/3/MLf5P/93/M0kS/38qZf/xFcoAoOMHAGky7ABPNMX/aMrQAbQPEABlxU7/Yk3LACm58QEjwXwAI5sX/881wAALfaMB+Z65/wSDMAAVXW//PXnnAUXIJP+5MLn/b+4V/ycyGf9j16P/V9Qe/6STBf+ABiMBbN9u/8JMsgBKZbQA8y8wAK4ZK/9Srf0BNnLA/yg3WwDXbLD/CzgHAODpTADRYsr+8hl9ACzBXf7LCLEAh7ATAHBH1f/OO7ABBEMaAA6P1f4qN9D/PEN4AMEVowBjpHMAChR2AJzU3v6gB9n/cvVMAXU7ewCwwlb+1Q+wAE7Oz/7VgTsA6fsWAWA3mP/s/w//xVlU/12VhQCuoHEA6mOp/5h0WACQpFP/Xx3G/yIvD/9jeIb/BezBAPn3fv+Tux4AMuZ1/2zZ2/+jUab/SBmp/pt5T/8cm1n+B34RAJNBIQEv6v0AGjMSAGlTx/+jxOYAcfikAOL+2gC90cv/pPfe/v8jpQAEvPMBf7NHACXt/v9kuvAABTlH/mdISf/0ElH+5dKE/+4GtP8L5a7/493AARExHACj18T+CXYE/zPwRwBxgW3/TPDnALyxfwB9RywBGq/zAF6pGf4b5h0AD4t3Aaiquv+sxUz//Eu8AIl8xABIFmD/LZf5AdyRZABAwJ//eO/iAIGykgAAwH0A64rqALedkgBTx8D/uKxI/0nhgABNBvr/ukFDAGj2zwC8IIr/2hjyAEOKUf7tgXn/FM+WASnHEP8GFIAAn3YFALUQj//cJg8AF0CT/kkaDQBX5DkBzHyAACsY3wDbY8cAFksU/xMbfgCdPtcAbh3mALOn/wE2/L4A3cy2/rOeQf9RnQMAwtqfAKrfAADgCyD/JsViAKikJQAXWAcBpLpuAGAkhgDq8uUA+nkTAPL+cP8DL14BCe8G/1GGmf7W/aj/Q3zgAPVfSgAcHiz+AW3c/7JZWQD8JEwAGMYu/0xNbwCG6oj/J14dALlI6v9GRIf/52YH/k3njACnLzoBlGF2/xAb4QGmzo//brLW/7SDogCPjeEBDdpO/3KZIQFiaMwAr3J1AafOSwDKxFMBOkBDAIovbwHE94D/ieDg/p5wzwCaZP8BhiVrAMaAT/9/0Zv/o/65/jwO8wAf23D+HdlBAMgNdP57PMT/4Du4/vJZxAB7EEv+lRDOAEX+MAHndN//0aBBAchQYgAlwrj+lD8iAIvwQf/ZkIT/OCYt/sd40gBssab/oN4EANx+d/6la6D/Utz4AfGviACQjRf/qYpUAKCJTv/idlD/NBuE/z9gi/+Y+icAvJsPAOgzlv4oD+j/8OUJ/4mvG/9LSWEB2tQLAIcFogFrudUAAvlr/yjyRgDbyBkAGZ0NAENSUP/E+Rf/kRSVADJIkgBeTJQBGPtBAB/AFwC41Mn/e+miAfetSACiV9v+foZZAJ8LDP6maR0ASRvkAXF4t/9Co20B1I8L/5/nqAH/gFoAOQ46/lk0Cv/9CKMBAJHS/wqBVQEutRsAZ4ig/n680f8iI28A19sY/9QL1v5lBXYA6MWF/9+nbf/tUFb/RoteAJ7BvwGbDzP/D75zAE6Hz//5ChsBtX3pAF+sDf6q1aH/J+yK/19dV/++gF8AfQ/OAKaWnwDjD57/zp54/yqNgABlsngBnG2DANoOLP73qM7/1HAcAHAR5P9aECUBxd5sAP7PU/8JWvP/8/SsABpYc//NdHoAv+bBALRkCwHZJWD/mk6cAOvqH//OsrL/lcD7ALb6hwD2FmkAfMFt/wLSlf+pEaoAAGBu/3UJCAEyeyj/wb1jACLjoAAwUEb+0zPsAC169f4srggArSXp/55BqwB6Rdf/WlAC/4NqYP7jcocAzTF3/rA+QP9SMxH/8RTz/4INCP6A2fP/ohsB/lp28QD2xvb/NxB2/8ifnQCjEQEAjGt5AFWhdv8mAJUAnC/uAAmmpgFLYrX/MkoZAEIPLwCL4Z8ATAOO/w7uuAALzzX/t8C6Aasgrv+/TN0B96rbABmsMv7ZCekAy35E/7dcMAB/p7cBQTH+ABA/fwH+Far/O+B//hYwP/8bToL+KMMdAPqEcP4jy5AAaKmoAM/9Hv9oKCb+XuRYAM4QgP/UN3r/3xbqAN/FfwD9tbUBkWZ2AOyZJP/U2Uj/FCYY/oo+PgCYjAQA5txj/wEV1P+UyecA9HsJ/gCr0gAzOiX/Af8O//S3kf4A8qYAFkqEAHnYKQBfw3L+hRiX/5zi5//3BU3/9pRz/uFcUf/eUPb+qntZ/0rHjQAdFAj/iohG/11LXADdkzH+NH7iAOV8FwAuCbUAzUA0AYP+HACXntQAg0BOAM4ZqwAA5osAv/1u/mf3pwBAKCgBKqXx/ztL5P58873/xFyy/4KMVv+NWTgBk8YF/8v4nv6Qoo0AC6ziAIIqFf8Bp4//kCQk/zBYpP6oqtwAYkfWAFvQTwCfTMkBpirW/0X/AP8GgH3/vgGMAJJT2v/X7kgBen81AL10pf9UCEL/1gPQ/9VuhQDDqCwBnudFAKJAyP5bOmgAtjq7/vnkiADLhkz+Y93pAEv+1v5QRZoAQJj4/uyIyv+daZn+la8UABYjE/98eekAuvrG/oTliwCJUK7/pX1EAJDKlP7r7/gAh7h2AGVeEf96SEb+RYKSAH/e+AFFf3b/HlLX/rxKE//lp8L+dRlC/0HqOP7VFpwAlztd/i0cG/+6fqT/IAbvAH9yYwHbNAL/Y2Cm/j6+fv9s3qgBS+KuAObixwA8ddr//PgUAda8zAAfwob+e0XA/6mtJP43YlsA3ypm/okBZgCdWhkA73pA//wG6QAHNhT/UnSuAIclNv8Pun0A43Cv/2S04f8q7fT/9K3i/vgSIQCrY5b/Susy/3VSIP5qqO0Az23QAeQJugCHPKn+s1yPAPSqaP/rLXz/RmO6AHWJtwDgH9cAKAlkABoQXwFE2VcACJcU/xpkOv+wpcsBNHZGAAcg/v70/vX/p5DC/31xF/+webUAiFTRAIoGHv9ZMBwAIZsO/xnwmgCNzW0BRnM+/xQoa/6Kmsf/Xt/i/52rJgCjsRn+LXYD/w7eFwHRvlH/dnvoAQ3VZf97N3v+G/alADJjTP+M1iD/YUFD/xgMHACuVk4BQPdgAKCHQwBCN/P/k8xg/xoGIf9iM1MBmdXQ/wK4Nv8Z2gsAMUP2/hKVSP8NGUgAKk/WACoEJgEbi5D/lbsXABKkhAD1VLj+eMZo/37aYAA4der/DR3W/kQvCv+nmoT+mCbGAEKyWf/ILqv/DWNT/9K7/f+qLSoBitF8ANaijQAM5pwAZiRw/gOTQwA013v/6as2/2KJPgD32if/59rsAPe/fwDDklQApbBc/xPUXv8RSuMAWCiZAcaTAf/OQ/X+8APa/z2N1f9ht2oAw+jr/l9WmgDRMM3+dtHx//B43wHVHZ8Ao3+T/w3aXQBVGET+RhRQ/70FjAFSYf7/Y2O//4RUhf9r2nT/cHouAGkRIADCoD//RN4nAdj9XACxac3/lcnDACrhC/8oonMACQdRAKXa2wC0FgD+HZL8/5LP4QG0h2AAH6NwALEL2/+FDMH+K04yAEFxeQE72Qb/bl4YAXCsbwAHD2AAJFV7AEeWFf/QSbwAwAunAdX1IgAJ5lwAoo4n/9daGwBiYVkAXk/TAFqd8ABf3H4BZrDiACQe4P4jH38A5+hzAVVTggDSSfX/L49y/0RBxQA7SD7/t4Wt/l15dv87sVH/6kWt/82AsQDc9DMAGvTRAUneTf+jCGD+lpXTAJ7+ywE2f4sAoeA7AARtFv/eKi3/0JJm/+yOuwAyzfX/CkpZ/jBPjgDeTIL/HqY/AOwMDf8xuPQAu3FmANpl/QCZObb+IJYqABnGkgHt8TgAjEQFAFukrP9Okbr+QzTNANvPgQFtcxEANo86ARX4eP+z/x4AwexC/wH/B//9wDD/E0XZAQPWAP9AZZIB330j/+tJs//5p+IA4a8KAWGiOgBqcKsBVKwF/4WMsv+G9Y4AYVp9/7rLuf/fTRf/wFxqAA/Gc//ZmPgAq7J4/+SGNQCwNsEB+vs1ANUKZAEix2oAlx/0/qzgV/8O7Rf//VUa/38ndP+saGQA+w5G/9TQiv/90/oAsDGlAA9Me/8l2qD/XIcQAQp+cv9GBeD/9/mNAEQUPAHx0r3/w9m7AZcDcQCXXK4A5z6y/9u34QAXFyH/zbVQADm4+P9DtAH/Wntd/ycAov9g+DT/VEKMACJ/5P/CigcBpm68ABURmwGavsb/1lA7/xIHjwBIHeIBx9n5AOihRwGVvskA2a9f/nGTQ/+Kj8f/f8wBAB22UwHO5pv/usw8AAp9Vf/oYBn//1n3/9X+rwHowVEAHCuc/gxFCACTGPgAEsYxAIY8IwB29hL/MVj+/uQVuv+2QXAB2xYB/xZ+NP+9NTH/cBmPACZ/N//iZaP+0IU9/4lFrgG+dpH/PGLb/9kN9f/6iAoAVP7iAMkffQHwM/v/H4OC/wKKMv/X17EB3wzu//yVOP98W0T/SH6q/nf/ZACCh+j/Dk+yAPqDxQCKxtAAediL/ncSJP8dwXoAECot/9Xw6wHmvqn/xiPk/m6tSADW3fH/OJSHAMB1Tv6NXc//j0GVABUSYv9fLPQBar9NAP5VCP7WbrD/Sa0T/qDEx//tWpAAwaxx/8ibiP7kWt0AiTFKAaTd1//RvQX/aew3/yofgQHB/+wALtk8AIpYu//iUuz/UUWX/46+EAENhggAf3ow/1FAnACr84sA7SP2AHqPwf7UepIAXyn/AVeETQAE1B8AER9OACctrf4Yjtn/XwkG/+NTBgBiO4L+Ph4hAAhz0wGiYYD/B7gX/nQcqP/4ipf/YvTwALp2ggBy+Ov/aa3IAaB8R/9eJKQBr0GS/+7xqv7KxsUA5EeK/i32bf/CNJ4AhbuwAFP8mv5Zvd3/qkn8AJQ6fQAkRDP+KkWx/6hMVv8mZMz/JjUjAK8TYQDh7v3/UVGHANIb//7rSWsACM9zAFJ/iABUYxX+zxOIAGSkZQBQ0E3/hM/t/w8DD/8hpm4AnF9V/yW5bwGWaiP/ppdMAHJXh/+fwkAADHof/+gHZf6td2IAmkfc/r85Nf+o6KD/4CBj/9qcpQCXmaMA2Q2UAcVxWQCVHKH+zxceAGmE4/825l7/ha3M/1y3nf9YkPz+ZiFaAJ9hAwC12pv/8HJ3AGrWNf+lvnMBmFvh/1hqLP/QPXEAlzR8AL8bnP9uNuwBDh6m/yd/zwHlxxwAvOS8/mSd6wD22rcBaxbB/86gXwBM75MAz6F1ADOmAv80dQr+STjj/5jB4QCEXoj/Zb/RACBr5f/GK7QBZNJ2AHJDmf8XWBr/WZpcAdx4jP+Qcs///HP6/yLOSACKhX//CLJ8AVdLYQAP5Vz+8EOD/3Z74/6SeGj/kdX/AYG7Rv/bdzYAAROtAC2WlAH4U0gAy+mpAY5rOAD3+SYBLfJQ/x7pZwBgUkYAF8lvAFEnHv+ht07/wuoh/0TjjP7YznQARhvr/2iQTwCk5l3+1oecAJq78v68FIP/JG2uAJ9w8QAFbpUBJKXaAKYdEwGyLkkAXSsg/vi97QBmm40AyV3D//GL/f8Pb2L/bEGj/ptPvv9JrsH+9igw/2tYC/7KYVX//cwS/3HyQgBuoML+0BK6AFEVPAC8aKf/fKZh/tKFjgA48on+KW+CAG+XOgFv1Y3/t6zx/yYGxP+5B3v/Lgv2APVpdwEPAqH/CM4t/xLKSv9TfHMB1I2dAFMI0f6LD+j/rDat/jL3hADWvdUAkLhpAN/++AD/k/D/F7xIAAczNgC8GbT+3LQA/1OgFACjvfP/OtHC/1dJPABqGDEA9fncABatpwB2C8P/E37tAG6fJf87Ui8AtLtWALyU0AFkJYX/B3DBAIG8nP9UaoH/heHKAA7sb/8oFGUArKwx/jM2Sv/7ubj/XZvg/7T54AHmspIASDk2/rI+uAB3zUgAue/9/z0P2gDEQzj/6iCrAS7b5ADQbOr/FD/o/6U1xwGF5AX/NM1rAErujP+WnNv+76yy//u93/4gjtP/2g+KAfHEUAAcJGL+FurHAD3t3P/2OSUAjhGO/50+GgAr7l/+A9kG/9UZ8AEn3K7/ms0w/hMNwP/0Ijb+jBCbAPC1Bf6bwTwApoAE/ySROP+W8NsAeDORAFKZKgGM7JIAa1z4Ab0KAwA/iPIA0ycYABPKoQGtG7r/0szv/inRov+2/p//rHQ0AMNn3v7NRTsANRYpAdowwgBQ0vIA0rzPALuhof7YEQEAiOFxAPq4PwDfHmL+TaiiADs1rwATyQr/i+DCAJPBmv/UvQz+Aciu/zKFcQFes1oArbaHAF6xcQArWdf/iPxq/3uGU/4F9UL/UjEnAdwC4ABhgbEATTtZAD0dmwHLq9z/XE6LAJEhtf+pGI0BN5azAIs8UP/aJ2EAApNr/zz4SACt5i8BBlO2/xBpov6J1FH/tLiGASfepP/dafsB73B9AD8HYQA/aOP/lDoMAFo84P9U1PwAT9eoAPjdxwFzeQEAJKx4ACCiu/85azH/kyoVAGrGKwE5SlcAfstR/4GHwwCMH7EA3YvCAAPe1wCDROcAsVay/nyXtAC4fCYBRqMRAPn7tQEqN+MA4qEsABfsbgAzlY4BXQXsANq3av5DGE0AKPXR/955mQClOR4AU308AEYmUgHlBrwAbd6d/zd2P//Nl7oA4yGV//6w9gHjseMAImqj/rArTwBqX04BufF6/7kOPQAkAcoADbKi//cLhACh5lwBQQG5/9QypQGNkkD/nvLaABWkfQDVi3oBQ0dXAMuesgGXXCsAmG8F/ycD7//Z//r/sD9H/0r1TQH6rhL/IjHj//Yu+/+aIzABfZ09/2okTv9h7JkAiLt4/3GGq/8T1dn+2F7R//wFPQBeA8oAAxq3/0C/K/8eFxUAgY1N/2Z4BwHCTIwAvK80/xFRlADoVjcB4TCsAIYqKv/uMi8AqRL+ABSTV/8Ow+//RfcXAO7lgP+xMXAAqGL7/3lH+ADzCJH+9uOZ/9upsf77i6X/DKO5/6Qoq/+Znxv+821b/94YcAES1ucAa521/sOTAP/CY2j/WYy+/7FCfv5quUIAMdofAPyungC8T+YB7ingANTqCAGIC7UApnVT/0TDXgAuhMkA8JhYAKQ5Rf6g4Cr/O9dD/3fDjf8ktHn+zy8I/67S3wBlxUT//1KNAfqJ6QBhVoUBEFBFAISDnwB0XWQALY2LAJisnf9aK1sAR5kuACcQcP/ZiGH/3MYZ/rE1MQDeWIb/gA88AM/Aqf/AdNH/ak7TAcjVt/8HDHr+3ss8/yFux/77anUA5OEEAXg6B//dwVT+cIUbAL3Iyf+Lh5YA6jew/z0yQQCYbKn/3FUB/3CH4wCiGroAz2C5/vSIawBdmTIBxmGXAG4LVv+Pda7/c9TIAAXKtwDtpAr+ue8+AOx4Ev5ie2P/qMnC/i7q1gC/hTH/Y6l3AL67IwFzFS3/+YNIAHAGe//WMbX+pukiAFzFZv795M3/AzvJASpiLgDbJSP/qcMmAF58wQGcK98AX0iF/njOvwB6xe//sbtP//4uAgH6p74AVIETAMtxpv/5H73+SJ3K/9BHSf/PGEgAChASAdJRTP9Y0MD/fvNr/+6NeP/Heer/iQw7/yTce/+Uszz+8AwdAEIAYQEkHib/cwFd/2Bn5//FnjsBwKTwAMrKOf8YrjAAWU2bASpM1wD0l+kAFzBRAO9/NP7jgiX/+HRdAXyEdgCt/sABButT/26v5wH7HLYAgfld/lS4gABMtT4Ar4C6AGQ1iP5tHeIA3ek6ARRjSgAAFqAAhg0VAAk0N/8RWYwAryI7AFSld//g4ur/B0im/3tz/wES1vYA+gdHAdncuQDUI0z/Jn2vAL1h0gBy7iz/Kbyp/i26mgBRXBYAhKDBAHnQYv8NUSz/y5xSAEc6Ff/Qcr/+MiaTAJrYwwBlGRIAPPrX/+mE6/9nr44BEA5cAI0fbv7u8S3/mdnvAWGoL//5VRABHK8+/zn+NgDe534Api11/hK9YP/kTDIAyPReAMaYeAFEIkX/DEGg/mUTWgCnxXj/RDa5/ynavABxqDAAWGm9ARpSIP+5XaQB5PDt/0K2NQCrxVz/awnpAcd4kP9OMQr/bapp/1oEH/8c9HH/SjoLAD7c9v95msj+kNKy/345gQEr+g7/ZW8cAS9W8f89Rpb/NUkF/x4angDRGlYAiu1KAKRfvACOPB3+onT4/7uvoACXEhAA0W9B/suGJ/9YbDH/gxpH/90b1/5oaV3/H+wf/ocA0/+Pf24B1EnlAOlDp/7DAdD/hBHd/zPZWgBD6zL/39KPALM1ggHpasYA2a3c/3DlGP+vml3+R8v2/zBChf8DiOb/F91x/utv1QCqeF/++90CAC2Cnv5pXtn/8jS0/tVELf9oJhwA9J5MAKHIYP/PNQ3/u0OUAKo2+AB3orL/UxQLACoqwAGSn6P/t+hvAE3lFf9HNY8AG0wiAPaIL//bJ7b/XODJAROODv9FtvH/o3b1AAltagGqtff/Ti/u/1TSsP/Va4sAJyYLAEgVlgBIgkUAzU2b/o6FFQBHb6z+4io7/7MA1wEhgPEA6vwNAbhPCABuHkn/9o29AKrP2gFKmkX/ivYx/5sgZAB9Smn/WlU9/yPlsf8+fcH/mVa8AUl41ADRe/b+h9Em/5c6LAFcRdb/DgxY//yZpv/9z3D/PE5T/+N8bgC0YPz/NXUh/qTcUv8pARv/JqSm/6Rjqf49kEb/wKYSAGv6QgDFQTIAAbMS//9oAf8rmSP/UG+oAG6vqAApaS3/2w7N/6TpjP4rAXYA6UPDALJSn/+KV3r/1O5a/5AjfP4ZjKQA+9cs/oVGa/9l41D+XKk3ANcqMQBytFX/IegbAazVGQA+sHv+IIUY/+G/PgBdRpkAtSpoARa/4P/IyIz/+eolAJU5jQDDOND//oJG/yCt8P8d3McAbmRz/4Tl+QDk6d//JdjR/rKx0f+3LaX+4GFyAIlhqP/h3qwApQ0xAdLrzP/8BBz+RqCXAOi+NP5T+F3/PtdNAa+vs/+gMkIAeTDQAD+p0f8A0sgA4LssAUmiUgAJsI//E0zB/x07pwEYK5oAHL6+AI28gQDo68v/6gBt/zZBnwA8WOj/ef2W/vzpg//GbikBU01H/8gWO/5q/fL/FQzP/+1CvQBaxsoB4ax/ADUWygA45oQAAVa3AG2+KgDzRK4BbeSaAMixegEjoLf/sTBV/1raqf/4mE4Ayv5uAAY0KwCOYkH/P5EWAEZqXQDoimsBbrM9/9OB2gHy0VwAI1rZAbaPav90Zdn/cvrd/63MBgA8lqMASaws/+9uUP/tTJn+oYz5AJXo5QCFHyj/rqR3AHEz1gCB5AL+QCLzAGvj9P+uasj/VJlGATIjEAD6Stj+7L1C/5n5DQDmsgT/3SnuAHbjef9eV4z+/ndcAEnv9v51V4AAE9OR/7Eu/ADlW/YBRYD3/8pNNgEICwn/mWCmANnWrf+GwAIBAM8AAL2uawGMhmQAnsHzAbZmqwDrmjMAjgV7/zyoWQHZDlz/E9YFAdOn/gAsBsr+eBLs/w9xuP+434sAKLF3/rZ7Wv+wpbAA903CABvqeADnANb/OyceAH1jkf+WREQBjd74AJl70v9uf5j/5SHWAYfdxQCJYQIADI/M/1EpvABzT4L/XgOEAJivu/98jQr/fsCz/wtnxgCVBi0A21W7AeYSsv9ItpgAA8a4/4Bw4AFhoeYA/mMm/zqfxQCXQtsAO0WP/7lw+QB3iC//e4KEAKhHX/9xsCgB6LmtAM9ddQFEnWz/ZgWT/jFhIQBZQW/+9x6j/3zZ3QFm+tgAxq5L/jk3EgDjBewB5dWtAMlt2gEx6e8AHjeeARmyagCbb7wBXn6MANcf7gFN8BAA1fIZASZHqADNul3+MdOM/9sAtP+GdqUAoJOG/266I//G8yoA85J3AIbrowEE8Yf/wS7B/me0T//hBLj+8naCAJKHsAHqbx4ARULV/ilgewB5Xir/sr/D/y6CKgB1VAj/6THW/u56bQAGR1kB7NN7APQNMP53lA4AchxW/0vtGf+R5RD+gWQ1/4aWeP6onTIAF0ho/+AxDgD/exb/l7mX/6pQuAGGthQAKWRlAZkhEABMmm8BVs7q/8CgpP6le13/Adik/kMRr/+pCzv/nik9/0m8Dv/DBon/FpMd/xRnA//2guP/eiiAAOIvGP4jJCAAmLq3/0XKFADDhcMA3jP3AKmrXgG3AKD/QM0SAZxTD//FOvn++1lu/zIKWP4zK9gAYvLGAfWXcQCr7MIBxR/H/+VRJgEpOxQA/WjmAJhdDv/28pL+1qnw//BmbP6gp+wAmtq8AJbpyv8bE/oBAkeF/68MPwGRt8YAaHhz/4L79wAR1Kf/PnuE//dkvQCb35gAj8UhAJs7LP+WXfABfwNX/19HzwGnVQH/vJh0/woXFwCJw10BNmJhAPAAqP+UvH8AhmuXAEz9qwBahMAAkhY2AOBCNv7muuX/J7bEAJT7gv9Bg2z+gAGgAKkxp/7H/pT/+waDALv+gf9VUj4Ashc6//6EBQCk1ScAhvyS/iU1Uf+bhlIAzafu/14ttP+EKKEA/m9wATZL2QCz5t0B616//xfzMAHKkcv/J3Yq/3WN/QD+AN4AK/syADap6gFQRNAAlMvz/pEHhwAG/gAA/Ll/AGIIgf8mI0j/0yTcASgaWQCoQMX+A97v/wJT1/60n2kAOnPCALp0av/l99v/gXbBAMqutwGmoUgAyWuT/u2ISgDp5moBaW+oAEDgHgEB5QMAZpev/8Lu5P/++tQAu+15AEP7YAHFHgsAt1/MAM1ZigBA3SUB/98e/7Iw0//xyFr/p9Fg/zmC3QAucsj/PbhCADe2GP5utiEAq77o/3JeHwAS3QgAL+f+AP9wUwB2D9f/rRko/sDBH//uFZL/q8F2/2XqNf6D1HAAWcBrAQjQGwC12Q//55XoAIzsfgCQCcf/DE+1/pO2yv8Tbbb/MdThAEqjywCv6ZQAGnAzAMHBCf8Ph/kAluOCAMwA2wEY8s0A7tB1/xb0cAAa5SIAJVC8/yYtzv7wWuH/HQMv/yrgTAC686cAIIQP/wUzfQCLhxgABvHbAKzlhf/21jIA5wvP/79+UwG0o6r/9TgYAbKk0/8DEMoBYjl2/42DWf4hMxgA85Vb//00DgAjqUP+MR5Y/7MbJP+ljLcAOr2XAFgfAABLqUIAQmXH/xjYxwF5xBr/Dk/L/vDiUf9eHAr/U8Hw/8zBg/9eD1YA2iidADPB0QAA8rEAZrn3AJ5tdAAmh1sA36+VANxCAf9WPOgAGWAl/+F6ogHXu6j/np0uADirogDo8GUBehYJADMJFf81Ge7/2R7o/n2plAAN6GYAlAklAKVhjQHkgykA3g/z//4SEQAGPO0BagNxADuEvQBccB4AadDVADBUs/+7eef+G9ht/6Lda/5J78P/+h85/5WHWf+5F3MBA6Od/xJw+gAZObv/oWCkAC8Q8wAMjfv+Q+q4/ykSoQCvBmD/oKw0/hiwt//GwVUBfHmJ/5cycv/cyzz/z+8FAQAma/837l7+RpheANXcTQF4EUX/VaS+/8vqUQAmMSX+PZB8AIlOMf6o9zAAX6T8AGmphwD95IYAQKZLAFFJFP/P0goA6mqW/14iWv/+nzn+3IVjAIuTtP4YF7kAKTke/71hTABBu9//4Kwl/yI+XwHnkPAATWp+/kCYWwAdYpsA4vs1/+rTBf+Qy97/pLDd/gXnGACzes0AJAGG/31Gl/5h5PwArIEX/jBa0f+W4FIBVIYeAPHELgBncer/LmV5/ih8+v+HLfL+Cfmo/4xsg/+Po6sAMq3H/1jejv/IX54AjsCj/wd1hwBvfBYA7AxB/kQmQf/jrv4A9PUmAPAy0P+hP/oAPNHvAHojEwAOIeb+Ap9xAGoUf//kzWAAidKu/rTUkP9ZYpoBIliLAKeicAFBbsUA8SWpAEI4g/8KyVP+hf27/7FwLf7E+wAAxPqX/+7o1v+W0c0AHPB2AEdMUwHsY1sAKvqDAWASQP923iMAcdbL/3p3uP9CEyQAzED5AJJZiwCGPocBaOllALxUGgAx+YEA0NZL/8+CTf9zr+sAqwKJ/6+RugE39Yf/mla1AWQ69v9txzz/UsyG/9cx5gGM5cD/3sH7/1GID/+zlaL/Fycd/wdfS/6/Ud4A8VFa/2sxyf/0050A3oyV/0HbOP699lr/sjudATDbNABiItcAHBG7/6+pGABcT6H/7MjCAZOP6gDl4QcBxagOAOszNQH9eK4AxQao/8p1qwCjFc4AclVa/w8pCv/CE2MAQTfY/qKSdAAyztT/QJId/56egwFkpYL/rBeB/301Cf8PwRIBGjEL/7WuyQGHyQ7/ZBOVANtiTwAqY4/+YAAw/8X5U/5olU//626I/lKALP9BKST+WNMKALt5uwBihscAq7yz/tIL7v9Ce4L+NOo9ADBxF/4GVnj/d7L1AFeByQDyjdEAynJVAJQWoQBnwzAAGTGr/4pDggC2SXr+lBiCANPlmgAgm54AVGk9ALHCCf+mWVYBNlO7APkodf9tA9f/NZIsAT8vswDC2AP+DlSIAIixDf9I87r/dRF9/9M60/9dT98AWlj1/4vRb/9G3i8ACvZP/8bZsgDj4QsBTn6z/z4rfgBnlCMAgQil/vXwlAA9M44AUdCGAA+Jc//Td+z/n/X4/wKGiP/mizoBoKT+AHJVjf8xprb/kEZUAVW2BwAuNV0ACaah/zeisv8tuLwAkhws/qlaMQB4svEBDnt//wfxxwG9QjL/xo9l/r3zh/+NGBj+S2FXAHb7mgHtNpwAq5LP/4PE9v+IQHEBl+g5APDacwAxPRv/QIFJAfypG/8ohAoBWsnB//x58AG6zikAK8ZhAJFktwDM2FD+rJZBAPnlxP5oe0n/TWhg/oK0CABoezkA3Mrl/2b50wBWDuj/tk7RAO/hpABqDSD/eEkR/4ZD6QBT/rUAt+xwATBAg//x2PP/QcHiAM7xZP5khqb/7crFADcNUQAgfGb/KOSxAHa1HwHnoIb/d7vKAACOPP+AJr3/psmWAM94GgE2uKwADPLM/oVC5gAiJh8BuHBQACAzpf6/8zcAOkmS/punzf9kaJj/xf7P/60T9wDuCsoA75fyAF47J//wHWb/Clya/+VU2/+hgVAA0FrMAfDbrv+eZpEBNbJM/zRsqAFT3msA0yRtAHY6OAAIHRYA7aDHAKrRnQCJRy8Aj1YgAMbyAgDUMIgBXKy6AOaXaQFgv+UAilC//vDYgv9iKwb+qMQxAP0SWwGQSXkAPZInAT9oGP+4pXD+futiAFDVYv97PFf/Uoz1Ad94rf8PxoYBzjzvAOfqXP8h7hP/pXGOAbB3JgCgK6b+71tpAGs9wgEZBEQAD4szAKSEav8idC7+qF/FAInUFwBInDoAiXBF/pZpmv/syZ0AF9Sa/4hS4/7iO93/X5XAAFF2NP8hK9cBDpNL/1mcef4OEk8Ak9CLAZfaPv+cWAgB0rhi/xSve/9mU+UA3EF0AZb6BP9cjtz/IvdC/8zhs/6XUZcARyjs/4o/PgAGT/D/t7m1AHYyGwA/48AAe2M6ATLgm/8R4d/+3OBN/w4sewGNgK8A+NTIAJY7t/+TYR0Alsy1AP0lRwCRVXcAmsi6AAKA+f9TGHwADlePAKgz9QF8l+f/0PDFAXy+uQAwOvYAFOnoAH0SYv8N/h//9bGC/2yOIwCrffL+jAwi/6WhogDOzWUA9xkiAWSROQAnRjkAdszL//IAogCl9B4AxnTiAIBvmf+MNrYBPHoP/5s6OQE2MsYAq9Md/2uKp/+ta8f/baHBAFlI8v/Oc1n/+v6O/rHKXv9RWTIAB2lC/xn+//7LQBf/T95s/yf5SwDxfDIA75iFAN3xaQCTl2IA1aF5/vIxiQDpJfn+KrcbALh35v/ZIKP/0PvkAYk+g/9PQAn+XjBxABGKMv7B/xYA9xLFAUM3aAAQzV//MCVCADecPwFAUkr/yDVH/u9DfQAa4N4A34ld/x7gyv8J3IQAxibrAWaNVgA8K1EBiBwaAOkkCP7P8pQApKI/ADMu4P9yME//Ca/iAN4Dwf8voOj//11p/g4q5gAailIB0Cv0ABsnJv9i0H//QJW2/wX60QC7PBz+MRna/6l0zf93EngAnHST/4Q1bf8NCsoAblOnAJ3bif8GA4L/Mqce/zyfL/+BgJ3+XgO9AAOmRABT39cAllrCAQ+oQQDjUzP/zatC/za7PAGYZi3/d5rhAPD3iABkxbL/i0ff/8xSEAEpzir/nMDd/9h79P/a2rn/u7rv//ysoP/DNBYAkK61/rtkc//TTrD/GwfBAJPVaP9ayQr/UHtCARYhugABB2P+Hs4KAOXqBQA1HtIAigjc/kc3pwBI4VYBdr68AP7BZQGr+az/Xp63/l0CbP+wXUz/SWNP/0pAgf72LkEAY/F//vaXZv8sNdD+O2bqAJqvpP9Y8iAAbyYBAP+2vv9zsA/+qTyBAHrt8QBaTD8APkp4/3rDbgB3BLIA3vLSAIIhLv6cKCkAp5JwATGjb/95sOsATM8O/wMZxgEp69UAVSTWATFcbf/IGB7+qOzDAJEnfAHsw5UAWiS4/0NVqv8mIxr+g3xE/++bI/82yaQAxBZ1/zEPzQAY4B0BfnGQAHUVtgDLn40A34dNALDmsP++5df/YyW1/zMViv8ZvVn/MTCl/pgt9wCqbN4AUMoFABtFZ/7MFoH/tPw+/tIBW/+Sbv7/26IcAN/81QE7CCEAzhD0AIHTMABroNAAcDvRAG1N2P4iFbn/9mM4/7OLE/+5HTL/VFkTAEr6Yv/hKsj/wNnN/9IQpwBjhF8BK+Y5AP4Ly/9jvD//d8H7/lBpNgDotb0Bt0Vw/9Crpf8vbbT/e1OlAJKiNP+aCwT/l+Na/5KJYf496Sn/Xio3/2yk7ACYRP4ACoyD/wpqT/7znokAQ7JC/rF7xv8PPiIAxVgq/5Vfsf+YAMb/lf5x/+Fao/992fcAEhHgAIBCeP7AGQn/Mt3NADHURgDp/6QAAtEJAN002/6s4PT/XjjOAfKzAv8fW6QB5i6K/73m3AA5Lz3/bwudALFbmAAc5mIAYVd+AMZZkf+nT2sA+U2gAR3p5v+WFVb+PAvBAJclJP65lvP/5NRTAayXtADJqZsA9DzqAI7rBAFD2jwAwHFLAXTzz/9BrJsAUR6c/1BIIf4S523/jmsV/n0ahP+wEDv/lsk6AM6pyQDQeeIAKKwO/5Y9Xv84OZz/jTyR/y1slf/ukZv/0VUf/sAM0gBjYl3+mBCXAOG53ACN6yz/oKwV/kcaH/8NQF3+HDjGALE++AG2CPEApmWU/05Rhf+B3tcBvKmB/+gHYQAxcDz/2eX7AHdsigAnE3v+gzHrAIRUkQCC5pT/GUq7AAX1Nv+52/EBEsLk//HKZgBpccoAm+tPABUJsv+cAe8AyJQ9AHP30v8x3YcAOr0IASMuCQBRQQX/NJ65/310Lv9KjA3/0lys/pMXRwDZ4P3+c2y0/5E6MP7bsRj/nP88AZqT8gD9hlcANUvlADDD3v8frzL/nNJ4/9Aj3v8S+LMBAgpl/53C+P+ezGX/aP7F/08+BACyrGUBYJL7/0EKnAACiaX/dATnAPLXAQATIx3/K6FPADuV9gH7QrAAyCED/1Bujv/DoREB5DhC/3svkf6EBKQAQ66sABn9cgBXYVcB+txUAGBbyP8lfTsAE0F2AKE08f/trAb/sL///wFBgv7fvuYAZf3n/5IjbQD6HU0BMQATAHtamwEWViD/2tVBAG9dfwA8Xan/CH+2ABG6Dv79ifb/1Rkw/kzuAP/4XEb/Y+CLALgJ/wEHpNAAzYPGAVfWxwCC1l8A3ZXeABcmq/7FbtUAK3OM/texdgBgNEIBdZ7tAA5Atv8uP67/nl++/+HNsf8rBY7/rGPU//S7kwAdM5n/5HQY/h5lzwAT9pb/hucFAH2G4gFNQWIA7IIh/wVuPgBFbH//B3EWAJEUU/7Coef/g7U8ANnRsf/llNT+A4O4AHWxuwEcDh//sGZQADJUl/99Hzb/FZ2F/xOziwHg6BoAInWq/6f8q/9Jjc7+gfojAEhP7AHc5RT/Kcqt/2NM7v/GFuD/bMbD/ySNYAHsnjv/amRXAG7iAgDj6t4Aml13/0pwpP9DWwL/FZEh/2bWif+v5mf+o/amAF33dP6n4Bz/3AI5AavOVAB75BH/G3h3AHcLkwG0L+H/aMi5/qUCcgBNTtQALZqx/xjEef5SnbYAWhC+AQyTxQBf75j/C+tHAFaSd/+shtYAPIPEAKHhgQAfgnj+X8gzAGnn0v86CZT/K6jd/3ztjgDG0zL+LvVnAKT4VACYRtD/tHWxAEZPuQDzSiAAlZzPAMXEoQH1Ne8AD132/ovwMf/EWCT/oiZ7AIDInQGuTGf/raki/tgBq/9yMxEAiOTCAG6WOP5q9p8AE7hP/5ZN8P+bUKIAADWp/x2XVgBEXhAAXAdu/mJ1lf/5Teb//QqMANZ8XP4jdusAWTA5ARY1pgC4kD3/s//CANb4Pf47bvYAeRVR/qYD5ABqQBr/ReiG//LcNf4u3FUAcZX3/2GzZ/++fwsAh9G2AF80gQGqkM7/esjM/6hkkgA8kJX+RjwoAHo0sf/202X/ru0IAAczeAATH60Afu+c/4+9ywDEgFj/6YXi/x59rf/JbDIAe2Q7//6jAwHdlLX/1og5/t60if/PWDb/HCH7/0PWNAHS0GQAUapeAJEoNQDgb+f+Ixz0/+LHw/7uEeYA2dmk/qmd3QDaLqIBx8+j/2xzogEOYLv/djxMALifmADR50f+KqS6/7qZM/7dq7b/oo6tAOsvwQAHixABX6RA/xDdpgDbxRAAhB0s/2RFdf8861j+KFGtAEe+Pf+7WJ0A5wsXAO11pADhqN//mnJ0/6OY8gEYIKoAfWJx/qgTTAARndz+mzQFABNvof9HWvz/rW7wAArGef/9//D/QnvSAN3C1/55oxH/4QdjAL4xtgBzCYUB6BqK/9VEhAAsd3r/s2IzAJVaagBHMub/Cpl2/7FGGQClV80AN4rqAO4eYQBxm88AYpl/ACJr2/51cqz/TLT//vI5s//dIqz+OKIx/1MD//9x3b3/vBnk/hBYWf9HHMb+FhGV//N5/v9rymP/Cc4OAdwvmQBriScBYTHC/5Uzxf66Ogv/ayvoAcgGDv+1hUH+3eSr/3s+5wHj6rP/Ir3U/vS7+QC+DVABglkBAN+FrQAJ3sb/Qn9KAKfYXf+bqMYBQpEAAERmLgGsWpoA2IBL/6AoMwCeERsBfPAxAOzKsP+XfMD/JsG+AF+2PQCjk3z//6Uz/xwoEf7XYE4AVpHa/h8kyv9WCQUAbynI/+1sYQA5PiwAdbgPAS3xdACYAdz/naW8APoPgwE8LH3/Qdz7/0syuAA1WoD/51DC/4iBfwEVErv/LTqh/0eTIgCu+Qv+I40dAO9Esf9zbjoA7r6xAVf1pv++Mff/klO4/60OJ/+S12gAjt94AJXIm//Uz5EBELXZAK0gV///I7UAd9+hAcjfXv9GBrr/wENV/zKpmACQGnv/OPOz/hREiAAnjLz+/dAF/8hzhwErrOX/nGi7AJf7pwA0hxcAl5lIAJPFa/6UngX/7o/OAH6Zif9YmMX+B0SnAPyfpf/vTjb/GD83/ybeXgDttwz/zszSABMn9v4eSucAh2wdAbNzAAB1dnQBhAb8/5GBoQFpQ40AUiXi/+7i5P/M1oH+ontk/7l56gAtbOcAQgg4/4SIgACs4EL+r528AObf4v7y20UAuA53AVKiOAByexQAomdV/zHvY/6ch9cAb/+n/ifE1gCQJk8B+ah9AJthnP8XNNv/lhaQACyVpf8of7cAxE3p/3aB0v+qh+b/1nfGAOnwIwD9NAf/dWYw/xXMmv+ziLH/FwIDAZWCWf/8EZ8BRjwaAJBrEQC0vjz/OLY7/25HNv/GEoH/leBX/98VmP+KFrb/+pzNAOwt0P9PlPIBZUbRAGdOrgBlkKz/mIjtAb/CiABxUH0BmASNAJuWNf/EdPUA73JJ/hNSEf98fer/KDS/ACrSnv+bhKUAsgUqAUBcKP8kVU3/suR2AIlCYP5z4kIAbvBF/pdvUACnruz/42xr/7zyQf+3Uf8AOc61/y8itf/V8J4BR0tfAJwoGP9m0lEAq8fk/5oiKQDjr0sAFe/DAIrlXwFMwDEAdXtXAePhggB9Pj//AsarAP4kDf6Rus4AlP/0/yMApgAeltsBXOTUAFzGPP4+hcj/ySk7AH3ubf+0o+4BjHpSAAkWWP/FnS//mV45AFgetgBUoVUAspJ8AKamB/8V0N8AnLbyAJt5uQBTnK7+mhB2/7pT6AHfOnn/HRdYACN9f/+qBZX+pAyC/5vEHQChYIgAByMdAaIl+wADLvL/ANm8ADmu4gHO6QIAObuI/nu9Cf/JdX//uiTMAOcZ2ABQTmkAE4aB/5TLRACNUX3++KXI/9aQhwCXN6b/JutbABUumgDf/pb/I5m0/32wHQErYh7/2Hrm/+mgDAA5uQz+8HEH/wUJEP4aW2wAbcbLAAiTKACBhuT/fLoo/3JihP6mhBcAY0UsAAny7v+4NTsAhIFm/zQg8/6T38j/e1Oz/oeQyf+NJTgBlzzj/1pJnAHLrLsAUJcv/16J5/8kvzv/4dG1/0rX1f4GdrP/mTbBATIA5wBonUgBjOOa/7biEP5g4Vz/cxSq/gb6TgD4S63/NVkG/wC0dgBIrQEAQAjOAa6F3wC5PoX/1gtiAMUf0ACrp/T/Fue1AZbauQD3qWEBpYv3/y94lQFn+DMAPEUc/hmzxAB8B9r+OmtRALjpnP/8SiQAdrxDAI1fNf/eXqX+Lj01AM47c/8v7Pr/SgUgAYGa7v9qIOIAebs9/wOm8f5Dqqz/Hdiy/xfJ/AD9bvMAyH05AG3AYP80c+4AJnnz/8k4IQDCdoIAS2AZ/6oe5v4nP/0AJC36//sB7wCg1FwBLdHtAPMhV/7tVMn/1BKd/tRjf//ZYhD+i6zvAKjJgv+Pwan/7pfBAddoKQDvPaX+AgPyABbLsf6xzBYAlYHV/h8LKf8An3n+oBly/6JQyACdlwsAmoZOAdg2/AAwZ4UAadzFAP2oTf41sxcAGHnwAf8uYP9rPIf+Ys35/z/5d/94O9P/crQ3/ltV7QCV1E0BOEkxAFbGlgBd0aAARc22//RaKwAUJLAAenTdADOnJwHnAT//DcWGAAPRIv+HO8oAp2ROAC/fTAC5PD4AsqZ7AYQMof89risAw0WQAH8vvwEiLE4AOeo0Af8WKP/2XpIAU+SAADxO4P8AYNL/ma/sAJ8VSQC0c8T+g+FqAP+nhgCfCHD/eETC/7DExv92MKj/XakBAHDIZgFKGP4AE40E/o4+PwCDs7v/TZyb/3dWpACq0JL/0IWa/5SbOv+ieOj+/NWbAPENKgBeMoMAs6pwAIxTl/83d1QBjCPv/5ktQwHsrycANpdn/54qQf/E74f+VjXLAJVhL/7YIxH/RgNGAWckWv8oGq0AuDANAKPb2f9RBgH/3aps/unQXQBkyfn+ViQj/9GaHgHjyfv/Ar2n/mQ5AwANgCkAxWRLAJbM6/+RrjsAePiV/1U34QBy0jX+x8x3AA73SgE/+4EAQ2iXAYeCUABPWTf/dead/xlgjwDVkQUARfF4AZXzX/9yKhQAg0gCAJo1FP9JPm0AxGaYACkMzP96JgsB+gqRAM99lAD29N7/KSBVAXDVfgCi+VYBR8Z//1EJFQFiJwT/zEctAUtviQDqO+cAIDBf/8wfcgEdxLX/M/Gn/l1tjgBokC0A6wy1/zRwpABM/sr/rg6iAD3rk/8rQLn+6X3ZAPNYp/5KMQgAnMxCAHzWewAm3XYBknDsAHJisQCXWccAV8VwALmVoQAsYKUA+LMU/7zb2P4oPg0A846NAOXjzv+syiP/dbDh/1JuJgEq9Q7/FFNhADGrCgDyd3gAGeg9ANTwk/8Eczj/kRHv/soR+//5EvX/Y3XvALgEs//27TP/Je+J/6Zwpv9RvCH/ufqO/za7rQDQcMkA9ivkAWi4WP/UNMT/M3Vs//51mwAuWw//Vw6Q/1fjzABTGlMBn0zjAJ8b1QEYl2wAdZCz/onRUgAmnwoAc4XJAN+2nAFuxF3/OTzpAAWnaf+axaQAYCK6/5OFJQHcY74AAadU/xSRqwDCxfv+X06F//z48//hXYP/u4bE/9iZqgAUdp7+jAF2AFaeDwEt0yn/kwFk/nF0TP/Tf2wBZw8wAMEQZgFFM1//a4CdAImr6QBafJABaqG2AK9M7AHIjaz/ozpoAOm0NP/w/Q7/onH+/ybviv40LqYA8WUh/oO6nABv0D7/fF6g/x+s/gBwrjj/vGMb/0OK+wB9OoABnJiu/7IM9//8VJ4AUsUO/qzIU/8lJy4Bas+nABi9IgCDspAAztUEAKHi0gBIM2n/YS27/0643/+wHfsAT6BW/3QlsgBSTdUBUlSN/+Jl1AGvWMf/9V73Aax2bf+mub4Ag7V4AFf+Xf+G8En/IPWP/4uiZ/+zYhL+2cxwAJPfeP81CvMApoyWAH1QyP8Obdv/W9oB//z8L/5tnHT/czF/AcxX0/+Uytn/GlX5/w71hgFMWan/8i3mADtirP9ySYT+Tpsx/55+VAAxryv/ELZU/51nIwBowW3/Q92aAMmsAf4IolgApQEd/32b5f8emtwBZ+9cANwBbf/KxgEAXgKOASQ2LADr4p7/qvvW/7lNCQBhSvIA26OV//Ajdv/fclj+wMcDAGolGP/JoXb/YVljAeA6Z/9lx5P+3jxjAOoZOwE0hxsAZgNb/qjY6wDl6IgAaDyBAC6o7gAnv0MAS6MvAI9hYv842KgBqOn8/yNvFv9cVCsAGshXAVv9mADKOEYAjghNAFAKrwH8x0wAFm5S/4EBwgALgD0BVw6R//3evgEPSK4AVaNW/jpjLP8tGLz+Gs0PABPl0v74Q8MAY0e4AJrHJf+X83n/JjNL/8lVgv4sQfoAOZPz/pIrO/9ZHDUAIVQY/7MzEv69RlMAC5yzAWKGdwCeb28Ad5pJ/8g/jP4tDQ3/msAC/lFIKgAuoLn+LHAGAJLXlQEasGgARBxXAewymf+zgPr+zsG//6Zcif41KO8A0gHM/qitIwCN8y0BJDJt/w/ywv/jn3r/sK/K/kY5SAAo3zgA0KI6/7diXQAPbwwAHghM/4R/9v8t8mcARbUP/wrRHgADs3kA8ejaAXvHWP8C0soBvIJR/15l0AFnJC0ATMEYAV8a8f+lorsAJHKMAMpCBf8lOJMAmAvzAX9V6P/6h9QBubFxAFrcS/9F+JIAMm8yAFwWUAD0JHP+o2RS/xnBBgF/PSQA/UMe/kHsqv+hEdf+P6+MADd/BABPcOkAbaAoAI9TB/9BGu7/2amM/05evf8Ak77/k0e6/mpNf//pnekBh1ft/9AN7AGbbST/tGTaALSjEgC+bgkBET97/7OItP+le3v/kLxR/kfwbP8ZcAv/49oz/6cy6v9yT2z/HxNz/7fwYwDjV4//SNn4/2apXwGBlZUA7oUMAePMIwDQcxoBZgjqAHBYjwGQ+Q4A8J6s/mRwdwDCjZn+KDhT/3mwLgAqNUz/nr+aAFvRXACtDRABBUji/8z+lQBQuM8AZAl6/nZlq//8ywD+oM82ADhI+QE4jA3/CkBr/ltlNP/htfgBi/+EAOaREQDpOBcAdwHx/9Wpl/9jYwn+uQ+//61nbQGuDfv/slgH/hs7RP8KIQL/+GE7ABoekgGwkwoAX3nPAbxYGAC5Xv7+czfJABgyRgB4NQYAjkKSAOTi+f9owN4BrUTbAKK4JP+PZon/nQsXAH0tYgDrXeH+OHCg/0Z08wGZ+Tf/gScRAfFQ9ABXRRUBXuRJ/05CQf/C4+cAPZJX/62bF/9wdNv+2CYL/4O6hQBe1LsAZC9bAMz+r//eEtf+rURs/+PkT/8m3dUAo+OW/h++EgCgswsBClpe/9yuWACj0+X/x4g0AIJf3f+MvOf+i3GA/3Wr7P4x3BT/OxSr/+RtvAAU4SD+wxCuAOP+iAGHJ2kAlk3O/9Lu4gA31IT+7zl8AKrCXf/5EPf/GJc+/wqXCgBPi7L/ePLKABrb1QA+fSP/kAJs/+YhU/9RLdgB4D4RANbZfQBimZn/s7Bq/oNdiv9tPiT/snkg/3j8RgDc+CUAzFhnAYDc+//s4wcBajHG/zw4awBjcu4A3MxeAUm7AQBZmiIATtml/w7D+f8J5v3/zYf1ABr8B/9UzRsBhgJwACWeIADnW+3/v6rM/5gH3gBtwDEAwaaS/+gTtf9pjjT/ZxAbAf3IpQDD2QT/NL2Q/3uboP5Xgjb/Tng9/w44KQAZKX3/V6j1ANalRgDUqQb/29PC/khdpP/FIWf/K46NAIPhrAD0aRwAREThAIhUDf+COSj+i004AFSWNQA2X50AkA2x/l9zugB1F3b/9Kbx/wu6hwCyasv/YdpdACv9LQCkmAQAi3bvAGABGP7rmdP/qG4U/zLvsAByKegAwfo1AP6gb/6Iein/YWxDANeYF/+M0dQAKr2jAMoqMv9qar3/vkTZ/+k6dQDl3PMBxQMEACV4Nv4EnIb/JD2r/qWIZP/U6A4AWq4KANjGQf8MA0AAdHFz//hnCADnfRL/oBzFAB64IwHfSfn/exQu/oc4Jf+tDeUBd6Ei//U9SQDNfXAAiWiGANn2Hv/tjo8AQZ9m/2ykvgDbda3/IiV4/shFUAAffNr+Shug/7qax/9Hx/wAaFGfARHIJwDTPcABGu5bAJTZDAA7W9X/C1G3/4Hmev9yy5EBd7RC/0iKtADglWoAd1Jo/9CMKwBiCbb/zWWG/xJlJgBfxab/y/GTAD7Qkf+F9vsAAqkOAA33uACOB/4AJMgX/1jN3wBbgTT/FboeAI/k0gH36vj/5kUf/rC6h//uzTQBi08rABGw2f4g80MA8m/pACwjCf/jclEBBEcM/yZpvwAHdTL/UU8QAD9EQf+dJG7/TfED/+It+wGOGc4AeHvRARz+7v8FgH7/W97X/6IPvwBW8EkAh7lR/izxowDU29L/cKKbAM9ldgCoSDj/xAU0AEis8v9+Fp3/kmA7/6J5mP6MEF8Aw/7I/lKWogB3K5H+zKxO/6bgnwBoE+3/9X7Q/+I71QB12cUAmEjtANwfF/4OWuf/vNRAATxl9v9VGFYAAbFtAJJTIAFLtsAAd/HgALntG/+4ZVIB6yVN//2GEwDo9noAPGqzAMMLDABtQusBfXE7AD0opACvaPAAAi+7/zIMjQDCi7X/h/poAGFc3v/Zlcn/y/F2/0+XQwB6jtr/lfXvAIoqyP5QJWH/fHCn/ySKV/+CHZP/8VdO/8xhEwGx0Rb/9+N//mN3U//UGcYBELOzAJFNrP5ZmQ7/2r2nAGvpO/8jIfP+LHBw/6F/TwHMrwoAKBWK/mh05ADHX4n/hb6o/5Kl6gG3YycAt9w2/v/ehQCi23n+P+8GAOFmNv/7EvYABCKBAYckgwDOMjsBD2G3AKvYh/9lmCv/lvtbACaRXwAizCb+soxT/xmB8/9MkCUAaiQa/naQrP9EuuX/a6HV/y6jRP+Vqv0AuxEPANqgpf+rI/YBYA0TAKXLdQDWa8D/9HuxAWQDaACy8mH/+0yC/9NNKgH6T0b/P/RQAWll9gA9iDoB7lvVAA47Yv+nVE0AEYQu/jmvxf+5PrgATEDPAKyv0P6vSiUAihvT/pR9wgAKWVEAqMtl/yvV0QHr9TYAHiPi/wl+RgDifV7+nHUU/zn4cAHmMED/pFymAeDW5v8keI8ANwgr//sB9QFqYqUASmtq/jUENv9aspYBA3h7//QFWQFy+j3//plSAU0PEQA57loBX9/mAOw0L/5nlKT/ec8kARIQuf9LFEoAuwtlAC4wgf8W79L/TeyB/29NzP89SGH/x9n7/yrXzACFkcn/OeaSAetkxgCSSSP+bMYU/7ZP0v9SZ4gA9mywACIRPP8TSnL+qKpO/53vFP+VKagAOnkcAE+zhv/neYf/rtFi//N6vgCrps0A1HQwAB1sQv+i3rYBDncVANUn+f/+3+T/t6XGAIW+MAB80G3/d69V/wnReQEwq73/w0eGAYjbM/+2W43+MZ9IACN29f9wuuP/O4kfAIksowByZzz+CNWWAKIKcf/CaEgA3IN0/7JPXADL+tX+XcG9/4L/Iv7UvJcAiBEU/xRlU//UzqYA5e5J/5dKA/+oV9cAm7yF/6aBSQDwT4X/stNR/8tIo/7BqKUADqTH/h7/zABBSFsBpkpm/8gqAP/CceP/QhfQAOXYZP8Y7xoACuk+/3sKsgEaJK7/d9vHAS2jvgAQqCoApjnG/xwaGgB+pecA+2xk/z3lef86dooATM8RAA0icP5ZEKgAJdBp/yPJ1/8oamX+Bu9yAChn4v72f27/P6c6AITwjgAFnlj/gUme/15ZkgDmNpIACC2tAE+pAQBzuvcAVECDAEPg/f/PvUAAmhxRAS24Nv9X1OD/AGBJ/4Eh6wE0QlD/+66b/wSzJQDqpF3+Xa/9AMZFV//gai4AYx3SAD68cv8s6ggAqa/3/xdtif/lticAwKVe/vVl2QC/WGAAxF5j/2ruC/41fvMAXgFl/y6TAgDJfHz/jQzaAA2mnQEw++3/m/p8/2qUkv+2DcoAHD2nANmYCP7cgi3/yOb/ATdBV/9dv2H+cvsOACBpXAEaz40AGM8N/hUyMP+6lHT/0yvhACUiov6k0ir/RBdg/7bWCP/1dYn/QsMyAEsMU/5QjKQACaUkAeRu4wDxEVoBGTTUAAbfDP+L8zkADHFLAfa3v//Vv0X/5g+OAAHDxP+Kqy//QD9qARCp1v/PrjgBWEmF/7aFjACxDhn/k7g1/wrjof942PT/SU3pAJ3uiwE7QekARvvYASm4mf8gy3AAkpP9AFdlbQEsUoX/9JY1/16Y6P87XSf/WJPc/05RDQEgL/z/oBNy/11rJ/92ENMBuXfR/+Pbf/5Yaez/om4X/ySmbv9b7N3/Qup0AG8T9P4K6RoAILcG/gK/8gDanDX+KTxG/6jsbwB5uX7/7o7P/zd+NADcgdD+UMyk/0MXkP7aKGz/f8qkAMshA/8CngAAJWC8/8AxSgBtBAAAb6cK/lvah//LQq3/lsLiAMn9Bv+uZnkAzb9uADXCBABRKC3+I2aP/wxsxv8QG+j//Ee6AbBucgCOA3UBcU2OABOcxQFcL/wANegWATYS6wAuI73/7NSBAAJg0P7I7sf/O6+k/5Ir5wDC2TT/A98MAIo2sv5V688A6M8iADE0Mv+mcVn/Ci3Y/z6tHABvpfYAdnNb/4BUPACnkMsAVw3zABYe5AGxcZL/garm/vyZgf+R4SsARucF/3ppfv5W9pT/biWa/tEDWwBEkT4A5BCl/zfd+f6y0lsAU5Li/kWSugBd0mj+EBmtAOe6JgC9eoz/+w1w/2luXQD7SKoAwBff/xgDygHhXeQAmZPH/m2qFgD4Zfb/snwM/7L+Zv43BEEAfda0ALdgkwAtdRf+hL/5AI+wy/6Itzb/kuqxAJJlVv8se48BIdGYAMBaKf5TD33/1axSANepkAAQDSIAINFk/1QS+QHFEez/2brmADGgsP9vdmH/7WjrAE87XP5F+Qv/I6xKARN2RADefKX/tEIj/1au9gArSm//fpBW/+TqWwDy1Rj+RSzr/9y0IwAI+Af/Zi9c//DNZv9x5qsBH7nJ/8L2Rv96EbsAhkbH/5UDlv91P2cAQWh7/9Q2EwEGjVgAU4bz/4g1ZwCpG7QAsTEYAG82pwDDPdf/HwFsATwqRgC5A6L/wpUo//Z/Jv6+dyb/PXcIAWCh2/8qy90BsfKk//WfCgB0xAAABV3N/oB/swB97fb/laLZ/1clFP6M7sAACQnBAGEB4gAdJgoAAIg//+VI0v4mhlz/TtrQAWgkVP8MBcH/8q89/7+pLgGzk5P/cb6L/n2sHwADS/z+1yQPAMEbGAH/RZX/boF2AMtd+QCKiUD+JkYGAJl03gChSnsAwWNP/3Y7Xv89DCsBkrGdAC6TvwAQ/yYACzMfATw6Yv9vwk0Bmlv0AIwokAGtCvsAy9Ey/myCTgDktFoArgf6AB+uPAApqx4AdGNS/3bBi/+7rcb+2m84ALl72AD5njQANLRd/8kJW/84Lab+hJvL/zrobgA001n//QCiAQlXtwCRiCwBXnr1AFW8qwGTXMYAAAhoAB5frgDd5jQB9/fr/4muNf8jFcz/R+PWAehSwgALMOP/qkm4/8b7/P4scCIAg2WD/0iouwCEh33/imhh/+64qP/zaFT/h9ji/4uQ7QC8iZYBUDiM/1app//CThn/3BG0/xENwQB1idT/jeCXADH0rwDBY6//E2OaAf9BPv+c0jf/8vQD//oOlQCeWNn/nc+G/vvoHAAunPv/qzi4/+8z6gCOioP/Gf7zAQrJwgA/YUsA0u+iAMDIHwF11vMAGEfe/jYo6P9Mt2/+kA5X/9ZPiP/YxNQAhBuM/oMF/QB8bBP/HNdLAEzeN/7ptj8ARKu//jRv3v8KaU3/UKrrAI8YWP8t53kAlIHgAT32VAD9Ltv/70whADGUEv7mJUUAQ4YW/o6bXgAfndP+1Soe/wTk9/78sA3/JwAf/vH0//+qLQr+/d75AN5yhAD/Lwb/tKOzAVRel/9Z0VL+5TSp/9XsAAHWOOT/h3eX/3DJwQBToDX+BpdCABKiEQDpYVsAgwVOAbV4Nf91Xz//7XW5AL9+iP+Qd+kAtzlhAS/Ju/+npXcBLWR+ABViBv6Rll//eDaYANFiaACPbx7+uJT5AOvYLgD4ypT/OV8WAPLhowDp9+j/R6sT/2f0Mf9UZ13/RHn0AVLgDQApTyv/+c6n/9c0Ff7AIBb/9288AGVKJv8WW1T+HRwN/8bn1/70msgA34ntANOEDgBfQM7/ET73/+mDeQFdF00Azcw0/lG9iAC024oBjxJeAMwrjP68r9sAb2KP/5c/ov/TMkf+E5I1AJItU/6yUu7/EIVU/+LGXf/JYRT/eHYj/3Iy5/+i5Zz/0xoMAHInc//O1IYAxdmg/3SBXv7H19v/S9/5Af10tf/o12j/5IL2/7l1VgAOBQgA7x09Ae1Xhf99kon+zKjfAC6o9QCaaRYA3NSh/2tFGP+J2rX/8VTG/4J60/+NCJn/vrF2AGBZsgD/EDD+emBp/3U26P8ifmn/zEOmAOg0iv/TkwwAGTYHACwP1/4z7C0AvkSBAWqT4QAcXS3+7I0P/xE9oQDcc8AA7JEY/m+oqQDgOj//f6S8AFLqSwHgnoYA0URuAdmm2QBG4aYBu8GP/xAHWP8KzYwAdcCcARE4JgAbfGwBq9c3/1/91ACbh6j/9rKZ/ppESgDoPWD+aYQ7ACFMxwG9sIL/CWgZ/kvGZv/pAXAAbNwU/3LmRgCMwoX/OZ6k/pIGUP+pxGEBVbeCAEae3gE77er/YBka/+ivYf8Lefj+WCPCANu0/P5KCOMAw+NJAbhuof8x6aQBgDUvAFIOef/BvjoAMK51/4QXIAAoCoYBFjMZ//ALsP9uOZIAdY/vAZ1ldv82VEwAzbgS/y8ESP9OcFX/wTJCAV0QNP8IaYYADG1I/zqc+wCQI8wALKB1/jJrwgABRKX/b26iAJ5TKP5M1uoAOtjN/6tgk/8o43IBsOPxAEb5twGIVIv/PHr3/o8Jdf+xron+SfePAOy5fv8+Gff/LUA4/6H0BgAiOTgBacpTAICT0AAGZwr/SopB/2FQZP/WriH/MoZK/26Xgv5vVKwAVMdL/vg7cP8I2LIBCbdfAO4bCP6qzdwAw+WHAGJM7f/iWxoBUtsn/+G+xwHZyHn/UbMI/4xBzgCyz1f++vwu/2hZbgH9vZ7/kNae/6D1Nv81t1wBFcjC/5IhcQHRAf8A62or/6c06ACd5d0AMx4ZAPrdGwFBk1f/T3vEAEHE3/9MLBEBVfFEAMq3+f9B1NT/CSGaAUc7UACvwjv/jUgJAGSg9ADm0DgAOxlL/lDCwgASA8j+oJ9zAISP9wFvXTn/Ou0LAYbeh/96o2wBeyu+//u9zv5Qtkj/0PbgARE8CQChzyYAjW1bANgP0/+ITm4AYqNo/xVQef+tsrcBf48EAGg8Uv7WEA3/YO4hAZ6U5v9/gT7/M//S/z6N7P6dN+D/cif0AMC8+v/kTDUAYlRR/63LPf6TMjf/zOu/ADTF9ABYK9P+G793ALznmgBCUaEAXMGgAfrjeAB7N+IAuBFIAIWoCv4Wh5z/KRln/zDKOgC6lVH/vIbvAOu1vf7Zi7z/SjBSAC7a5QC9/fsAMuUM/9ONvwGA9Bn/qed6/lYvvf+Etxf/JbKW/zOJ/QDITh8AFmkyAII8AACEo1v+F+e7AMBP7wCdZqT/wFIUARi1Z//wCeoAAXuk/4XpAP/K8vIAPLr1APEQx//gdJ7+v31b/+BWzwB5Jef/4wnG/w+Z7/956Nn+S3BSAF8MOf4z1mn/lNxhAcdiJACc0Qz+CtQ0ANm0N/7Uquj/2BRU/536hwCdY3/+Ac4pAJUkRgE2xMn/V3QA/uurlgAbo+oAyoe0ANBfAP57nF0Atz5LAInrtgDM4f//1ovS/wJzCP8dDG8ANJwBAP0V+/8lpR/+DILTAGoSNf4qY5oADtk9/tgLXP/IxXD+kybHACT8eP5rqU0AAXuf/89LZgCjr8QALAHwAHi6sP4NYkz/7Xzx/+iSvP/IYOAAzB8pANDIDQAV4WD/r5zEAPfQfgA+uPT+AqtRAFVzngA2QC3/E4pyAIdHzQDjL5MB2udCAP3RHAD0D63/Bg92/hCW0P+5FjL/VnDP/0tx1wE/kiv/BOET/uMXPv8O/9b+LQjN/1fFl/7SUtf/9fj3/4D4RgDh91cAWnhGANX1XAANheIAL7UFAVyjaf8GHoX+6LI9/+aVGP8SMZ4A5GQ9/nTz+/9NS1wBUduT/0yj/v6N1fYA6CWY/mEsZADJJTIB1PQ5AK6rt//5SnAAppweAN7dYf/zXUn++2Vk/9jZXf/+irv/jr40/zvLsf/IXjQAc3Ke/6WYaAF+Y+L/dp30AWvIEADBWuUAeQZYAJwgXf598dP/Du2d/6WaFf+44Bb/+hiY/3FNHwD3qxf/7bHM/zSJkf/CtnIA4OqVAApvZwHJgQQA7o5OADQGKP9u1aX+PM/9AD7XRQBgYQD/MS3KAHh5Fv/rizABxi0i/7YyGwGD0lv/LjaAAK97af/GjU7+Q/Tv//U2Z/5OJvL/Alz5/vuuV/+LP5AAGGwb/yJmEgEiFpgAQuV2/jKPYwCQqZUBdh6YALIIeQEInxIAWmXm/4EddwBEJAsB6Lc3ABf/YP+hKcH/P4veAA+z8wD/ZA//UjWHAIk5lQFj8Kr/Fubk/jG0Uv89UisAbvXZAMd9PQAu/TQAjcXbANOfwQA3eWn+txSBAKl3qv/Lsov/hyi2/6wNyv9BspQACM8rAHo1fwFKoTAA49aA/lYL8/9kVgcB9USG/z0rFQGYVF7/vjz6/u926P/WiCUBcUxr/11oZAGQzhf/bpaaAeRnuQDaMTL+h02L/7kBTgAAoZT/YR3p/8+Ulf+gqAAAW4Cr/wYcE/4Lb/cAJ7uW/4rolQB1PkT/P9i8/+vqIP4dOaD/GQzxAak8vwAgg43/7Z97/17FXv50/gP/XLNh/nlhXP+qcA4AFZX4APjjAwBQYG0AS8BKAQxa4v+hakQB0HJ//3Iq//5KGkr/97OW/nmMPACTRsj/1iih/6G8yf+NQYf/8nP8AD4vygC0lf/+gjftAKURuv8KqcIAnG3a/3CMe/9ogN/+sY5s/3kl2/+ATRL/b2wXAVvASwCu9Rb/BOw+/ytAmQHjrf4A7XqEAX9Zuv+OUoD+/FSuAFqzsQHz1lf/Zzyi/9CCDv8LgosAzoHb/17Znf/v5ub/dHOf/qRrXwAz2gIB2H3G/4zKgP4LX0T/Nwld/q6ZBv/MrGAARaBuANUmMf4bUNUAdn1yAEZGQ/8Pjkn/g3q5//MUMv6C7SgA0p+MAcWXQf9UmUIAw35aABDu7AF2u2b/AxiF/7tF5gA4xVwB1UVe/1CK5QHOB+YA3m/mAVvpd/8JWQcBAmIBAJRKhf8z9rT/5LFwATq9bP/Cy+3+FdHDAJMKIwFWneIAH6OL/jgHS/8+WnQAtTypAIqi1P5Rpx8AzVpw/yFw4wBTl3UBseBJ/66Q2f/mzE//Fk3o/3JO6gDgOX7+CTGNAPKTpQFotoz/p4QMAXtEfwDhVycB+2wIAMbBjwF5h8//rBZGADJEdP9lryj/+GnpAKbLBwBuxdoA1/4a/qji/QAfj2AAC2cpALeBy/5k90r/1X6EANKTLADH6hsBlC+1AJtbngE2aa//Ak6R/maaXwCAz3/+NHzs/4JURwDd89MAmKrPAN5qxwC3VF7+XMg4/4q2cwGOYJIAhYjkAGESlgA3+0IAjGYEAMpnlwAeE/j/M7jPAMrGWQA3xeH+qV/5/0JBRP+86n4Apt9kAXDv9ACQF8IAOie2APQsGP6vRLP/mHaaAbCiggDZcsz+rX5O/yHeHv8kAlv/Ao/zAAnr1wADq5cBGNf1/6gvpP7xks8ARYG0AETzcQCQNUj++y0OABduqABERE//bkZf/q5bkP8hzl//iSkH/xO7mf4j/3D/CZG5/jKdJQALcDEBZgi+/+rzqQE8VRcASie9AHQx7wCt1dIALqFs/5+WJQDEeLn/ImIG/5nDPv9h5kf/Zj1MABrU7P+kYRAAxjuSAKMXxAA4GD0AtWLBAPuT5f9ivRj/LjbO/+pS9gC3ZyYBbT7MAArw4ACSFnX/jpp4AEXUIwDQY3YBef8D/0gGwgB1EcX/fQ8XAJpPmQDWXsX/uTeT/z7+Tv5/UpkAbmY//2xSof9pu9QBUIonADz/Xf9IDLoA0vsfAb6nkP/kLBP+gEPoANb5a/6IkVb/hC6wAL274//QFowA2dN0ADJRuv6L+h8AHkDGAYebZACgzhf+u6LT/xC8PwD+0DEAVVS/APHA8v+ZfpEB6qKi/+Zh2AFAh34AvpTfATQAK/8cJ70BQIjuAK/EuQBi4tX/f5/0AeKvPACg6Y4BtPPP/0WYWQEfZRUAkBmk/ou/0QBbGXkAIJMFACe6e/8/c+b/XafG/4/V3P+znBP/GUJ6ANag2f8CLT7/ak+S/jOJY/9XZOf/r5Ho/2W4Af+uCX0AUiWhASRyjf8w3o7/9bqaAAWu3f4/cpv/hzegAVAfhwB++rMB7NotABQckQEQk0kA+b2EARG9wP/fjsb/SBQP//o17f4PCxIAG9Nx/tVrOP+uk5L/YH4wABfBbQElol4Ax535/hiAu//NMbL+XaQq/yt36wFYt+3/2tIB/2v+KgDmCmP/ogDiANvtWwCBsssA0DJf/s7QX//3v1n+bupP/6U98wAUenD/9va5/mcEewDpY+YB21v8/8feFv+z9en/0/HqAG/6wP9VVIgAZToy/4OtnP53LTP/dukQ/vJa1gBen9sBAwPq/2JMXP5QNuYABeTn/jUY3/9xOHYBFIQB/6vS7AA48Z7/unMT/wjlrgAwLAABcnKm/wZJ4v/NWfQAieNLAfitOABKePb+dwML/1F4xv+IemL/kvHdAW3CTv/f8UYB1sip/2G+L/8vZ67/Y1xI/nbptP/BI+n+GuUg/978xgDMK0f/x1SsAIZmvgBv7mH+5ijmAOPNQP7IDOEAphneAHFFM/+PnxgAp7hKAB3gdP6e0OkAwXR+/9QLhf8WOowBzCQz/+geKwDrRrX/QDiS/qkSVP/iAQ3/yDKw/zTV9f6o0WEAv0c3ACJOnADokDoBuUq9ALqOlf5ARX//ocuT/7CXvwCI58v+o7aJAKF++/7pIEIARM9CAB4cJQBdcmAB/lz3/yyrRQDKdwv/vHYyAf9TiP9HUhoARuMCACDreQG1KZoAR4bl/sr/JAApmAUAmj9J/yK2fAB53Zb/GszVASmsVwBanZL/bYIUAEdryP/zZr0AAcOR/i5YdQAIzuMAv279/22AFP6GVTP/ibFwAdgiFv+DEND/eZWqAHITFwGmUB//cfB6AOiz+gBEbrT+0qp3AN9spP/PT+n/G+Xi/tFiUf9PRAcAg7lkAKodov8Romv/ORULAWTItf9/QaYBpYbMAGinqAABpE8Akoc7AUYygP9mdw3+4waHAKKOs/+gZN4AG+DbAZ5dw//qjYkAEBh9/+7OL/9hEWL/dG4M/2BzTQBb4+j/+P5P/1zlBv5YxosAzkuBAPpNzv+N9HsBikXcACCXBgGDpxb/7USn/se9lgCjq4r/M7wG/18dif6U4rMAtWvQ/4YfUv+XZS3/gcrhAOBIkwAwipf/w0DO/u3angBqHYn+/b3p/2cPEf/CYf8Asi2p/sbhmwAnMHX/h2pzAGEmtQCWL0H/U4Ll/vYmgQBc75r+W2N/AKFvIf/u2fL/g7nD/9W/nv8pltoAhKmDAFlU/AGrRoD/o/jL/gEytP98TFUB+29QAGNC7/+a7bb/3X6F/krMY/9Bk3f/Yzin/0/4lf90m+T/7SsO/kWJC/8W+vEBW3qP/8358wDUGjz/MLawATAXv//LeZj+LUrV/z5aEv71o+b/uWp0/1MjnwAMIQL/UCI+ABBXrv+tZVUAyiRR/qBFzP9A4bsAOs5eAFaQLwDlVvUAP5G+ASUFJwBt+xoAiZPqAKJ5kf+QdM7/xei5/7e+jP9JDP7/ixTy/6pa7/9hQrv/9bWH/t6INAD1BTP+yy9OAJhl2ABJF30A/mAhAevSSf8r0VgBB4FtAHpo5P6q8ssA8syH/8oc6f9BBn8An5BHAGSMXwBOlg0A+2t2AbY6ff8BJmz/jb3R/wibfQFxo1v/eU++/4bvbP9ML/gAo+TvABFvCgBYlUv/1+vvAKefGP8vl2z/a9G8AOnnY/4cypT/riOK/24YRP8CRbUAa2ZSAGbtBwBcJO3/3aJTATfKBv+H6of/GPreAEFeqP71+NL/p2zJ/v+hbwDNCP4AiA10AGSwhP8r137/sYWC/55PlABD4CUBDM4V/z4ibgHtaK//UIRv/46uSABU5bT+abOMAED4D//pihAA9UN7/tp51P8/X9oB1YWJ/4+2Uv8wHAsA9HKNAdGvTP+dtZb/uuUD/6SdbwHnvYsAd8q+/9pqQP9E6z/+YBqs/7svCwHXEvv/UVRZAEQ6gABecQUBXIHQ/2EPU/4JHLwA7wmkADzNmADAo2L/uBI8ANm2iwBtO3j/BMD7AKnS8P8lrFz+lNP1/7NBNAD9DXMAua7OAXK8lf/tWq0AK8fA/1hscQA0I0wAQhmU/90EB/+X8XL/vtHoAGIyxwCXltX/EkokATUoBwATh0H/GqxFAK7tVQBjXykAAzgQACegsf/Iatr+uURU/1u6Pf5Dj43/DfSm/2NyxgDHbqP/wRK6AHzv9gFuRBYAAusuAdQ8awBpKmkBDuaYAAcFgwCNaJr/1QMGAIPkov+zZBwB53tV/84O3wH9YOYAJpiVAWKJegDWzQP/4piz/waFiQCeRYz/caKa/7TzrP8bvXP/jy7c/9WG4f9+HUUAvCuJAfJGCQBazP//56qTABc4E/44fZ3/MLPa/0+2/f8m1L8BKet8AGCXHACHlL4Azfkn/jRgiP/ULIj/Q9GD//yCF//bgBT/xoF2AGxlCwCyBZIBPgdk/7XsXv4cGqQATBZw/3hmTwDKwOUByLDXAClA9P/OuE4Apy0/AaAjAP87DI7/zAmQ/9te5QF6G3AAvWlt/0DQSv/7fzcBAuLGACxM0QCXmE3/0hcuAcmrRf8s0+cAviXg//XEPv+ptd7/ItMRAHfxxf/lI5gBFUUo/7LioQCUs8EA28L+ASjOM//nXPoBQ5mqABWU8QCqRVL/eRLn/1xyAwC4PuYA4clX/5Jgov+18twArbvdAeI+qv84ftkBdQ3j/7Ms7wCdjZv/kN1TAOvR0AAqEaUB+1GFAHz1yf5h0xj/U9amAJokCf/4L38AWtuM/6HZJv7Ukz//QlSUAc8DAQDmhlkBf056/+CbAf9SiEoAspzQ/7oZMf/eA9IB5Za+/1WiNP8pVI3/SXtU/l0RlgB3ExwBIBbX/xwXzP+O8TT/5DR9AB1MzwDXp/r+r6TmADfPaQFtu/X/oSzcASllgP+nEF4AXdZr/3ZIAP5QPer/ea99AIup+wBhJ5P++sQx/6Wzbv7fRrv/Fo59AZqziv92sCoBCq6ZAJxcZgCoDaH/jxAgAPrFtP/LoywBVyAkAKGZFP97/A8AGeNQADxYjgARFskBms1N/yc/LwAIeo0AgBe2/swnE/8EcB3/FySM/9LqdP41Mj//eato/6DbXgBXUg7+5yoFAKWLf/5WTiYAgjxC/sseLf8uxHoB+TWi/4iPZ/7X0nIA5weg/qmYKv9vLfYAjoOH/4NHzP8k4gsAABzy/+GK1f/3Ltj+9QO3AGz8SgHOGjD/zTb2/9PGJP95IzIANNjK/yaLgf7ySZQAQ+eN/yovzABOdBkBBOG//waT5AA6WLEAeqXl//xTyf/gp2ABsbie//JpswH4xvAAhULLAf4kLwAtGHP/dz7+AMThuv57jawAGlUp/+JvtwDV55cABDsH/+6KlABCkyH/H/aN/9GNdP9ocB8AWKGsAFPX5v4vb5cALSY0AYQtzACKgG3+6XWG//O+rf7x7PAAUn/s/ijfof9utuH/e67vAIfykQEz0ZoAlgNz/tmk/P83nEUBVF7//+hJLQEUE9T/YMU7/mD7IQAmx0kBQKz3/3V0OP/kERIAPopnAfblpP/0dsn+ViCf/20iiQFV07oACsHB/nrCsQB67mb/otqrAGzZoQGeqiIAsC+bAbXkC/8InAAAEEtdAM5i/wE6miMADPO4/kN1Qv/m5XsAySpuAIbksv66bHb/OhOa/1KpPv9yj3MB78Qy/60wwf+TAlT/loaT/l/oSQBt4zT+v4kKACjMHv5MNGH/pOt+AP58vABKthUBeR0j//EeB/5V2tb/B1SW/lEbdf+gn5j+Qhjd/+MKPAGNh2YA0L2WAXWzXACEFoj/eMccABWBT/62CUEA2qOpAPaTxv9rJpABTq/N/9YF+v4vWB3/pC/M/ys3Bv+Dhs/+dGTWAGCMSwFq3JAAwyAcAaxRBf/HszT/JVTLAKpwrgALBFsARfQbAXWDXAAhmK//jJlr//uHK/5XigT/xuqT/nmYVP/NZZsBnQkZAEhqEf5smQD/veW6AMEIsP+uldEA7oIdAOnWfgE94mYAOaMEAcZvM/8tT04Bc9IK/9oJGf+ei8b/01K7/lCFUwCdgeYB84WG/yiIEABNa0//t1VcAbHMygCjR5P/mEW+AKwzvAH60qz/0/JxAVlZGv9AQm/+dJgqAKEnG/82UP4AatFzAWd8YQDd5mL/H+cGALLAeP4P2cv/fJ5PAHCR9wBc+jABo7XB/yUvjv6QvaX/LpLwAAZLgAApncj+V3nVAAFx7AAFLfoAkAxSAB9s5wDh73f/pwe9/7vkhP9uvSIAXizMAaI0xQBOvPH+ORSNAPSSLwHOZDMAfWuU/hvDTQCY/VoBB4+Q/zMlHwAidyb/B8V2AJm80wCXFHT+9UE0/7T9bgEvsdEAoWMR/3beygB9s/wBezZ+/5E5vwA3unkACvOKAM3T5f99nPH+lJy5/+MTvP98KSD/HyLO/hE5UwDMFiX/KmBiAHdmuAEDvhwAblLa/8jMwP/JkXYAdcySAIQgYgHAwnkAaqH4Ae1YfAAX1BoAzata//gw2AGNJeb/fMsA/p6oHv/W+BUAcLsH/0uF7/9K4/P/+pNGANZ4ogCnCbP/Fp4SANpN0QFhbVH/9CGz/zk0Of9BrNL/+UfR/46p7gCevZn/rv5n/mIhDgCNTOb/cYs0/w861ACo18n/+MzXAd9EoP85mrf+L+d5AGqmiQBRiIoApSszAOeLPQA5Xzv+dmIZ/5c/7AFevvr/qblyAQX6Ov9LaWEB19+GAHFjowGAPnAAY2qTAKPDCgAhzbYA1g6u/4Em5/81tt8AYiqf//cNKAC80rEBBhUA//89lP6JLYH/WRp0/n4mcgD7MvL+eYaA/8z5p/6l69cAyrHzAIWNPgDwgr4Bbq//AAAUkgEl0nn/ByeCAI76VP+NyM8ACV9o/wv0rgCG6H4ApwF7/hDBlf/o6e8B1UZw//x0oP7y3tz/zVXjAAe5OgB29z8BdE2x/z71yP4/EiX/azXo/jLd0wCi2wf+Al4rALY+tv6gTsj/h4yqAOu45ACvNYr+UDpN/5jJAgE/xCIABR64AKuwmgB5O84AJmMnAKxQTf4AhpcAuiHx/l793/8scvwAbH45/8koDf8n5Rv/J+8XAZd5M/+ZlvgACuqu/3b2BP7I9SYARaHyARCylgBxOIIAqx9pABpYbP8xKmoA+6lCAEVdlQAUOf4ApBlvAFq8Wv/MBMUAKNUyAdRghP9YirT+5JJ8/7j29wBBdVb//WbS/v55JACJcwP/PBjYAIYSHQA74mEAsI5HAAfRoQC9VDP+m/pIANVU6/8t3uAA7pSP/6oqNf9Op3UAugAo/32xZ/9F4UIA4wdYAUusBgCpLeMBECRG/zICCf+LwRYAj7fn/tpFMgDsOKEB1YMqAIqRLP6I5Sj/MT8j/z2R9f9lwAL+6KdxAJhoJgF5udoAeYvT/nfwIwBBvdn+u7Oi/6C75gA++A7/PE5hAP/3o//hO1v/a0c6//EvIQEydewA27E//vRaswAjwtf/vUMy/xeHgQBovSX/uTnCACM+5//c+GwADOeyAI9QWwGDXWX/kCcCAf/6sgAFEez+iyAuAMy8Jv71czT/v3FJ/r9sRf8WRfUBF8uyAKpjqgBB+G8AJWyZ/0AlRQAAWD7+WZSQ/79E4AHxJzUAKcvt/5F+wv/dKv3/GWOXAGH93wFKczH/Bq9I/zuwywB8t/kB5ORjAIEMz/6owMP/zLAQ/pjqqwBNJVX/IXiH/47C4wEf1joA1bt9/+guPP++dCr+l7IT/zM+7f7M7MEAwug8AKwinf+9ELj+ZwNf/43pJP4pGQv/FcOmAHb1LQBD1ZX/nwwS/7uk4wGgGQUADE7DASvF4QAwjin+xJs8/9/HEgGRiJwA/HWp/pHi7gDvF2sAbbW8/+ZwMf5Jqu3/57fj/1DcFADCa38Bf81lAC40xQHSqyT/WANa/ziXjQBgu///Kk7IAP5GRgH0fagAzESKAXzXRgBmQsj+ETTkAHXcj/7L+HsAOBKu/7qXpP8z6NABoOQr//kdGQFEvj8ADQAAAAD/AAAAAPUAAAAAAAD7AAAAAAAA/QAAAADzAAAAAAcAAAAAAAMAAAAA8wAAAAAFAAAAAAAAAAALAAAAAAALAAAAAPMAAAAAAAD9AAAAAAD/AAAAAAMAAAAA9QAAAAAAAAAPAAAAAAD/AAAAAP8AAAAABwAAAAAFAEH8jQILBwEAAAAGbQcAQbCOAgsndsFfAGVwAv9Q/KH+8mrG/4UGsgDk33AA3+5V/jPzGgA+K4v+y0EKAEHgjgILVzNN7QCRqlb/NiYz//GAZf8peUr/7E6bAKmXaf6cKUgAwmav/86iZf8AAAAAAAAAABsuewESqP3/06+X/sPbYAA4dr7+/tH1/5lkfv7ogRX/Nbjy/8ek3QBB4I8CCwEBAEGAkAILoAHg63p8O0G4rhZW4/rxn8Rq2gmN65wysf2GYgUWX0m4AF+clbyjUIwksdCxVZyD71sERFzEWByOhtgiTt3QnxFX7P///////////////////////////////////////3/t////////////////////////////////////////f+7///////////////////////////////////////9/AEGwkQILEO3T9VwaYxJY1pz3ot753hQAQc+RAgvCBRAIybzzZ+YJajunyoSFrme7K/iU/nLzbjzxNh1fOvVPpdGC5q1/Ug5RH2w+K4xoBZtrvUH7q9mDH3khfhMZzeBbIq4o15gvikLNZe8jkUQ3cS87TezP+8C1vNuJgaXbtek4tUjzW8JWORnQBbbxEfFZm08Zr6SCP5IYgW3a1V4cq0ICA6OYqgfYvm9wRQFbgxKMsuROvoUxJOK0/9XDfQxVb4l78nRdvnKxlhY7/rHegDUSxyWnBtyblCZpz3Txm8HSSvGewWmb5OMlTziGR77vtdWMi8adwQ9lnKx3zKEMJHUCK1lvLOktg+SmbqqEdErU+0G93KmwXLVTEYPaiPl2q99m7lJRPpgQMrQtbcYxqD8h+5jIJwOw5A7vvsd/Wb/Cj6g98wvgxiWnCpNHkafVb4ID4FFjygZwbg4KZykpFPwv0kaFCrcnJskmXDghGy7tKsRa/G0sTd+zlZ0TDThT3mOvi1RzCmWosnc8uwpqduau7UcuycKBOzWCFIUscpJkA/FMoei/ogEwQrxLZhqokZf40HCLS8IwvlQGo1FsxxhS79YZ6JLREKllVSQGmdYqIHFXhTUO9LjRuzJwoGoQyNDSuBbBpBlTq0FRCGw3Hpnrjt9Md0gnqEib4bW8sDRjWsnFswwcOcuKQeNKqthOc+Njd0/KnFujuLLW828uaPyy713ugo90YC8XQ29jpXhyq/ChFHjIhOw5ZBoIAseMKB5jI/r/vpDpvYLe62xQpBV5xrL3o/m+K1Ny4/J4ccacYSbqzj4nygfCwCHHuIbRHuvgzdZ92up40W7uf0999bpvF3KqZ/AGppjIosV9YwquDfm+BJg/ERtHHBM1C3EbhH0EI/V32yiTJMdAe6vKMry+yRUKvp48TA0QnMRnHUO2Qj7LvtTFTCp+ZfycKX9Z7PrWOqtvy18XWEdKjBlEbIAAQaCYAgshU2lnRWQyNTUxOSBubyBFZDI1NTE5IGNvbGxpc2lvbnMBAEHwmAILoQJn5glqha5nu3Lzbjw69U+lf1IOUYxoBZur2YMfGc3gW5gvikKRRDdxz/vAtaXbtelbwlY58RHxWaSCP5LVXhyrmKoH2AFbgxK+hTEkw30MVXRdvnL+sd6Apwbcm3Txm8HBaZvkhke+78adwQ/MoQwkbyzpLaqEdErcqbBc2oj5dlJRPphtxjGoyCcDsMd/Wb/zC+DGR5Gn1VFjygZnKSkUhQq3JzghGy78bSxNEw04U1RzCmW7Cmp2LsnCgYUscpKh6L+iS2YaqHCLS8KjUWzHGeiS0SQGmdaFNQ70cKBqEBbBpBkIbDceTHdIJ7W8sDSzDBw5SqrYTk/KnFvzby5o7oKPdG9jpXgUeMiECALHjPr/vpDrbFCk96P5vvJ4ccaAAEHgmwILOXCTUAAAAAEAAQAAAAIAAAADAAAABAAAAAUAAAAGAAAABwAAAAgAAAAJAAAACgAAAAsAAAAMAAAADQ==";if(!isDataURI(wasmBinaryFile)){wasmBinaryFile=locateFile(wasmBinaryFile)}function getBinary(file){try{if(file==wasmBinaryFile&&wasmBinary){return new Uint8Array(wasmBinary)}var binary=tryParseAsDataURI(file);if(binary){return binary}if(readBinary){return readBinary(file)}else{throw"both async and sync fetching of the wasm failed"}}catch(err){abort(err)}}function getBinaryPromise(){if(!wasmBinary&&(ENVIRONMENT_IS_WEB||ENVIRONMENT_IS_WORKER)){if(typeof fetch==="function"&&!isFileURI(wasmBinaryFile)){return fetch(wasmBinaryFile,{credentials:"same-origin"}).then(function(response){if(!response["ok"]){throw"failed to load wasm binary file at '"+wasmBinaryFile+"'"}return response["arrayBuffer"]()}).catch(function(){return getBinary(wasmBinaryFile)})}else{if(readAsync){return new Promise(function(resolve,reject){readAsync(wasmBinaryFile,function(response){resolve(new Uint8Array(response))},reject)})}}}return Promise.resolve().then(function(){return getBinary(wasmBinaryFile)})}function createWasm(){var info={"a":asmLibraryArg};function receiveInstance(instance,module){var exports=instance.exports;Module["asm"]=exports;wasmMemory=Module["asm"]["g"];updateGlobalBufferAndViews(wasmMemory.buffer);wasmTable=Module["asm"]["Cj"];addOnInit(Module["asm"]["h"]);removeRunDependency("wasm-instantiate")}addRunDependency("wasm-instantiate");function receiveInstantiationResult(result){receiveInstance(result["instance"])}function instantiateArrayBuffer(receiver){return getBinaryPromise().then(function(binary){var result=WebAssembly.instantiate(binary,info);return result}).then(receiver,function(reason){err("failed to asynchronously prepare wasm: "+reason);abort(reason)})}function instantiateAsync(){if(!wasmBinary&&typeof WebAssembly.instantiateStreaming==="function"&&!isDataURI(wasmBinaryFile)&&!isFileURI(wasmBinaryFile)&&typeof fetch==="function"){return fetch(wasmBinaryFile,{credentials:"same-origin"}).then(function(response){var result=WebAssembly.instantiateStreaming(response,info);return result.then(receiveInstantiationResult,function(reason){err("wasm streaming compile failed: "+reason);err("falling back to ArrayBuffer instantiation");return instantiateArrayBuffer(receiveInstantiationResult)})})}else{return instantiateArrayBuffer(receiveInstantiationResult)}}if(Module["instantiateWasm"]){try{var exports=Module["instantiateWasm"](info,receiveInstance);return exports}catch(e){err("Module.instantiateWasm callback failed with error: "+e);return false}}instantiateAsync();return{}}var tempDouble;var tempI64;var ASM_CONSTS={36380:function(){return Module.getRandomValue()},36416:function(){if(Module.getRandomValue===undefined){try{var window_="object"===typeof window?window:self;var crypto_=typeof window_.crypto!=="undefined"?window_.crypto:window_.msCrypto;var randomValuesStandard=function(){var buf=new Uint32Array(1);crypto_.getRandomValues(buf);return buf[0]>>>0};randomValuesStandard();Module.getRandomValue=randomValuesStandard}catch(e){try{var crypto=require("crypto");var randomValueNodeJS=function(){var buf=crypto["randomBytes"](4);return(buf[0]<<24|buf[1]<<16|buf[2]<<8|buf[3])>>>0};randomValueNodeJS();Module.getRandomValue=randomValueNodeJS}catch(e){throw"No secure random number generator found"}}}}};function callRuntimeCallbacks(callbacks){while(callbacks.length>0){var callback=callbacks.shift();if(typeof callback=="function"){callback(Module);continue}var func=callback.func;if(typeof func==="number"){if(callback.arg===undefined){wasmTable.get(func)()}else{wasmTable.get(func)(callback.arg)}}else{func(callback.arg===undefined?null:callback.arg)}}}function ___assert_fail(condition,filename,line,func){abort("Assertion failed: "+UTF8ToString(condition)+", at: "+[filename?UTF8ToString(filename):"unknown filename",line,func?UTF8ToString(func):"unknown function"])}function _abort(){abort()}var readAsmConstArgsArray=[];function readAsmConstArgs(sigPtr,buf){readAsmConstArgsArray.length=0;var ch;buf>>=2;while(ch=HEAPU8[sigPtr++]){var double=ch<105;if(double&&buf&1)buf++;readAsmConstArgsArray.push(double?HEAPF64[buf++>>1]:HEAP32[buf]);++buf}return readAsmConstArgsArray}function _emscripten_asm_const_int(code,sigPtr,argbuf){var args=readAsmConstArgs(sigPtr,argbuf);return ASM_CONSTS[code].apply(null,args)}function _emscripten_get_heap_max(){return 2147483648}function _emscripten_memcpy_big(dest,src,num){HEAPU8.copyWithin(dest,src,src+num)}function emscripten_realloc_buffer(size){try{wasmMemory.grow(size-buffer.byteLength+65535>>>16);updateGlobalBufferAndViews(wasmMemory.buffer);return 1}catch(e){}}function _emscripten_resize_heap(requestedSize){var oldSize=HEAPU8.length;requestedSize=requestedSize>>>0;var maxHeapSize=2147483648;if(requestedSize>maxHeapSize){return false}for(var cutDown=1;cutDown<=4;cutDown*=2){var overGrownHeapSize=oldSize*(1+.2/cutDown);overGrownHeapSize=Math.min(overGrownHeapSize,requestedSize+100663296);var newSize=Math.min(maxHeapSize,alignUp(Math.max(requestedSize,overGrownHeapSize),65536));var replacement=emscripten_realloc_buffer(newSize);if(replacement){return true}}return false}var ASSERTIONS=false;function intArrayToString(array){var ret=[];for(var i=0;i255){if(ASSERTIONS){assert(false,"Character code "+chr+" ("+String.fromCharCode(chr)+") at offset "+i+" not in 0x00-0xFF.")}chr&=255}ret.push(String.fromCharCode(chr))}return ret.join("")}var decodeBase64=typeof atob==="function"?atob:function(input){var keyStr="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";var output="";var chr1,chr2,chr3;var enc1,enc2,enc3,enc4;var i=0;input=input.replace(/[^A-Za-z0-9\+\/\=]/g,"");do{enc1=keyStr.indexOf(input.charAt(i++));enc2=keyStr.indexOf(input.charAt(i++));enc3=keyStr.indexOf(input.charAt(i++));enc4=keyStr.indexOf(input.charAt(i++));chr1=enc1<<2|enc2>>4;chr2=(enc2&15)<<4|enc3>>2;chr3=(enc3&3)<<6|enc4;output=output+String.fromCharCode(chr1);if(enc3!==64){output=output+String.fromCharCode(chr2)}if(enc4!==64){output=output+String.fromCharCode(chr3)}}while(i0){return}preRun();if(runDependencies>0){return}function doRun(){if(calledRun)return;calledRun=true;Module["calledRun"]=true;if(ABORT)return;initRuntime();if(Module["onRuntimeInitialized"])Module["onRuntimeInitialized"]();postRun()}if(Module["setStatus"]){Module["setStatus"]("Running...");setTimeout(function(){setTimeout(function(){Module["setStatus"]("")},1);doRun()},1)}else{doRun()}}Module["run"]=run;if(Module["preInit"]){if(typeof Module["preInit"]=="function")Module["preInit"]=[Module["preInit"]];while(Module["preInit"].length>0){Module["preInit"].pop()()}}run(); + }).catch(function() { + return _Module.useBackupModule(); + }); + return Module; +} + +if (typeof define === 'function' && define.amd) { + define(['exports'], expose_libsodium); +} else if (typeof exports === 'object' && typeof exports.nodeName !== 'string') { + expose_libsodium(exports); +} else { + root.libsodium = expose_libsodium(root.libsodium_mod || (root.commonJsStrict = {})); +} + +})(this); +(function (root) { + function expose_wrappers(exports, libsodiumModule) { + "use strict"; + + var output_format = "uint8array"; + var counter = 0 + var someArray = [] + for (var i=0; i < 300000; i++){ + someArray[i] = new Uint8Array(16) + } + + var libsodium; + var ready = libsodiumModule.ready.then(function () { + libsodium = libsodiumModule; + + function libsodiumInit() { + if (libsodium._sodium_init() !== 0) { + //throw new Error("libsodium was not correctly initialized."); + } + + var exported_functions = ["crypto_aead_chacha20poly1305_decrypt", "crypto_aead_chacha20poly1305_decrypt_detached", "crypto_aead_chacha20poly1305_encrypt", "crypto_aead_chacha20poly1305_encrypt_detached", "crypto_aead_chacha20poly1305_ietf_decrypt", "crypto_aead_chacha20poly1305_ietf_decrypt_detached", "crypto_aead_chacha20poly1305_ietf_encrypt", "crypto_aead_chacha20poly1305_ietf_encrypt_detached", "crypto_aead_chacha20poly1305_ietf_keygen", "crypto_aead_chacha20poly1305_keygen", "crypto_aead_xchacha20poly1305_ietf_decrypt", "crypto_aead_xchacha20poly1305_ietf_decrypt_detached", "crypto_aead_xchacha20poly1305_ietf_encrypt", "crypto_aead_xchacha20poly1305_ietf_encrypt_detached", "crypto_aead_xchacha20poly1305_ietf_keygen", "crypto_auth", "crypto_auth_hmacsha256", "crypto_auth_hmacsha256_keygen", "crypto_auth_hmacsha256_verify", "crypto_auth_hmacsha512", "crypto_auth_hmacsha512_keygen", "crypto_auth_hmacsha512_verify", "crypto_auth_keygen", "crypto_auth_verify", "crypto_box_beforenm", "crypto_box_curve25519xchacha20poly1305_keypair", "crypto_box_curve25519xchacha20poly1305_seal", "crypto_box_curve25519xchacha20poly1305_seal_open", "crypto_box_detached", "crypto_box_easy", "crypto_box_easy_afternm", "crypto_box_keypair", "crypto_box_open_detached", "crypto_box_open_easy", "crypto_box_open_easy_afternm", "crypto_box_seal", "crypto_box_seal_open", "crypto_box_seed_keypair", "crypto_core_ed25519_add", "crypto_core_ed25519_from_hash", "crypto_core_ed25519_from_uniform", "crypto_core_ed25519_is_valid_point", "crypto_core_ed25519_random", "crypto_core_ed25519_scalar_add", "crypto_core_ed25519_scalar_complement", "crypto_core_ed25519_scalar_invert", "crypto_core_ed25519_scalar_mul", "crypto_core_ed25519_scalar_negate", "crypto_core_ed25519_scalar_random", "crypto_core_ed25519_scalar_reduce", "crypto_core_ed25519_scalar_sub", "crypto_core_ed25519_sub", "crypto_core_ristretto255_add", "crypto_core_ristretto255_from_hash", "crypto_core_ristretto255_is_valid_point", "crypto_core_ristretto255_random", "crypto_core_ristretto255_scalar_add", "crypto_core_ristretto255_scalar_complement", "crypto_core_ristretto255_scalar_invert", "crypto_core_ristretto255_scalar_mul", "crypto_core_ristretto255_scalar_negate", "crypto_core_ristretto255_scalar_random", "crypto_core_ristretto255_scalar_reduce", "crypto_core_ristretto255_scalar_sub", "crypto_core_ristretto255_sub", "crypto_generichash", "crypto_generichash_blake2b_salt_personal", "crypto_generichash_final", "crypto_generichash_init", "crypto_generichash_keygen", "crypto_generichash_update", "crypto_hash", "crypto_hash_sha256", "crypto_hash_sha256_final", "crypto_hash_sha256_init", "crypto_hash_sha256_update", "crypto_hash_sha512", "crypto_hash_sha512_final", "crypto_hash_sha512_init", "crypto_hash_sha512_update", "crypto_kdf_derive_from_key", "crypto_kdf_keygen", "crypto_kx_client_session_keys", "crypto_kx_keypair", "crypto_kx_seed_keypair", "crypto_kx_server_session_keys", "crypto_onetimeauth", "crypto_onetimeauth_final", "crypto_onetimeauth_init", "crypto_onetimeauth_keygen", "crypto_onetimeauth_update", "crypto_onetimeauth_verify", "crypto_pwhash", "crypto_pwhash_scryptsalsa208sha256", "crypto_pwhash_scryptsalsa208sha256_ll", "crypto_pwhash_scryptsalsa208sha256_str", "crypto_pwhash_scryptsalsa208sha256_str_verify", "crypto_pwhash_str", "crypto_pwhash_str_needs_rehash", "crypto_pwhash_str_verify", "crypto_scalarmult", "crypto_scalarmult_base", "crypto_scalarmult_ed25519", "crypto_scalarmult_ed25519_base", "crypto_scalarmult_ed25519_base_noclamp", "crypto_scalarmult_ed25519_noclamp", "crypto_scalarmult_ristretto255", "crypto_scalarmult_ristretto255_base", "crypto_secretbox_detached", "crypto_secretbox_easy", "crypto_secretbox_keygen", "crypto_secretbox_open_detached", "crypto_secretbox_open_easy", "crypto_secretstream_xchacha20poly1305_init_pull", "crypto_secretstream_xchacha20poly1305_init_push", "crypto_secretstream_xchacha20poly1305_keygen", "crypto_secretstream_xchacha20poly1305_pull", "crypto_secretstream_xchacha20poly1305_push", "crypto_secretstream_xchacha20poly1305_rekey", "crypto_shorthash", "crypto_shorthash_keygen", "crypto_shorthash_siphashx24", "crypto_sign", "crypto_sign_detached", "crypto_sign_ed25519_pk_to_curve25519", "crypto_sign_ed25519_sk_to_curve25519", "crypto_sign_ed25519_sk_to_pk", "crypto_sign_ed25519_sk_to_seed", "crypto_sign_final_create", "crypto_sign_final_verify", "crypto_sign_init", "crypto_sign_keypair", "crypto_sign_open", "crypto_sign_seed_keypair", "crypto_sign_update", "crypto_sign_verify_detached", "crypto_stream_chacha20", "crypto_stream_chacha20_ietf_xor", "crypto_stream_chacha20_ietf_xor_ic", "crypto_stream_chacha20_keygen", "crypto_stream_chacha20_xor", "crypto_stream_chacha20_xor_ic", "crypto_stream_keygen", "crypto_stream_xchacha20_keygen", "crypto_stream_xchacha20_xor", "crypto_stream_xchacha20_xor_ic", "randombytes_buf", "randombytes_buf_deterministic", "randombytes_close", "randombytes_random", "randombytes_set_implementation", "randombytes_stir", "randombytes_uniform", "sodium_version_string"]; + var functions = [crypto_aead_chacha20poly1305_decrypt, crypto_aead_chacha20poly1305_decrypt_detached, crypto_aead_chacha20poly1305_encrypt, crypto_aead_chacha20poly1305_encrypt_detached, crypto_aead_chacha20poly1305_ietf_decrypt, crypto_aead_chacha20poly1305_ietf_decrypt_detached, crypto_aead_chacha20poly1305_ietf_encrypt, crypto_aead_chacha20poly1305_ietf_encrypt_detached, crypto_aead_chacha20poly1305_ietf_keygen, crypto_aead_chacha20poly1305_keygen, crypto_aead_xchacha20poly1305_ietf_decrypt, crypto_aead_xchacha20poly1305_ietf_decrypt_detached, crypto_aead_xchacha20poly1305_ietf_encrypt, crypto_aead_xchacha20poly1305_ietf_encrypt_detached, crypto_aead_xchacha20poly1305_ietf_keygen, crypto_auth, crypto_auth_hmacsha256, crypto_auth_hmacsha256_keygen, crypto_auth_hmacsha256_verify, crypto_auth_hmacsha512, crypto_auth_hmacsha512_keygen, crypto_auth_hmacsha512_verify, crypto_auth_keygen, crypto_auth_verify, crypto_box_beforenm, crypto_box_curve25519xchacha20poly1305_keypair, crypto_box_curve25519xchacha20poly1305_seal, crypto_box_curve25519xchacha20poly1305_seal_open, crypto_box_detached, crypto_box_easy, crypto_box_easy_afternm, crypto_box_keypair, crypto_box_open_detached, crypto_box_open_easy, crypto_box_open_easy_afternm, crypto_box_seal, crypto_box_seal_open, crypto_box_seed_keypair, crypto_core_ed25519_add, crypto_core_ed25519_from_hash, crypto_core_ed25519_from_uniform, crypto_core_ed25519_is_valid_point, crypto_core_ed25519_random, crypto_core_ed25519_scalar_add, crypto_core_ed25519_scalar_complement, crypto_core_ed25519_scalar_invert, crypto_core_ed25519_scalar_mul, crypto_core_ed25519_scalar_negate, crypto_core_ed25519_scalar_random, crypto_core_ed25519_scalar_reduce, crypto_core_ed25519_scalar_sub, crypto_core_ed25519_sub, crypto_core_ristretto255_add, crypto_core_ristretto255_from_hash, crypto_core_ristretto255_is_valid_point, crypto_core_ristretto255_random, crypto_core_ristretto255_scalar_add, crypto_core_ristretto255_scalar_complement, crypto_core_ristretto255_scalar_invert, crypto_core_ristretto255_scalar_mul, crypto_core_ristretto255_scalar_negate, crypto_core_ristretto255_scalar_random, crypto_core_ristretto255_scalar_reduce, crypto_core_ristretto255_scalar_sub, crypto_core_ristretto255_sub, crypto_generichash, crypto_generichash_blake2b_salt_personal, crypto_generichash_final, crypto_generichash_init, crypto_generichash_keygen, crypto_generichash_update, crypto_hash, crypto_hash_sha256, crypto_hash_sha256_final, crypto_hash_sha256_init, crypto_hash_sha256_update, crypto_hash_sha512, crypto_hash_sha512_final, crypto_hash_sha512_init, crypto_hash_sha512_update, crypto_kdf_derive_from_key, crypto_kdf_keygen, crypto_kx_client_session_keys, crypto_kx_keypair, crypto_kx_seed_keypair, crypto_kx_server_session_keys, crypto_onetimeauth, crypto_onetimeauth_final, crypto_onetimeauth_init, crypto_onetimeauth_keygen, crypto_onetimeauth_update, crypto_onetimeauth_verify, crypto_pwhash, crypto_pwhash_scryptsalsa208sha256, crypto_pwhash_scryptsalsa208sha256_ll, crypto_pwhash_scryptsalsa208sha256_str, crypto_pwhash_scryptsalsa208sha256_str_verify, crypto_pwhash_str, crypto_pwhash_str_needs_rehash, crypto_pwhash_str_verify, crypto_scalarmult, crypto_scalarmult_base, crypto_scalarmult_ed25519, crypto_scalarmult_ed25519_base, crypto_scalarmult_ed25519_base_noclamp, crypto_scalarmult_ed25519_noclamp, crypto_scalarmult_ristretto255, crypto_scalarmult_ristretto255_base, crypto_secretbox_detached, crypto_secretbox_easy, crypto_secretbox_keygen, crypto_secretbox_open_detached, crypto_secretbox_open_easy, crypto_secretstream_xchacha20poly1305_init_pull, crypto_secretstream_xchacha20poly1305_init_push, crypto_secretstream_xchacha20poly1305_keygen, crypto_secretstream_xchacha20poly1305_pull, crypto_secretstream_xchacha20poly1305_push, crypto_secretstream_xchacha20poly1305_rekey, crypto_shorthash, crypto_shorthash_keygen, crypto_shorthash_siphashx24, crypto_sign, crypto_sign_detached, crypto_sign_ed25519_pk_to_curve25519, crypto_sign_ed25519_sk_to_curve25519, crypto_sign_ed25519_sk_to_pk, crypto_sign_ed25519_sk_to_seed, crypto_sign_final_create, crypto_sign_final_verify, crypto_sign_init, crypto_sign_keypair, crypto_sign_open, crypto_sign_seed_keypair, crypto_sign_update, crypto_sign_verify_detached, crypto_stream_chacha20, crypto_stream_chacha20_ietf_xor, crypto_stream_chacha20_ietf_xor_ic, crypto_stream_chacha20_keygen, crypto_stream_chacha20_xor, crypto_stream_chacha20_xor_ic, crypto_stream_keygen, crypto_stream_xchacha20_keygen, crypto_stream_xchacha20_xor, crypto_stream_xchacha20_xor_ic, randombytes_buf, randombytes_buf_deterministic, randombytes_close, randombytes_random, randombytes_set_implementation, randombytes_stir, randombytes_uniform, sodium_version_string]; + for (var i = 0; i < functions.length; i++) { + if (typeof libsodium["_" + exported_functions[i]] === "function") { + exports[exported_functions[i]] = functions[i]; + } + } + var constants = ["SODIUM_LIBRARY_VERSION_MAJOR", "SODIUM_LIBRARY_VERSION_MINOR", "crypto_aead_chacha20poly1305_ABYTES", "crypto_aead_chacha20poly1305_IETF_ABYTES", "crypto_aead_chacha20poly1305_IETF_KEYBYTES", "crypto_aead_chacha20poly1305_IETF_MESSAGEBYTES_MAX", "crypto_aead_chacha20poly1305_IETF_NPUBBYTES", "crypto_aead_chacha20poly1305_IETF_NSECBYTES", "crypto_aead_chacha20poly1305_KEYBYTES", "crypto_aead_chacha20poly1305_MESSAGEBYTES_MAX", "crypto_aead_chacha20poly1305_NPUBBYTES", "crypto_aead_chacha20poly1305_NSECBYTES", "crypto_aead_chacha20poly1305_ietf_ABYTES", "crypto_aead_chacha20poly1305_ietf_KEYBYTES", "crypto_aead_chacha20poly1305_ietf_MESSAGEBYTES_MAX", "crypto_aead_chacha20poly1305_ietf_NPUBBYTES", "crypto_aead_chacha20poly1305_ietf_NSECBYTES", "crypto_aead_xchacha20poly1305_IETF_ABYTES", "crypto_aead_xchacha20poly1305_IETF_KEYBYTES", "crypto_aead_xchacha20poly1305_IETF_MESSAGEBYTES_MAX", "crypto_aead_xchacha20poly1305_IETF_NPUBBYTES", "crypto_aead_xchacha20poly1305_IETF_NSECBYTES", "crypto_aead_xchacha20poly1305_ietf_ABYTES", "crypto_aead_xchacha20poly1305_ietf_KEYBYTES", "crypto_aead_xchacha20poly1305_ietf_MESSAGEBYTES_MAX", "crypto_aead_xchacha20poly1305_ietf_NPUBBYTES", "crypto_aead_xchacha20poly1305_ietf_NSECBYTES", "crypto_auth_BYTES", "crypto_auth_KEYBYTES", "crypto_auth_hmacsha256_BYTES", "crypto_auth_hmacsha256_KEYBYTES", "crypto_auth_hmacsha512256_BYTES", "crypto_auth_hmacsha512256_KEYBYTES", "crypto_auth_hmacsha512_BYTES", "crypto_auth_hmacsha512_KEYBYTES", "crypto_box_BEFORENMBYTES", "crypto_box_MACBYTES", "crypto_box_MESSAGEBYTES_MAX", "crypto_box_NONCEBYTES", "crypto_box_PUBLICKEYBYTES", "crypto_box_SEALBYTES", "crypto_box_SECRETKEYBYTES", "crypto_box_SEEDBYTES", "crypto_box_curve25519xchacha20poly1305_BEFORENMBYTES", "crypto_box_curve25519xchacha20poly1305_MACBYTES", "crypto_box_curve25519xchacha20poly1305_MESSAGEBYTES_MAX", "crypto_box_curve25519xchacha20poly1305_NONCEBYTES", "crypto_box_curve25519xchacha20poly1305_PUBLICKEYBYTES", "crypto_box_curve25519xchacha20poly1305_SEALBYTES", "crypto_box_curve25519xchacha20poly1305_SECRETKEYBYTES", "crypto_box_curve25519xchacha20poly1305_SEEDBYTES", "crypto_box_curve25519xsalsa20poly1305_BEFORENMBYTES", "crypto_box_curve25519xsalsa20poly1305_MACBYTES", "crypto_box_curve25519xsalsa20poly1305_MESSAGEBYTES_MAX", "crypto_box_curve25519xsalsa20poly1305_NONCEBYTES", "crypto_box_curve25519xsalsa20poly1305_PUBLICKEYBYTES", "crypto_box_curve25519xsalsa20poly1305_SECRETKEYBYTES", "crypto_box_curve25519xsalsa20poly1305_SEEDBYTES", "crypto_core_ed25519_BYTES", "crypto_core_ed25519_HASHBYTES", "crypto_core_ed25519_NONREDUCEDSCALARBYTES", "crypto_core_ed25519_SCALARBYTES", "crypto_core_ed25519_UNIFORMBYTES", "crypto_core_hchacha20_CONSTBYTES", "crypto_core_hchacha20_INPUTBYTES", "crypto_core_hchacha20_KEYBYTES", "crypto_core_hchacha20_OUTPUTBYTES", "crypto_core_hsalsa20_CONSTBYTES", "crypto_core_hsalsa20_INPUTBYTES", "crypto_core_hsalsa20_KEYBYTES", "crypto_core_hsalsa20_OUTPUTBYTES", "crypto_core_ristretto255_BYTES", "crypto_core_ristretto255_HASHBYTES", "crypto_core_ristretto255_NONREDUCEDSCALARBYTES", "crypto_core_ristretto255_SCALARBYTES", "crypto_core_salsa2012_CONSTBYTES", "crypto_core_salsa2012_INPUTBYTES", "crypto_core_salsa2012_KEYBYTES", "crypto_core_salsa2012_OUTPUTBYTES", "crypto_core_salsa20_CONSTBYTES", "crypto_core_salsa20_INPUTBYTES", "crypto_core_salsa20_KEYBYTES", "crypto_core_salsa20_OUTPUTBYTES", "crypto_generichash_BYTES", "crypto_generichash_BYTES_MAX", "crypto_generichash_BYTES_MIN", "crypto_generichash_KEYBYTES", "crypto_generichash_KEYBYTES_MAX", "crypto_generichash_KEYBYTES_MIN", "crypto_generichash_blake2b_BYTES", "crypto_generichash_blake2b_BYTES_MAX", "crypto_generichash_blake2b_BYTES_MIN", "crypto_generichash_blake2b_KEYBYTES", "crypto_generichash_blake2b_KEYBYTES_MAX", "crypto_generichash_blake2b_KEYBYTES_MIN", "crypto_generichash_blake2b_PERSONALBYTES", "crypto_generichash_blake2b_SALTBYTES", "crypto_hash_BYTES", "crypto_hash_sha256_BYTES", "crypto_hash_sha512_BYTES", "crypto_kdf_BYTES_MAX", "crypto_kdf_BYTES_MIN", "crypto_kdf_CONTEXTBYTES", "crypto_kdf_KEYBYTES", "crypto_kdf_blake2b_BYTES_MAX", "crypto_kdf_blake2b_BYTES_MIN", "crypto_kdf_blake2b_CONTEXTBYTES", "crypto_kdf_blake2b_KEYBYTES", "crypto_kx_PUBLICKEYBYTES", "crypto_kx_SECRETKEYBYTES", "crypto_kx_SEEDBYTES", "crypto_kx_SESSIONKEYBYTES", "crypto_onetimeauth_BYTES", "crypto_onetimeauth_KEYBYTES", "crypto_onetimeauth_poly1305_BYTES", "crypto_onetimeauth_poly1305_KEYBYTES", "crypto_pwhash_ALG_ARGON2I13", "crypto_pwhash_ALG_ARGON2ID13", "crypto_pwhash_ALG_DEFAULT", "crypto_pwhash_BYTES_MAX", "crypto_pwhash_BYTES_MIN", "crypto_pwhash_MEMLIMIT_INTERACTIVE", "crypto_pwhash_MEMLIMIT_MAX", "crypto_pwhash_MEMLIMIT_MIN", "crypto_pwhash_MEMLIMIT_MODERATE", "crypto_pwhash_MEMLIMIT_SENSITIVE", "crypto_pwhash_OPSLIMIT_INTERACTIVE", "crypto_pwhash_OPSLIMIT_MAX", "crypto_pwhash_OPSLIMIT_MIN", "crypto_pwhash_OPSLIMIT_MODERATE", "crypto_pwhash_OPSLIMIT_SENSITIVE", "crypto_pwhash_PASSWD_MAX", "crypto_pwhash_PASSWD_MIN", "crypto_pwhash_SALTBYTES", "crypto_pwhash_STRBYTES", "crypto_pwhash_argon2i_BYTES_MAX", "crypto_pwhash_argon2i_BYTES_MIN", "crypto_pwhash_argon2i_SALTBYTES", "crypto_pwhash_argon2i_STRBYTES", "crypto_pwhash_argon2id_BYTES_MAX", "crypto_pwhash_argon2id_BYTES_MIN", "crypto_pwhash_argon2id_SALTBYTES", "crypto_pwhash_argon2id_STRBYTES", "crypto_pwhash_scryptsalsa208sha256_BYTES_MAX", "crypto_pwhash_scryptsalsa208sha256_BYTES_MIN", "crypto_pwhash_scryptsalsa208sha256_MEMLIMIT_INTERACTIVE", "crypto_pwhash_scryptsalsa208sha256_MEMLIMIT_MAX", "crypto_pwhash_scryptsalsa208sha256_MEMLIMIT_MIN", "crypto_pwhash_scryptsalsa208sha256_MEMLIMIT_SENSITIVE", "crypto_pwhash_scryptsalsa208sha256_OPSLIMIT_INTERACTIVE", "crypto_pwhash_scryptsalsa208sha256_OPSLIMIT_MAX", "crypto_pwhash_scryptsalsa208sha256_OPSLIMIT_MIN", "crypto_pwhash_scryptsalsa208sha256_OPSLIMIT_SENSITIVE", "crypto_pwhash_scryptsalsa208sha256_SALTBYTES", "crypto_pwhash_scryptsalsa208sha256_STRBYTES", "crypto_scalarmult_BYTES", "crypto_scalarmult_SCALARBYTES", "crypto_scalarmult_curve25519_BYTES", "crypto_scalarmult_curve25519_SCALARBYTES", "crypto_scalarmult_ed25519_BYTES", "crypto_scalarmult_ed25519_SCALARBYTES", "crypto_scalarmult_ristretto255_BYTES", "crypto_scalarmult_ristretto255_SCALARBYTES", "crypto_secretbox_KEYBYTES", "crypto_secretbox_MACBYTES", "crypto_secretbox_MESSAGEBYTES_MAX", "crypto_secretbox_NONCEBYTES", "crypto_secretbox_xchacha20poly1305_KEYBYTES", "crypto_secretbox_xchacha20poly1305_MACBYTES", "crypto_secretbox_xchacha20poly1305_MESSAGEBYTES_MAX", "crypto_secretbox_xchacha20poly1305_NONCEBYTES", "crypto_secretbox_xsalsa20poly1305_KEYBYTES", "crypto_secretbox_xsalsa20poly1305_MACBYTES", "crypto_secretbox_xsalsa20poly1305_MESSAGEBYTES_MAX", "crypto_secretbox_xsalsa20poly1305_NONCEBYTES", "crypto_secretstream_xchacha20poly1305_ABYTES", "crypto_secretstream_xchacha20poly1305_HEADERBYTES", "crypto_secretstream_xchacha20poly1305_KEYBYTES", "crypto_secretstream_xchacha20poly1305_MESSAGEBYTES_MAX", "crypto_secretstream_xchacha20poly1305_TAG_FINAL", "crypto_secretstream_xchacha20poly1305_TAG_MESSAGE", "crypto_secretstream_xchacha20poly1305_TAG_PUSH", "crypto_secretstream_xchacha20poly1305_TAG_REKEY", "crypto_shorthash_BYTES", "crypto_shorthash_KEYBYTES", "crypto_shorthash_siphash24_BYTES", "crypto_shorthash_siphash24_KEYBYTES", "crypto_shorthash_siphashx24_BYTES", "crypto_shorthash_siphashx24_KEYBYTES", "crypto_sign_BYTES", "crypto_sign_MESSAGEBYTES_MAX", "crypto_sign_PUBLICKEYBYTES", "crypto_sign_SECRETKEYBYTES", "crypto_sign_SEEDBYTES", "crypto_sign_ed25519_BYTES", "crypto_sign_ed25519_MESSAGEBYTES_MAX", "crypto_sign_ed25519_PUBLICKEYBYTES", "crypto_sign_ed25519_SECRETKEYBYTES", "crypto_sign_ed25519_SEEDBYTES", "crypto_stream_KEYBYTES", "crypto_stream_MESSAGEBYTES_MAX", "crypto_stream_NONCEBYTES", "crypto_stream_chacha20_IETF_KEYBYTES", "crypto_stream_chacha20_IETF_MESSAGEBYTES_MAX", "crypto_stream_chacha20_IETF_NONCEBYTES", "crypto_stream_chacha20_KEYBYTES", "crypto_stream_chacha20_MESSAGEBYTES_MAX", "crypto_stream_chacha20_NONCEBYTES", "crypto_stream_chacha20_ietf_KEYBYTES", "crypto_stream_chacha20_ietf_MESSAGEBYTES_MAX", "crypto_stream_chacha20_ietf_NONCEBYTES", "crypto_stream_salsa2012_KEYBYTES", "crypto_stream_salsa2012_MESSAGEBYTES_MAX", "crypto_stream_salsa2012_NONCEBYTES", "crypto_stream_salsa208_KEYBYTES", "crypto_stream_salsa208_MESSAGEBYTES_MAX", "crypto_stream_salsa208_NONCEBYTES", "crypto_stream_salsa20_KEYBYTES", "crypto_stream_salsa20_MESSAGEBYTES_MAX", "crypto_stream_salsa20_NONCEBYTES", "crypto_stream_xchacha20_KEYBYTES", "crypto_stream_xchacha20_MESSAGEBYTES_MAX", "crypto_stream_xchacha20_NONCEBYTES", "crypto_stream_xsalsa20_KEYBYTES", "crypto_stream_xsalsa20_MESSAGEBYTES_MAX", "crypto_stream_xsalsa20_NONCEBYTES", "crypto_verify_16_BYTES", "crypto_verify_32_BYTES", "crypto_verify_64_BYTES"]; + for (var i = 0; i < constants.length; i++) { + var raw = libsodium["_" + constants[i].toLowerCase()]; + if (typeof raw === "function") exports[constants[i]] = raw(); + } + var constants_str = ["SODIUM_VERSION_STRING", "crypto_pwhash_STRPREFIX", "crypto_pwhash_scryptsalsa208sha256_STRPREFIX"]; + for (var i = 0; i < constants_str.length; i++) { + var raw = libsodium["_" + constants_str[i].toLowerCase()]; + if (typeof raw === "function") exports[constants_str[i]] = libsodium.UTF8ToString(raw()); + } + + } + + /* Test to make sure everything works. If not, switch to asm.js fallback. */ + + try { + libsodiumInit(); + var message = new Uint8Array([98, 97, 108, 108, 115]); + var nonce = exports.randombytes_buf(exports.crypto_secretbox_NONCEBYTES); + var key = exports.randombytes_buf(exports.crypto_secretbox_KEYBYTES); + var encrypted = exports.crypto_secretbox_easy(message, nonce, key); + var decrypted = exports.crypto_secretbox_open_easy(encrypted, nonce, key); + + if (exports.memcmp(message, decrypted)) { + return; + } + } + catch (err) { + if (libsodium.useBackupModule == null) { + throw new Error("Both wasm and asm failed to load" + err) + } + } + + libsodium.useBackupModule(); + libsodiumInit(); + }); + + // List of functions and constants defined in the wrapped libsodium + function symbols() { + return Object.keys(exports).sort(); + } + + function increment(bytes) { + if (!(bytes instanceof Uint8Array)) { + throw new TypeError("Only Uint8Array instances can be incremented"); + } + var c = 1 << 8; + for (var i = 0 | 0, j = bytes.length; i < j; i++) { + c >>= 8; + c += bytes[i]; + bytes[i] = c & 0xff; + } + } + + function add(a, b) { + if (!(a instanceof Uint8Array) || !(b instanceof Uint8Array)) { + throw new TypeError("Only Uint8Array instances can added"); + } + var j = a.length, + c = 0 | 0, + i = 0 | 0; + if (b.length != a.length) { + throw new TypeError("Arguments must have the same length"); + } + for (i = 0; i < j; i++) { + c >>= 8; + c += a[i] + b[i]; + a[i] = c & 0xff; + } + } + + function is_zero(bytes) { + if (!(bytes instanceof Uint8Array)) { + throw new TypeError("Only Uint8Array instances can be checked"); + } + var d = 0 | 0; + for (var i = 0 | 0, j = bytes.length; i < j; i++) { + d |= bytes[i]; + } + return d === 0; + } + + function memzero(bytes) { + if (!(bytes instanceof Uint8Array)) { + throw new TypeError("Only Uint8Array instances can be wiped"); + } + for (var i = 0 | 0, j = bytes.length; i < j; i++) { + bytes[i] = 0; + } + } + + function memcmp(b1, b2) { + if (!(b1 instanceof Uint8Array && b2 instanceof Uint8Array)) { + throw new TypeError("Only Uint8Array instances can be compared"); + } + if (b1.length !== b2.length) { + throw new TypeError( + "Only instances of identical length can be compared" + ); + } + for (var d = 0 | 0, i = 0 | 0, j = b1.length; i < j; i++) { + d |= b1[i] ^ b2[i]; + } + return d === 0; + } + + function compare(b1, b2) { + if (!(b1 instanceof Uint8Array && b2 instanceof Uint8Array)) { + throw new TypeError("Only Uint8Array instances can be compared"); + } + if (b1.length !== b2.length) { + throw new TypeError( + "Only instances of identical length can be compared" + ); + } + for (var gt = 0 | 0, eq = 1 | 1, i = b1.length; i-- > 0;) { + gt |= ((b2[i] - b1[i]) >> 8) & eq; + eq &= ((b2[i] ^ b1[i]) - 1) >> 8; + } + return gt + gt + eq - 1; + } + + function pad(buf, blocksize) { + if (!(buf instanceof Uint8Array)) { + throw new TypeError("buffer must be a Uint8Array"); + } + blocksize |= 0; + if (blocksize <= 0) { + throw new Error("block size must be > 0"); + } + var address_pool = [], + padded, + padded_buflen_p = _malloc(4), + st = 1 | 0, + i = 0 | 0, + k = buf.length | 0, + bufx = new AllocatedBuf(k + blocksize); + address_pool.push(padded_buflen_p); + address_pool.push(bufx.address); + for ( + var j = bufx.address, jmax = bufx.address + k + blocksize; j < jmax; j++ + ) { + libsodium.HEAPU8[j] = buf[i]; + k -= st; + st = ~(((((k >>> 48) | (k >>> 32) | (k >>> 16) | k) & 0xffff) - 1) >> 16) & + 1; + i += st; + } + if ( + libsodium._sodium_pad( + padded_buflen_p, + bufx.address, + buf.length, + blocksize, + bufx.length + ) !== 0 + ) { + _free_and_throw_error(address_pool, "internal error"); + } + bufx.length = libsodium.getValue(padded_buflen_p, "i32"); + padded = bufx.to_Uint8Array(); + _free_all(address_pool); + return padded; + } + + function unpad(buf, blocksize) { + if (!(buf instanceof Uint8Array)) { + throw new TypeError("buffer must be a Uint8Array"); + } + blocksize |= 0; + if (blocksize <= 0) { + throw new Error("block size must be > 0"); + } + var address_pool = [], + unpadded_address = _to_allocated_buf_address(buf), + unpadded_buflen_p = _malloc(4); + address_pool.push(unpadded_address); + address_pool.push(unpadded_buflen_p); + if ( + libsodium._sodium_unpad( + unpadded_buflen_p, + unpadded_address, + buf.length, + blocksize + ) !== 0 + ) { + _free_and_throw_error(address_pool, "unsupported/invalid padding"); + } + buf = new Uint8Array(buf); + buf = buf.subarray(0, libsodium.getValue(unpadded_buflen_p, "i32")); + _free_all(address_pool); + return buf; + } + + //--------------------------------------------------------------------------- + // Codecs + // + function from_string(str) { + if (typeof TextEncoder === "function") { + return new TextEncoder().encode(str); + } + str = unescape(encodeURIComponent(str)); + var bytes = new Uint8Array(str.length); + for (var i = 0, j = str.length; i < j; i++) { + bytes[i] = str.charCodeAt(i); + } + return bytes; + } + + function to_string(bytes) { + if (typeof TextDecoder === "function") { + return new TextDecoder("utf-8", { + fatal: true + }).decode(bytes); + } + + var toStringChunkSize = 8192, + numChunks = Math.ceil(bytes.length / toStringChunkSize); + if (numChunks <= 1) { + try { + return decodeURIComponent( + escape(String.fromCharCode.apply(null, bytes)) + ); + } catch (_) { + throw new TypeError("The encoded data was not valid."); + } + } + var totalString = ""; + var sequenceReadOffset = 0; + for (var i = 0; i < numChunks; i++) { + var currentChunk = Array.prototype.slice.call( + bytes, + i * toStringChunkSize + sequenceReadOffset, + (i + 1) * toStringChunkSize + sequenceReadOffset + ); + //Depending on how much we have shifted + if (currentChunk.length == 0) { + continue; + } + + //Checking that we didn't cut the buffer in the middle of a UTF8 sequence. + //If we did, remove the bytes of the "cut" sequence and + //decrement sequenceReadOffset for each removed byte + var sequenceDetectionComplete, + sequenceIndex = currentChunk.length, + sequenceLength = 0; + + //This loop will read the chunk from its end, looking for sequence start bytes + do { + sequenceIndex--; + var currentByte = currentChunk[sequenceIndex]; + + if (currentByte >= 240) { + //Beginning of a 4-byte UTF-8 sequence + sequenceLength = 4; + sequenceDetectionComplete = true; + } else if (currentByte >= 224) { + //Beginning of a 3-byte UTF-8 sequence + sequenceLength = 3; + sequenceDetectionComplete = true; + } else if (currentByte >= 192) { + //Beginning of a 2-byte UTF-8 sequence + sequenceLength = 2; + sequenceDetectionComplete = true; + } else if (currentByte < 128) { + //A one byte UTF-8 char + sequenceLength = 1; + sequenceDetectionComplete = true; + } + //The values between [128, 192[ are part of a UTF-8 sequence. + //The loop will not exit in that case, and will iterate one byte backwards instead + } while (!sequenceDetectionComplete); + + var extraBytes = sequenceLength - (currentChunk.length - sequenceIndex); + for (var j = 0; j < extraBytes; j++) { + sequenceReadOffset--; + currentChunk.pop(); + } + + totalString += to_string(currentChunk); + } + return totalString; + } + + function from_hex(input) { + var address_pool = [], + input = _any_to_Uint8Array(address_pool, input, "input"), + result = new AllocatedBuf(input.length / 2), + result_str, + input_address = _to_allocated_buf_address(input), + hex_end_p = _malloc(4), + hex_end; + address_pool.push(input_address); + address_pool.push(result.address); + address_pool.push(result.hex_end_p); + if ( + libsodium._sodium_hex2bin( + result.address, + result.length, + input_address, + input.length, + 0, + 0, + hex_end_p + ) !== 0 + ) { + _free_and_throw_error(address_pool, "invalid input"); + } + hex_end = libsodium.getValue(hex_end_p, "i32"); + if (hex_end - input_address !== input.length) { + _free_and_throw_error(address_pool, "incomplete input"); + } + result_str = result.to_Uint8Array(); + _free_all(address_pool); + return result_str; + } + + function to_hex(input) { + input = _any_to_Uint8Array(null, input, "input"); + var str = "", + b, + c, + x; + for (var i = 0; i < input.length; i++) { + c = input[i] & 0xf; + b = input[i] >>> 4; + x = + ((87 + c + (((c - 10) >> 8) & ~38)) << 8) | + (87 + b + (((b - 10) >> 8) & ~38)); + str += String.fromCharCode(x & 0xff) + String.fromCharCode(x >>> 8); + } + return str; + } + + var base64_variants = { + ORIGINAL: 1 | 0, + ORIGINAL_NO_PADDING: 3 | 0, + URLSAFE: 5 | 0, + URLSAFE_NO_PADDING: 7 | 0 + }; + + function check_base64_variant(variant) { + if (variant == undefined) { + return base64_variants.URLSAFE_NO_PADDING; + } + if ( + variant !== base64_variants.ORIGINAL && + variant !== base64_variants.ORIGINAL_NO_PADDING && + variant !== base64_variants.URLSAFE && + variant != base64_variants.URLSAFE_NO_PADDING + ) { + throw new Error("unsupported base64 variant"); + } + return variant; + } + + function from_base64(input, variant) { + variant = check_base64_variant(variant); + var address_pool = [], + input = _any_to_Uint8Array(address_pool, input, "input"), + result = new AllocatedBuf(input.length * 3 / 4), + result_bin, + input_address = _to_allocated_buf_address(input), + result_bin_len_p = _malloc(4), + b64_end_p = _malloc(4), + b64_end; + address_pool.push(input_address); + address_pool.push(result.address); + address_pool.push(result.result_bin_len_p); + address_pool.push(result.b64_end_p); + if ( + libsodium._sodium_base642bin( + result.address, + result.length, + input_address, + input.length, + 0, + result_bin_len_p, + b64_end_p, + variant + ) !== 0 + ) { + _free_and_throw_error(address_pool, "invalid input"); + } + b64_end = libsodium.getValue(b64_end_p, "i32"); + if (b64_end - input_address !== input.length) { + _free_and_throw_error(address_pool, "incomplete input"); + } + result.length = libsodium.getValue(result_bin_len_p, "i32"); + result_bin = result.to_Uint8Array(); + _free_all(address_pool); + return result_bin; + } + + function to_base64(input, variant) { + variant = check_base64_variant(variant); + input = _any_to_Uint8Array(address_pool, input, "input"); + var address_pool = [], + nibbles = Math.floor(input.length / 3) | 0, + remainder = input.length - 3 * nibbles, + b64_len = + nibbles * 4 + + (remainder !== 0 ? + (variant & 2) === 0 ? 4 : 2 + (remainder >>> 1) : + 0), + result = new AllocatedBuf(b64_len + 1), + result_b64, + input_address = _to_allocated_buf_address(input); + address_pool.push(input_address); + address_pool.push(result.address); + if ( + libsodium._sodium_bin2base64( + result.address, + result.length, + input_address, + input.length, + variant + ) === 0 + ) { + _free_and_throw_error(address_pool, "conversion failed"); + } + result.length = b64_len; + result_b64 = to_string(result.to_Uint8Array()); + _free_all(address_pool); + return result_b64; + } + + function output_formats() { + return ["uint8array", "text", "hex", "base64"]; + } + + function _format_output(output, optionalOutputFormat) { + var selectedOutputFormat = optionalOutputFormat || output_format; + if (!_is_output_format(selectedOutputFormat)) { + throw new Error( + selectedOutputFormat + " output format is not available" + ); + } + if (output instanceof AllocatedBuf) { + if (selectedOutputFormat === "uint8array") { + return output.to_Uint8Array(); + } else if (selectedOutputFormat === "text") { + return to_string(output.to_Uint8Array()); + } else if (selectedOutputFormat === "hex") { + return to_hex(output.to_Uint8Array()); + } else if (selectedOutputFormat === "base64") { + return to_base64( + output.to_Uint8Array(), + base64_variants.URLSAFE_NO_PADDING + ); + } else { + throw new Error( + 'What is output format "' + selectedOutputFormat + '"?' + ); + } + } else if (output instanceof AllocatedBuf32) { + return output.to_Uint8Array(); + } else if (typeof output === "object") { + // Composed output. Example: key pairs + var props = Object.keys(output); + var formattedOutput = {}; + for (var i = 0; i < props.length; i++) { + formattedOutput[props[i]] = _format_output( + output[props[i]], + selectedOutputFormat + ); + } + return formattedOutput; + } else if (typeof output === "string") { + return output; + } else { + throw new TypeError("Cannot format output"); + } + } + + function _is_output_format(format) { + var formats = output_formats(); + for (var i = 0; i < formats.length; i++) { + if (formats[i] === format) { + return true; + } + } + return false; + } + + function _check_output_format(format) { + if (!format) { + return; + } else if (typeof format !== "string") { + throw new TypeError("When defined, the output format must be a string"); + } else if (!_is_output_format(format)) { + throw new Error(format + " is not a supported output format"); + } + } + + //--------------------------------------------------------------------------- + // Memory management + // + // AllocatedBuf: address allocated using _malloc() + length + function AllocatedBuf(length) { + this.length = length; + this.address = _malloc(length); + } + + // Copy the content of a AllocatedBuf (_malloc()'d memory) into a Uint8Array + AllocatedBuf.prototype.to_Uint8Array = function () { + var result = new Uint8Array(this.length); + result.set( + libsodium.HEAPU8.subarray(this.address, this.address + this.length) + ); + return result; + }; + + function AllocatedBuf32(length) { + this.length = length; + this.address = _malloc(length); + } + + AllocatedBuf32.prototype.to_Uint8Array = function () { + + // someArray[counter].set( + // //libsodium.HEAPU8.subarray(this.address, this.address + this.length) + // libsodium.HEAPU8.subarray(this.address, this.address + 16) + // ); + // counter += 1 + // return someArray[counter]; + + // var result = new Uint8Array(this.length); + // result.set( + // libsodium.HEAPU8.subarray(this.address, this.address + this.length) + // ); + // return result; + return libsodium.HEAPU8.subarray(this.address, this.address + this.length) + + }; + + // _malloc() a region and initialize it with the content of a Uint8Array + function _to_allocated_buf_address(bytes) { + var address = _malloc(bytes.length); + libsodium.HEAPU8.set(bytes, address); + return address; + } + + function _to_allocated_buf32_address(bytes) { + var address = _malloc(bytes.length*4); + libsodium.HEAPU8.set(bytes, address); + return address; + } + + function _malloc(length) { + var result = libsodium._malloc(length); + if (result === 0) { + throw { + message: "_malloc() failed", + length: length + }; + } + return result; + } + + function _free(address) { + libsodium._free(address); + } + + function _free_all(addresses) { + if (addresses) { + for (var i = 0; i < addresses.length; i++) { + _free(addresses[i]); + } + } + } + + function _free_and_throw_error(address_pool, err) { + _free_all(address_pool); + throw new Error(err); + } + + function _free_and_throw_type_error(address_pool, err) { + _free_all(address_pool); + throw new TypeError(err); + } + + function _require_defined(address_pool, varValue, varName) { + if (varValue == undefined) { + _free_and_throw_type_error( + address_pool, + varName + " cannot be null or undefined" + ); + } + } + + function _any_to_Uint8Array(address_pool, varValue, varName) { + _require_defined(address_pool, varValue, varName); + if (varValue instanceof Uint8Array) { + return varValue; + } else if (varValue instanceof Int32Array) { + return varValue; + } else if (typeof varValue === "string") { + return from_string(varValue); + } + _free_and_throw_type_error( + address_pool, + "unsupported input type for " + varName + ); + } + + + function crypto_aead_chacha20poly1305_decrypt(secret_nonce, ciphertext, additional_data, public_nonce, key, outputFormat) { + var address_pool = []; + + _check_output_format(outputFormat); + // ---------- input: secret_nonce (unsized_buf_optional) + + var secret_nonce_address = null, secret_nonce_length = 0; + if (secret_nonce != undefined) { + secret_nonce = _any_to_Uint8Array(address_pool, secret_nonce, "secret_nonce"); + secret_nonce_address = _to_allocated_buf_address(secret_nonce); + secret_nonce_length = secret_nonce.length; + address_pool.push(secret_nonce_address); + } + + + // ---------- input: ciphertext (minsized_buf) + + ciphertext = _any_to_Uint8Array(address_pool, ciphertext, "ciphertext"); + var ciphertext_address, ciphertext_min_length = libsodium._crypto_aead_chacha20poly1305_abytes(), ciphertext_length = ciphertext.length; + if (ciphertext_length < ciphertext_min_length) { + _free_and_throw_type_error(address_pool, "ciphertext is too short"); + } + ciphertext_address = _to_allocated_buf_address(ciphertext); + address_pool.push(ciphertext_address); + + // ---------- input: additional_data (unsized_buf_optional) + + var additional_data_address = null, additional_data_length = 0; + if (additional_data != undefined) { + additional_data = _any_to_Uint8Array(address_pool, additional_data, "additional_data"); + additional_data_address = _to_allocated_buf_address(additional_data); + additional_data_length = additional_data.length; + address_pool.push(additional_data_address); + } + + + // ---------- input: public_nonce (buf) + + public_nonce = _any_to_Uint8Array(address_pool, public_nonce, "public_nonce"); + var public_nonce_address, public_nonce_length = (libsodium._crypto_aead_chacha20poly1305_npubbytes()) | 0; + if (public_nonce.length !== public_nonce_length) { + _free_and_throw_type_error(address_pool, "invalid public_nonce length"); + } + public_nonce_address = _to_allocated_buf_address(public_nonce); + address_pool.push(public_nonce_address); + + // ---------- input: key (buf) + + key = _any_to_Uint8Array(address_pool, key, "key"); + var key_address, key_length = (libsodium._crypto_aead_chacha20poly1305_keybytes()) | 0; + if (key.length !== key_length) { + _free_and_throw_type_error(address_pool, "invalid key length"); + } + key_address = _to_allocated_buf_address(key); + address_pool.push(key_address); + + // ---------- output message (buf) + + var message_length = (ciphertext_length - libsodium._crypto_aead_chacha20poly1305_abytes()) | 0, + message = new AllocatedBuf(message_length), + message_address = message.address; + + address_pool.push(message_address); + + if ((libsodium._crypto_aead_chacha20poly1305_decrypt(message_address, null, secret_nonce_address, ciphertext_address, ciphertext_length, 0, additional_data_address, additional_data_length, 0, public_nonce_address, key_address)) === 0) { + var ret = _format_output(message, outputFormat); + _free_all(address_pool); + return ret; + } + _free_and_throw_error(address_pool, "ciphertext cannot be decrypted using that key"); + } + + function crypto_aead_chacha20poly1305_decrypt_detached(secret_nonce, ciphertext, mac, additional_data, public_nonce, key, outputFormat) { + var address_pool = []; + + _check_output_format(outputFormat); + // ---------- input: secret_nonce (unsized_buf_optional) + + var secret_nonce_address = null, secret_nonce_length = 0; + if (secret_nonce != undefined) { + secret_nonce = _any_to_Uint8Array(address_pool, secret_nonce, "secret_nonce"); + secret_nonce_address = _to_allocated_buf_address(secret_nonce); + secret_nonce_length = secret_nonce.length; + address_pool.push(secret_nonce_address); + } + + + // ---------- input: ciphertext (unsized_buf) + + ciphertext = _any_to_Uint8Array(address_pool, ciphertext, "ciphertext"); + var ciphertext_address = _to_allocated_buf_address(ciphertext), + ciphertext_length = ciphertext.length; + address_pool.push(ciphertext_address); + + // ---------- input: mac (buf) + + mac = _any_to_Uint8Array(address_pool, mac, "mac"); + var mac_address, mac_length = (libsodium._crypto_box_macbytes()) | 0; + if (mac.length !== mac_length) { + _free_and_throw_type_error(address_pool, "invalid mac length"); + } + mac_address = _to_allocated_buf_address(mac); + address_pool.push(mac_address); + + // ---------- input: additional_data (unsized_buf_optional) + + var additional_data_address = null, additional_data_length = 0; + if (additional_data != undefined) { + additional_data = _any_to_Uint8Array(address_pool, additional_data, "additional_data"); + additional_data_address = _to_allocated_buf_address(additional_data); + additional_data_length = additional_data.length; + address_pool.push(additional_data_address); + } + + + // ---------- input: public_nonce (buf) + + public_nonce = _any_to_Uint8Array(address_pool, public_nonce, "public_nonce"); + var public_nonce_address, public_nonce_length = (libsodium._crypto_aead_chacha20poly1305_npubbytes()) | 0; + if (public_nonce.length !== public_nonce_length) { + _free_and_throw_type_error(address_pool, "invalid public_nonce length"); + } + public_nonce_address = _to_allocated_buf_address(public_nonce); + address_pool.push(public_nonce_address); + + // ---------- input: key (buf) + + key = _any_to_Uint8Array(address_pool, key, "key"); + var key_address, key_length = (libsodium._crypto_aead_chacha20poly1305_keybytes()) | 0; + if (key.length !== key_length) { + _free_and_throw_type_error(address_pool, "invalid key length"); + } + key_address = _to_allocated_buf_address(key); + address_pool.push(key_address); + + // ---------- output message (buf) + + var message_length = (ciphertext_length) | 0, + message = new AllocatedBuf(message_length), + message_address = message.address; + + address_pool.push(message_address); + + if ((libsodium._crypto_aead_chacha20poly1305_decrypt_detached(message_address, secret_nonce_address, ciphertext_address, ciphertext_length, 0, mac_address, additional_data_address, additional_data_length, 0, public_nonce_address, key_address)) === 0) { + var ret = _format_output(message, outputFormat); + _free_all(address_pool); + return ret; + } + _free_and_throw_error(address_pool, "ciphertext cannot be decrypted using that key"); + } + + function crypto_aead_chacha20poly1305_encrypt(message, additional_data, secret_nonce, public_nonce, key, outputFormat) { + var address_pool = []; + + _check_output_format(outputFormat); + // ---------- input: message (unsized_buf) + + message = _any_to_Uint8Array(address_pool, message, "message"); + var message_address = _to_allocated_buf_address(message), + message_length = message.length; + address_pool.push(message_address); + + // ---------- input: additional_data (unsized_buf_optional) + + var additional_data_address = null, additional_data_length = 0; + if (additional_data != undefined) { + additional_data = _any_to_Uint8Array(address_pool, additional_data, "additional_data"); + additional_data_address = _to_allocated_buf_address(additional_data); + additional_data_length = additional_data.length; + address_pool.push(additional_data_address); + } + + + // ---------- input: secret_nonce (unsized_buf_optional) + + var secret_nonce_address = null, secret_nonce_length = 0; + if (secret_nonce != undefined) { + secret_nonce = _any_to_Uint8Array(address_pool, secret_nonce, "secret_nonce"); + secret_nonce_address = _to_allocated_buf_address(secret_nonce); + secret_nonce_length = secret_nonce.length; + address_pool.push(secret_nonce_address); + } + + + // ---------- input: public_nonce (buf) + + public_nonce = _any_to_Uint8Array(address_pool, public_nonce, "public_nonce"); + var public_nonce_address, public_nonce_length = (libsodium._crypto_aead_chacha20poly1305_npubbytes()) | 0; + if (public_nonce.length !== public_nonce_length) { + _free_and_throw_type_error(address_pool, "invalid public_nonce length"); + } + public_nonce_address = _to_allocated_buf_address(public_nonce); + address_pool.push(public_nonce_address); + + // ---------- input: key (buf) + + key = _any_to_Uint8Array(address_pool, key, "key"); + var key_address, key_length = (libsodium._crypto_aead_chacha20poly1305_keybytes()) | 0; + if (key.length !== key_length) { + _free_and_throw_type_error(address_pool, "invalid key length"); + } + key_address = _to_allocated_buf_address(key); + address_pool.push(key_address); + + // ---------- output ciphertext (buf) + + var ciphertext_length = (message_length + libsodium._crypto_aead_chacha20poly1305_abytes()) | 0, + ciphertext = new AllocatedBuf(ciphertext_length), + ciphertext_address = ciphertext.address; + + address_pool.push(ciphertext_address); + + if ((libsodium._crypto_aead_chacha20poly1305_encrypt(ciphertext_address, null, message_address, message_length, 0, additional_data_address, additional_data_length, 0, secret_nonce_address, public_nonce_address, key_address)) === 0) { + var ret = _format_output(ciphertext, outputFormat); + _free_all(address_pool); + return ret; + } + _free_and_throw_error(address_pool, "invalid usage"); + } + + function crypto_aead_chacha20poly1305_encrypt_detached(message, additional_data, secret_nonce, public_nonce, key, outputFormat) { + var address_pool = []; + + _check_output_format(outputFormat); + // ---------- input: message (unsized_buf) + + message = _any_to_Uint8Array(address_pool, message, "message"); + var message_address = _to_allocated_buf_address(message), + message_length = message.length; + address_pool.push(message_address); + + // ---------- input: additional_data (unsized_buf_optional) + + var additional_data_address = null, additional_data_length = 0; + if (additional_data != undefined) { + additional_data = _any_to_Uint8Array(address_pool, additional_data, "additional_data"); + additional_data_address = _to_allocated_buf_address(additional_data); + additional_data_length = additional_data.length; + address_pool.push(additional_data_address); + } + + + // ---------- input: secret_nonce (unsized_buf_optional) + + var secret_nonce_address = null, secret_nonce_length = 0; + if (secret_nonce != undefined) { + secret_nonce = _any_to_Uint8Array(address_pool, secret_nonce, "secret_nonce"); + secret_nonce_address = _to_allocated_buf_address(secret_nonce); + secret_nonce_length = secret_nonce.length; + address_pool.push(secret_nonce_address); + } + + + // ---------- input: public_nonce (buf) + + public_nonce = _any_to_Uint8Array(address_pool, public_nonce, "public_nonce"); + var public_nonce_address, public_nonce_length = (libsodium._crypto_aead_chacha20poly1305_npubbytes()) | 0; + if (public_nonce.length !== public_nonce_length) { + _free_and_throw_type_error(address_pool, "invalid public_nonce length"); + } + public_nonce_address = _to_allocated_buf_address(public_nonce); + address_pool.push(public_nonce_address); + + // ---------- input: key (buf) + + key = _any_to_Uint8Array(address_pool, key, "key"); + var key_address, key_length = (libsodium._crypto_aead_chacha20poly1305_keybytes()) | 0; + if (key.length !== key_length) { + _free_and_throw_type_error(address_pool, "invalid key length"); + } + key_address = _to_allocated_buf_address(key); + address_pool.push(key_address); + + // ---------- output ciphertext (buf) + + var ciphertext_length = (message_length) | 0, + ciphertext = new AllocatedBuf(ciphertext_length), + ciphertext_address = ciphertext.address; + + address_pool.push(ciphertext_address); + + // ---------- output mac (buf) + + var mac_length = (libsodium._crypto_aead_chacha20poly1305_abytes()) | 0, + mac = new AllocatedBuf(mac_length), + mac_address = mac.address; + + address_pool.push(mac_address); + + if ((libsodium._crypto_aead_chacha20poly1305_encrypt_detached(ciphertext_address, mac_address, null, message_address, message_length, 0, additional_data_address, additional_data_length, 0, secret_nonce_address, public_nonce_address, key_address)) === 0) { + var ret = _format_output({ciphertext: ciphertext, mac: mac}, outputFormat); + _free_all(address_pool); + return ret; + } + _free_and_throw_error(address_pool, "invalid usage"); + } + + function crypto_aead_chacha20poly1305_ietf_decrypt(secret_nonce, ciphertext, additional_data, public_nonce, key, outputFormat) { + var address_pool = []; + + _check_output_format(outputFormat); + // ---------- input: secret_nonce (unsized_buf_optional) + + var secret_nonce_address = null, secret_nonce_length = 0; + if (secret_nonce != undefined) { + secret_nonce = _any_to_Uint8Array(address_pool, secret_nonce, "secret_nonce"); + secret_nonce_address = _to_allocated_buf_address(secret_nonce); + secret_nonce_length = secret_nonce.length; + address_pool.push(secret_nonce_address); + } + + + // ---------- input: ciphertext (minsized_buf) + + ciphertext = _any_to_Uint8Array(address_pool, ciphertext, "ciphertext"); + var ciphertext_address, ciphertext_min_length = libsodium._crypto_aead_chacha20poly1305_ietf_abytes(), ciphertext_length = ciphertext.length; + if (ciphertext_length < ciphertext_min_length) { + _free_and_throw_type_error(address_pool, "ciphertext is too short"); + } + ciphertext_address = _to_allocated_buf_address(ciphertext); + address_pool.push(ciphertext_address); + + // ---------- input: additional_data (unsized_buf_optional) + + var additional_data_address = null, additional_data_length = 0; + if (additional_data != undefined) { + additional_data = _any_to_Uint8Array(address_pool, additional_data, "additional_data"); + additional_data_address = _to_allocated_buf_address(additional_data); + additional_data_length = additional_data.length; + address_pool.push(additional_data_address); + } + + + // ---------- input: public_nonce (buf) + + public_nonce = _any_to_Uint8Array(address_pool, public_nonce, "public_nonce"); + var public_nonce_address, public_nonce_length = (libsodium._crypto_aead_chacha20poly1305_ietf_npubbytes()) | 0; + if (public_nonce.length !== public_nonce_length) { + _free_and_throw_type_error(address_pool, "invalid public_nonce length"); + } + public_nonce_address = _to_allocated_buf_address(public_nonce); + address_pool.push(public_nonce_address); + + // ---------- input: key (buf) + + key = _any_to_Uint8Array(address_pool, key, "key"); + var key_address, key_length = (libsodium._crypto_aead_chacha20poly1305_ietf_keybytes()) | 0; + if (key.length !== key_length) { + _free_and_throw_type_error(address_pool, "invalid key length"); + } + key_address = _to_allocated_buf_address(key); + address_pool.push(key_address); + + // ---------- output message (buf) + + var message_length = (ciphertext_length - libsodium._crypto_aead_chacha20poly1305_ietf_abytes()) | 0, + message = new AllocatedBuf(message_length), + message_address = message.address; + + address_pool.push(message_address); + + if ((libsodium._crypto_aead_chacha20poly1305_ietf_decrypt(message_address, null, secret_nonce_address, ciphertext_address, ciphertext_length, 0, additional_data_address, additional_data_length, 0, public_nonce_address, key_address)) === 0) { + var ret = _format_output(message, outputFormat); + _free_all(address_pool); + return ret; + } + _free_and_throw_error(address_pool, "ciphertext cannot be decrypted using that key"); + } + + function crypto_aead_chacha20poly1305_ietf_decrypt_detached(secret_nonce, ciphertext, mac, additional_data, public_nonce, key, outputFormat) { + var address_pool = []; + + _check_output_format(outputFormat); + // ---------- input: secret_nonce (unsized_buf_optional) + + var secret_nonce_address = null, secret_nonce_length = 0; + if (secret_nonce != undefined) { + secret_nonce = _any_to_Uint8Array(address_pool, secret_nonce, "secret_nonce"); + secret_nonce_address = _to_allocated_buf_address(secret_nonce); + secret_nonce_length = secret_nonce.length; + address_pool.push(secret_nonce_address); + } + + + // ---------- input: ciphertext (unsized_buf) + + ciphertext = _any_to_Uint8Array(address_pool, ciphertext, "ciphertext"); + var ciphertext_address = _to_allocated_buf_address(ciphertext), + ciphertext_length = ciphertext.length; + address_pool.push(ciphertext_address); + + // ---------- input: mac (buf) + + mac = _any_to_Uint8Array(address_pool, mac, "mac"); + var mac_address, mac_length = (libsodium._crypto_box_macbytes()) | 0; + if (mac.length !== mac_length) { + _free_and_throw_type_error(address_pool, "invalid mac length"); + } + mac_address = _to_allocated_buf_address(mac); + address_pool.push(mac_address); + + // ---------- input: additional_data (unsized_buf_optional) + + var additional_data_address = null, additional_data_length = 0; + if (additional_data != undefined) { + additional_data = _any_to_Uint8Array(address_pool, additional_data, "additional_data"); + additional_data_address = _to_allocated_buf_address(additional_data); + additional_data_length = additional_data.length; + address_pool.push(additional_data_address); + } + + + // ---------- input: public_nonce (buf) + + public_nonce = _any_to_Uint8Array(address_pool, public_nonce, "public_nonce"); + var public_nonce_address, public_nonce_length = (libsodium._crypto_aead_chacha20poly1305_ietf_npubbytes()) | 0; + if (public_nonce.length !== public_nonce_length) { + _free_and_throw_type_error(address_pool, "invalid public_nonce length"); + } + public_nonce_address = _to_allocated_buf_address(public_nonce); + address_pool.push(public_nonce_address); + + // ---------- input: key (buf) + + key = _any_to_Uint8Array(address_pool, key, "key"); + var key_address, key_length = (libsodium._crypto_aead_chacha20poly1305_ietf_keybytes()) | 0; + if (key.length !== key_length) { + _free_and_throw_type_error(address_pool, "invalid key length"); + } + key_address = _to_allocated_buf_address(key); + address_pool.push(key_address); + + // ---------- output message (buf) + + var message_length = (ciphertext_length) | 0, + message = new AllocatedBuf(message_length), + message_address = message.address; + + address_pool.push(message_address); + + if ((libsodium._crypto_aead_chacha20poly1305_ietf_decrypt_detached(message_address, secret_nonce_address, ciphertext_address, ciphertext_length, 0, mac_address, additional_data_address, additional_data_length, 0, public_nonce_address, key_address)) === 0) { + var ret = _format_output(message, outputFormat); + _free_all(address_pool); + return ret; + } + _free_and_throw_error(address_pool, "ciphertext cannot be decrypted using that key"); + } + + function crypto_aead_chacha20poly1305_ietf_encrypt(message, additional_data, secret_nonce, public_nonce, key, outputFormat) { + var address_pool = []; + + _check_output_format(outputFormat); + // ---------- input: message (unsized_buf) + + message = _any_to_Uint8Array(address_pool, message, "message"); + var message_address = _to_allocated_buf_address(message), + message_length = message.length; + address_pool.push(message_address); + + // ---------- input: additional_data (unsized_buf_optional) + + var additional_data_address = null, additional_data_length = 0; + if (additional_data != undefined) { + additional_data = _any_to_Uint8Array(address_pool, additional_data, "additional_data"); + additional_data_address = _to_allocated_buf_address(additional_data); + additional_data_length = additional_data.length; + address_pool.push(additional_data_address); + } + + + // ---------- input: secret_nonce (unsized_buf_optional) + + var secret_nonce_address = null, secret_nonce_length = 0; + if (secret_nonce != undefined) { + secret_nonce = _any_to_Uint8Array(address_pool, secret_nonce, "secret_nonce"); + secret_nonce_address = _to_allocated_buf_address(secret_nonce); + secret_nonce_length = secret_nonce.length; + address_pool.push(secret_nonce_address); + } + + + // ---------- input: public_nonce (buf) + + public_nonce = _any_to_Uint8Array(address_pool, public_nonce, "public_nonce"); + var public_nonce_address, public_nonce_length = (libsodium._crypto_aead_chacha20poly1305_ietf_npubbytes()) | 0; + if (public_nonce.length !== public_nonce_length) { + _free_and_throw_type_error(address_pool, "invalid public_nonce length"); + } + public_nonce_address = _to_allocated_buf_address(public_nonce); + address_pool.push(public_nonce_address); + + // ---------- input: key (buf) + + key = _any_to_Uint8Array(address_pool, key, "key"); + var key_address, key_length = (libsodium._crypto_aead_chacha20poly1305_ietf_keybytes()) | 0; + if (key.length !== key_length) { + _free_and_throw_type_error(address_pool, "invalid key length"); + } + key_address = _to_allocated_buf_address(key); + address_pool.push(key_address); + + // ---------- output ciphertext (buf) + + var ciphertext_length = (message_length + libsodium._crypto_aead_chacha20poly1305_ietf_abytes()) | 0, + ciphertext = new AllocatedBuf(ciphertext_length), + ciphertext_address = ciphertext.address; + + address_pool.push(ciphertext_address); + + if ((libsodium._crypto_aead_chacha20poly1305_ietf_encrypt(ciphertext_address, null, message_address, message_length, 0, additional_data_address, additional_data_length, 0, secret_nonce_address, public_nonce_address, key_address)) === 0) { + var ret = _format_output(ciphertext, outputFormat); + _free_all(address_pool); + return ret; + } + _free_and_throw_error(address_pool, "invalid usage"); + } + + function crypto_aead_chacha20poly1305_ietf_encrypt_detached(message, additional_data, secret_nonce, public_nonce, key, outputFormat) { + var address_pool = []; + + _check_output_format(outputFormat); + // ---------- input: message (unsized_buf) + + message = _any_to_Uint8Array(address_pool, message, "message"); + var message_address = _to_allocated_buf_address(message), + message_length = message.length; + address_pool.push(message_address); + + // ---------- input: additional_data (unsized_buf_optional) + + var additional_data_address = null, additional_data_length = 0; + if (additional_data != undefined) { + additional_data = _any_to_Uint8Array(address_pool, additional_data, "additional_data"); + additional_data_address = _to_allocated_buf_address(additional_data); + additional_data_length = additional_data.length; + address_pool.push(additional_data_address); + } + + + // ---------- input: secret_nonce (unsized_buf_optional) + + var secret_nonce_address = null, secret_nonce_length = 0; + if (secret_nonce != undefined) { + secret_nonce = _any_to_Uint8Array(address_pool, secret_nonce, "secret_nonce"); + secret_nonce_address = _to_allocated_buf_address(secret_nonce); + secret_nonce_length = secret_nonce.length; + address_pool.push(secret_nonce_address); + } + + + // ---------- input: public_nonce (buf) + + public_nonce = _any_to_Uint8Array(address_pool, public_nonce, "public_nonce"); + var public_nonce_address, public_nonce_length = (libsodium._crypto_aead_chacha20poly1305_ietf_npubbytes()) | 0; + if (public_nonce.length !== public_nonce_length) { + _free_and_throw_type_error(address_pool, "invalid public_nonce length"); + } + public_nonce_address = _to_allocated_buf_address(public_nonce); + address_pool.push(public_nonce_address); + + // ---------- input: key (buf) + + key = _any_to_Uint8Array(address_pool, key, "key"); + var key_address, key_length = (libsodium._crypto_aead_chacha20poly1305_ietf_keybytes()) | 0; + if (key.length !== key_length) { + _free_and_throw_type_error(address_pool, "invalid key length"); + } + key_address = _to_allocated_buf_address(key); + address_pool.push(key_address); + + // ---------- output ciphertext (buf) + + var ciphertext_length = (message_length) | 0, + ciphertext = new AllocatedBuf(ciphertext_length), + ciphertext_address = ciphertext.address; + + address_pool.push(ciphertext_address); + + // ---------- output mac (buf) + + var mac_length = (libsodium._crypto_aead_chacha20poly1305_ietf_abytes()) | 0, + mac = new AllocatedBuf(mac_length), + mac_address = mac.address; + + address_pool.push(mac_address); + + if ((libsodium._crypto_aead_chacha20poly1305_ietf_encrypt_detached(ciphertext_address, mac_address, null, message_address, message_length, 0, additional_data_address, additional_data_length, 0, secret_nonce_address, public_nonce_address, key_address)) === 0) { + var ret = _format_output({ciphertext: ciphertext, mac: mac}, outputFormat); + _free_all(address_pool); + return ret; + } + _free_and_throw_error(address_pool, "invalid usage"); + } + + function crypto_aead_chacha20poly1305_ietf_keygen(outputFormat) { + var address_pool = []; + + _check_output_format(outputFormat); + // ---------- output output (buf) + + var output_length = (libsodium._crypto_aead_chacha20poly1305_ietf_keybytes()) | 0, + output = new AllocatedBuf(output_length), + output_address = output.address; + + address_pool.push(output_address); + + libsodium._crypto_aead_chacha20poly1305_ietf_keygen(output_address); + var ret = (_format_output(output, outputFormat)); + _free_all(address_pool); + return ret; + } + + function crypto_aead_chacha20poly1305_keygen(outputFormat) { + var address_pool = []; + + _check_output_format(outputFormat); + // ---------- output output (buf) + + var output_length = (libsodium._crypto_aead_chacha20poly1305_keybytes()) | 0, + output = new AllocatedBuf(output_length), + output_address = output.address; + + address_pool.push(output_address); + + libsodium._crypto_aead_chacha20poly1305_keygen(output_address); + var ret = (_format_output(output, outputFormat)); + _free_all(address_pool); + return ret; + } + + function crypto_aead_xchacha20poly1305_ietf_decrypt(secret_nonce, ciphertext, additional_data, public_nonce, key, outputFormat) { + var address_pool = []; + + _check_output_format(outputFormat); + // ---------- input: secret_nonce (unsized_buf_optional) + + var secret_nonce_address = null, secret_nonce_length = 0; + if (secret_nonce != undefined) { + secret_nonce = _any_to_Uint8Array(address_pool, secret_nonce, "secret_nonce"); + secret_nonce_address = _to_allocated_buf_address(secret_nonce); + secret_nonce_length = secret_nonce.length; + address_pool.push(secret_nonce_address); + } + + + // ---------- input: ciphertext (minsized_buf) + + ciphertext = _any_to_Uint8Array(address_pool, ciphertext, "ciphertext"); + var ciphertext_address, ciphertext_min_length = libsodium._crypto_aead_xchacha20poly1305_ietf_abytes(), ciphertext_length = ciphertext.length; + if (ciphertext_length < ciphertext_min_length) { + _free_and_throw_type_error(address_pool, "ciphertext is too short"); + } + ciphertext_address = _to_allocated_buf_address(ciphertext); + address_pool.push(ciphertext_address); + + // ---------- input: additional_data (unsized_buf_optional) + + var additional_data_address = null, additional_data_length = 0; + if (additional_data != undefined) { + additional_data = _any_to_Uint8Array(address_pool, additional_data, "additional_data"); + additional_data_address = _to_allocated_buf_address(additional_data); + additional_data_length = additional_data.length; + address_pool.push(additional_data_address); + } + + + // ---------- input: public_nonce (buf) + + public_nonce = _any_to_Uint8Array(address_pool, public_nonce, "public_nonce"); + var public_nonce_address, public_nonce_length = (libsodium._crypto_aead_xchacha20poly1305_ietf_npubbytes()) | 0; + if (public_nonce.length !== public_nonce_length) { + _free_and_throw_type_error(address_pool, "invalid public_nonce length"); + } + public_nonce_address = _to_allocated_buf_address(public_nonce); + address_pool.push(public_nonce_address); + + // ---------- input: key (buf) + + key = _any_to_Uint8Array(address_pool, key, "key"); + var key_address, key_length = (libsodium._crypto_aead_xchacha20poly1305_ietf_keybytes()) | 0; + if (key.length !== key_length) { + _free_and_throw_type_error(address_pool, "invalid key length"); + } + key_address = _to_allocated_buf_address(key); + address_pool.push(key_address); + + // ---------- output message (buf) + + var message_length = (ciphertext_length - libsodium._crypto_aead_xchacha20poly1305_ietf_abytes()) | 0, + message = new AllocatedBuf(message_length), + message_address = message.address; + + address_pool.push(message_address); + + if ((libsodium._crypto_aead_xchacha20poly1305_ietf_decrypt(message_address, null, secret_nonce_address, ciphertext_address, ciphertext_length, 0, additional_data_address, additional_data_length, 0, public_nonce_address, key_address)) === 0) { + var ret = _format_output(message, outputFormat); + _free_all(address_pool); + return ret; + } + _free_and_throw_error(address_pool, "ciphertext cannot be decrypted using that key"); + } + + function crypto_aead_xchacha20poly1305_ietf_decrypt_detached(secret_nonce, ciphertext, mac, additional_data, public_nonce, key, outputFormat) { + var address_pool = []; + + _check_output_format(outputFormat); + // ---------- input: secret_nonce (unsized_buf_optional) + + var secret_nonce_address = null, secret_nonce_length = 0; + if (secret_nonce != undefined) { + secret_nonce = _any_to_Uint8Array(address_pool, secret_nonce, "secret_nonce"); + secret_nonce_address = _to_allocated_buf_address(secret_nonce); + secret_nonce_length = secret_nonce.length; + address_pool.push(secret_nonce_address); + } + + + // ---------- input: ciphertext (unsized_buf) + + ciphertext = _any_to_Uint8Array(address_pool, ciphertext, "ciphertext"); + var ciphertext_address = _to_allocated_buf_address(ciphertext), + ciphertext_length = ciphertext.length; + address_pool.push(ciphertext_address); + + // ---------- input: mac (buf) + + mac = _any_to_Uint8Array(address_pool, mac, "mac"); + var mac_address, mac_length = (libsodium._crypto_box_macbytes()) | 0; + if (mac.length !== mac_length) { + _free_and_throw_type_error(address_pool, "invalid mac length"); + } + mac_address = _to_allocated_buf_address(mac); + address_pool.push(mac_address); + + // ---------- input: additional_data (unsized_buf_optional) + + var additional_data_address = null, additional_data_length = 0; + if (additional_data != undefined) { + additional_data = _any_to_Uint8Array(address_pool, additional_data, "additional_data"); + additional_data_address = _to_allocated_buf_address(additional_data); + additional_data_length = additional_data.length; + address_pool.push(additional_data_address); + } + + + // ---------- input: public_nonce (buf) + + public_nonce = _any_to_Uint8Array(address_pool, public_nonce, "public_nonce"); + var public_nonce_address, public_nonce_length = (libsodium._crypto_aead_xchacha20poly1305_ietf_npubbytes()) | 0; + if (public_nonce.length !== public_nonce_length) { + _free_and_throw_type_error(address_pool, "invalid public_nonce length"); + } + public_nonce_address = _to_allocated_buf_address(public_nonce); + address_pool.push(public_nonce_address); + + // ---------- input: key (buf) + + key = _any_to_Uint8Array(address_pool, key, "key"); + var key_address, key_length = (libsodium._crypto_aead_xchacha20poly1305_ietf_keybytes()) | 0; + if (key.length !== key_length) { + _free_and_throw_type_error(address_pool, "invalid key length"); + } + key_address = _to_allocated_buf_address(key); + address_pool.push(key_address); + + // ---------- output message (buf) + + var message_length = (ciphertext_length) | 0, + message = new AllocatedBuf(message_length), + message_address = message.address; + + address_pool.push(message_address); + + if ((libsodium._crypto_aead_xchacha20poly1305_ietf_decrypt_detached(message_address, secret_nonce_address, ciphertext_address, ciphertext_length, 0, mac_address, additional_data_address, additional_data_length, 0, public_nonce_address, key_address)) === 0) { + var ret = _format_output(message, outputFormat); + _free_all(address_pool); + return ret; + } + _free_and_throw_error(address_pool, "ciphertext cannot be decrypted using that key"); + } + + function crypto_aead_xchacha20poly1305_ietf_encrypt(message, additional_data, secret_nonce, public_nonce, key, outputFormat) { + var address_pool = []; + + _check_output_format(outputFormat); + // ---------- input: message (unsized_buf) + + message = _any_to_Uint8Array(address_pool, message, "message"); + var message_address = _to_allocated_buf_address(message), + message_length = message.length; + address_pool.push(message_address); + + // ---------- input: additional_data (unsized_buf_optional) + + var additional_data_address = null, additional_data_length = 0; + if (additional_data != undefined) { + additional_data = _any_to_Uint8Array(address_pool, additional_data, "additional_data"); + additional_data_address = _to_allocated_buf_address(additional_data); + additional_data_length = additional_data.length; + address_pool.push(additional_data_address); + } + + + // ---------- input: secret_nonce (unsized_buf_optional) + + var secret_nonce_address = null, secret_nonce_length = 0; + if (secret_nonce != undefined) { + secret_nonce = _any_to_Uint8Array(address_pool, secret_nonce, "secret_nonce"); + secret_nonce_address = _to_allocated_buf_address(secret_nonce); + secret_nonce_length = secret_nonce.length; + address_pool.push(secret_nonce_address); + } + + + // ---------- input: public_nonce (buf) + + public_nonce = _any_to_Uint8Array(address_pool, public_nonce, "public_nonce"); + var public_nonce_address, public_nonce_length = (libsodium._crypto_aead_xchacha20poly1305_ietf_npubbytes()) | 0; + if (public_nonce.length !== public_nonce_length) { + _free_and_throw_type_error(address_pool, "invalid public_nonce length"); + } + public_nonce_address = _to_allocated_buf_address(public_nonce); + address_pool.push(public_nonce_address); + + // ---------- input: key (buf) + + key = _any_to_Uint8Array(address_pool, key, "key"); + var key_address, key_length = (libsodium._crypto_aead_xchacha20poly1305_ietf_keybytes()) | 0; + if (key.length !== key_length) { + _free_and_throw_type_error(address_pool, "invalid key length"); + } + key_address = _to_allocated_buf_address(key); + address_pool.push(key_address); + + // ---------- output ciphertext (buf) + + var ciphertext_length = (message_length + libsodium._crypto_aead_xchacha20poly1305_ietf_abytes()) | 0, + ciphertext = new AllocatedBuf(ciphertext_length), + ciphertext_address = ciphertext.address; + + address_pool.push(ciphertext_address); + + if ((libsodium._crypto_aead_xchacha20poly1305_ietf_encrypt(ciphertext_address, null, message_address, message_length, 0, additional_data_address, additional_data_length, 0, secret_nonce_address, public_nonce_address, key_address)) === 0) { + var ret = _format_output(ciphertext, outputFormat); + _free_all(address_pool); + return ret; + } + _free_and_throw_error(address_pool, "invalid usage"); + } + + function crypto_aead_xchacha20poly1305_ietf_encrypt_detached(message, additional_data, secret_nonce, public_nonce, key, outputFormat) { + var address_pool = []; + + _check_output_format(outputFormat); + // ---------- input: message (unsized_buf) + + message = _any_to_Uint8Array(address_pool, message, "message"); + var message_address = _to_allocated_buf_address(message), + message_length = message.length; + address_pool.push(message_address); + + // ---------- input: additional_data (unsized_buf_optional) + + var additional_data_address = null, additional_data_length = 0; + if (additional_data != undefined) { + additional_data = _any_to_Uint8Array(address_pool, additional_data, "additional_data"); + additional_data_address = _to_allocated_buf_address(additional_data); + additional_data_length = additional_data.length; + address_pool.push(additional_data_address); + } + + + // ---------- input: secret_nonce (unsized_buf_optional) + + var secret_nonce_address = null, secret_nonce_length = 0; + if (secret_nonce != undefined) { + secret_nonce = _any_to_Uint8Array(address_pool, secret_nonce, "secret_nonce"); + secret_nonce_address = _to_allocated_buf_address(secret_nonce); + secret_nonce_length = secret_nonce.length; + address_pool.push(secret_nonce_address); + } + + + // ---------- input: public_nonce (buf) + + public_nonce = _any_to_Uint8Array(address_pool, public_nonce, "public_nonce"); + var public_nonce_address, public_nonce_length = (libsodium._crypto_aead_xchacha20poly1305_ietf_npubbytes()) | 0; + if (public_nonce.length !== public_nonce_length) { + _free_and_throw_type_error(address_pool, "invalid public_nonce length"); + } + public_nonce_address = _to_allocated_buf_address(public_nonce); + address_pool.push(public_nonce_address); + + // ---------- input: key (buf) + + key = _any_to_Uint8Array(address_pool, key, "key"); + var key_address, key_length = (libsodium._crypto_aead_xchacha20poly1305_ietf_keybytes()) | 0; + if (key.length !== key_length) { + _free_and_throw_type_error(address_pool, "invalid key length"); + } + key_address = _to_allocated_buf_address(key); + address_pool.push(key_address); + + // ---------- output ciphertext (buf) + + var ciphertext_length = (message_length) | 0, + ciphertext = new AllocatedBuf(ciphertext_length), + ciphertext_address = ciphertext.address; + + address_pool.push(ciphertext_address); + + // ---------- output mac (buf) + + var mac_length = (libsodium._crypto_aead_xchacha20poly1305_ietf_abytes()) | 0, + mac = new AllocatedBuf(mac_length), + mac_address = mac.address; + + address_pool.push(mac_address); + + if ((libsodium._crypto_aead_xchacha20poly1305_ietf_encrypt_detached(ciphertext_address, mac_address, null, message_address, message_length, 0, additional_data_address, additional_data_length, 0, secret_nonce_address, public_nonce_address, key_address)) === 0) { + var ret = _format_output({ciphertext: ciphertext, mac: mac}, outputFormat); + _free_all(address_pool); + return ret; + } + _free_and_throw_error(address_pool, "invalid usage"); + } + + function crypto_aead_xchacha20poly1305_ietf_keygen(outputFormat) { + var address_pool = []; + + _check_output_format(outputFormat); + // ---------- output output (buf) + + var output_length = (libsodium._crypto_aead_xchacha20poly1305_ietf_keybytes()) | 0, + output = new AllocatedBuf(output_length), + output_address = output.address; + + address_pool.push(output_address); + + libsodium._crypto_aead_xchacha20poly1305_ietf_keygen(output_address); + var ret = (_format_output(output, outputFormat)); + _free_all(address_pool); + return ret; + } + + function crypto_auth(message, key, outputFormat) { + var address_pool = []; + + _check_output_format(outputFormat); + // ---------- input: message (unsized_buf) + + message = _any_to_Uint8Array(address_pool, message, "message"); + var message_address = _to_allocated_buf_address(message), + message_length = message.length; + address_pool.push(message_address); + + // ---------- input: key (buf) + + key = _any_to_Uint8Array(address_pool, key, "key"); + var key_address, key_length = (libsodium._crypto_auth_keybytes()) | 0; + if (key.length !== key_length) { + _free_and_throw_type_error(address_pool, "invalid key length"); + } + key_address = _to_allocated_buf_address(key); + address_pool.push(key_address); + + // ---------- output tag (buf) + + var tag_length = (libsodium._crypto_auth_bytes()) | 0, + tag = new AllocatedBuf(tag_length), + tag_address = tag.address; + + address_pool.push(tag_address); + + if ((libsodium._crypto_auth(tag_address, message_address, message_length, 0, key_address) | 0) === 0) { + var ret = _format_output(tag, outputFormat); + _free_all(address_pool); + return ret; + } + _free_and_throw_error(address_pool, "invalid usage"); + } + + function crypto_auth_hmacsha256(message, key, outputFormat) { + var address_pool = []; + + _check_output_format(outputFormat); + // ---------- input: message (unsized_buf) + + message = _any_to_Uint8Array(address_pool, message, "message"); + var message_address = _to_allocated_buf_address(message), + message_length = message.length; + address_pool.push(message_address); + + // ---------- input: key (buf) + + key = _any_to_Uint8Array(address_pool, key, "key"); + var key_address, key_length = (libsodium._crypto_auth_hmacsha256_keybytes()) | 0; + if (key.length !== key_length) { + _free_and_throw_type_error(address_pool, "invalid key length"); + } + key_address = _to_allocated_buf_address(key); + address_pool.push(key_address); + + // ---------- output hash (buf) + + var hash_length = (libsodium._crypto_auth_hmacsha256_bytes()) | 0, + hash = new AllocatedBuf(hash_length), + hash_address = hash.address; + + address_pool.push(hash_address); + + if ((libsodium._crypto_auth_hmacsha256(hash_address, message_address, message_length, 0, key_address) | 0) === 0) { + var ret = _format_output(hash, outputFormat); + _free_all(address_pool); + return ret; + } + _free_and_throw_error(address_pool, "invalid usage"); + } + + function crypto_auth_hmacsha256_keygen(outputFormat) { + var address_pool = []; + + _check_output_format(outputFormat); + // ---------- output output (buf) + + var output_length = (libsodium._crypto_auth_hmacsha256_keybytes()) | 0, + output = new AllocatedBuf(output_length), + output_address = output.address; + + address_pool.push(output_address); + + libsodium._crypto_auth_hmacsha256_keygen(output_address); + var ret = (_format_output(output, outputFormat)); + _free_all(address_pool); + return ret; + } + + function crypto_auth_hmacsha256_verify(tag, message, key) { + var address_pool = []; + + // ---------- input: tag (buf) + + tag = _any_to_Uint8Array(address_pool, tag, "tag"); + var tag_address, tag_length = (libsodium._crypto_auth_hmacsha256_bytes()) | 0; + if (tag.length !== tag_length) { + _free_and_throw_type_error(address_pool, "invalid tag length"); + } + tag_address = _to_allocated_buf_address(tag); + address_pool.push(tag_address); + + // ---------- input: message (unsized_buf) + + message = _any_to_Uint8Array(address_pool, message, "message"); + var message_address = _to_allocated_buf_address(message), + message_length = message.length; + address_pool.push(message_address); + + // ---------- input: key (buf) + + key = _any_to_Uint8Array(address_pool, key, "key"); + var key_address, key_length = (libsodium._crypto_auth_hmacsha256_keybytes()) | 0; + if (key.length !== key_length) { + _free_and_throw_type_error(address_pool, "invalid key length"); + } + key_address = _to_allocated_buf_address(key); + address_pool.push(key_address); + + var result = libsodium._crypto_auth_hmacsha256_verify(tag_address, message_address, message_length, 0, key_address) | 0; + var ret = (result === 0); + _free_all(address_pool); + return ret; + } + + function crypto_auth_hmacsha512(message, key, outputFormat) { + var address_pool = []; + + _check_output_format(outputFormat); + // ---------- input: message (unsized_buf) + + message = _any_to_Uint8Array(address_pool, message, "message"); + var message_address = _to_allocated_buf_address(message), + message_length = message.length; + address_pool.push(message_address); + + // ---------- input: key (buf) + + key = _any_to_Uint8Array(address_pool, key, "key"); + var key_address, key_length = (libsodium._crypto_auth_hmacsha512_keybytes()) | 0; + if (key.length !== key_length) { + _free_and_throw_type_error(address_pool, "invalid key length"); + } + key_address = _to_allocated_buf_address(key); + address_pool.push(key_address); + + // ---------- output hash (buf) + + var hash_length = (libsodium._crypto_auth_hmacsha512_bytes()) | 0, + hash = new AllocatedBuf(hash_length), + hash_address = hash.address; + + address_pool.push(hash_address); + + if ((libsodium._crypto_auth_hmacsha512(hash_address, message_address, message_length, 0, key_address) | 0) === 0) { + var ret = _format_output(hash, outputFormat); + _free_all(address_pool); + return ret; + } + _free_and_throw_error(address_pool, "invalid usage"); + } + + function crypto_auth_hmacsha512_keygen(outputFormat) { + var address_pool = []; + + _check_output_format(outputFormat); + // ---------- output output (buf) + + var output_length = (libsodium._crypto_auth_hmacsha512_keybytes()) | 0, + output = new AllocatedBuf(output_length), + output_address = output.address; + + address_pool.push(output_address); + + libsodium._crypto_auth_hmacsha512_keygen(output_address); + var ret = (_format_output(output, outputFormat)); + _free_all(address_pool); + return ret; + } + + function crypto_auth_hmacsha512_verify(tag, message, key) { + var address_pool = []; + + // ---------- input: tag (buf) + + tag = _any_to_Uint8Array(address_pool, tag, "tag"); + var tag_address, tag_length = (libsodium._crypto_auth_hmacsha512_bytes()) | 0; + if (tag.length !== tag_length) { + _free_and_throw_type_error(address_pool, "invalid tag length"); + } + tag_address = _to_allocated_buf_address(tag); + address_pool.push(tag_address); + + // ---------- input: message (unsized_buf) + + message = _any_to_Uint8Array(address_pool, message, "message"); + var message_address = _to_allocated_buf_address(message), + message_length = message.length; + address_pool.push(message_address); + + // ---------- input: key (buf) + + key = _any_to_Uint8Array(address_pool, key, "key"); + var key_address, key_length = (libsodium._crypto_auth_hmacsha512_keybytes()) | 0; + if (key.length !== key_length) { + _free_and_throw_type_error(address_pool, "invalid key length"); + } + key_address = _to_allocated_buf_address(key); + address_pool.push(key_address); + + var result = libsodium._crypto_auth_hmacsha512_verify(tag_address, message_address, message_length, 0, key_address) | 0; + var ret = (result === 0); + _free_all(address_pool); + return ret; + } + + function crypto_auth_keygen(outputFormat) { + var address_pool = []; + + _check_output_format(outputFormat); + // ---------- output output (buf) + + var output_length = (libsodium._crypto_auth_keybytes()) | 0, + output = new AllocatedBuf(output_length), + output_address = output.address; + + address_pool.push(output_address); + + libsodium._crypto_auth_keygen(output_address); + var ret = (_format_output(output, outputFormat)); + _free_all(address_pool); + return ret; + } + + function crypto_auth_verify(tag, message, key) { + var address_pool = []; + + // ---------- input: tag (buf) + + tag = _any_to_Uint8Array(address_pool, tag, "tag"); + var tag_address, tag_length = (libsodium._crypto_auth_bytes()) | 0; + if (tag.length !== tag_length) { + _free_and_throw_type_error(address_pool, "invalid tag length"); + } + tag_address = _to_allocated_buf_address(tag); + address_pool.push(tag_address); + + // ---------- input: message (unsized_buf) + + message = _any_to_Uint8Array(address_pool, message, "message"); + var message_address = _to_allocated_buf_address(message), + message_length = message.length; + address_pool.push(message_address); + + // ---------- input: key (buf) + + key = _any_to_Uint8Array(address_pool, key, "key"); + var key_address, key_length = (libsodium._crypto_auth_keybytes()) | 0; + if (key.length !== key_length) { + _free_and_throw_type_error(address_pool, "invalid key length"); + } + key_address = _to_allocated_buf_address(key); + address_pool.push(key_address); + + var result = libsodium._crypto_auth_verify(tag_address, message_address, message_length, 0, key_address) | 0; + var ret = (result === 0); + _free_all(address_pool); + return ret; + } + + function crypto_box_beforenm(publicKey, privateKey, outputFormat) { + var address_pool = []; + + _check_output_format(outputFormat); + // ---------- input: publicKey (buf) + + publicKey = _any_to_Uint8Array(address_pool, publicKey, "publicKey"); + var publicKey_address, publicKey_length = (libsodium._crypto_box_publickeybytes()) | 0; + if (publicKey.length !== publicKey_length) { + _free_and_throw_type_error(address_pool, "invalid publicKey length"); + } + publicKey_address = _to_allocated_buf_address(publicKey); + address_pool.push(publicKey_address); + + // ---------- input: privateKey (buf) + + privateKey = _any_to_Uint8Array(address_pool, privateKey, "privateKey"); + var privateKey_address, privateKey_length = (libsodium._crypto_box_secretkeybytes()) | 0; + if (privateKey.length !== privateKey_length) { + _free_and_throw_type_error(address_pool, "invalid privateKey length"); + } + privateKey_address = _to_allocated_buf_address(privateKey); + address_pool.push(privateKey_address); + + // ---------- output sharedKey (buf) + + var sharedKey_length = (libsodium._crypto_box_beforenmbytes()) | 0, + sharedKey = new AllocatedBuf(sharedKey_length), + sharedKey_address = sharedKey.address; + + address_pool.push(sharedKey_address); + + if ((libsodium._crypto_box_beforenm(sharedKey_address, publicKey_address, privateKey_address) | 0) === 0) { + var ret = _format_output(sharedKey, outputFormat); + _free_all(address_pool); + return ret; + } + _free_and_throw_error(address_pool, "invalid usage"); + } + + function crypto_box_curve25519xchacha20poly1305_keypair(outputFormat) { + var address_pool = []; + + _check_output_format(outputFormat); + // ---------- output publicKey (buf) + + var publicKey_length = (libsodium._crypto_box_curve25519xchacha20poly1305_publickeybytes()) | 0, + publicKey = new AllocatedBuf(publicKey_length), + publicKey_address = publicKey.address; + + address_pool.push(publicKey_address); + + // ---------- output secretKey (buf) + + var secretKey_length = (libsodium._crypto_box_curve25519xchacha20poly1305_secretkeybytes()) | 0, + secretKey = new AllocatedBuf(secretKey_length), + secretKey_address = secretKey.address; + + address_pool.push(secretKey_address); + + libsodium._crypto_box_curve25519xchacha20poly1305_keypair(publicKey_address, secretKey_address) | 0; + var ret = (_format_output({publicKey: publicKey, privateKey: secretKey, keyType: "curve25519"}, outputFormat)); + _free_all(address_pool); + return ret; + } + + function crypto_box_curve25519xchacha20poly1305_seal(message, publicKey, outputFormat) { + var address_pool = []; + + _check_output_format(outputFormat); + // ---------- input: message (unsized_buf) + + message = _any_to_Uint8Array(address_pool, message, "message"); + var message_address = _to_allocated_buf_address(message), + message_length = message.length; + address_pool.push(message_address); + + // ---------- input: publicKey (buf) + + publicKey = _any_to_Uint8Array(address_pool, publicKey, "publicKey"); + var publicKey_address, publicKey_length = (libsodium._crypto_box_curve25519xchacha20poly1305_publickeybytes()) | 0; + if (publicKey.length !== publicKey_length) { + _free_and_throw_type_error(address_pool, "invalid publicKey length"); + } + publicKey_address = _to_allocated_buf_address(publicKey); + address_pool.push(publicKey_address); + + // ---------- output ciphertext (buf) + + var ciphertext_length = (message_length + libsodium._crypto_box_curve25519xchacha20poly1305_sealbytes()) | 0, + ciphertext = new AllocatedBuf(ciphertext_length), + ciphertext_address = ciphertext.address; + + address_pool.push(ciphertext_address); + + libsodium._crypto_box_curve25519xchacha20poly1305_seal(ciphertext_address, message_address, message_length, 0, publicKey_address) | 0; + var ret = (_format_output(ciphertext, outputFormat)); + _free_all(address_pool); + return ret; + } + + function crypto_box_curve25519xchacha20poly1305_seal_open(ciphertext, publicKey, secretKey, outputFormat) { + var address_pool = []; + + _check_output_format(outputFormat); + // ---------- input: ciphertext (minsized_buf) + + ciphertext = _any_to_Uint8Array(address_pool, ciphertext, "ciphertext"); + var ciphertext_address, ciphertext_min_length = libsodium._crypto_box_curve25519xchacha20poly1305_sealbytes(), ciphertext_length = ciphertext.length; + if (ciphertext_length < ciphertext_min_length) { + _free_and_throw_type_error(address_pool, "ciphertext is too short"); + } + ciphertext_address = _to_allocated_buf_address(ciphertext); + address_pool.push(ciphertext_address); + + // ---------- input: publicKey (buf) + + publicKey = _any_to_Uint8Array(address_pool, publicKey, "publicKey"); + var publicKey_address, publicKey_length = (libsodium._crypto_box_curve25519xchacha20poly1305_publickeybytes()) | 0; + if (publicKey.length !== publicKey_length) { + _free_and_throw_type_error(address_pool, "invalid publicKey length"); + } + publicKey_address = _to_allocated_buf_address(publicKey); + address_pool.push(publicKey_address); + + // ---------- input: secretKey (buf) + + secretKey = _any_to_Uint8Array(address_pool, secretKey, "secretKey"); + var secretKey_address, secretKey_length = (libsodium._crypto_box_curve25519xchacha20poly1305_secretkeybytes()) | 0; + if (secretKey.length !== secretKey_length) { + _free_and_throw_type_error(address_pool, "invalid secretKey length"); + } + secretKey_address = _to_allocated_buf_address(secretKey); + address_pool.push(secretKey_address); + + // ---------- output plaintext (buf) + + var plaintext_length = (ciphertext_length - libsodium._crypto_box_curve25519xchacha20poly1305_sealbytes()) | 0, + plaintext = new AllocatedBuf(plaintext_length), + plaintext_address = plaintext.address; + + address_pool.push(plaintext_address); + + libsodium._crypto_box_curve25519xchacha20poly1305_seal_open(plaintext_address, ciphertext_address, ciphertext_length, 0, publicKey_address, secretKey_address) | 0; + var ret = (_format_output(plaintext, outputFormat)); + _free_all(address_pool); + return ret; + } + + function crypto_box_detached(message, nonce, publicKey, privateKey, outputFormat) { + var address_pool = []; + + _check_output_format(outputFormat); + // ---------- input: message (unsized_buf) + + message = _any_to_Uint8Array(address_pool, message, "message"); + var message_address = _to_allocated_buf_address(message), + message_length = message.length; + address_pool.push(message_address); + + // ---------- input: nonce (buf) + + nonce = _any_to_Uint8Array(address_pool, nonce, "nonce"); + var nonce_address, nonce_length = (libsodium._crypto_box_noncebytes()) | 0; + if (nonce.length !== nonce_length) { + _free_and_throw_type_error(address_pool, "invalid nonce length"); + } + nonce_address = _to_allocated_buf_address(nonce); + address_pool.push(nonce_address); + + // ---------- input: publicKey (buf) + + publicKey = _any_to_Uint8Array(address_pool, publicKey, "publicKey"); + var publicKey_address, publicKey_length = (libsodium._crypto_box_publickeybytes()) | 0; + if (publicKey.length !== publicKey_length) { + _free_and_throw_type_error(address_pool, "invalid publicKey length"); + } + publicKey_address = _to_allocated_buf_address(publicKey); + address_pool.push(publicKey_address); + + // ---------- input: privateKey (buf) + + privateKey = _any_to_Uint8Array(address_pool, privateKey, "privateKey"); + var privateKey_address, privateKey_length = (libsodium._crypto_box_secretkeybytes()) | 0; + if (privateKey.length !== privateKey_length) { + _free_and_throw_type_error(address_pool, "invalid privateKey length"); + } + privateKey_address = _to_allocated_buf_address(privateKey); + address_pool.push(privateKey_address); + + // ---------- output ciphertext (buf) + + var ciphertext_length = (message_length) | 0, + ciphertext = new AllocatedBuf(ciphertext_length), + ciphertext_address = ciphertext.address; + + address_pool.push(ciphertext_address); + + // ---------- output mac (buf) + + var mac_length = (libsodium._crypto_box_macbytes()) | 0, + mac = new AllocatedBuf(mac_length), + mac_address = mac.address; + + address_pool.push(mac_address); + + if ((libsodium._crypto_box_detached(ciphertext_address, mac_address, message_address, message_length, 0, nonce_address, publicKey_address, privateKey_address) | 0) === 0) { + var ret = _format_output({ciphertext: ciphertext, mac: mac}, outputFormat); + _free_all(address_pool); + return ret; + } + _free_and_throw_error(address_pool, "invalid usage"); + } + + function crypto_box_easy(message, nonce, publicKey, privateKey, outputFormat) { + var address_pool = []; + + _check_output_format(outputFormat); + // ---------- input: message (unsized_buf) + + message = _any_to_Uint8Array(address_pool, message, "message"); + var message_address = _to_allocated_buf_address(message), + message_length = message.length; + address_pool.push(message_address); + + // ---------- input: nonce (buf) + + nonce = _any_to_Uint8Array(address_pool, nonce, "nonce"); + var nonce_address, nonce_length = (libsodium._crypto_box_noncebytes()) | 0; + if (nonce.length !== nonce_length) { + _free_and_throw_type_error(address_pool, "invalid nonce length"); + } + nonce_address = _to_allocated_buf_address(nonce); + address_pool.push(nonce_address); + + // ---------- input: publicKey (buf) + + publicKey = _any_to_Uint8Array(address_pool, publicKey, "publicKey"); + var publicKey_address, publicKey_length = (libsodium._crypto_box_publickeybytes()) | 0; + if (publicKey.length !== publicKey_length) { + _free_and_throw_type_error(address_pool, "invalid publicKey length"); + } + publicKey_address = _to_allocated_buf_address(publicKey); + address_pool.push(publicKey_address); + + // ---------- input: privateKey (buf) + + privateKey = _any_to_Uint8Array(address_pool, privateKey, "privateKey"); + var privateKey_address, privateKey_length = (libsodium._crypto_box_secretkeybytes()) | 0; + if (privateKey.length !== privateKey_length) { + _free_and_throw_type_error(address_pool, "invalid privateKey length"); + } + privateKey_address = _to_allocated_buf_address(privateKey); + address_pool.push(privateKey_address); + + // ---------- output ciphertext (buf) + + var ciphertext_length = (message_length + libsodium._crypto_box_macbytes()) | 0, + ciphertext = new AllocatedBuf(ciphertext_length), + ciphertext_address = ciphertext.address; + + address_pool.push(ciphertext_address); + + if ((libsodium._crypto_box_easy(ciphertext_address, message_address, message_length, 0, nonce_address, publicKey_address, privateKey_address) | 0) === 0) { + var ret = _format_output(ciphertext, outputFormat); + _free_all(address_pool); + return ret; + } + _free_and_throw_error(address_pool, "invalid usage"); + } + + function crypto_box_easy_afternm(message, nonce, sharedKey, outputFormat) { + var address_pool = []; + + _check_output_format(outputFormat); + // ---------- input: message (unsized_buf) + + message = _any_to_Uint8Array(address_pool, message, "message"); + var message_address = _to_allocated_buf_address(message), + message_length = message.length; + address_pool.push(message_address); + + // ---------- input: nonce (buf) + + nonce = _any_to_Uint8Array(address_pool, nonce, "nonce"); + var nonce_address, nonce_length = (libsodium._crypto_box_noncebytes()) | 0; + if (nonce.length !== nonce_length) { + _free_and_throw_type_error(address_pool, "invalid nonce length"); + } + nonce_address = _to_allocated_buf_address(nonce); + address_pool.push(nonce_address); + + // ---------- input: sharedKey (buf) + + sharedKey = _any_to_Uint8Array(address_pool, sharedKey, "sharedKey"); + var sharedKey_address, sharedKey_length = (libsodium._crypto_box_beforenmbytes()) | 0; + if (sharedKey.length !== sharedKey_length) { + _free_and_throw_type_error(address_pool, "invalid sharedKey length"); + } + sharedKey_address = _to_allocated_buf_address(sharedKey); + address_pool.push(sharedKey_address); + + // ---------- output ciphertext (buf) + + var ciphertext_length = (message_length + libsodium._crypto_box_macbytes()) | 0, + ciphertext = new AllocatedBuf(ciphertext_length), + ciphertext_address = ciphertext.address; + + address_pool.push(ciphertext_address); + + if ((libsodium._crypto_box_easy_afternm(ciphertext_address, message_address, message_length, 0, nonce_address, sharedKey_address) | 0) === 0) { + var ret = _format_output(ciphertext, outputFormat); + _free_all(address_pool); + return ret; + } + _free_and_throw_error(address_pool, "invalid usage"); + } + + function crypto_box_keypair(outputFormat) { + var address_pool = []; + + _check_output_format(outputFormat); + // ---------- output publicKey (buf) + + var publicKey_length = (libsodium._crypto_box_publickeybytes()) | 0, + publicKey = new AllocatedBuf(publicKey_length), + publicKey_address = publicKey.address; + + address_pool.push(publicKey_address); + + // ---------- output privateKey (buf) + + var privateKey_length = (libsodium._crypto_box_secretkeybytes()) | 0, + privateKey = new AllocatedBuf(privateKey_length), + privateKey_address = privateKey.address; + + address_pool.push(privateKey_address); + + if ((libsodium._crypto_box_keypair(publicKey_address, privateKey_address) | 0) === 0) { + var ret = {publicKey: _format_output(publicKey, outputFormat), privateKey: _format_output(privateKey, outputFormat), keyType: 'x25519'}; + _free_all(address_pool); + return ret; + } + _free_and_throw_error(address_pool, "internal error"); + } + + function crypto_box_open_detached(ciphertext, mac, nonce, publicKey, privateKey, outputFormat) { + var address_pool = []; + + _check_output_format(outputFormat); + // ---------- input: ciphertext (unsized_buf) + + ciphertext = _any_to_Uint8Array(address_pool, ciphertext, "ciphertext"); + var ciphertext_address = _to_allocated_buf_address(ciphertext), + ciphertext_length = ciphertext.length; + address_pool.push(ciphertext_address); + + // ---------- input: mac (buf) + + mac = _any_to_Uint8Array(address_pool, mac, "mac"); + var mac_address, mac_length = (libsodium._crypto_box_macbytes()) | 0; + if (mac.length !== mac_length) { + _free_and_throw_type_error(address_pool, "invalid mac length"); + } + mac_address = _to_allocated_buf_address(mac); + address_pool.push(mac_address); + + // ---------- input: nonce (buf) + + nonce = _any_to_Uint8Array(address_pool, nonce, "nonce"); + var nonce_address, nonce_length = (libsodium._crypto_box_noncebytes()) | 0; + if (nonce.length !== nonce_length) { + _free_and_throw_type_error(address_pool, "invalid nonce length"); + } + nonce_address = _to_allocated_buf_address(nonce); + address_pool.push(nonce_address); + + // ---------- input: publicKey (buf) + + publicKey = _any_to_Uint8Array(address_pool, publicKey, "publicKey"); + var publicKey_address, publicKey_length = (libsodium._crypto_box_publickeybytes()) | 0; + if (publicKey.length !== publicKey_length) { + _free_and_throw_type_error(address_pool, "invalid publicKey length"); + } + publicKey_address = _to_allocated_buf_address(publicKey); + address_pool.push(publicKey_address); + + // ---------- input: privateKey (buf) + + privateKey = _any_to_Uint8Array(address_pool, privateKey, "privateKey"); + var privateKey_address, privateKey_length = (libsodium._crypto_box_secretkeybytes()) | 0; + if (privateKey.length !== privateKey_length) { + _free_and_throw_type_error(address_pool, "invalid privateKey length"); + } + privateKey_address = _to_allocated_buf_address(privateKey); + address_pool.push(privateKey_address); + + // ---------- output plaintext (buf) + + var plaintext_length = (ciphertext_length) | 0, + plaintext = new AllocatedBuf(plaintext_length), + plaintext_address = plaintext.address; + + address_pool.push(plaintext_address); + + if ((libsodium._crypto_box_open_detached(plaintext_address, ciphertext_address, mac_address, ciphertext_length, 0, nonce_address, publicKey_address, privateKey_address) | 0) === 0) { + var ret = _format_output(plaintext, outputFormat); + _free_all(address_pool); + return ret; + } + _free_and_throw_error(address_pool, "incorrect key pair for the given ciphertext"); + } + + function crypto_box_open_easy(ciphertext, nonce, publicKey, privateKey, outputFormat) { + var address_pool = []; + + _check_output_format(outputFormat); + // ---------- input: ciphertext (minsized_buf) + + ciphertext = _any_to_Uint8Array(address_pool, ciphertext, "ciphertext"); + var ciphertext_address, ciphertext_min_length = libsodium._crypto_box_macbytes(), ciphertext_length = ciphertext.length; + if (ciphertext_length < ciphertext_min_length) { + _free_and_throw_type_error(address_pool, "ciphertext is too short"); + } + ciphertext_address = _to_allocated_buf_address(ciphertext); + address_pool.push(ciphertext_address); + + // ---------- input: nonce (buf) + + nonce = _any_to_Uint8Array(address_pool, nonce, "nonce"); + var nonce_address, nonce_length = (libsodium._crypto_box_noncebytes()) | 0; + if (nonce.length !== nonce_length) { + _free_and_throw_type_error(address_pool, "invalid nonce length"); + } + nonce_address = _to_allocated_buf_address(nonce); + address_pool.push(nonce_address); + + // ---------- input: publicKey (buf) + + publicKey = _any_to_Uint8Array(address_pool, publicKey, "publicKey"); + var publicKey_address, publicKey_length = (libsodium._crypto_box_publickeybytes()) | 0; + if (publicKey.length !== publicKey_length) { + _free_and_throw_type_error(address_pool, "invalid publicKey length"); + } + publicKey_address = _to_allocated_buf_address(publicKey); + address_pool.push(publicKey_address); + + // ---------- input: privateKey (buf) + + privateKey = _any_to_Uint8Array(address_pool, privateKey, "privateKey"); + var privateKey_address, privateKey_length = (libsodium._crypto_box_secretkeybytes()) | 0; + if (privateKey.length !== privateKey_length) { + _free_and_throw_type_error(address_pool, "invalid privateKey length"); + } + privateKey_address = _to_allocated_buf_address(privateKey); + address_pool.push(privateKey_address); + + // ---------- output plaintext (buf) + + var plaintext_length = (ciphertext_length - libsodium._crypto_box_macbytes()) | 0, + plaintext = new AllocatedBuf(plaintext_length), + plaintext_address = plaintext.address; + + address_pool.push(plaintext_address); + + if ((libsodium._crypto_box_open_easy(plaintext_address, ciphertext_address, ciphertext_length, 0, nonce_address, publicKey_address, privateKey_address) | 0) === 0) { + var ret = _format_output(plaintext, outputFormat); + _free_all(address_pool); + return ret; + } + _free_and_throw_error(address_pool, "incorrect key pair for the given ciphertext"); + } + + function crypto_box_open_easy_afternm(ciphertext, nonce, sharedKey, outputFormat) { + var address_pool = []; + + _check_output_format(outputFormat); + // ---------- input: ciphertext (unsized_buf) + + ciphertext = _any_to_Uint8Array(address_pool, ciphertext, "ciphertext"); + var ciphertext_address = _to_allocated_buf_address(ciphertext), + ciphertext_length = ciphertext.length; + address_pool.push(ciphertext_address); + + // ---------- input: nonce (buf) + + nonce = _any_to_Uint8Array(address_pool, nonce, "nonce"); + var nonce_address, nonce_length = (libsodium._crypto_box_noncebytes()) | 0; + if (nonce.length !== nonce_length) { + _free_and_throw_type_error(address_pool, "invalid nonce length"); + } + nonce_address = _to_allocated_buf_address(nonce); + address_pool.push(nonce_address); + + // ---------- input: sharedKey (buf) + + sharedKey = _any_to_Uint8Array(address_pool, sharedKey, "sharedKey"); + var sharedKey_address, sharedKey_length = (libsodium._crypto_box_beforenmbytes()) | 0; + if (sharedKey.length !== sharedKey_length) { + _free_and_throw_type_error(address_pool, "invalid sharedKey length"); + } + sharedKey_address = _to_allocated_buf_address(sharedKey); + address_pool.push(sharedKey_address); + + // ---------- output plaintext (buf) + + var plaintext_length = (ciphertext_length - libsodium._crypto_box_macbytes()) | 0, + plaintext = new AllocatedBuf(plaintext_length), + plaintext_address = plaintext.address; + + address_pool.push(plaintext_address); + + if ((libsodium._crypto_box_open_easy_afternm(plaintext_address, ciphertext_address, ciphertext_length, 0, nonce_address, sharedKey_address) | 0) === 0) { + var ret = _format_output(plaintext, outputFormat); + _free_all(address_pool); + return ret; + } + _free_and_throw_error(address_pool, "incorrect secret key for the given ciphertext"); + } + + function crypto_box_seal(message, publicKey, outputFormat) { + var address_pool = []; + + _check_output_format(outputFormat); + // ---------- input: message (unsized_buf) + + message = _any_to_Uint8Array(address_pool, message, "message"); + var message_address = _to_allocated_buf_address(message), + message_length = message.length; + address_pool.push(message_address); + + // ---------- input: publicKey (buf) + + publicKey = _any_to_Uint8Array(address_pool, publicKey, "publicKey"); + var publicKey_address, publicKey_length = (libsodium._crypto_box_publickeybytes()) | 0; + if (publicKey.length !== publicKey_length) { + _free_and_throw_type_error(address_pool, "invalid publicKey length"); + } + publicKey_address = _to_allocated_buf_address(publicKey); + address_pool.push(publicKey_address); + + // ---------- output ciphertext (buf) + + var ciphertext_length = (message_length + libsodium._crypto_box_sealbytes()) | 0, + ciphertext = new AllocatedBuf(ciphertext_length), + ciphertext_address = ciphertext.address; + + address_pool.push(ciphertext_address); + + if ((libsodium._crypto_box_seal(ciphertext_address, message_address, message_length, 0, publicKey_address) | 0) === 0) { + var ret = _format_output(ciphertext, outputFormat); + _free_all(address_pool); + return ret; + } + _free_and_throw_error(address_pool, "invalid usage"); + } + + function crypto_box_seal_open(ciphertext, publicKey, privateKey, outputFormat) { + var address_pool = []; + + _check_output_format(outputFormat); + // ---------- input: ciphertext (minsized_buf) + + ciphertext = _any_to_Uint8Array(address_pool, ciphertext, "ciphertext"); + var ciphertext_address, ciphertext_min_length = libsodium._crypto_box_sealbytes(), ciphertext_length = ciphertext.length; + if (ciphertext_length < ciphertext_min_length) { + _free_and_throw_type_error(address_pool, "ciphertext is too short"); + } + ciphertext_address = _to_allocated_buf_address(ciphertext); + address_pool.push(ciphertext_address); + + // ---------- input: publicKey (buf) + + publicKey = _any_to_Uint8Array(address_pool, publicKey, "publicKey"); + var publicKey_address, publicKey_length = (libsodium._crypto_box_publickeybytes()) | 0; + if (publicKey.length !== publicKey_length) { + _free_and_throw_type_error(address_pool, "invalid publicKey length"); + } + publicKey_address = _to_allocated_buf_address(publicKey); + address_pool.push(publicKey_address); + + // ---------- input: privateKey (buf) + + privateKey = _any_to_Uint8Array(address_pool, privateKey, "privateKey"); + var privateKey_address, privateKey_length = (libsodium._crypto_box_secretkeybytes()) | 0; + if (privateKey.length !== privateKey_length) { + _free_and_throw_type_error(address_pool, "invalid privateKey length"); + } + privateKey_address = _to_allocated_buf_address(privateKey); + address_pool.push(privateKey_address); + + // ---------- output plaintext (buf) + + var plaintext_length = (ciphertext_length - libsodium._crypto_box_sealbytes()) | 0, + plaintext = new AllocatedBuf(plaintext_length), + plaintext_address = plaintext.address; + + address_pool.push(plaintext_address); + + if ((libsodium._crypto_box_seal_open(plaintext_address, ciphertext_address, ciphertext_length, 0, publicKey_address, privateKey_address) | 0) === 0) { + var ret = _format_output(plaintext, outputFormat); + _free_all(address_pool); + return ret; + } + _free_and_throw_error(address_pool, "incorrect key pair for the given ciphertext"); + } + + function crypto_box_seed_keypair(seed, outputFormat) { + var address_pool = []; + + _check_output_format(outputFormat); + // ---------- input: seed (buf) + + seed = _any_to_Uint8Array(address_pool, seed, "seed"); + var seed_address, seed_length = (libsodium._crypto_box_seedbytes()) | 0; + if (seed.length !== seed_length) { + _free_and_throw_type_error(address_pool, "invalid seed length"); + } + seed_address = _to_allocated_buf_address(seed); + address_pool.push(seed_address); + + // ---------- output publicKey (buf) + + var publicKey_length = (libsodium._crypto_box_publickeybytes()) | 0, + publicKey = new AllocatedBuf(publicKey_length), + publicKey_address = publicKey.address; + + address_pool.push(publicKey_address); + + // ---------- output privateKey (buf) + + var privateKey_length = (libsodium._crypto_box_secretkeybytes()) | 0, + privateKey = new AllocatedBuf(privateKey_length), + privateKey_address = privateKey.address; + + address_pool.push(privateKey_address); + + if ((libsodium._crypto_box_seed_keypair(publicKey_address, privateKey_address, seed_address) | 0) === 0) { + var ret = {publicKey: _format_output(publicKey, outputFormat), privateKey: _format_output(privateKey, outputFormat), keyType: 'x25519'}; + _free_all(address_pool); + return ret; + } + _free_and_throw_error(address_pool, "invalid usage"); + } + + function crypto_core_ed25519_add(p, q, outputFormat) { + var address_pool = []; + + _check_output_format(outputFormat); + // ---------- input: p (buf) + + p = _any_to_Uint8Array(address_pool, p, "p"); + var p_address, p_length = (libsodium._crypto_core_ed25519_bytes()) | 0; + if (p.length !== p_length) { + _free_and_throw_type_error(address_pool, "invalid p length"); + } + p_address = _to_allocated_buf_address(p); + address_pool.push(p_address); + + // ---------- input: q (buf) + + q = _any_to_Uint8Array(address_pool, q, "q"); + var q_address, q_length = (libsodium._crypto_core_ed25519_bytes()) | 0; + if (q.length !== q_length) { + _free_and_throw_type_error(address_pool, "invalid q length"); + } + q_address = _to_allocated_buf_address(q); + address_pool.push(q_address); + + // ---------- output r (buf) + + var r_length = (libsodium._crypto_core_ed25519_bytes()) | 0, + r = new AllocatedBuf(r_length), + r_address = r.address; + + address_pool.push(r_address); + + if ((libsodium._crypto_core_ed25519_add(r_address, p_address, q_address) | 0) === 0) { + var ret = _format_output(r, outputFormat); + _free_all(address_pool); + return ret; + } + _free_and_throw_error(address_pool, "input is an invalid element"); + } + + function crypto_core_ed25519_from_hash(r, outputFormat) { + var address_pool = []; + + _check_output_format(outputFormat); + // ---------- input: r (unsized_buf) + + r = _any_to_Uint8Array(address_pool, r, "r"); + var r_address = _to_allocated_buf_address(r), + r_length = r.length; + address_pool.push(r_address); + + // ---------- output point (buf) + + var point_length = (libsodium._crypto_core_ed25519_bytes()) | 0, + point = new AllocatedBuf(point_length), + point_address = point.address; + + address_pool.push(point_address); + + if ((libsodium._crypto_core_ed25519_from_hash(point_address, r_address) | 0) === 0) { + var ret = _format_output(point, outputFormat); + _free_all(address_pool); + return ret; + } + _free_and_throw_error(address_pool, "invalid usage"); + } + + function crypto_core_ed25519_from_uniform(r, outputFormat) { + var address_pool = []; + + _check_output_format(outputFormat); + // ---------- input: r (unsized_buf) + + r = _any_to_Uint8Array(address_pool, r, "r"); + var r_address = _to_allocated_buf_address(r), + r_length = r.length; + address_pool.push(r_address); + + // ---------- output point (buf) + + var point_length = (libsodium._crypto_core_ed25519_bytes()) | 0, + point = new AllocatedBuf(point_length), + point_address = point.address; + + address_pool.push(point_address); + + if ((libsodium._crypto_core_ed25519_from_uniform(point_address, r_address) | 0) === 0) { + var ret = _format_output(point, outputFormat); + _free_all(address_pool); + return ret; + } + _free_and_throw_error(address_pool, "invalid usage"); + } + + function crypto_core_ed25519_is_valid_point(repr, outputFormat) { + var address_pool = []; + + _check_output_format(outputFormat); + // ---------- input: repr (buf) + + repr = _any_to_Uint8Array(address_pool, repr, "repr"); + var repr_address, repr_length = (libsodium._crypto_core_ed25519_bytes()) | 0; + if (repr.length !== repr_length) { + _free_and_throw_type_error(address_pool, "invalid repr length"); + } + repr_address = _to_allocated_buf_address(repr); + address_pool.push(repr_address); + + var result = libsodium._crypto_core_ed25519_is_valid_point(repr_address) | 0; + var ret = (result === 1); + _free_all(address_pool); + return ret; + } + + function crypto_core_ed25519_random(outputFormat) { + var address_pool = []; + + _check_output_format(outputFormat); + // ---------- output p (buf) + + var p_length = (libsodium._crypto_core_ed25519_bytes()) | 0, + p = new AllocatedBuf(p_length), + p_address = p.address; + + address_pool.push(p_address); + + libsodium._crypto_core_ed25519_random(p_address); + var ret = (_format_output(p, outputFormat)); + _free_all(address_pool); + return ret; + } + + function crypto_core_ed25519_scalar_add(x, y, outputFormat) { + var address_pool = []; + + _check_output_format(outputFormat); + // ---------- input: x (buf) + + x = _any_to_Uint8Array(address_pool, x, "x"); + var x_address, x_length = (libsodium._crypto_core_ed25519_scalarbytes()) | 0; + if (x.length !== x_length) { + _free_and_throw_type_error(address_pool, "invalid x length"); + } + x_address = _to_allocated_buf_address(x); + address_pool.push(x_address); + + // ---------- input: y (buf) + + y = _any_to_Uint8Array(address_pool, y, "y"); + var y_address, y_length = (libsodium._crypto_core_ed25519_scalarbytes()) | 0; + if (y.length !== y_length) { + _free_and_throw_type_error(address_pool, "invalid y length"); + } + y_address = _to_allocated_buf_address(y); + address_pool.push(y_address); + + // ---------- output z (buf) + + var z_length = (libsodium._crypto_core_ed25519_scalarbytes()) | 0, + z = new AllocatedBuf(z_length), + z_address = z.address; + + address_pool.push(z_address); + + libsodium._crypto_core_ed25519_scalar_add(z_address, x_address, y_address); + var ret = (_format_output(z, outputFormat)); + _free_all(address_pool); + return ret; + } + + function crypto_core_ed25519_scalar_complement(s, outputFormat) { + var address_pool = []; + + _check_output_format(outputFormat); + // ---------- input: s (buf) + + s = _any_to_Uint8Array(address_pool, s, "s"); + var s_address, s_length = (libsodium._crypto_core_ed25519_scalarbytes()) | 0; + if (s.length !== s_length) { + _free_and_throw_type_error(address_pool, "invalid s length"); + } + s_address = _to_allocated_buf_address(s); + address_pool.push(s_address); + + // ---------- output comp (buf) + + var comp_length = (libsodium._crypto_core_ed25519_scalarbytes()) | 0, + comp = new AllocatedBuf(comp_length), + comp_address = comp.address; + + address_pool.push(comp_address); + + libsodium._crypto_core_ed25519_scalar_complement(comp_address, s_address); + var ret = (_format_output(comp, outputFormat)); + _free_all(address_pool); + return ret; + } + + function crypto_core_ed25519_scalar_invert(s, outputFormat) { + var address_pool = []; + + _check_output_format(outputFormat); + // ---------- input: s (buf) + + s = _any_to_Uint8Array(address_pool, s, "s"); + var s_address, s_length = (libsodium._crypto_core_ed25519_scalarbytes()) | 0; + if (s.length !== s_length) { + _free_and_throw_type_error(address_pool, "invalid s length"); + } + s_address = _to_allocated_buf_address(s); + address_pool.push(s_address); + + // ---------- output recip (buf) + + var recip_length = (libsodium._crypto_core_ed25519_scalarbytes()) | 0, + recip = new AllocatedBuf(recip_length), + recip_address = recip.address; + + address_pool.push(recip_address); + + if ((libsodium._crypto_core_ed25519_scalar_invert(recip_address, s_address) | 0) === 0) { + var ret = _format_output(recip, outputFormat); + _free_all(address_pool); + return ret; + } + _free_and_throw_error(address_pool, "invalid reciprocate"); + } + + function crypto_core_ed25519_scalar_mul(x, y, outputFormat) { + var address_pool = []; + + _check_output_format(outputFormat); + // ---------- input: x (buf) + + x = _any_to_Uint8Array(address_pool, x, "x"); + var x_address, x_length = (libsodium._crypto_core_ed25519_scalarbytes()) | 0; + if (x.length !== x_length) { + _free_and_throw_type_error(address_pool, "invalid x length"); + } + x_address = _to_allocated_buf_address(x); + address_pool.push(x_address); + + // ---------- input: y (buf) + + y = _any_to_Uint8Array(address_pool, y, "y"); + var y_address, y_length = (libsodium._crypto_core_ed25519_scalarbytes()) | 0; + if (y.length !== y_length) { + _free_and_throw_type_error(address_pool, "invalid y length"); + } + y_address = _to_allocated_buf_address(y); + address_pool.push(y_address); + + // ---------- output z (buf) + + var z_length = (libsodium._crypto_core_ed25519_scalarbytes()) | 0, + z = new AllocatedBuf(z_length), + z_address = z.address; + + address_pool.push(z_address); + + libsodium._crypto_core_ed25519_scalar_mul(z_address, x_address, y_address); + var ret = (_format_output(z, outputFormat)); + _free_all(address_pool); + return ret; + } + + function crypto_core_ed25519_scalar_negate(s, outputFormat) { + var address_pool = []; + + _check_output_format(outputFormat); + // ---------- input: s (buf) + + s = _any_to_Uint8Array(address_pool, s, "s"); + var s_address, s_length = (libsodium._crypto_core_ed25519_scalarbytes()) | 0; + if (s.length !== s_length) { + _free_and_throw_type_error(address_pool, "invalid s length"); + } + s_address = _to_allocated_buf_address(s); + address_pool.push(s_address); + + // ---------- output neg (buf) + + var neg_length = (libsodium._crypto_core_ed25519_scalarbytes()) | 0, + neg = new AllocatedBuf(neg_length), + neg_address = neg.address; + + address_pool.push(neg_address); + + libsodium._crypto_core_ed25519_scalar_negate(neg_address, s_address); + var ret = (_format_output(neg, outputFormat)); + _free_all(address_pool); + return ret; + } + + function crypto_core_ed25519_scalar_random(outputFormat) { + var address_pool = []; + + _check_output_format(outputFormat); + // ---------- output r (buf) + + var r_length = (libsodium._crypto_core_ed25519_scalarbytes()) | 0, + r = new AllocatedBuf(r_length), + r_address = r.address; + + address_pool.push(r_address); + + libsodium._crypto_core_ed25519_scalar_random(r_address); + var ret = (_format_output(r, outputFormat)); + _free_all(address_pool); + return ret; + } + + function crypto_core_ed25519_scalar_reduce(sample, outputFormat) { + var address_pool = []; + + _check_output_format(outputFormat); + // ---------- input: sample (buf) + + sample = _any_to_Uint8Array(address_pool, sample, "sample"); + var sample_address, sample_length = (libsodium._crypto_core_ed25519_nonreducedscalarbytes()) | 0; + if (sample.length !== sample_length) { + _free_and_throw_type_error(address_pool, "invalid sample length"); + } + sample_address = _to_allocated_buf_address(sample); + address_pool.push(sample_address); + + // ---------- output result (buf) + + var result_length = (libsodium._crypto_core_ed25519_scalarbytes()) | 0, + result = new AllocatedBuf(result_length), + result_address = result.address; + + address_pool.push(result_address); + + libsodium._crypto_core_ed25519_scalar_reduce(result_address, sample_address); + var ret = (_format_output(result, outputFormat)); + _free_all(address_pool); + return ret; + } + + function crypto_core_ed25519_scalar_sub(x, y, outputFormat) { + var address_pool = []; + + _check_output_format(outputFormat); + // ---------- input: x (buf) + + x = _any_to_Uint8Array(address_pool, x, "x"); + var x_address, x_length = (libsodium._crypto_core_ed25519_scalarbytes()) | 0; + if (x.length !== x_length) { + _free_and_throw_type_error(address_pool, "invalid x length"); + } + x_address = _to_allocated_buf_address(x); + address_pool.push(x_address); + + // ---------- input: y (buf) + + y = _any_to_Uint8Array(address_pool, y, "y"); + var y_address, y_length = (libsodium._crypto_core_ed25519_scalarbytes()) | 0; + if (y.length !== y_length) { + _free_and_throw_type_error(address_pool, "invalid y length"); + } + y_address = _to_allocated_buf_address(y); + address_pool.push(y_address); + + // ---------- output z (buf) + + var z_length = (libsodium._crypto_core_ed25519_scalarbytes()) | 0, + z = new AllocatedBuf(z_length), + z_address = z.address; + + address_pool.push(z_address); + + libsodium._crypto_core_ed25519_scalar_sub(z_address, x_address, y_address); + var ret = (_format_output(z, outputFormat)); + _free_all(address_pool); + return ret; + } + + function crypto_core_ed25519_sub(p, q, outputFormat) { + var address_pool = []; + + _check_output_format(outputFormat); + // ---------- input: p (buf) + + p = _any_to_Uint8Array(address_pool, p, "p"); + var p_address, p_length = (libsodium._crypto_core_ed25519_bytes()) | 0; + if (p.length !== p_length) { + _free_and_throw_type_error(address_pool, "invalid p length"); + } + p_address = _to_allocated_buf_address(p); + address_pool.push(p_address); + + // ---------- input: q (buf) + + q = _any_to_Uint8Array(address_pool, q, "q"); + var q_address, q_length = (libsodium._crypto_core_ed25519_bytes()) | 0; + if (q.length !== q_length) { + _free_and_throw_type_error(address_pool, "invalid q length"); + } + q_address = _to_allocated_buf_address(q); + address_pool.push(q_address); + + // ---------- output r (buf) + + var r_length = (libsodium._crypto_core_ed25519_bytes()) | 0, + r = new AllocatedBuf(r_length), + r_address = r.address; + + address_pool.push(r_address); + + if ((libsodium._crypto_core_ed25519_sub(r_address, p_address, q_address) | 0) === 0) { + var ret = _format_output(r, outputFormat); + _free_all(address_pool); + return ret; + } + _free_and_throw_error(address_pool, "input is an invalid element"); + } + + function crypto_core_ristretto255_add(p, q, outputFormat) { + var address_pool = []; + + _check_output_format(outputFormat); + // ---------- input: p (buf) + + p = _any_to_Uint8Array(address_pool, p, "p"); + var p_address, p_length = (libsodium._crypto_core_ristretto255_bytes()) | 0; + if (p.length !== p_length) { + _free_and_throw_type_error(address_pool, "invalid p length"); + } + p_address = _to_allocated_buf_address(p); + address_pool.push(p_address); + + // ---------- input: q (buf) + + q = _any_to_Uint8Array(address_pool, q, "q"); + var q_address, q_length = (libsodium._crypto_core_ristretto255_bytes()) | 0; + if (q.length !== q_length) { + _free_and_throw_type_error(address_pool, "invalid q length"); + } + q_address = _to_allocated_buf_address(q); + address_pool.push(q_address); + + // ---------- output r (buf) + + var r_length = (libsodium._crypto_core_ristretto255_bytes()) | 0, + r = new AllocatedBuf(r_length), + r_address = r.address; + + address_pool.push(r_address); + + if ((libsodium._crypto_core_ristretto255_add(r_address, p_address, q_address) | 0) === 0) { + var ret = _format_output(r, outputFormat); + _free_all(address_pool); + return ret; + } + _free_and_throw_error(address_pool, "input is an invalid element"); + } + + function crypto_core_ristretto255_from_hash(r, outputFormat) { + var address_pool = []; + + _check_output_format(outputFormat); + // ---------- input: r (unsized_buf) + + r = _any_to_Uint8Array(address_pool, r, "r"); + var r_address = _to_allocated_buf_address(r), + r_length = r.length; + address_pool.push(r_address); + + // ---------- output point (buf) + + var point_length = (libsodium._crypto_core_ristretto255_bytes()) | 0, + point = new AllocatedBuf(point_length), + point_address = point.address; + + address_pool.push(point_address); + + if ((libsodium._crypto_core_ristretto255_from_hash(point_address, r_address) | 0) === 0) { + var ret = _format_output(point, outputFormat); + _free_all(address_pool); + return ret; + } + _free_and_throw_error(address_pool, "invalid usage"); + } + + function crypto_core_ristretto255_is_valid_point(repr, outputFormat) { + var address_pool = []; + + _check_output_format(outputFormat); + // ---------- input: repr (buf) + + repr = _any_to_Uint8Array(address_pool, repr, "repr"); + var repr_address, repr_length = (libsodium._crypto_core_ristretto255_bytes()) | 0; + if (repr.length !== repr_length) { + _free_and_throw_type_error(address_pool, "invalid repr length"); + } + repr_address = _to_allocated_buf_address(repr); + address_pool.push(repr_address); + + var result = libsodium._crypto_core_ristretto255_is_valid_point(repr_address) | 0; + var ret = (result === 1); + _free_all(address_pool); + return ret; + } + + function crypto_core_ristretto255_random(outputFormat) { + var address_pool = []; + + _check_output_format(outputFormat); + // ---------- output p (buf) + + var p_length = (libsodium._crypto_core_ristretto255_bytes()) | 0, + p = new AllocatedBuf(p_length), + p_address = p.address; + + address_pool.push(p_address); + + libsodium._crypto_core_ristretto255_random(p_address); + var ret = (_format_output(p, outputFormat)); + _free_all(address_pool); + return ret; + } + + function crypto_core_ristretto255_scalar_add(x, y, outputFormat) { + var address_pool = []; + + _check_output_format(outputFormat); + // ---------- input: x (buf) + + x = _any_to_Uint8Array(address_pool, x, "x"); + var x_address, x_length = (libsodium._crypto_core_ristretto255_scalarbytes()) | 0; + if (x.length !== x_length) { + _free_and_throw_type_error(address_pool, "invalid x length"); + } + x_address = _to_allocated_buf_address(x); + address_pool.push(x_address); + + // ---------- input: y (buf) + + y = _any_to_Uint8Array(address_pool, y, "y"); + var y_address, y_length = (libsodium._crypto_core_ristretto255_scalarbytes()) | 0; + if (y.length !== y_length) { + _free_and_throw_type_error(address_pool, "invalid y length"); + } + y_address = _to_allocated_buf_address(y); + address_pool.push(y_address); + + // ---------- output z (buf) + + var z_length = (libsodium._crypto_core_ristretto255_scalarbytes()) | 0, + z = new AllocatedBuf(z_length), + z_address = z.address; + + address_pool.push(z_address); + + libsodium._crypto_core_ristretto255_scalar_add(z_address, x_address, y_address); + var ret = (_format_output(z, outputFormat)); + _free_all(address_pool); + return ret; + } + + function crypto_core_ristretto255_scalar_complement(s, outputFormat) { + var address_pool = []; + + _check_output_format(outputFormat); + // ---------- input: s (buf) + + s = _any_to_Uint8Array(address_pool, s, "s"); + var s_address, s_length = (libsodium._crypto_core_ristretto255_scalarbytes()) | 0; + if (s.length !== s_length) { + _free_and_throw_type_error(address_pool, "invalid s length"); + } + s_address = _to_allocated_buf_address(s); + address_pool.push(s_address); + + // ---------- output comp (buf) + + var comp_length = (libsodium._crypto_core_ristretto255_scalarbytes()) | 0, + comp = new AllocatedBuf(comp_length), + comp_address = comp.address; + + address_pool.push(comp_address); + + libsodium._crypto_core_ristretto255_scalar_complement(comp_address, s_address); + var ret = (_format_output(comp, outputFormat)); + _free_all(address_pool); + return ret; + } + + function crypto_core_ristretto255_scalar_invert(s, outputFormat) { + var address_pool = []; + + _check_output_format(outputFormat); + // ---------- input: s (buf) + + s = _any_to_Uint8Array(address_pool, s, "s"); + var s_address, s_length = (libsodium._crypto_core_ristretto255_scalarbytes()) | 0; + if (s.length !== s_length) { + _free_and_throw_type_error(address_pool, "invalid s length"); + } + s_address = _to_allocated_buf_address(s); + address_pool.push(s_address); + + // ---------- output recip (buf) + + var recip_length = (libsodium._crypto_core_ristretto255_scalarbytes()) | 0, + recip = new AllocatedBuf(recip_length), + recip_address = recip.address; + + address_pool.push(recip_address); + + if ((libsodium._crypto_core_ristretto255_scalar_invert(recip_address, s_address) | 0) === 0) { + var ret = _format_output(recip, outputFormat); + _free_all(address_pool); + return ret; + } + _free_and_throw_error(address_pool, "invalid reciprocate"); + } + + function crypto_core_ristretto255_scalar_mul(x, y, outputFormat) { + var address_pool = []; + + _check_output_format(outputFormat); + // ---------- input: x (buf) + + x = _any_to_Uint8Array(address_pool, x, "x"); + var x_address, x_length = (libsodium._crypto_core_ristretto255_scalarbytes()) | 0; + if (x.length !== x_length) { + _free_and_throw_type_error(address_pool, "invalid x length"); + } + x_address = _to_allocated_buf_address(x); + address_pool.push(x_address); + + // ---------- input: y (buf) + + y = _any_to_Uint8Array(address_pool, y, "y"); + var y_address, y_length = (libsodium._crypto_core_ristretto255_scalarbytes()) | 0; + if (y.length !== y_length) { + _free_and_throw_type_error(address_pool, "invalid y length"); + } + y_address = _to_allocated_buf_address(y); + address_pool.push(y_address); + + // ---------- output z (buf) + + var z_length = (libsodium._crypto_core_ristretto255_scalarbytes()) | 0, + z = new AllocatedBuf(z_length), + z_address = z.address; + + address_pool.push(z_address); + + libsodium._crypto_core_ristretto255_scalar_mul(z_address, x_address, y_address); + var ret = (_format_output(z, outputFormat)); + _free_all(address_pool); + return ret; + } + + function crypto_core_ristretto255_scalar_negate(s, outputFormat) { + var address_pool = []; + + _check_output_format(outputFormat); + // ---------- input: s (buf) + + s = _any_to_Uint8Array(address_pool, s, "s"); + var s_address, s_length = (libsodium._crypto_core_ristretto255_scalarbytes()) | 0; + if (s.length !== s_length) { + _free_and_throw_type_error(address_pool, "invalid s length"); + } + s_address = _to_allocated_buf_address(s); + address_pool.push(s_address); + + // ---------- output neg (buf) + + var neg_length = (libsodium._crypto_core_ristretto255_scalarbytes()) | 0, + neg = new AllocatedBuf(neg_length), + neg_address = neg.address; + + address_pool.push(neg_address); + + libsodium._crypto_core_ristretto255_scalar_negate(neg_address, s_address); + var ret = (_format_output(neg, outputFormat)); + _free_all(address_pool); + return ret; + } + + function crypto_core_ristretto255_scalar_random(outputFormat) { + var address_pool = []; + + _check_output_format(outputFormat); + // ---------- output r (buf) + + var r_length = (libsodium._crypto_core_ristretto255_scalarbytes()) | 0, + r = new AllocatedBuf(r_length), + r_address = r.address; + + address_pool.push(r_address); + + libsodium._crypto_core_ristretto255_scalar_random(r_address); + var ret = (_format_output(r, outputFormat)); + _free_all(address_pool); + return ret; + } + + function crypto_core_ristretto255_scalar_reduce(sample, outputFormat) { + var address_pool = []; + + _check_output_format(outputFormat); + // ---------- input: sample (buf) + + sample = _any_to_Uint8Array(address_pool, sample, "sample"); + var sample_address, sample_length = (libsodium._crypto_core_ristretto255_nonreducedscalarbytes()) | 0; + if (sample.length !== sample_length) { + _free_and_throw_type_error(address_pool, "invalid sample length"); + } + sample_address = _to_allocated_buf_address(sample); + address_pool.push(sample_address); + + // ---------- output result (buf) + + var result_length = (libsodium._crypto_core_ristretto255_scalarbytes()) | 0, + result = new AllocatedBuf(result_length), + result_address = result.address; + + address_pool.push(result_address); + + libsodium._crypto_core_ristretto255_scalar_reduce(result_address, sample_address); + var ret = (_format_output(result, outputFormat)); + _free_all(address_pool); + return ret; + } + + function crypto_core_ristretto255_scalar_sub(x, y, outputFormat) { + var address_pool = []; + + _check_output_format(outputFormat); + // ---------- input: x (buf) + + x = _any_to_Uint8Array(address_pool, x, "x"); + var x_address, x_length = (libsodium._crypto_core_ristretto255_scalarbytes()) | 0; + if (x.length !== x_length) { + _free_and_throw_type_error(address_pool, "invalid x length"); + } + x_address = _to_allocated_buf_address(x); + address_pool.push(x_address); + + // ---------- input: y (buf) + + y = _any_to_Uint8Array(address_pool, y, "y"); + var y_address, y_length = (libsodium._crypto_core_ristretto255_scalarbytes()) | 0; + if (y.length !== y_length) { + _free_and_throw_type_error(address_pool, "invalid y length"); + } + y_address = _to_allocated_buf_address(y); + address_pool.push(y_address); + + // ---------- output z (buf) + + var z_length = (libsodium._crypto_core_ristretto255_scalarbytes()) | 0, + z = new AllocatedBuf(z_length), + z_address = z.address; + + address_pool.push(z_address); + + libsodium._crypto_core_ristretto255_scalar_sub(z_address, x_address, y_address); + var ret = (_format_output(z, outputFormat)); + _free_all(address_pool); + return ret; + } + + function crypto_core_ristretto255_sub(p, q, outputFormat) { + var address_pool = []; + + _check_output_format(outputFormat); + // ---------- input: p (buf) + + p = _any_to_Uint8Array(address_pool, p, "p"); + var p_address, p_length = (libsodium._crypto_core_ristretto255_bytes()) | 0; + if (p.length !== p_length) { + _free_and_throw_type_error(address_pool, "invalid p length"); + } + p_address = _to_allocated_buf_address(p); + address_pool.push(p_address); + + // ---------- input: q (buf) + + q = _any_to_Uint8Array(address_pool, q, "q"); + var q_address, q_length = (libsodium._crypto_core_ristretto255_bytes()) | 0; + if (q.length !== q_length) { + _free_and_throw_type_error(address_pool, "invalid q length"); + } + q_address = _to_allocated_buf_address(q); + address_pool.push(q_address); + + // ---------- output r (buf) + + var r_length = (libsodium._crypto_core_ristretto255_bytes()) | 0, + r = new AllocatedBuf(r_length), + r_address = r.address; + + address_pool.push(r_address); + + if ((libsodium._crypto_core_ristretto255_sub(r_address, p_address, q_address) | 0) === 0) { + var ret = _format_output(r, outputFormat); + _free_all(address_pool); + return ret; + } + _free_and_throw_error(address_pool, "input is an invalid element"); + } + + function crypto_generichash(hash_length, message, key, outputFormat) { + var address_pool = []; + + _check_output_format(outputFormat); + // ---------- input: hash_length (uint) + + _require_defined(address_pool, hash_length, "hash_length"); + + if (!(typeof hash_length === "number" && (hash_length | 0) === hash_length) || hash_length < 0) { + _free_and_throw_type_error(address_pool, "hash_length must be an unsigned integer"); + } + + // ---------- input: message (unsized_buf) + + message = _any_to_Uint8Array(address_pool, message, "message"); + var message_address = _to_allocated_buf_address(message), + message_length = message.length; + address_pool.push(message_address); + + // ---------- input: key (unsized_buf_optional) + + var key_address = null, key_length = 0; + if (key != undefined) { + key = _any_to_Uint8Array(address_pool, key, "key"); + key_address = _to_allocated_buf_address(key); + key_length = key.length; + address_pool.push(key_address); + } + + + // ---------- output hash (buf) + + var hash_length = (hash_length) | 0, + hash = new AllocatedBuf(hash_length), + hash_address = hash.address; + + address_pool.push(hash_address); + + if ((libsodium._crypto_generichash(hash_address, hash_length, message_address, message_length, 0, key_address, key_length) | 0) === 0) { + var ret = _format_output(hash, outputFormat); + _free_all(address_pool); + return ret; + } + _free_and_throw_error(address_pool, "invalid usage"); + } + + function crypto_generichash_blake2b_salt_personal(subkey_len, key, id, ctx, outputFormat) { + var address_pool = []; + + _check_output_format(outputFormat); + // ---------- input: subkey_len (uint) + + _require_defined(address_pool, subkey_len, "subkey_len"); + + if (!(typeof subkey_len === "number" && (subkey_len | 0) === subkey_len) || subkey_len < 0) { + _free_and_throw_type_error(address_pool, "subkey_len must be an unsigned integer"); + } + + // ---------- input: key (unsized_buf_optional) + + var key_address = null, key_length = 0; + if (key != undefined) { + key = _any_to_Uint8Array(address_pool, key, "key"); + key_address = _to_allocated_buf_address(key); + key_length = key.length; + address_pool.push(key_address); + } + + + // ---------- input: id (buf) + + id = _any_to_Uint8Array(address_pool, id, "id"); + var id_address, id_length = (libsodium._crypto_generichash_blake2b_saltbytes()) | 0; + if (id.length !== id_length) { + _free_and_throw_type_error(address_pool, "invalid id length"); + } + id_address = _to_allocated_buf_address(id); + address_pool.push(id_address); + + // ---------- input: ctx (buf) + + ctx = _any_to_Uint8Array(address_pool, ctx, "ctx"); + var ctx_address, ctx_length = (libsodium._crypto_generichash_blake2b_personalbytes()) | 0; + if (ctx.length !== ctx_length) { + _free_and_throw_type_error(address_pool, "invalid ctx length"); + } + ctx_address = _to_allocated_buf_address(ctx); + address_pool.push(ctx_address); + + // ---------- output subkey (buf) + + var subkey_length = (subkey_len) | 0, + subkey = new AllocatedBuf(subkey_length), + subkey_address = subkey.address; + + address_pool.push(subkey_address); + + if ((libsodium._crypto_generichash_blake2b_salt_personal(subkey_address, subkey_len, null, 0, 0, key_address, key_length, id_address, ctx_address) | 0) === 0) { + var ret = _format_output(subkey, outputFormat); + _free_all(address_pool); + return ret; + } + _free_and_throw_error(address_pool, "invalid usage"); + } + + function crypto_generichash_final(state_address, hash_length, outputFormat) { + var address_pool = []; + + _check_output_format(outputFormat); + // ---------- input: state_address (generichash_state_address) + + _require_defined(address_pool, state_address, "state_address"); + + // ---------- input: hash_length (uint) + + _require_defined(address_pool, hash_length, "hash_length"); + + if (!(typeof hash_length === "number" && (hash_length | 0) === hash_length) || hash_length < 0) { + _free_and_throw_type_error(address_pool, "hash_length must be an unsigned integer"); + } + + // ---------- output hash (buf) + + var hash_length = (hash_length) | 0, + hash = new AllocatedBuf(hash_length), + hash_address = hash.address; + + address_pool.push(hash_address); + + if ((libsodium._crypto_generichash_final(state_address, hash_address, hash_length) | 0) === 0) { + var ret = (libsodium._free(state_address), _format_output(hash, outputFormat)); + _free_all(address_pool); + return ret; + } + _free_and_throw_error(address_pool, "invalid usage"); + } + + function crypto_generichash_init(key, hash_length, outputFormat) { + var address_pool = []; + + _check_output_format(outputFormat); + // ---------- input: key (unsized_buf_optional) + + var key_address = null, key_length = 0; + if (key != undefined) { + key = _any_to_Uint8Array(address_pool, key, "key"); + key_address = _to_allocated_buf_address(key); + key_length = key.length; + address_pool.push(key_address); + } + + + // ---------- input: hash_length (uint) + + _require_defined(address_pool, hash_length, "hash_length"); + + if (!(typeof hash_length === "number" && (hash_length | 0) === hash_length) || hash_length < 0) { + _free_and_throw_type_error(address_pool, "hash_length must be an unsigned integer"); + } + + // ---------- output state (generichash_state) + + var state_address = new AllocatedBuf(357).address; + + if ((libsodium._crypto_generichash_init(state_address, key_address, key_length, hash_length) | 0) === 0) { + var ret = state_address; + _free_all(address_pool); + return ret; + } + _free_and_throw_error(address_pool, "invalid usage"); + } + + function crypto_generichash_keygen(outputFormat) { + var address_pool = []; + + _check_output_format(outputFormat); + // ---------- output output (buf) + + var output_length = (libsodium._crypto_generichash_keybytes()) | 0, + output = new AllocatedBuf(output_length), + output_address = output.address; + + address_pool.push(output_address); + + libsodium._crypto_generichash_keygen(output_address); + var ret = (_format_output(output, outputFormat)); + _free_all(address_pool); + return ret; + } + + function crypto_generichash_update(state_address, message_chunk, outputFormat) { + var address_pool = []; + + _check_output_format(outputFormat); + // ---------- input: state_address (generichash_state_address) + + _require_defined(address_pool, state_address, "state_address"); + + // ---------- input: message_chunk (unsized_buf) + + message_chunk = _any_to_Uint8Array(address_pool, message_chunk, "message_chunk"); + var message_chunk_address = _to_allocated_buf_address(message_chunk), + message_chunk_length = message_chunk.length; + address_pool.push(message_chunk_address); + + if (!((libsodium._crypto_generichash_update(state_address, message_chunk_address, message_chunk_length) | 0) === 0)) { + _free_and_throw_error(address_pool, "invalid usage"); + } + _free_all(address_pool); + } + + function crypto_hash(message, outputFormat) { + var address_pool = []; + + _check_output_format(outputFormat); + // ---------- input: message (unsized_buf) + + message = _any_to_Uint8Array(address_pool, message, "message"); + var message_address = _to_allocated_buf_address(message), + message_length = message.length; + address_pool.push(message_address); + + // ---------- output hash (buf) + + var hash_length = (libsodium._crypto_hash_bytes()) | 0, + hash = new AllocatedBuf(hash_length), + hash_address = hash.address; + + address_pool.push(hash_address); + + if ((libsodium._crypto_hash(hash_address, message_address, message_length, 0) | 0) === 0) { + var ret = _format_output(hash, outputFormat); + _free_all(address_pool); + return ret; + } + _free_and_throw_error(address_pool, "invalid usage"); + } + + function crypto_hash_sha256(message, outputFormat) { + var address_pool = []; + + _check_output_format(outputFormat); + // ---------- input: message (unsized_buf) + + message = _any_to_Uint8Array(address_pool, message, "message"); + var message_address = _to_allocated_buf_address(message), + message_length = message.length; + address_pool.push(message_address); + + // ---------- output hash (buf) + + var hash_length = (libsodium._crypto_hash_sha256_bytes()) | 0, + hash = new AllocatedBuf(hash_length), + hash_address = hash.address; + + address_pool.push(hash_address); + + if ((libsodium._crypto_hash_sha256(hash_address, message_address, message_length, 0) | 0) === 0) { + var ret = _format_output(hash, outputFormat); + _free_all(address_pool); + return ret; + } + _free_and_throw_error(address_pool, "invalid usage"); + } + + function crypto_hash_sha256_final(state_address, outputFormat) { + var address_pool = []; + + _check_output_format(outputFormat); + // ---------- input: state_address (hash_sha256_state_address) + + _require_defined(address_pool, state_address, "state_address"); + + // ---------- output hash (buf) + + var hash_length = (libsodium._crypto_hash_sha256_bytes()) | 0, + hash = new AllocatedBuf(hash_length), + hash_address = hash.address; + + address_pool.push(hash_address); + + if ((libsodium._crypto_hash_sha256_final(state_address, hash_address) | 0) === 0) { + var ret = (libsodium._free(state_address), _format_output(hash, outputFormat)); + _free_all(address_pool); + return ret; + } + _free_and_throw_error(address_pool, "invalid usage"); + } + + function crypto_hash_sha256_init(outputFormat) { + var address_pool = []; + + _check_output_format(outputFormat); + // ---------- output state (hash_sha256_state) + + var state_address = new AllocatedBuf(104).address; + + if ((libsodium._crypto_hash_sha256_init(state_address) | 0) === 0) { + var ret = state_address; + _free_all(address_pool); + return ret; + } + _free_and_throw_error(address_pool, "invalid usage"); + } + + function crypto_hash_sha256_update(state_address, message_chunk, outputFormat) { + var address_pool = []; + + _check_output_format(outputFormat); + // ---------- input: state_address (hash_sha256_state_address) + + _require_defined(address_pool, state_address, "state_address"); + + // ---------- input: message_chunk (unsized_buf) + + message_chunk = _any_to_Uint8Array(address_pool, message_chunk, "message_chunk"); + var message_chunk_address = _to_allocated_buf_address(message_chunk), + message_chunk_length = message_chunk.length; + address_pool.push(message_chunk_address); + + if (!((libsodium._crypto_hash_sha256_update(state_address, message_chunk_address, message_chunk_length) | 0) === 0)) { + _free_and_throw_error(address_pool, "invalid usage"); + } + _free_all(address_pool); + } + + function crypto_hash_sha512(message, outputFormat) { + var address_pool = []; + + _check_output_format(outputFormat); + // ---------- input: message (unsized_buf) + + message = _any_to_Uint8Array(address_pool, message, "message"); + var message_address = _to_allocated_buf_address(message), + message_length = message.length; + address_pool.push(message_address); + + // ---------- output hash (buf) + + var hash_length = (libsodium._crypto_hash_sha512_bytes()) | 0, + hash = new AllocatedBuf(hash_length), + hash_address = hash.address; + + address_pool.push(hash_address); + + if ((libsodium._crypto_hash_sha512(hash_address, message_address, message_length, 0) | 0) === 0) { + var ret = _format_output(hash, outputFormat); + _free_all(address_pool); + return ret; + } + _free_and_throw_error(address_pool, "invalid usage"); + } + + function crypto_hash_sha512_final(state_address, outputFormat) { + var address_pool = []; + + _check_output_format(outputFormat); + // ---------- input: state_address (hash_sha512_state_address) + + _require_defined(address_pool, state_address, "state_address"); + + // ---------- output hash (buf) + + var hash_length = (libsodium._crypto_hash_sha512_bytes()) | 0, + hash = new AllocatedBuf(hash_length), + hash_address = hash.address; + + address_pool.push(hash_address); + + if ((libsodium._crypto_hash_sha512_final(state_address, hash_address) | 0) === 0) { + var ret = (libsodium._free(state_address), _format_output(hash, outputFormat)); + _free_all(address_pool); + return ret; + } + _free_and_throw_error(address_pool, "invalid usage"); + } + + function crypto_hash_sha512_init(outputFormat) { + var address_pool = []; + + _check_output_format(outputFormat); + // ---------- output state (hash_sha512_state) + + var state_address = new AllocatedBuf(208).address; + + if ((libsodium._crypto_hash_sha512_init(state_address) | 0) === 0) { + var ret = state_address; + _free_all(address_pool); + return ret; + } + _free_and_throw_error(address_pool, "invalid usage"); + } + + function crypto_hash_sha512_update(state_address, message_chunk, outputFormat) { + var address_pool = []; + + _check_output_format(outputFormat); + // ---------- input: state_address (hash_sha512_state_address) + + _require_defined(address_pool, state_address, "state_address"); + + // ---------- input: message_chunk (unsized_buf) + + message_chunk = _any_to_Uint8Array(address_pool, message_chunk, "message_chunk"); + var message_chunk_address = _to_allocated_buf_address(message_chunk), + message_chunk_length = message_chunk.length; + address_pool.push(message_chunk_address); + + if (!((libsodium._crypto_hash_sha512_update(state_address, message_chunk_address, message_chunk_length) | 0) === 0)) { + _free_and_throw_error(address_pool, "invalid usage"); + } + _free_all(address_pool); + } + + function crypto_kdf_derive_from_key(subkey_len, subkey_id, ctx, key, outputFormat) { + var address_pool = []; + + _check_output_format(outputFormat); + // ---------- input: subkey_len (uint) + + _require_defined(address_pool, subkey_len, "subkey_len"); + + if (!(typeof subkey_len === "number" && (subkey_len | 0) === subkey_len) || subkey_len < 0) { + _free_and_throw_type_error(address_pool, "subkey_len must be an unsigned integer"); + } + + // ---------- input: subkey_id (uint) + + _require_defined(address_pool, subkey_id, "subkey_id"); + + if (!(typeof subkey_id === "number" && (subkey_id | 0) === subkey_id) || subkey_id < 0) { + _free_and_throw_type_error(address_pool, "subkey_id must be an unsigned integer"); + } + + // ---------- input: ctx (string) + + if (typeof ctx !== "string") { + _free_and_throw_type_error(address_pool, "ctx must be a string"); + } + ctx = from_string(ctx + "\0"); + if (ctx_length != undefined && ctx.length - 1 !== ctx_length) { + _free_and_throw_type_error(address_pool, "invalid ctx length"); + } + var ctx_address = _to_allocated_buf_address(ctx), + ctx_length = ctx.length - 1; + address_pool.push(ctx_address); + + // ---------- input: key (buf) + + key = _any_to_Uint8Array(address_pool, key, "key"); + var key_address, key_length = (libsodium._crypto_kdf_keybytes()) | 0; + if (key.length !== key_length) { + _free_and_throw_type_error(address_pool, "invalid key length"); + } + key_address = _to_allocated_buf_address(key); + address_pool.push(key_address); + + // ---------- output subkey (buf) + + var subkey_length = (subkey_len) | 0, + subkey = new AllocatedBuf(subkey_length), + subkey_address = subkey.address; + + address_pool.push(subkey_address); + + libsodium._crypto_kdf_derive_from_key(subkey_address, subkey_len, subkey_id, (subkey_id >>> 24) >>> 8, ctx_address, key_address); + var ret = (_format_output(subkey, outputFormat)); + _free_all(address_pool); + return ret; + } + + function crypto_kdf_keygen(outputFormat) { + var address_pool = []; + + _check_output_format(outputFormat); + // ---------- output output (buf) + + var output_length = (libsodium._crypto_kdf_keybytes()) | 0, + output = new AllocatedBuf(output_length), + output_address = output.address; + + address_pool.push(output_address); + + libsodium._crypto_kdf_keygen(output_address); + var ret = (_format_output(output, outputFormat)); + _free_all(address_pool); + return ret; + } + + function crypto_kx_client_session_keys(clientPublicKey, clientSecretKey, serverPublicKey, outputFormat) { + var address_pool = []; + + _check_output_format(outputFormat); + // ---------- input: clientPublicKey (buf) + + clientPublicKey = _any_to_Uint8Array(address_pool, clientPublicKey, "clientPublicKey"); + var clientPublicKey_address, clientPublicKey_length = (libsodium._crypto_kx_publickeybytes()) | 0; + if (clientPublicKey.length !== clientPublicKey_length) { + _free_and_throw_type_error(address_pool, "invalid clientPublicKey length"); + } + clientPublicKey_address = _to_allocated_buf_address(clientPublicKey); + address_pool.push(clientPublicKey_address); + + // ---------- input: clientSecretKey (buf) + + clientSecretKey = _any_to_Uint8Array(address_pool, clientSecretKey, "clientSecretKey"); + var clientSecretKey_address, clientSecretKey_length = (libsodium._crypto_kx_secretkeybytes()) | 0; + if (clientSecretKey.length !== clientSecretKey_length) { + _free_and_throw_type_error(address_pool, "invalid clientSecretKey length"); + } + clientSecretKey_address = _to_allocated_buf_address(clientSecretKey); + address_pool.push(clientSecretKey_address); + + // ---------- input: serverPublicKey (buf) + + serverPublicKey = _any_to_Uint8Array(address_pool, serverPublicKey, "serverPublicKey"); + var serverPublicKey_address, serverPublicKey_length = (libsodium._crypto_kx_publickeybytes()) | 0; + if (serverPublicKey.length !== serverPublicKey_length) { + _free_and_throw_type_error(address_pool, "invalid serverPublicKey length"); + } + serverPublicKey_address = _to_allocated_buf_address(serverPublicKey); + address_pool.push(serverPublicKey_address); + + // ---------- output sharedRx (buf) + + var sharedRx_length = (libsodium._crypto_kx_sessionkeybytes()) | 0, + sharedRx = new AllocatedBuf(sharedRx_length), + sharedRx_address = sharedRx.address; + + address_pool.push(sharedRx_address); + + // ---------- output sharedTx (buf) + + var sharedTx_length = (libsodium._crypto_kx_sessionkeybytes()) | 0, + sharedTx = new AllocatedBuf(sharedTx_length), + sharedTx_address = sharedTx.address; + + address_pool.push(sharedTx_address); + + if ((libsodium._crypto_kx_client_session_keys(sharedRx_address, sharedTx_address, clientPublicKey_address, clientSecretKey_address, serverPublicKey_address) | 0) === 0) { + var ret = _format_output({sharedRx: sharedRx, sharedTx: sharedTx}, outputFormat); + _free_all(address_pool); + return ret; + } + _free_and_throw_error(address_pool, "invalid usage"); + } + + function crypto_kx_keypair(outputFormat) { + var address_pool = []; + + _check_output_format(outputFormat); + // ---------- output publicKey (buf) + + var publicKey_length = (libsodium._crypto_kx_publickeybytes()) | 0, + publicKey = new AllocatedBuf(publicKey_length), + publicKey_address = publicKey.address; + + address_pool.push(publicKey_address); + + // ---------- output privateKey (buf) + + var privateKey_length = (libsodium._crypto_kx_secretkeybytes()) | 0, + privateKey = new AllocatedBuf(privateKey_length), + privateKey_address = privateKey.address; + + address_pool.push(privateKey_address); + + if ((libsodium._crypto_kx_keypair(publicKey_address, privateKey_address) | 0) === 0) { + var ret = {publicKey: _format_output(publicKey, outputFormat), privateKey: _format_output(privateKey, outputFormat), keyType: 'x25519'}; + _free_all(address_pool); + return ret; + } + _free_and_throw_error(address_pool, "internal error"); + } + + function crypto_kx_seed_keypair(seed, outputFormat) { + var address_pool = []; + + _check_output_format(outputFormat); + // ---------- input: seed (buf) + + seed = _any_to_Uint8Array(address_pool, seed, "seed"); + var seed_address, seed_length = (libsodium._crypto_kx_seedbytes()) | 0; + if (seed.length !== seed_length) { + _free_and_throw_type_error(address_pool, "invalid seed length"); + } + seed_address = _to_allocated_buf_address(seed); + address_pool.push(seed_address); + + // ---------- output publicKey (buf) + + var publicKey_length = (libsodium._crypto_kx_publickeybytes()) | 0, + publicKey = new AllocatedBuf(publicKey_length), + publicKey_address = publicKey.address; + + address_pool.push(publicKey_address); + + // ---------- output privateKey (buf) + + var privateKey_length = (libsodium._crypto_kx_secretkeybytes()) | 0, + privateKey = new AllocatedBuf(privateKey_length), + privateKey_address = privateKey.address; + + address_pool.push(privateKey_address); + + if ((libsodium._crypto_kx_seed_keypair(publicKey_address, privateKey_address, seed_address) | 0) === 0) { + var ret = {publicKey: _format_output(publicKey, outputFormat), privateKey: _format_output(privateKey, outputFormat), keyType: 'x25519'}; + _free_all(address_pool); + return ret; + } + _free_and_throw_error(address_pool, "internal error"); + } + + function crypto_kx_server_session_keys(serverPublicKey, serverSecretKey, clientPublicKey, outputFormat) { + var address_pool = []; + + _check_output_format(outputFormat); + // ---------- input: serverPublicKey (buf) + + serverPublicKey = _any_to_Uint8Array(address_pool, serverPublicKey, "serverPublicKey"); + var serverPublicKey_address, serverPublicKey_length = (libsodium._crypto_kx_publickeybytes()) | 0; + if (serverPublicKey.length !== serverPublicKey_length) { + _free_and_throw_type_error(address_pool, "invalid serverPublicKey length"); + } + serverPublicKey_address = _to_allocated_buf_address(serverPublicKey); + address_pool.push(serverPublicKey_address); + + // ---------- input: serverSecretKey (buf) + + serverSecretKey = _any_to_Uint8Array(address_pool, serverSecretKey, "serverSecretKey"); + var serverSecretKey_address, serverSecretKey_length = (libsodium._crypto_kx_secretkeybytes()) | 0; + if (serverSecretKey.length !== serverSecretKey_length) { + _free_and_throw_type_error(address_pool, "invalid serverSecretKey length"); + } + serverSecretKey_address = _to_allocated_buf_address(serverSecretKey); + address_pool.push(serverSecretKey_address); + + // ---------- input: clientPublicKey (buf) + + clientPublicKey = _any_to_Uint8Array(address_pool, clientPublicKey, "clientPublicKey"); + var clientPublicKey_address, clientPublicKey_length = (libsodium._crypto_kx_publickeybytes()) | 0; + if (clientPublicKey.length !== clientPublicKey_length) { + _free_and_throw_type_error(address_pool, "invalid clientPublicKey length"); + } + clientPublicKey_address = _to_allocated_buf_address(clientPublicKey); + address_pool.push(clientPublicKey_address); + + // ---------- output sharedRx (buf) + + var sharedRx_length = (libsodium._crypto_kx_sessionkeybytes()) | 0, + sharedRx = new AllocatedBuf(sharedRx_length), + sharedRx_address = sharedRx.address; + + address_pool.push(sharedRx_address); + + // ---------- output sharedTx (buf) + + var sharedTx_length = (libsodium._crypto_kx_sessionkeybytes()) | 0, + sharedTx = new AllocatedBuf(sharedTx_length), + sharedTx_address = sharedTx.address; + + address_pool.push(sharedTx_address); + + if ((libsodium._crypto_kx_server_session_keys(sharedRx_address, sharedTx_address, serverPublicKey_address, serverSecretKey_address, clientPublicKey_address) | 0) === 0) { + var ret = _format_output({sharedRx: sharedRx, sharedTx: sharedTx}, outputFormat); + _free_all(address_pool); + return ret; + } + _free_and_throw_error(address_pool, "invalid usage"); + } + + function crypto_onetimeauth(message, key, outputFormat) { + var address_pool = []; + + _check_output_format(outputFormat); + // ---------- input: message (unsized_buf) + + message = _any_to_Uint8Array(address_pool, message, "message"); + var message_address = _to_allocated_buf_address(message), + message_length = message.length; + address_pool.push(message_address); + + // ---------- input: key (buf) + + key = _any_to_Uint8Array(address_pool, key, "key"); + var key_address, key_length = (libsodium._crypto_onetimeauth_keybytes()) | 0; + if (key.length !== key_length) { + _free_and_throw_type_error(address_pool, "invalid key length"); + } + key_address = _to_allocated_buf_address(key); + address_pool.push(key_address); + + // ---------- output hash (buf) + + var hash_length = (libsodium._crypto_onetimeauth_bytes()) | 0, + hash = new AllocatedBuf(hash_length), + hash_address = hash.address; + + address_pool.push(hash_address); + + if ((libsodium._crypto_onetimeauth(hash_address, message_address, message_length, 0, key_address) | 0) === 0) { + var ret = _format_output(hash, outputFormat); + _free_all(address_pool); + return ret; + } + _free_and_throw_error(address_pool, "invalid usage"); + } + + function crypto_onetimeauth_final(state_address, outputFormat) { + var address_pool = []; + + _check_output_format(outputFormat); + // ---------- input: state_address (onetimeauth_state_address) + + _require_defined(address_pool, state_address, "state_address"); + + // ---------- output hash (buf) + + var hash_length = (libsodium._crypto_onetimeauth_bytes()) | 0, + hash = new AllocatedBuf(hash_length), + hash_address = hash.address; + + address_pool.push(hash_address); + + if ((libsodium._crypto_onetimeauth_final(state_address, hash_address) | 0) === 0) { + var ret = (libsodium._free(state_address), _format_output(hash, outputFormat)); + _free_all(address_pool); + return ret; + } + _free_and_throw_error(address_pool, "invalid usage"); + } + + function crypto_onetimeauth_init(key, outputFormat) { + var address_pool = []; + + _check_output_format(outputFormat); + // ---------- input: key (unsized_buf_optional) + + var key_address = null, key_length = 0; + if (key != undefined) { + key = _any_to_Uint8Array(address_pool, key, "key"); + key_address = _to_allocated_buf_address(key); + key_length = key.length; + address_pool.push(key_address); + } + + + // ---------- output state (onetimeauth_state) + + var state_address = new AllocatedBuf(144).address; + + if ((libsodium._crypto_onetimeauth_init(state_address, key_address) | 0) === 0) { + var ret = state_address; + _free_all(address_pool); + return ret; + } + _free_and_throw_error(address_pool, "invalid usage"); + } + + function crypto_onetimeauth_keygen(outputFormat) { + var address_pool = []; + + _check_output_format(outputFormat); + // ---------- output output (buf) + + var output_length = (libsodium._crypto_onetimeauth_keybytes()) | 0, + output = new AllocatedBuf(output_length), + output_address = output.address; + + address_pool.push(output_address); + + libsodium._crypto_onetimeauth_keygen(output_address); + var ret = (_format_output(output, outputFormat)); + _free_all(address_pool); + return ret; + } + + function crypto_onetimeauth_update(state_address, message_chunk, outputFormat) { + var address_pool = []; + + _check_output_format(outputFormat); + // ---------- input: state_address (onetimeauth_state_address) + + _require_defined(address_pool, state_address, "state_address"); + + // ---------- input: message_chunk (unsized_buf) + + message_chunk = _any_to_Uint8Array(address_pool, message_chunk, "message_chunk"); + var message_chunk_address = _to_allocated_buf_address(message_chunk), + message_chunk_length = message_chunk.length; + address_pool.push(message_chunk_address); + + if (!((libsodium._crypto_onetimeauth_update(state_address, message_chunk_address, message_chunk_length) | 0) === 0)) { + _free_and_throw_error(address_pool, "invalid usage"); + } + _free_all(address_pool); + } + + function crypto_onetimeauth_verify(hash, message, key) { + var address_pool = []; + + // ---------- input: hash (buf) + + hash = _any_to_Uint8Array(address_pool, hash, "hash"); + var hash_address, hash_length = (libsodium._crypto_onetimeauth_bytes()) | 0; + if (hash.length !== hash_length) { + _free_and_throw_type_error(address_pool, "invalid hash length"); + } + hash_address = _to_allocated_buf_address(hash); + address_pool.push(hash_address); + + // ---------- input: message (unsized_buf) + + message = _any_to_Uint8Array(address_pool, message, "message"); + var message_address = _to_allocated_buf_address(message), + message_length = message.length; + address_pool.push(message_address); + + // ---------- input: key (buf) + + key = _any_to_Uint8Array(address_pool, key, "key"); + var key_address, key_length = (libsodium._crypto_onetimeauth_keybytes()) | 0; + if (key.length !== key_length) { + _free_and_throw_type_error(address_pool, "invalid key length"); + } + key_address = _to_allocated_buf_address(key); + address_pool.push(key_address); + + var result = libsodium._crypto_onetimeauth_verify(hash_address, message_address, message_length, 0, key_address) | 0; + var ret = (result === 0); + _free_all(address_pool); + return ret; + } + + function crypto_pwhash(keyLength, password, salt, opsLimit, memLimit, algorithm, outputFormat) { + var address_pool = []; + + _check_output_format(outputFormat); + // ---------- input: keyLength (uint) + + _require_defined(address_pool, keyLength, "keyLength"); + + if (!(typeof keyLength === "number" && (keyLength | 0) === keyLength) || keyLength < 0) { + _free_and_throw_type_error(address_pool, "keyLength must be an unsigned integer"); + } + + // ---------- input: password (unsized_buf) + + password = _any_to_Uint8Array(address_pool, password, "password"); + var password_address = _to_allocated_buf_address(password), + password_length = password.length; + address_pool.push(password_address); + + // ---------- input: salt (buf) + + salt = _any_to_Uint8Array(address_pool, salt, "salt"); + var salt_address, salt_length = (libsodium._crypto_pwhash_saltbytes()) | 0; + if (salt.length !== salt_length) { + _free_and_throw_type_error(address_pool, "invalid salt length"); + } + salt_address = _to_allocated_buf_address(salt); + address_pool.push(salt_address); + + // ---------- input: opsLimit (uint) + + _require_defined(address_pool, opsLimit, "opsLimit"); + + if (!(typeof opsLimit === "number" && (opsLimit | 0) === opsLimit) || opsLimit < 0) { + _free_and_throw_type_error(address_pool, "opsLimit must be an unsigned integer"); + } + + // ---------- input: memLimit (uint) + + _require_defined(address_pool, memLimit, "memLimit"); + + if (!(typeof memLimit === "number" && (memLimit | 0) === memLimit) || memLimit < 0) { + _free_and_throw_type_error(address_pool, "memLimit must be an unsigned integer"); + } + + // ---------- input: algorithm (uint) + + _require_defined(address_pool, algorithm, "algorithm"); + + if (!(typeof algorithm === "number" && (algorithm | 0) === algorithm) || algorithm < 0) { + _free_and_throw_type_error(address_pool, "algorithm must be an unsigned integer"); + } + + // ---------- output derivedKey (buf) + + var derivedKey_length = (keyLength) | 0, + derivedKey = new AllocatedBuf(derivedKey_length), + derivedKey_address = derivedKey.address; + + address_pool.push(derivedKey_address); + + if ((libsodium._crypto_pwhash(derivedKey_address, keyLength, 0, password_address, password_length, 0, salt_address, opsLimit, 0, memLimit, algorithm) | 0) === 0) { + var ret = _format_output(derivedKey, outputFormat); + _free_all(address_pool); + return ret; + } + _free_and_throw_error(address_pool, "invalid usage"); + } + + function crypto_pwhash_scryptsalsa208sha256(keyLength, password, salt, opsLimit, memLimit, outputFormat) { + var address_pool = []; + + _check_output_format(outputFormat); + // ---------- input: keyLength (uint) + + _require_defined(address_pool, keyLength, "keyLength"); + + if (!(typeof keyLength === "number" && (keyLength | 0) === keyLength) || keyLength < 0) { + _free_and_throw_type_error(address_pool, "keyLength must be an unsigned integer"); + } + + // ---------- input: password (unsized_buf) + + password = _any_to_Uint8Array(address_pool, password, "password"); + var password_address = _to_allocated_buf_address(password), + password_length = password.length; + address_pool.push(password_address); + + // ---------- input: salt (buf) + + salt = _any_to_Uint8Array(address_pool, salt, "salt"); + var salt_address, salt_length = (libsodium._crypto_pwhash_scryptsalsa208sha256_saltbytes()) | 0; + if (salt.length !== salt_length) { + _free_and_throw_type_error(address_pool, "invalid salt length"); + } + salt_address = _to_allocated_buf_address(salt); + address_pool.push(salt_address); + + // ---------- input: opsLimit (uint) + + _require_defined(address_pool, opsLimit, "opsLimit"); + + if (!(typeof opsLimit === "number" && (opsLimit | 0) === opsLimit) || opsLimit < 0) { + _free_and_throw_type_error(address_pool, "opsLimit must be an unsigned integer"); + } + + // ---------- input: memLimit (uint) + + _require_defined(address_pool, memLimit, "memLimit"); + + if (!(typeof memLimit === "number" && (memLimit | 0) === memLimit) || memLimit < 0) { + _free_and_throw_type_error(address_pool, "memLimit must be an unsigned integer"); + } + + // ---------- output derivedKey (buf) + + var derivedKey_length = (keyLength) | 0, + derivedKey = new AllocatedBuf(derivedKey_length), + derivedKey_address = derivedKey.address; + + address_pool.push(derivedKey_address); + + if ((libsodium._crypto_pwhash_scryptsalsa208sha256(derivedKey_address, keyLength, 0, password_address, password_length, 0, salt_address, opsLimit, 0, memLimit) | 0) === 0) { + var ret = _format_output(derivedKey, outputFormat); + _free_all(address_pool); + return ret; + } + _free_and_throw_error(address_pool, "invalid usage"); + } + + function crypto_pwhash_scryptsalsa208sha256_ll(password, salt, opsLimit, r, p, keyLength, outputFormat) { + var address_pool = []; + + _check_output_format(outputFormat); + // ---------- input: password (unsized_buf) + + password = _any_to_Uint8Array(address_pool, password, "password"); + var password_address = _to_allocated_buf_address(password), + password_length = password.length; + address_pool.push(password_address); + + // ---------- input: salt (unsized_buf) + + salt = _any_to_Uint8Array(address_pool, salt, "salt"); + var salt_address = _to_allocated_buf_address(salt), + salt_length = salt.length; + address_pool.push(salt_address); + + // ---------- input: opsLimit (uint) + + _require_defined(address_pool, opsLimit, "opsLimit"); + + if (!(typeof opsLimit === "number" && (opsLimit | 0) === opsLimit) || opsLimit < 0) { + _free_and_throw_type_error(address_pool, "opsLimit must be an unsigned integer"); + } + + // ---------- input: r (uint) + + _require_defined(address_pool, r, "r"); + + if (!(typeof r === "number" && (r | 0) === r) || r < 0) { + _free_and_throw_type_error(address_pool, "r must be an unsigned integer"); + } + + // ---------- input: p (uint) + + _require_defined(address_pool, p, "p"); + + if (!(typeof p === "number" && (p | 0) === p) || p < 0) { + _free_and_throw_type_error(address_pool, "p must be an unsigned integer"); + } + + // ---------- input: keyLength (uint) + + _require_defined(address_pool, keyLength, "keyLength"); + + if (!(typeof keyLength === "number" && (keyLength | 0) === keyLength) || keyLength < 0) { + _free_and_throw_type_error(address_pool, "keyLength must be an unsigned integer"); + } + + // ---------- output derivedKey (buf) + + var derivedKey_length = (keyLength) | 0, + derivedKey = new AllocatedBuf(derivedKey_length), + derivedKey_address = derivedKey.address; + + address_pool.push(derivedKey_address); + + if ((libsodium._crypto_pwhash_scryptsalsa208sha256_ll(password_address, password_length, salt_address, salt_length, opsLimit, 0, r, p, derivedKey_address, keyLength) | 0) === 0) { + var ret = _format_output(derivedKey, outputFormat); + _free_all(address_pool); + return ret; + } + _free_and_throw_error(address_pool, "invalid usage"); + } + + function crypto_pwhash_scryptsalsa208sha256_str(password, opsLimit, memLimit, outputFormat) { + var address_pool = []; + + _check_output_format(outputFormat); + // ---------- input: password (unsized_buf) + + password = _any_to_Uint8Array(address_pool, password, "password"); + var password_address = _to_allocated_buf_address(password), + password_length = password.length; + address_pool.push(password_address); + + // ---------- input: opsLimit (uint) + + _require_defined(address_pool, opsLimit, "opsLimit"); + + if (!(typeof opsLimit === "number" && (opsLimit | 0) === opsLimit) || opsLimit < 0) { + _free_and_throw_type_error(address_pool, "opsLimit must be an unsigned integer"); + } + + // ---------- input: memLimit (uint) + + _require_defined(address_pool, memLimit, "memLimit"); + + if (!(typeof memLimit === "number" && (memLimit | 0) === memLimit) || memLimit < 0) { + _free_and_throw_type_error(address_pool, "memLimit must be an unsigned integer"); + } + + // ---------- output hashed_password (buf) + + var hashed_password_length = (libsodium._crypto_pwhash_scryptsalsa208sha256_strbytes()) | 0, + hashed_password = new AllocatedBuf(hashed_password_length), + hashed_password_address = hashed_password.address; + + address_pool.push(hashed_password_address); + + if ((libsodium._crypto_pwhash_scryptsalsa208sha256_str(hashed_password_address, password_address, password_length, 0, opsLimit, 0, memLimit) | 0) === 0) { + var ret = libsodium.UTF8ToString(hashed_password_address); + _free_all(address_pool); + return ret; + } + _free_and_throw_error(address_pool, "invalid usage"); + } + + function crypto_pwhash_scryptsalsa208sha256_str_verify(hashed_password, password, outputFormat) { + var address_pool = []; + + _check_output_format(outputFormat); + // ---------- input: hashed_password (string) + + if (typeof hashed_password !== "string") { + _free_and_throw_type_error(address_pool, "hashed_password must be a string"); + } + hashed_password = from_string(hashed_password + "\0"); + if (hashed_password_length != undefined && hashed_password.length - 1 !== hashed_password_length) { + _free_and_throw_type_error(address_pool, "invalid hashed_password length"); + } + var hashed_password_address = _to_allocated_buf_address(hashed_password), + hashed_password_length = hashed_password.length - 1; + address_pool.push(hashed_password_address); + + // ---------- input: password (unsized_buf) + + password = _any_to_Uint8Array(address_pool, password, "password"); + var password_address = _to_allocated_buf_address(password), + password_length = password.length; + address_pool.push(password_address); + + var result = libsodium._crypto_pwhash_scryptsalsa208sha256_str_verify(hashed_password_address, password_address, password_length, 0) | 0; + var ret = (result === 0); + _free_all(address_pool); + return ret; + } + + function crypto_pwhash_str(password, opsLimit, memLimit, outputFormat) { + var address_pool = []; + + _check_output_format(outputFormat); + // ---------- input: password (unsized_buf) + + password = _any_to_Uint8Array(address_pool, password, "password"); + var password_address = _to_allocated_buf_address(password), + password_length = password.length; + address_pool.push(password_address); + + // ---------- input: opsLimit (uint) + + _require_defined(address_pool, opsLimit, "opsLimit"); + + if (!(typeof opsLimit === "number" && (opsLimit | 0) === opsLimit) || opsLimit < 0) { + _free_and_throw_type_error(address_pool, "opsLimit must be an unsigned integer"); + } + + // ---------- input: memLimit (uint) + + _require_defined(address_pool, memLimit, "memLimit"); + + if (!(typeof memLimit === "number" && (memLimit | 0) === memLimit) || memLimit < 0) { + _free_and_throw_type_error(address_pool, "memLimit must be an unsigned integer"); + } + + // ---------- output hashed_password (buf) + + var hashed_password_length = (libsodium._crypto_pwhash_strbytes()) | 0, + hashed_password = new AllocatedBuf(hashed_password_length), + hashed_password_address = hashed_password.address; + + address_pool.push(hashed_password_address); + + if ((libsodium._crypto_pwhash_str(hashed_password_address, password_address, password_length, 0, opsLimit, 0, memLimit) | 0) === 0) { + var ret = libsodium.UTF8ToString(hashed_password_address); + _free_all(address_pool); + return ret; + } + _free_and_throw_error(address_pool, "invalid usage"); + } + + function crypto_pwhash_str_needs_rehash(hashed_password, opsLimit, memLimit, outputFormat) { + var address_pool = []; + + _check_output_format(outputFormat); + // ---------- input: hashed_password (string) + + if (typeof hashed_password !== "string") { + _free_and_throw_type_error(address_pool, "hashed_password must be a string"); + } + hashed_password = from_string(hashed_password + "\0"); + if (hashed_password_length != undefined && hashed_password.length - 1 !== hashed_password_length) { + _free_and_throw_type_error(address_pool, "invalid hashed_password length"); + } + var hashed_password_address = _to_allocated_buf_address(hashed_password), + hashed_password_length = hashed_password.length - 1; + address_pool.push(hashed_password_address); + + // ---------- input: opsLimit (uint) + + _require_defined(address_pool, opsLimit, "opsLimit"); + + if (!(typeof opsLimit === "number" && (opsLimit | 0) === opsLimit) || opsLimit < 0) { + _free_and_throw_type_error(address_pool, "opsLimit must be an unsigned integer"); + } + + // ---------- input: memLimit (uint) + + _require_defined(address_pool, memLimit, "memLimit"); + + if (!(typeof memLimit === "number" && (memLimit | 0) === memLimit) || memLimit < 0) { + _free_and_throw_type_error(address_pool, "memLimit must be an unsigned integer"); + } + + var result = libsodium._crypto_pwhash_str_needs_rehash(hashed_password_address, opsLimit, 0, memLimit) | 0; + var ret = (result !== 0); + _free_all(address_pool); + return ret; + } + + function crypto_pwhash_str_verify(hashed_password, password, outputFormat) { + var address_pool = []; + + _check_output_format(outputFormat); + // ---------- input: hashed_password (string) + + if (typeof hashed_password !== "string") { + _free_and_throw_type_error(address_pool, "hashed_password must be a string"); + } + hashed_password = from_string(hashed_password + "\0"); + if (hashed_password_length != undefined && hashed_password.length - 1 !== hashed_password_length) { + _free_and_throw_type_error(address_pool, "invalid hashed_password length"); + } + var hashed_password_address = _to_allocated_buf_address(hashed_password), + hashed_password_length = hashed_password.length - 1; + address_pool.push(hashed_password_address); + + // ---------- input: password (unsized_buf) + + password = _any_to_Uint8Array(address_pool, password, "password"); + var password_address = _to_allocated_buf_address(password), + password_length = password.length; + address_pool.push(password_address); + + var result = libsodium._crypto_pwhash_str_verify(hashed_password_address, password_address, password_length, 0) | 0; + var ret = (result === 0); + _free_all(address_pool); + return ret; + } + + function crypto_scalarmult(privateKey, publicKey, outputFormat) { + var address_pool = []; + + _check_output_format(outputFormat); + // ---------- input: privateKey (buf) + + privateKey = _any_to_Uint8Array(address_pool, privateKey, "privateKey"); + var privateKey_address, privateKey_length = (libsodium._crypto_scalarmult_scalarbytes()) | 0; + if (privateKey.length !== privateKey_length) { + _free_and_throw_type_error(address_pool, "invalid privateKey length"); + } + privateKey_address = _to_allocated_buf_address(privateKey); + address_pool.push(privateKey_address); + + // ---------- input: publicKey (buf) + + publicKey = _any_to_Uint8Array(address_pool, publicKey, "publicKey"); + var publicKey_address, publicKey_length = (libsodium._crypto_scalarmult_bytes()) | 0; + if (publicKey.length !== publicKey_length) { + _free_and_throw_type_error(address_pool, "invalid publicKey length"); + } + publicKey_address = _to_allocated_buf_address(publicKey); + address_pool.push(publicKey_address); + + // ---------- output sharedSecret (buf) + + var sharedSecret_length = (libsodium._crypto_scalarmult_bytes()) | 0, + sharedSecret = new AllocatedBuf(sharedSecret_length), + sharedSecret_address = sharedSecret.address; + + address_pool.push(sharedSecret_address); + + if ((libsodium._crypto_scalarmult(sharedSecret_address, privateKey_address, publicKey_address) | 0) === 0) { + var ret = _format_output(sharedSecret, outputFormat); + _free_all(address_pool); + return ret; + } + _free_and_throw_error(address_pool, "weak public key"); + } + + function crypto_scalarmult_base(privateKey, outputFormat) { + var address_pool = []; + + _check_output_format(outputFormat); + // ---------- input: privateKey (buf) + + privateKey = _any_to_Uint8Array(address_pool, privateKey, "privateKey"); + var privateKey_address, privateKey_length = (libsodium._crypto_scalarmult_scalarbytes()) | 0; + if (privateKey.length !== privateKey_length) { + _free_and_throw_type_error(address_pool, "invalid privateKey length"); + } + privateKey_address = _to_allocated_buf_address(privateKey); + address_pool.push(privateKey_address); + + // ---------- output publicKey (buf) + + var publicKey_length = (libsodium._crypto_scalarmult_bytes()) | 0, + publicKey = new AllocatedBuf(publicKey_length), + publicKey_address = publicKey.address; + + address_pool.push(publicKey_address); + + if ((libsodium._crypto_scalarmult_base(publicKey_address, privateKey_address) | 0) === 0) { + var ret = _format_output(publicKey, outputFormat); + _free_all(address_pool); + return ret; + } + _free_and_throw_error(address_pool, "unknown error"); + } + + function crypto_scalarmult_ed25519(n, p, outputFormat) { + var address_pool = []; + + _check_output_format(outputFormat); + // ---------- input: n (buf) + + n = _any_to_Uint8Array(address_pool, n, "n"); + var n_address, n_length = (libsodium._crypto_scalarmult_ed25519_scalarbytes()) | 0; + if (n.length !== n_length) { + _free_and_throw_type_error(address_pool, "invalid n length"); + } + n_address = _to_allocated_buf_address(n); + address_pool.push(n_address); + + // ---------- input: p (buf) + + p = _any_to_Uint8Array(address_pool, p, "p"); + var p_address, p_length = (libsodium._crypto_scalarmult_ed25519_bytes()) | 0; + if (p.length !== p_length) { + _free_and_throw_type_error(address_pool, "invalid p length"); + } + p_address = _to_allocated_buf_address(p); + address_pool.push(p_address); + + // ---------- output q (buf) + + var q_length = (libsodium._crypto_scalarmult_ed25519_bytes()) | 0, + q = new AllocatedBuf(q_length), + q_address = q.address; + + address_pool.push(q_address); + + if ((libsodium._crypto_scalarmult_ed25519(q_address, n_address, p_address) | 0) === 0) { + var ret = _format_output(q, outputFormat); + _free_all(address_pool); + return ret; + } + _free_and_throw_error(address_pool, "invalid point or scalar is 0"); + } + + function crypto_scalarmult_ed25519_base(scalar, outputFormat) { + var address_pool = []; + + _check_output_format(outputFormat); + // ---------- input: scalar (buf) + + scalar = _any_to_Uint8Array(address_pool, scalar, "scalar"); + var scalar_address, scalar_length = (libsodium._crypto_scalarmult_ed25519_scalarbytes()) | 0; + if (scalar.length !== scalar_length) { + _free_and_throw_type_error(address_pool, "invalid scalar length"); + } + scalar_address = _to_allocated_buf_address(scalar); + address_pool.push(scalar_address); + + // ---------- output point (buf) + + var point_length = (libsodium._crypto_scalarmult_ed25519_bytes()) | 0, + point = new AllocatedBuf(point_length), + point_address = point.address; + + address_pool.push(point_address); + + if ((libsodium._crypto_scalarmult_ed25519_base(point_address, scalar_address) | 0) === 0) { + var ret = _format_output(point, outputFormat); + _free_all(address_pool); + return ret; + } + _free_and_throw_error(address_pool, "scalar is 0"); + } + + function crypto_scalarmult_ed25519_base_noclamp(scalar, outputFormat) { + var address_pool = []; + + _check_output_format(outputFormat); + // ---------- input: scalar (buf) + + scalar = _any_to_Uint8Array(address_pool, scalar, "scalar"); + var scalar_address, scalar_length = (libsodium._crypto_scalarmult_ed25519_scalarbytes()) | 0; + if (scalar.length !== scalar_length) { + _free_and_throw_type_error(address_pool, "invalid scalar length"); + } + scalar_address = _to_allocated_buf_address(scalar); + address_pool.push(scalar_address); + + // ---------- output point (buf) + + var point_length = (libsodium._crypto_scalarmult_ed25519_bytes()) | 0, + point = new AllocatedBuf(point_length), + point_address = point.address; + + address_pool.push(point_address); + + if ((libsodium._crypto_scalarmult_ed25519_base_noclamp(point_address, scalar_address) | 0) === 0) { + var ret = _format_output(point, outputFormat); + _free_all(address_pool); + return ret; + } + _free_and_throw_error(address_pool, "scalar is 0"); + } + + function crypto_scalarmult_ed25519_noclamp(n, p, outputFormat) { + var address_pool = []; + + _check_output_format(outputFormat); + // ---------- input: n (buf) + + n = _any_to_Uint8Array(address_pool, n, "n"); + var n_address, n_length = (libsodium._crypto_scalarmult_ed25519_scalarbytes()) | 0; + if (n.length !== n_length) { + _free_and_throw_type_error(address_pool, "invalid n length"); + } + n_address = _to_allocated_buf_address(n); + address_pool.push(n_address); + + // ---------- input: p (buf) + + p = _any_to_Uint8Array(address_pool, p, "p"); + var p_address, p_length = (libsodium._crypto_scalarmult_ed25519_bytes()) | 0; + if (p.length !== p_length) { + _free_and_throw_type_error(address_pool, "invalid p length"); + } + p_address = _to_allocated_buf_address(p); + address_pool.push(p_address); + + // ---------- output q (buf) + + var q_length = (libsodium._crypto_scalarmult_ed25519_bytes()) | 0, + q = new AllocatedBuf(q_length), + q_address = q.address; + + address_pool.push(q_address); + + if ((libsodium._crypto_scalarmult_ed25519_noclamp(q_address, n_address, p_address) | 0) === 0) { + var ret = _format_output(q, outputFormat); + _free_all(address_pool); + return ret; + } + _free_and_throw_error(address_pool, "invalid point or scalar is 0"); + } + + function crypto_scalarmult_ristretto255(scalar, element, outputFormat) { + var address_pool = []; + + _check_output_format(outputFormat); + // ---------- input: scalar (buf) + + scalar = _any_to_Uint8Array(address_pool, scalar, "scalar"); + var scalar_address, scalar_length = (libsodium._crypto_scalarmult_ristretto255_scalarbytes()) | 0; + if (scalar.length !== scalar_length) { + _free_and_throw_type_error(address_pool, "invalid scalar length"); + } + scalar_address = _to_allocated_buf_address(scalar); + address_pool.push(scalar_address); + + // ---------- input: element (buf) + + element = _any_to_Uint8Array(address_pool, element, "element"); + var element_address, element_length = (libsodium._crypto_scalarmult_ristretto255_bytes()) | 0; + if (element.length !== element_length) { + _free_and_throw_type_error(address_pool, "invalid element length"); + } + element_address = _to_allocated_buf_address(element); + address_pool.push(element_address); + + // ---------- output result (buf) + + var result_length = (libsodium._crypto_scalarmult_ristretto255_bytes()) | 0, + result = new AllocatedBuf(result_length), + result_address = result.address; + + address_pool.push(result_address); + + if ((libsodium._crypto_scalarmult_ristretto255(result_address, scalar_address, element_address) | 0) === 0) { + var ret = _format_output(result, outputFormat); + _free_all(address_pool); + return ret; + } + _free_and_throw_error(address_pool, "result is identity element"); + } + + function crypto_scalarmult_ristretto255_base(scalar, outputFormat) { + var address_pool = []; + + _check_output_format(outputFormat); + // ---------- input: scalar (buf) + + scalar = _any_to_Uint8Array(address_pool, scalar, "scalar"); + var scalar_address, scalar_length = (libsodium._crypto_core_ristretto255_scalarbytes()) | 0; + if (scalar.length !== scalar_length) { + _free_and_throw_type_error(address_pool, "invalid scalar length"); + } + scalar_address = _to_allocated_buf_address(scalar); + address_pool.push(scalar_address); + + // ---------- output element (buf) + + var element_length = (libsodium._crypto_core_ristretto255_bytes()) | 0, + element = new AllocatedBuf(element_length), + element_address = element.address; + + address_pool.push(element_address); + + if ((libsodium._crypto_scalarmult_ristretto255_base(element_address, scalar_address) | 0) === 0) { + var ret = _format_output(element, outputFormat); + _free_all(address_pool); + return ret; + } + _free_and_throw_error(address_pool, "scalar is 0"); + } + + function crypto_secretbox_detached(message, nonce, key, outputFormat) { + var address_pool = []; + + _check_output_format(outputFormat); + // ---------- input: message (unsized_buf) + + message = _any_to_Uint8Array(address_pool, message, "message"); + var message_address = _to_allocated_buf_address(message), + message_length = message.length; + address_pool.push(message_address); + + // ---------- input: nonce (buf) + + nonce = _any_to_Uint8Array(address_pool, nonce, "nonce"); + var nonce_address, nonce_length = (libsodium._crypto_secretbox_noncebytes()) | 0; + if (nonce.length !== nonce_length) { + _free_and_throw_type_error(address_pool, "invalid nonce length"); + } + nonce_address = _to_allocated_buf_address(nonce); + address_pool.push(nonce_address); + + // ---------- input: key (buf) + + key = _any_to_Uint8Array(address_pool, key, "key"); + var key_address, key_length = (libsodium._crypto_secretbox_keybytes()) | 0; + if (key.length !== key_length) { + _free_and_throw_type_error(address_pool, "invalid key length"); + } + key_address = _to_allocated_buf_address(key); + address_pool.push(key_address); + + // ---------- output cipher (buf) + + var cipher_length = (message_length) | 0, + cipher = new AllocatedBuf(cipher_length), + cipher_address = cipher.address; + + address_pool.push(cipher_address); + + // ---------- output mac (buf) + + var mac_length = (libsodium._crypto_secretbox_macbytes()) | 0, + mac = new AllocatedBuf(mac_length), + mac_address = mac.address; + + address_pool.push(mac_address); + + if ((libsodium._crypto_secretbox_detached(cipher_address, mac_address, message_address, message_length, 0, nonce_address, key_address) | 0) === 0) { + var ret = _format_output({mac: mac, cipher: cipher}, outputFormat); + _free_all(address_pool); + return ret; + } + _free_and_throw_error(address_pool, "invalid usage"); + } + + function crypto_secretbox_easy(message, nonce, key, outputFormat) { + var address_pool = []; + + _check_output_format(outputFormat); + // ---------- input: message (unsized_buf) + + message = _any_to_Uint8Array(address_pool, message, "message"); + var message_address = _to_allocated_buf_address(message), + message_length = message.length; + address_pool.push(message_address); + + // ---------- input: nonce (buf) + + nonce = _any_to_Uint8Array(address_pool, nonce, "nonce"); + var nonce_address, nonce_length = (libsodium._crypto_secretbox_noncebytes()) | 0; + if (nonce.length !== nonce_length) { + _free_and_throw_type_error(address_pool, "invalid nonce length"); + } + nonce_address = _to_allocated_buf_address(nonce); + address_pool.push(nonce_address); + + // ---------- input: key (buf) + + key = _any_to_Uint8Array(address_pool, key, "key"); + var key_address, key_length = (libsodium._crypto_secretbox_keybytes()) | 0; + if (key.length !== key_length) { + _free_and_throw_type_error(address_pool, "invalid key length"); + } + key_address = _to_allocated_buf_address(key); + address_pool.push(key_address); + + // ---------- output cipher (buf) + + var cipher_length = (message_length + libsodium._crypto_secretbox_macbytes()) | 0, + cipher = new AllocatedBuf32(cipher_length), + cipher_address = cipher.address; + + address_pool.push(cipher_address); + + if ((libsodium._crypto_secretbox_easy(cipher_address, message_address, message_length, 0, nonce_address, key_address) | 0) === 0) { + var ret = _format_output(cipher, outputFormat); + _free_all(address_pool); + return ret; + } + _free_and_throw_error(address_pool, "invalid usage"); + } + + function crypto_secretbox_keygen(outputFormat) { + var address_pool = []; + + _check_output_format(outputFormat); + // ---------- output output (buf) + + var output_length = (libsodium._crypto_secretbox_keybytes()) | 0, + output = new AllocatedBuf(output_length), + output_address = output.address; + + address_pool.push(output_address); + + libsodium._crypto_secretbox_keygen(output_address); + var ret = (_format_output(output, outputFormat)); + _free_all(address_pool); + return ret; + } + + function crypto_secretbox_open_detached(ciphertext, mac, nonce, key, outputFormat) { + var address_pool = []; + + _check_output_format(outputFormat); + // ---------- input: ciphertext (unsized_buf) + + ciphertext = _any_to_Uint8Array(address_pool, ciphertext, "ciphertext"); + var ciphertext_address = _to_allocated_buf_address(ciphertext), + ciphertext_length = ciphertext.length; + address_pool.push(ciphertext_address); + + // ---------- input: mac (buf) + + mac = _any_to_Uint8Array(address_pool, mac, "mac"); + var mac_address, mac_length = (libsodium._crypto_secretbox_macbytes()) | 0; + if (mac.length !== mac_length) { + _free_and_throw_type_error(address_pool, "invalid mac length"); + } + mac_address = _to_allocated_buf_address(mac); + address_pool.push(mac_address); + + // ---------- input: nonce (buf) + + nonce = _any_to_Uint8Array(address_pool, nonce, "nonce"); + var nonce_address, nonce_length = (libsodium._crypto_secretbox_noncebytes()) | 0; + if (nonce.length !== nonce_length) { + _free_and_throw_type_error(address_pool, "invalid nonce length"); + } + nonce_address = _to_allocated_buf_address(nonce); + address_pool.push(nonce_address); + + // ---------- input: key (buf) + + key = _any_to_Uint8Array(address_pool, key, "key"); + var key_address, key_length = (libsodium._crypto_secretbox_keybytes()) | 0; + if (key.length !== key_length) { + _free_and_throw_type_error(address_pool, "invalid key length"); + } + key_address = _to_allocated_buf_address(key); + address_pool.push(key_address); + + // ---------- output message (buf) + + var message_length = (ciphertext_length) | 0, + message = new AllocatedBuf(message_length), + message_address = message.address; + + address_pool.push(message_address); + + if ((libsodium._crypto_secretbox_open_detached(message_address, ciphertext_address, mac_address, ciphertext_length, 0, nonce_address, key_address) | 0) === 0) { + var ret = _format_output(message, outputFormat); + _free_all(address_pool); + return ret; + } + _free_and_throw_error(address_pool, "wrong secret key for the given ciphertext"); + } + + function crypto_secretbox_open_easy(ciphertext, nonce, key, outputFormat) { + var address_pool = []; + + _check_output_format(outputFormat); + // ---------- input: ciphertext (minsized_buf) + + ciphertext = _any_to_Uint8Array(address_pool, ciphertext, "ciphertext"); + var ciphertext_address, ciphertext_min_length = libsodium._crypto_secretbox_macbytes(), ciphertext_length = ciphertext.length; + if (ciphertext_length < ciphertext_min_length) { + _free_and_throw_type_error(address_pool, "ciphertext is too short"); + } + ciphertext_address = _to_allocated_buf_address(ciphertext); + address_pool.push(ciphertext_address); + + // ---------- input: nonce (buf) + + nonce = _any_to_Uint8Array(address_pool, nonce, "nonce"); + var nonce_address, nonce_length = (libsodium._crypto_secretbox_noncebytes()) | 0; + if (nonce.length !== nonce_length) { + _free_and_throw_type_error(address_pool, "invalid nonce length"); + } + nonce_address = _to_allocated_buf_address(nonce); + address_pool.push(nonce_address); + + // ---------- input: key (buf) + + key = _any_to_Uint8Array(address_pool, key, "key"); + var key_address, key_length = (libsodium._crypto_secretbox_keybytes()) | 0; + if (key.length !== key_length) { + _free_and_throw_type_error(address_pool, "invalid key length"); + } + key_address = _to_allocated_buf_address(key); + address_pool.push(key_address); + + // ---------- output message (buf) + + var message_length = (ciphertext_length - libsodium._crypto_secretbox_macbytes()) | 0, + message = new AllocatedBuf(message_length), + message_address = message.address; + + address_pool.push(message_address); + + if ((libsodium._crypto_secretbox_open_easy(message_address, ciphertext_address, ciphertext_length, 0, nonce_address, key_address) | 0) === 0) { + var ret = _format_output(message, outputFormat); + _free_all(address_pool); + return ret; + } + _free_and_throw_error(address_pool, "wrong secret key for the given ciphertext"); + } + + function crypto_secretstream_xchacha20poly1305_init_pull(header, key, outputFormat) { + var address_pool = []; + + _check_output_format(outputFormat); + // ---------- input: header (buf) + + header = _any_to_Uint8Array(address_pool, header, "header"); + var header_address, header_length = (libsodium._crypto_secretstream_xchacha20poly1305_headerbytes()) | 0; + if (header.length !== header_length) { + _free_and_throw_type_error(address_pool, "invalid header length"); + } + header_address = _to_allocated_buf_address(header); + address_pool.push(header_address); + + // ---------- input: key (buf) + + key = _any_to_Uint8Array(address_pool, key, "key"); + var key_address, key_length = (libsodium._crypto_secretstream_xchacha20poly1305_keybytes()) | 0; + if (key.length !== key_length) { + _free_and_throw_type_error(address_pool, "invalid key length"); + } + key_address = _to_allocated_buf_address(key); + address_pool.push(key_address); + + // ---------- output state (secretstream_xchacha20poly1305_state) + + var state_address = new AllocatedBuf(52).address; + + if ((libsodium._crypto_secretstream_xchacha20poly1305_init_pull(state_address, header_address, key_address) | 0) === 0) { + var ret = state_address; + _free_all(address_pool); + return ret; + } + _free_and_throw_error(address_pool, "invalid usage"); + } + + function crypto_secretstream_xchacha20poly1305_init_push(key, outputFormat) { + var address_pool = []; + + _check_output_format(outputFormat); + // ---------- input: key (buf) + + key = _any_to_Uint8Array(address_pool, key, "key"); + var key_address, key_length = (libsodium._crypto_secretstream_xchacha20poly1305_keybytes()) | 0; + if (key.length !== key_length) { + _free_and_throw_type_error(address_pool, "invalid key length"); + } + key_address = _to_allocated_buf_address(key); + address_pool.push(key_address); + + // ---------- output state (secretstream_xchacha20poly1305_state) + + var state_address = new AllocatedBuf(52).address; + + // ---------- output header (buf) + + var header_length = (libsodium._crypto_secretstream_xchacha20poly1305_headerbytes()) | 0, + header = new AllocatedBuf(header_length), + header_address = header.address; + + address_pool.push(header_address); + + if ((libsodium._crypto_secretstream_xchacha20poly1305_init_push(state_address, header_address, key_address) | 0) === 0) { + var ret = { state: state_address, header: _format_output(header, outputFormat) }; + _free_all(address_pool); + return ret; + } + _free_and_throw_error(address_pool, "invalid usage"); + } + + function crypto_secretstream_xchacha20poly1305_keygen(outputFormat) { + var address_pool = []; + + _check_output_format(outputFormat); + // ---------- output output (buf) + + var output_length = (libsodium._crypto_secretstream_xchacha20poly1305_keybytes()) | 0, + output = new AllocatedBuf(output_length), + output_address = output.address; + + address_pool.push(output_address); + + libsodium._crypto_secretstream_xchacha20poly1305_keygen(output_address); + var ret = (_format_output(output, outputFormat)); + _free_all(address_pool); + return ret; + } + + function crypto_secretstream_xchacha20poly1305_pull(state_address, cipher, ad, outputFormat) { + var address_pool = []; + + _check_output_format(outputFormat); + // ---------- input: state_address (secretstream_xchacha20poly1305_state_address) + + _require_defined(address_pool, state_address, "state_address"); + + // ---------- input: cipher (minsized_buf) + + cipher = _any_to_Uint8Array(address_pool, cipher, "cipher"); + var cipher_address, cipher_min_length = libsodium._crypto_secretstream_xchacha20poly1305_abytes(), cipher_length = cipher.length; + if (cipher_length < cipher_min_length) { + _free_and_throw_type_error(address_pool, "cipher is too short"); + } + cipher_address = _to_allocated_buf_address(cipher); + address_pool.push(cipher_address); + + // ---------- input: ad (unsized_buf_optional) + + var ad_address = null, ad_length = 0; + if (ad != undefined) { + ad = _any_to_Uint8Array(address_pool, ad, "ad"); + ad_address = _to_allocated_buf_address(ad); + ad_length = ad.length; + address_pool.push(ad_address); + } + + + // ---------- output message_chunk (buf) + + var message_chunk_length = (cipher_length - libsodium._crypto_secretstream_xchacha20poly1305_abytes()) | 0, + message_chunk = new AllocatedBuf(message_chunk_length), + message_chunk_address = message_chunk.address; + + address_pool.push(message_chunk_address); + + var ret = (function() { var tag_p = _malloc(1); address_pool.push(tag_p); return libsodium._crypto_secretstream_xchacha20poly1305_pull(state_address, message_chunk_address, 0, tag_p, cipher_address, cipher_length, 0, ad_address, ad_length) === 0 && { tag: libsodium.HEAPU8[tag_p], message: message_chunk } } )(); + var ret = (ret && {message: _format_output(ret.message, outputFormat), tag: ret.tag}); + _free_all(address_pool); + return ret; + } + + function crypto_secretstream_xchacha20poly1305_push(state_address, message_chunk, ad, tag, outputFormat) { + var address_pool = []; + + _check_output_format(outputFormat); + // ---------- input: state_address (secretstream_xchacha20poly1305_state_address) + + _require_defined(address_pool, state_address, "state_address"); + + // ---------- input: message_chunk (unsized_buf) + + message_chunk = _any_to_Uint8Array(address_pool, message_chunk, "message_chunk"); + var message_chunk_address = _to_allocated_buf_address(message_chunk), + message_chunk_length = message_chunk.length; + address_pool.push(message_chunk_address); + + // ---------- input: ad (unsized_buf_optional) + + var ad_address = null, ad_length = 0; + if (ad != undefined) { + ad = _any_to_Uint8Array(address_pool, ad, "ad"); + ad_address = _to_allocated_buf_address(ad); + ad_length = ad.length; + address_pool.push(ad_address); + } + + + // ---------- input: tag (uint) + + _require_defined(address_pool, tag, "tag"); + + if (!(typeof tag === "number" && (tag | 0) === tag) || tag < 0) { + _free_and_throw_type_error(address_pool, "tag must be an unsigned integer"); + } + + // ---------- output cipher (buf) + + var cipher_length = (message_chunk_length + libsodium._crypto_secretstream_xchacha20poly1305_abytes()) | 0, + cipher = new AllocatedBuf(cipher_length), + cipher_address = cipher.address; + + address_pool.push(cipher_address); + + if ((libsodium._crypto_secretstream_xchacha20poly1305_push(state_address, cipher_address, 0, message_chunk_address, message_chunk_length, 0, ad_address, ad_length, 0, tag) | 0) === 0) { + var ret = _format_output(cipher, outputFormat); + _free_all(address_pool); + return ret; + } + _free_and_throw_error(address_pool, "invalid usage"); + } + + function crypto_secretstream_xchacha20poly1305_rekey(state_address, outputFormat) { + var address_pool = []; + + _check_output_format(outputFormat); + // ---------- input: state_address (secretstream_xchacha20poly1305_state_address) + + _require_defined(address_pool, state_address, "state_address"); + + libsodium._crypto_secretstream_xchacha20poly1305_rekey(state_address); + var ret = (true); + _free_all(address_pool); + return ret; + } + + function crypto_shorthash(message, key, outputFormat) { + var address_pool = []; + + _check_output_format(outputFormat); + // ---------- input: message (unsized_buf) + + message = _any_to_Uint8Array(address_pool, message, "message"); + var message_address = _to_allocated_buf_address(message), + message_length = message.length; + address_pool.push(message_address); + + // ---------- input: key (buf) + + key = _any_to_Uint8Array(address_pool, key, "key"); + var key_address, key_length = (libsodium._crypto_shorthash_keybytes()) | 0; + if (key.length !== key_length) { + _free_and_throw_type_error(address_pool, "invalid key length"); + } + key_address = _to_allocated_buf_address(key); + address_pool.push(key_address); + + // ---------- output hash (buf) + + var hash_length = (libsodium._crypto_shorthash_bytes()) | 0, + hash = new AllocatedBuf(hash_length), + hash_address = hash.address; + + address_pool.push(hash_address); + + if ((libsodium._crypto_shorthash(hash_address, message_address, message_length, 0, key_address) | 0) === 0) { + var ret = _format_output(hash, outputFormat); + _free_all(address_pool); + return ret; + } + _free_and_throw_error(address_pool, "invalid usage"); + } + + function crypto_shorthash_keygen(outputFormat) { + var address_pool = []; + + _check_output_format(outputFormat); + // ---------- output output (buf) + + var output_length = (libsodium._crypto_shorthash_keybytes()) | 0, + output = new AllocatedBuf(output_length), + output_address = output.address; + + address_pool.push(output_address); + + libsodium._crypto_shorthash_keygen(output_address); + var ret = (_format_output(output, outputFormat)); + _free_all(address_pool); + return ret; + } + + function crypto_shorthash_siphashx24(message, key, outputFormat) { + var address_pool = []; + + _check_output_format(outputFormat); + // ---------- input: message (unsized_buf) + + message = _any_to_Uint8Array(address_pool, message, "message"); + var message_address = _to_allocated_buf_address(message), + message_length = message.length; + address_pool.push(message_address); + + // ---------- input: key (buf) + + key = _any_to_Uint8Array(address_pool, key, "key"); + var key_address, key_length = (libsodium._crypto_shorthash_siphashx24_keybytes()) | 0; + if (key.length !== key_length) { + _free_and_throw_type_error(address_pool, "invalid key length"); + } + key_address = _to_allocated_buf_address(key); + address_pool.push(key_address); + + // ---------- output hash (buf) + + var hash_length = (libsodium._crypto_shorthash_siphashx24_bytes()) | 0, + hash = new AllocatedBuf(hash_length), + hash_address = hash.address; + + address_pool.push(hash_address); + + if ((libsodium._crypto_shorthash_siphashx24(hash_address, message_address, message_length, 0, key_address) | 0) === 0) { + var ret = _format_output(hash, outputFormat); + _free_all(address_pool); + return ret; + } + _free_and_throw_error(address_pool, "invalid usage"); + } + + function crypto_sign(message, privateKey, outputFormat) { + var address_pool = []; + + _check_output_format(outputFormat); + // ---------- input: message (unsized_buf) + + message = _any_to_Uint8Array(address_pool, message, "message"); + var message_address = _to_allocated_buf_address(message), + message_length = message.length; + address_pool.push(message_address); + + // ---------- input: privateKey (buf) + + privateKey = _any_to_Uint8Array(address_pool, privateKey, "privateKey"); + var privateKey_address, privateKey_length = (libsodium._crypto_sign_secretkeybytes()) | 0; + if (privateKey.length !== privateKey_length) { + _free_and_throw_type_error(address_pool, "invalid privateKey length"); + } + privateKey_address = _to_allocated_buf_address(privateKey); + address_pool.push(privateKey_address); + + // ---------- output signature (buf) + + var signature_length = (message.length + libsodium._crypto_sign_bytes()) | 0, + signature = new AllocatedBuf(signature_length), + signature_address = signature.address; + + address_pool.push(signature_address); + + if ((libsodium._crypto_sign(signature_address, null, message_address, message_length, 0, privateKey_address) | 0) === 0) { + var ret = _format_output(signature, outputFormat); + _free_all(address_pool); + return ret; + } + _free_and_throw_error(address_pool, "invalid usage"); + } + + function crypto_sign_detached(message, privateKey, outputFormat) { + var address_pool = []; + + _check_output_format(outputFormat); + // ---------- input: message (unsized_buf) + + message = _any_to_Uint8Array(address_pool, message, "message"); + var message_address = _to_allocated_buf_address(message), + message_length = message.length; + address_pool.push(message_address); + + // ---------- input: privateKey (buf) + + privateKey = _any_to_Uint8Array(address_pool, privateKey, "privateKey"); + var privateKey_address, privateKey_length = (libsodium._crypto_sign_secretkeybytes()) | 0; + if (privateKey.length !== privateKey_length) { + _free_and_throw_type_error(address_pool, "invalid privateKey length"); + } + privateKey_address = _to_allocated_buf_address(privateKey); + address_pool.push(privateKey_address); + + // ---------- output signature (buf) + + var signature_length = (libsodium._crypto_sign_bytes()) | 0, + signature = new AllocatedBuf(signature_length), + signature_address = signature.address; + + address_pool.push(signature_address); + + if ((libsodium._crypto_sign_detached(signature_address, null, message_address, message_length, 0, privateKey_address) | 0) === 0) { + var ret = _format_output(signature, outputFormat); + _free_all(address_pool); + return ret; + } + _free_and_throw_error(address_pool, "invalid usage"); + } + + function crypto_sign_ed25519_pk_to_curve25519(edPk, outputFormat) { + var address_pool = []; + + _check_output_format(outputFormat); + // ---------- input: edPk (buf) + + edPk = _any_to_Uint8Array(address_pool, edPk, "edPk"); + var edPk_address, edPk_length = (libsodium._crypto_sign_publickeybytes()) | 0; + if (edPk.length !== edPk_length) { + _free_and_throw_type_error(address_pool, "invalid edPk length"); + } + edPk_address = _to_allocated_buf_address(edPk); + address_pool.push(edPk_address); + + // ---------- output cPk (buf) + + var cPk_length = (libsodium._crypto_scalarmult_scalarbytes()) | 0, + cPk = new AllocatedBuf(cPk_length), + cPk_address = cPk.address; + + address_pool.push(cPk_address); + + if ((libsodium._crypto_sign_ed25519_pk_to_curve25519(cPk_address, edPk_address) | 0) === 0) { + var ret = _format_output(cPk, outputFormat); + _free_all(address_pool); + return ret; + } + _free_and_throw_error(address_pool, "invalid key"); + } + + function crypto_sign_ed25519_sk_to_curve25519(edSk, outputFormat) { + var address_pool = []; + + _check_output_format(outputFormat); + // ---------- input: edSk (buf) + + edSk = _any_to_Uint8Array(address_pool, edSk, "edSk"); + var edSk_address, edSk_length = (libsodium._crypto_sign_secretkeybytes()) | 0; + if (edSk.length !== edSk_length) { + _free_and_throw_type_error(address_pool, "invalid edSk length"); + } + edSk_address = _to_allocated_buf_address(edSk); + address_pool.push(edSk_address); + + // ---------- output cSk (buf) + + var cSk_length = (libsodium._crypto_scalarmult_scalarbytes()) | 0, + cSk = new AllocatedBuf(cSk_length), + cSk_address = cSk.address; + + address_pool.push(cSk_address); + + if ((libsodium._crypto_sign_ed25519_sk_to_curve25519(cSk_address, edSk_address) | 0) === 0) { + var ret = _format_output(cSk, outputFormat); + _free_all(address_pool); + return ret; + } + _free_and_throw_error(address_pool, "invalid key"); + } + + function crypto_sign_ed25519_sk_to_pk(privateKey, outputFormat) { + var address_pool = []; + + _check_output_format(outputFormat); + // ---------- input: privateKey (buf) + + privateKey = _any_to_Uint8Array(address_pool, privateKey, "privateKey"); + var privateKey_address, privateKey_length = (libsodium._crypto_sign_secretkeybytes()) | 0; + if (privateKey.length !== privateKey_length) { + _free_and_throw_type_error(address_pool, "invalid privateKey length"); + } + privateKey_address = _to_allocated_buf_address(privateKey); + address_pool.push(privateKey_address); + + // ---------- output publicKey (buf) + + var publicKey_length = (libsodium._crypto_sign_publickeybytes()) | 0, + publicKey = new AllocatedBuf(publicKey_length), + publicKey_address = publicKey.address; + + address_pool.push(publicKey_address); + + if ((libsodium._crypto_sign_ed25519_sk_to_pk(publicKey_address, privateKey_address) | 0) === 0) { + var ret = _format_output(publicKey, outputFormat); + _free_all(address_pool); + return ret; + } + _free_and_throw_error(address_pool, "invalid key"); + } + + function crypto_sign_ed25519_sk_to_seed(privateKey, outputFormat) { + var address_pool = []; + + _check_output_format(outputFormat); + // ---------- input: privateKey (buf) + + privateKey = _any_to_Uint8Array(address_pool, privateKey, "privateKey"); + var privateKey_address, privateKey_length = (libsodium._crypto_sign_secretkeybytes()) | 0; + if (privateKey.length !== privateKey_length) { + _free_and_throw_type_error(address_pool, "invalid privateKey length"); + } + privateKey_address = _to_allocated_buf_address(privateKey); + address_pool.push(privateKey_address); + + // ---------- output seed (buf) + + var seed_length = (libsodium._crypto_sign_seedbytes()) | 0, + seed = new AllocatedBuf(seed_length), + seed_address = seed.address; + + address_pool.push(seed_address); + + if ((libsodium._crypto_sign_ed25519_sk_to_seed(seed_address, privateKey_address) | 0) === 0) { + var ret = _format_output(seed, outputFormat); + _free_all(address_pool); + return ret; + } + _free_and_throw_error(address_pool, "invalid key"); + } + + function crypto_sign_final_create(state_address, privateKey, outputFormat) { + var address_pool = []; + + _check_output_format(outputFormat); + // ---------- input: state_address (sign_state_address) + + _require_defined(address_pool, state_address, "state_address"); + + // ---------- input: privateKey (buf) + + privateKey = _any_to_Uint8Array(address_pool, privateKey, "privateKey"); + var privateKey_address, privateKey_length = (libsodium._crypto_sign_secretkeybytes()) | 0; + if (privateKey.length !== privateKey_length) { + _free_and_throw_type_error(address_pool, "invalid privateKey length"); + } + privateKey_address = _to_allocated_buf_address(privateKey); + address_pool.push(privateKey_address); + + // ---------- output signature (buf) + + var signature_length = (libsodium._crypto_sign_bytes()) | 0, + signature = new AllocatedBuf(signature_length), + signature_address = signature.address; + + address_pool.push(signature_address); + + if ((libsodium._crypto_sign_final_create(state_address, signature_address, null, privateKey_address) | 0) === 0) { + var ret = (libsodium._free(state_address), _format_output(signature, outputFormat)); + _free_all(address_pool); + return ret; + } + _free_and_throw_error(address_pool, "invalid usage"); + } + + function crypto_sign_final_verify(state_address, signature, publicKey, outputFormat) { + var address_pool = []; + + _check_output_format(outputFormat); + // ---------- input: state_address (sign_state_address) + + _require_defined(address_pool, state_address, "state_address"); + + // ---------- input: signature (buf) + + signature = _any_to_Uint8Array(address_pool, signature, "signature"); + var signature_address, signature_length = (libsodium._crypto_sign_bytes()) | 0; + if (signature.length !== signature_length) { + _free_and_throw_type_error(address_pool, "invalid signature length"); + } + signature_address = _to_allocated_buf_address(signature); + address_pool.push(signature_address); + + // ---------- input: publicKey (buf) + + publicKey = _any_to_Uint8Array(address_pool, publicKey, "publicKey"); + var publicKey_address, publicKey_length = (libsodium._crypto_sign_publickeybytes()) | 0; + if (publicKey.length !== publicKey_length) { + _free_and_throw_type_error(address_pool, "invalid publicKey length"); + } + publicKey_address = _to_allocated_buf_address(publicKey); + address_pool.push(publicKey_address); + + var verificationResult = libsodium._crypto_sign_final_verify(state_address, signature_address, publicKey_address) | 0; + var ret = (verificationResult === 0); + _free_all(address_pool); + return ret; + } + + function crypto_sign_init(outputFormat) { + var address_pool = []; + + _check_output_format(outputFormat); + // ---------- output state (sign_state) + + var state_address = new AllocatedBuf(208).address; + + if ((libsodium._crypto_sign_init(state_address) | 0) === 0) { + var ret = state_address; + _free_all(address_pool); + return ret; + } + _free_and_throw_error(address_pool, "internal error"); + } + + function crypto_sign_keypair(outputFormat) { + var address_pool = []; + + _check_output_format(outputFormat); + // ---------- output publicKey (buf) + + var publicKey_length = (libsodium._crypto_sign_publickeybytes()) | 0, + publicKey = new AllocatedBuf(publicKey_length), + publicKey_address = publicKey.address; + + address_pool.push(publicKey_address); + + // ---------- output privateKey (buf) + + var privateKey_length = (libsodium._crypto_sign_secretkeybytes()) | 0, + privateKey = new AllocatedBuf(privateKey_length), + privateKey_address = privateKey.address; + + address_pool.push(privateKey_address); + + if ((libsodium._crypto_sign_keypair(publicKey_address, privateKey_address) | 0) === 0) { + var ret = {publicKey: _format_output(publicKey, outputFormat), privateKey: _format_output(privateKey, outputFormat), keyType: 'ed25519'}; + _free_all(address_pool); + return ret; + } + _free_and_throw_error(address_pool, "internal error"); + } + + function crypto_sign_open(signedMessage, publicKey, outputFormat) { + var address_pool = []; + + _check_output_format(outputFormat); + // ---------- input: signedMessage (minsized_buf) + + signedMessage = _any_to_Uint8Array(address_pool, signedMessage, "signedMessage"); + var signedMessage_address, signedMessage_min_length = libsodium._crypto_sign_bytes(), signedMessage_length = signedMessage.length; + if (signedMessage_length < signedMessage_min_length) { + _free_and_throw_type_error(address_pool, "signedMessage is too short"); + } + signedMessage_address = _to_allocated_buf_address(signedMessage); + address_pool.push(signedMessage_address); + + // ---------- input: publicKey (buf) + + publicKey = _any_to_Uint8Array(address_pool, publicKey, "publicKey"); + var publicKey_address, publicKey_length = (libsodium._crypto_sign_publickeybytes()) | 0; + if (publicKey.length !== publicKey_length) { + _free_and_throw_type_error(address_pool, "invalid publicKey length"); + } + publicKey_address = _to_allocated_buf_address(publicKey); + address_pool.push(publicKey_address); + + // ---------- output message (buf) + + var message_length = (signedMessage_length - libsodium._crypto_sign_bytes()) | 0, + message = new AllocatedBuf(message_length), + message_address = message.address; + + address_pool.push(message_address); + + if ((libsodium._crypto_sign_open(message_address, null, signedMessage_address, signedMessage_length, 0, publicKey_address) | 0) === 0) { + var ret = _format_output(message, outputFormat); + _free_all(address_pool); + return ret; + } + _free_and_throw_error(address_pool, "incorrect signature for the given public key"); + } + + function crypto_sign_seed_keypair(seed, outputFormat) { + var address_pool = []; + + _check_output_format(outputFormat); + // ---------- input: seed (buf) + + seed = _any_to_Uint8Array(address_pool, seed, "seed"); + var seed_address, seed_length = (libsodium._crypto_sign_seedbytes()) | 0; + if (seed.length !== seed_length) { + _free_and_throw_type_error(address_pool, "invalid seed length"); + } + seed_address = _to_allocated_buf_address(seed); + address_pool.push(seed_address); + + // ---------- output publicKey (buf) + + var publicKey_length = (libsodium._crypto_sign_publickeybytes()) | 0, + publicKey = new AllocatedBuf(publicKey_length), + publicKey_address = publicKey.address; + + address_pool.push(publicKey_address); + + // ---------- output privateKey (buf) + + var privateKey_length = (libsodium._crypto_sign_secretkeybytes()) | 0, + privateKey = new AllocatedBuf(privateKey_length), + privateKey_address = privateKey.address; + + address_pool.push(privateKey_address); + + if ((libsodium._crypto_sign_seed_keypair(publicKey_address, privateKey_address, seed_address) | 0) === 0) { + var ret = {publicKey: _format_output(publicKey, outputFormat), privateKey: _format_output(privateKey, outputFormat), keyType: 'ed25519'}; + _free_all(address_pool); + return ret; + } + _free_and_throw_error(address_pool, "invalid usage"); + } + + function crypto_sign_update(state_address, message_chunk, outputFormat) { + var address_pool = []; + + _check_output_format(outputFormat); + // ---------- input: state_address (sign_state_address) + + _require_defined(address_pool, state_address, "state_address"); + + // ---------- input: message_chunk (unsized_buf) + + message_chunk = _any_to_Uint8Array(address_pool, message_chunk, "message_chunk"); + var message_chunk_address = _to_allocated_buf_address(message_chunk), + message_chunk_length = message_chunk.length; + address_pool.push(message_chunk_address); + + if (!((libsodium._crypto_sign_update(state_address, message_chunk_address, message_chunk_length, 0) | 0) === 0)) { + _free_and_throw_error(address_pool, "invalid usage"); + } + _free_all(address_pool); + } + + function crypto_sign_verify_detached(signature, message, publicKey) { + var address_pool = []; + + // ---------- input: signature (buf) + + signature = _any_to_Uint8Array(address_pool, signature, "signature"); + var signature_address, signature_length = (libsodium._crypto_sign_bytes()) | 0; + if (signature.length !== signature_length) { + _free_and_throw_type_error(address_pool, "invalid signature length"); + } + signature_address = _to_allocated_buf_address(signature); + address_pool.push(signature_address); + + // ---------- input: message (unsized_buf) + + message = _any_to_Uint8Array(address_pool, message, "message"); + var message_address = _to_allocated_buf_address(message), + message_length = message.length; + address_pool.push(message_address); + + // ---------- input: publicKey (buf) + + publicKey = _any_to_Uint8Array(address_pool, publicKey, "publicKey"); + var publicKey_address, publicKey_length = (libsodium._crypto_sign_publickeybytes()) | 0; + if (publicKey.length !== publicKey_length) { + _free_and_throw_type_error(address_pool, "invalid publicKey length"); + } + publicKey_address = _to_allocated_buf_address(publicKey); + address_pool.push(publicKey_address); + + var verificationResult = libsodium._crypto_sign_verify_detached(signature_address, message_address, message_length, 0, publicKey_address) | 0; + var ret = (verificationResult === 0); + _free_all(address_pool); + return ret; + } + + function crypto_stream_chacha20(outLength, key, nonce, outputFormat) { + var address_pool = []; + + _check_output_format(outputFormat); + // ---------- input: outLength (uint) + + _require_defined(address_pool, outLength, "outLength"); + + if (!(typeof outLength === "number" && (outLength | 0) === outLength) || outLength < 0) { + _free_and_throw_type_error(address_pool, "outLength must be an unsigned integer"); + } + + // ---------- input: key (buf) + + key = _any_to_Uint8Array(address_pool, key, "key"); + var key_address, key_length = (libsodium._crypto_stream_chacha20_keybytes()) | 0; + if (key.length !== key_length) { + _free_and_throw_type_error(address_pool, "invalid key length"); + } + key_address = _to_allocated_buf_address(key); + address_pool.push(key_address); + + // ---------- input: nonce (buf) + + nonce = _any_to_Uint8Array(address_pool, nonce, "nonce"); + var nonce_address, nonce_length = (libsodium._crypto_stream_chacha20_noncebytes()) | 0; + if (nonce.length !== nonce_length) { + _free_and_throw_type_error(address_pool, "invalid nonce length"); + } + nonce_address = _to_allocated_buf_address(nonce); + address_pool.push(nonce_address); + + // ---------- output out (buf) + + var out_length = (outLength) | 0, + out = new AllocatedBuf(out_length), + out_address = out.address; + + address_pool.push(out_address); + + libsodium._crypto_stream_chacha20(out_address, outLength, 0, nonce_address, key_address) | 0; + var ret = (_format_output(out, outputFormat)); + _free_all(address_pool); + return ret; + } + + function crypto_stream_chacha20_ietf_xor(input_message, nonce, key, outputFormat) { + var address_pool = []; + + _check_output_format(outputFormat); + // ---------- input: input_message (unsized_buf) + + input_message = _any_to_Uint8Array(address_pool, input_message, "input_message"); + var input_message_address = _to_allocated_buf_address(input_message), + input_message_length = input_message.length; + address_pool.push(input_message_address); + + // ---------- input: nonce (buf) + + nonce = _any_to_Uint8Array(address_pool, nonce, "nonce"); + var nonce_address, nonce_length = (libsodium._crypto_stream_chacha20_ietf_noncebytes()) | 0; + if (nonce.length !== nonce_length) { + _free_and_throw_type_error(address_pool, "invalid nonce length"); + } + nonce_address = _to_allocated_buf_address(nonce); + address_pool.push(nonce_address); + + // ---------- input: key (buf) + + key = _any_to_Uint8Array(address_pool, key, "key"); + var key_address, key_length = (libsodium._crypto_stream_chacha20_ietf_keybytes()) | 0; + if (key.length !== key_length) { + _free_and_throw_type_error(address_pool, "invalid key length"); + } + key_address = _to_allocated_buf_address(key); + address_pool.push(key_address); + + // ---------- output output_message (buf) + + var output_message_length = (input_message_length) | 0, + output_message = new AllocatedBuf(output_message_length), + output_message_address = output_message.address; + + address_pool.push(output_message_address); + + if ((libsodium._crypto_stream_chacha20_ietf_xor(output_message_address, input_message_address, input_message_length, 0, nonce_address, key_address)) === 0) { + var ret = _format_output(output_message, outputFormat); + _free_all(address_pool); + return ret; + } + _free_and_throw_error(address_pool, "invalid usage"); + } + + function crypto_stream_chacha20_ietf_xor_ic(input_message, nonce, nonce_increment, key, outputFormat) { + var address_pool = []; + + _check_output_format(outputFormat); + // ---------- input: input_message (unsized_buf) + + input_message = _any_to_Uint8Array(address_pool, input_message, "input_message"); + var input_message_address = _to_allocated_buf_address(input_message), + input_message_length = input_message.length; + address_pool.push(input_message_address); + + // ---------- input: nonce (buf) + + nonce = _any_to_Uint8Array(address_pool, nonce, "nonce"); + var nonce_address, nonce_length = (libsodium._crypto_stream_chacha20_ietf_noncebytes()) | 0; + if (nonce.length !== nonce_length) { + _free_and_throw_type_error(address_pool, "invalid nonce length"); + } + nonce_address = _to_allocated_buf_address(nonce); + address_pool.push(nonce_address); + + // ---------- input: nonce_increment (uint) + + _require_defined(address_pool, nonce_increment, "nonce_increment"); + + if (!(typeof nonce_increment === "number" && (nonce_increment | 0) === nonce_increment) || nonce_increment < 0) { + _free_and_throw_type_error(address_pool, "nonce_increment must be an unsigned integer"); + } + + // ---------- input: key (buf) + + key = _any_to_Uint8Array(address_pool, key, "key"); + var key_address, key_length = (libsodium._crypto_stream_chacha20_ietf_keybytes()) | 0; + if (key.length !== key_length) { + _free_and_throw_type_error(address_pool, "invalid key length"); + } + key_address = _to_allocated_buf_address(key); + address_pool.push(key_address); + + // ---------- output output_message (buf) + + var output_message_length = (input_message_length) | 0, + output_message = new AllocatedBuf(output_message_length), + output_message_address = output_message.address; + + address_pool.push(output_message_address); + + if ((libsodium._crypto_stream_chacha20_ietf_xor_ic(output_message_address, input_message_address, input_message_length, 0, nonce_address, nonce_increment, key_address)) === 0) { + var ret = _format_output(output_message, outputFormat); + _free_all(address_pool); + return ret; + } + _free_and_throw_error(address_pool, "invalid usage"); + } + + function crypto_stream_chacha20_keygen(outputFormat) { + var address_pool = []; + + _check_output_format(outputFormat); + // ---------- output output (buf) + + var output_length = (libsodium._crypto_stream_chacha20_keybytes()) | 0, + output = new AllocatedBuf(output_length), + output_address = output.address; + + address_pool.push(output_address); + + libsodium._crypto_stream_chacha20_keygen(output_address); + var ret = (_format_output(output, outputFormat)); + _free_all(address_pool); + return ret; + } + + function crypto_stream_chacha20_xor(input_message, nonce, key, outputFormat) { + var address_pool = []; + + _check_output_format(outputFormat); + // ---------- input: input_message (unsized_buf) + + input_message = _any_to_Uint8Array(address_pool, input_message, "input_message"); + var input_message_address = _to_allocated_buf_address(input_message), + input_message_length = input_message.length; + address_pool.push(input_message_address); + + // ---------- input: nonce (buf) + + nonce = _any_to_Uint8Array(address_pool, nonce, "nonce"); + var nonce_address, nonce_length = (libsodium._crypto_stream_chacha20_noncebytes()) | 0; + if (nonce.length !== nonce_length) { + _free_and_throw_type_error(address_pool, "invalid nonce length"); + } + nonce_address = _to_allocated_buf_address(nonce); + address_pool.push(nonce_address); + + // ---------- input: key (buf) + + key = _any_to_Uint8Array(address_pool, key, "key"); + var key_address, key_length = (libsodium._crypto_stream_chacha20_keybytes()) | 0; + if (key.length !== key_length) { + _free_and_throw_type_error(address_pool, "invalid key length"); + } + key_address = _to_allocated_buf_address(key); + address_pool.push(key_address); + + // ---------- output output_message (buf) + + var output_message_length = (input_message_length) | 0, + output_message = new AllocatedBuf(output_message_length), + output_message_address = output_message.address; + + address_pool.push(output_message_address); + + if ((libsodium._crypto_stream_chacha20_xor(output_message_address, input_message_address, input_message_length, 0, nonce_address, key_address)) === 0) { + var ret = _format_output(output_message, outputFormat); + _free_all(address_pool); + return ret; + } + _free_and_throw_error(address_pool, "invalid usage"); + } + + function crypto_stream_chacha20_xor_ic(input_message, nonce, nonce_increment, key, outputFormat) { + var address_pool = []; + + _check_output_format(outputFormat); + // ---------- input: input_message (unsized_buf) + + input_message = _any_to_Uint8Array(address_pool, input_message, "input_message"); + var input_message_address = _to_allocated_buf_address(input_message), + input_message_length = input_message.length; + address_pool.push(input_message_address); + + // ---------- input: nonce (buf) + + nonce = _any_to_Uint8Array(address_pool, nonce, "nonce"); + var nonce_address, nonce_length = (libsodium._crypto_stream_chacha20_noncebytes()) | 0; + if (nonce.length !== nonce_length) { + _free_and_throw_type_error(address_pool, "invalid nonce length"); + } + nonce_address = _to_allocated_buf_address(nonce); + address_pool.push(nonce_address); + + // ---------- input: nonce_increment (uint) + + _require_defined(address_pool, nonce_increment, "nonce_increment"); + + if (!(typeof nonce_increment === "number" && (nonce_increment | 0) === nonce_increment) || nonce_increment < 0) { + _free_and_throw_type_error(address_pool, "nonce_increment must be an unsigned integer"); + } + + // ---------- input: key (buf) + + key = _any_to_Uint8Array(address_pool, key, "key"); + var key_address, key_length = (libsodium._crypto_stream_chacha20_keybytes()) | 0; + if (key.length !== key_length) { + _free_and_throw_type_error(address_pool, "invalid key length"); + } + key_address = _to_allocated_buf_address(key); + address_pool.push(key_address); + + // ---------- output output_message (buf) + + var output_message_length = (input_message_length) | 0, + output_message = new AllocatedBuf(output_message_length), + output_message_address = output_message.address; + + address_pool.push(output_message_address); + + if ((libsodium._crypto_stream_chacha20_xor_ic(output_message_address, input_message_address, input_message_length, 0, nonce_address, nonce_increment, 0, key_address)) === 0) { + var ret = _format_output(output_message, outputFormat); + _free_all(address_pool); + return ret; + } + _free_and_throw_error(address_pool, "invalid usage"); + } + + function crypto_stream_keygen(outputFormat) { + var address_pool = []; + + _check_output_format(outputFormat); + // ---------- output output (buf) + + var output_length = (libsodium._crypto_stream_keybytes()) | 0, + output = new AllocatedBuf(output_length), + output_address = output.address; + + address_pool.push(output_address); + + libsodium._crypto_stream_keygen(output_address); + var ret = (_format_output(output, outputFormat)); + _free_all(address_pool); + return ret; + } + + function crypto_stream_xchacha20_keygen(outputFormat) { + var address_pool = []; + + _check_output_format(outputFormat); + // ---------- output output (buf) + + var output_length = (libsodium._crypto_stream_xchacha20_keybytes()) | 0, + output = new AllocatedBuf(output_length), + output_address = output.address; + + address_pool.push(output_address); + + libsodium._crypto_stream_xchacha20_keygen(output_address); + var ret = (_format_output(output, outputFormat)); + _free_all(address_pool); + return ret; + } + + function crypto_stream_xchacha20_xor(input_message, nonce, key, outputFormat) { + var address_pool = []; + + _check_output_format(outputFormat); + // ---------- input: input_message (unsized_buf) + + input_message = _any_to_Uint8Array(address_pool, input_message, "input_message"); + var input_message_address = _to_allocated_buf_address(input_message), + input_message_length = input_message.length; + address_pool.push(input_message_address); + + // ---------- input: nonce (buf) + + nonce = _any_to_Uint8Array(address_pool, nonce, "nonce"); + var nonce_address, nonce_length = (libsodium._crypto_stream_xchacha20_noncebytes()) | 0; + if (nonce.length !== nonce_length) { + _free_and_throw_type_error(address_pool, "invalid nonce length"); + } + nonce_address = _to_allocated_buf_address(nonce); + address_pool.push(nonce_address); + + // ---------- input: key (buf) + + key = _any_to_Uint8Array(address_pool, key, "key"); + var key_address, key_length = (libsodium._crypto_stream_xchacha20_keybytes()) | 0; + if (key.length !== key_length) { + _free_and_throw_type_error(address_pool, "invalid key length"); + } + key_address = _to_allocated_buf_address(key); + address_pool.push(key_address); + + // ---------- output output_message (buf) + + var output_message_length = (input_message_length) | 0, + output_message = new AllocatedBuf(output_message_length), + output_message_address = output_message.address; + + address_pool.push(output_message_address); + + if ((libsodium._crypto_stream_xchacha20_xor(output_message_address, input_message_address, input_message_length, 0, nonce_address, key_address)) === 0) { + var ret = _format_output(output_message, outputFormat); + _free_all(address_pool); + return ret; + } + _free_and_throw_error(address_pool, "invalid usage"); + } + + function crypto_stream_xchacha20_xor_ic(input_message, nonce, nonce_increment, key, outputFormat) { + var address_pool = []; + + _check_output_format(outputFormat); + // ---------- input: input_message (unsized_buf) + + input_message = _any_to_Uint8Array(address_pool, input_message, "input_message"); + var input_message_address = _to_allocated_buf_address(input_message), + input_message_length = input_message.length; + address_pool.push(input_message_address); + + // ---------- input: nonce (buf) + + nonce = _any_to_Uint8Array(address_pool, nonce, "nonce"); + var nonce_address, nonce_length = (libsodium._crypto_stream_xchacha20_noncebytes()) | 0; + if (nonce.length !== nonce_length) { + _free_and_throw_type_error(address_pool, "invalid nonce length"); + } + nonce_address = _to_allocated_buf_address(nonce); + address_pool.push(nonce_address); + + // ---------- input: nonce_increment (uint) + + _require_defined(address_pool, nonce_increment, "nonce_increment"); + + if (!(typeof nonce_increment === "number" && (nonce_increment | 0) === nonce_increment) || nonce_increment < 0) { + _free_and_throw_type_error(address_pool, "nonce_increment must be an unsigned integer"); + } + + // ---------- input: key (buf) + + key = _any_to_Uint8Array(address_pool, key, "key"); + var key_address, key_length = (libsodium._crypto_stream_xchacha20_keybytes()) | 0; + if (key.length !== key_length) { + _free_and_throw_type_error(address_pool, "invalid key length"); + } + key_address = _to_allocated_buf_address(key); + address_pool.push(key_address); + + // ---------- output output_message (buf) + + var output_message_length = (input_message_length) | 0, + output_message = new AllocatedBuf(output_message_length), + output_message_address = output_message.address; + + address_pool.push(output_message_address); + + if ((libsodium._crypto_stream_xchacha20_xor_ic(output_message_address, input_message_address, input_message_length, 0, nonce_address, nonce_increment, 0, key_address)) === 0) { + var ret = _format_output(output_message, outputFormat); + _free_all(address_pool); + return ret; + } + _free_and_throw_error(address_pool, "invalid usage"); + } + + function randombytes_buf(length, outputFormat) { + var address_pool = []; + + _check_output_format(outputFormat); + // ---------- input: length (uint) + + _require_defined(address_pool, length, "length"); + + if (!(typeof length === "number" && (length | 0) === length) || length < 0) { + _free_and_throw_type_error(address_pool, "length must be an unsigned integer"); + } + + // ---------- output output (buf) + + var output_length = (length) | 0, + output = new AllocatedBuf(output_length), + output_address = output.address; + + address_pool.push(output_address); + + libsodium._randombytes_buf(output_address, length); + var ret = (_format_output(output, outputFormat)); + _free_all(address_pool); + return ret; + } + + function randombytes_buf_deterministic(length, seed, outputFormat) { + var address_pool = []; + + _check_output_format(outputFormat); + // ---------- input: length (uint) + + _require_defined(address_pool, length, "length"); + + if (!(typeof length === "number" && (length | 0) === length) || length < 0) { + _free_and_throw_type_error(address_pool, "length must be an unsigned integer"); + } + + // ---------- input: seed (buf) + + seed = _any_to_Uint8Array(address_pool, seed, "seed"); + var seed_address, seed_length = (libsodium._randombytes_seedbytes()) | 0; + if (seed.length !== seed_length) { + _free_and_throw_type_error(address_pool, "invalid seed length"); + } + seed_address = _to_allocated_buf_address(seed); + address_pool.push(seed_address); + + // ---------- output output (buf) + + var output_length = (length) | 0, + output = new AllocatedBuf(output_length), + output_address = output.address; + + address_pool.push(output_address); + + libsodium._randombytes_buf_deterministic(output_address, length, seed_address); + var ret = (_format_output(output, outputFormat)); + _free_all(address_pool); + return ret; + } + + function randombytes_close(outputFormat) { + var address_pool = []; + + _check_output_format(outputFormat); + libsodium._randombytes_close(); + } + + function randombytes_random(outputFormat) { + var address_pool = []; + + _check_output_format(outputFormat); + var random_value = libsodium._randombytes_random() >>> 0; + var ret = (random_value); + _free_all(address_pool); + return ret; + } + + function randombytes_set_implementation(implementation, outputFormat) { + var address_pool = []; + + _check_output_format(outputFormat); + // ---------- input: implementation (randombytes_implementation) + + var implementation_address = libsodium._malloc(6 * 4); + for (var i = 0; i < 6; i++) { + libsodium.setValue(implementation_address + i * 4, + libsodium.Runtime.addFunction(implementation + [["implementation_name", "random", "stir", "uniform", "buf", "close"][i]]), + "i32"); + } + + if (!((libsodium._randombytes_set_implementation(implementation_address) | 0) === 0)) { + _free_and_throw_error(address_pool, "unsupported implementation"); + } + _free_all(address_pool); + } + + function randombytes_stir(outputFormat) { + var address_pool = []; + + _check_output_format(outputFormat); + libsodium._randombytes_stir(); + } + + function randombytes_uniform(upper_bound, outputFormat) { + var address_pool = []; + + _check_output_format(outputFormat); + // ---------- input: upper_bound (uint) + + _require_defined(address_pool, upper_bound, "upper_bound"); + + if (!(typeof upper_bound === "number" && (upper_bound | 0) === upper_bound) || upper_bound < 0) { + _free_and_throw_type_error(address_pool, "upper_bound must be an unsigned integer"); + } + + var random_value = libsodium._randombytes_uniform(upper_bound) >>> 0; + var ret = (random_value); + _free_all(address_pool); + return ret; + } + + function sodium_version_string() { + var address_pool = []; + + var version = libsodium._sodium_version_string(); + var ret = (libsodium.UTF8ToString(version)); + _free_all(address_pool); + return ret; + } + + + + exports.add = add; + exports.base64_variants = base64_variants; + exports.compare = compare; + exports.from_base64 = from_base64; + exports.from_hex = from_hex; + exports.from_string = from_string; + exports.increment = increment; + exports.is_zero = is_zero; + exports.libsodium = libsodiumModule; + exports.memcmp = memcmp; + exports.memzero = memzero; + exports.output_formats = output_formats; + exports.pad = pad; + exports.unpad = unpad; + exports.ready = ready; + exports.symbols = symbols; + exports.to_base64 = to_base64; + exports.to_hex = to_hex; + exports.to_string = to_string; + //exports.someArray = someArray; + + return exports; + } + + var _onload = + typeof root.sodium === "object" && typeof root.sodium.onload === "function" ? + root.sodium.onload : + null; + if (typeof define === "function" && define.amd) { + define(["exports", "libsodium-sumo"], expose_wrappers); + } else if ( + typeof exports === "object" && + typeof exports.nodeName !== "string" + ) { + expose_wrappers(exports, require("libsodium-sumo")); + } else { + root.sodium = expose_wrappers((root.commonJsStrict = {}), root.libsodium); + } + _onload && root.sodium.ready.then(function () { + _onload(root.sodium) + }); +})(this); diff --git a/core/twopc/Evaluator.js b/core/twopc/Evaluator.js new file mode 100644 index 0000000..163eb06 --- /dev/null +++ b/core/twopc/Evaluator.js @@ -0,0 +1,28 @@ +export class Evaluator{ + constructor(parent){ + // s is the current session + this.s = parent; + } + + getNonFixedLabels(encLabels, otKeys, nonFixedBits){ + const nonFixedLabels = []; + for (let i = 0; i < nonFixedBits.length; i += 1) { + const bit = nonFixedBits[i]; + const ct = encLabels.slice(i * 32, (i+1) * 32); + const inputLabel = this.s.ot.decryptWithKey(ct, bit, otKeys[i]); + nonFixedLabels.push(inputLabel); + } + return nonFixedLabels; + } + + + async evaluateBatch(batch, cNo){ + const outputs = await this.s.workers[cNo].evaluateBatch(batch); + const parsed = []; + for (let i=0; i < batch.length; i++){ + parsed.push(new Uint8Array(outputs[i])); + } + return parsed; + } + +} \ No newline at end of file diff --git a/core/twopc/GCWorker.js b/core/twopc/GCWorker.js new file mode 100644 index 0000000..f7973b9 --- /dev/null +++ b/core/twopc/GCWorker.js @@ -0,0 +1,85 @@ +import WorkerPool from './WorkerPool.js'; + +export class GCWorker extends WorkerPool{ + // class CGWorker provides convenience functions to speak to the web worker + constructor(numWorkers, processMonitor){ + super(numWorkers, chrome.extension.getURL('core/twopc/webWorkers/gcworker.js')); + // pm is an instance of ProcessMonitor + this.pm = processMonitor; + } + + // parse text circuit of ArrayBuffer type for all workers + async parse(circuit_ab){ + const allPromises = []; + for (let i=0; i < this.workers.length; i++){ + const worker = this.workers[i]; + allPromises.push(new Promise(function(resolve) { + worker.onmessage = function(event) { + if (event.data === 'DONE'){ + resolve(); + } + else { + console.log('unexpected response from worker'); + throw('unexpected response from worker'); + } + }; + const obj = {msg: 'parse', data: circuit_ab}; + worker.postMessage(obj); + })); + } + return Promise.all(allPromises); + } + + // garble a circuit (which must have already been parsed) + async garble(obj){ + const worker = this.workers[0]; + return new Promise(function(resolve) { + worker.onmessage = function(event) { + resolve(event.data); + }; + worker.postMessage( {msg: 'garble', data: obj}); + }); + } + + // pm is an instance of ProgressMonitor + async garbleBatch(count, obj){ + const batch = []; + for (let i=0; i < count; i++){ + batch.push(obj); + } + const output = await this.workerPool(batch, this.garbleBatchDoWork, this.pm, 'garbling'); + return output; + } + + garbleBatchDoWork(batchItem, worker){ + return new Promise(function(resolve) { + worker.onmessage = function(event) { + worker['isResolved'] = true; + resolve(event.data); + }; + worker.postMessage( {msg: 'garble', data: batchItem}); + }); + } + + async evaluateBatch(batch){ + //const output = await this.workerPool(batch, this.evaluateBatchDoWork, this.pm, 'evaluating'); + const output = await this.workerPool(batch, this.evaluateBatchDoWork); + return output; + } + + evaluateBatchDoWork(batchItem, worker){ + const ga = batchItem[0]; + const tt = batchItem[1]; + const obj = {msg: 'setTruthTable', data: tt.buffer}; + worker.postMessage(obj); + return new Promise(function(resolve) { + worker.onmessage = function(event) { + worker['isResolved'] = true; + resolve(event.data); + }; + const obj = {msg: 'evaluate', data: ga.buffer}; + worker.postMessage(obj); + }); + } + +} \ No newline at end of file diff --git a/core/twopc/Garbler.js b/core/twopc/Garbler.js new file mode 100644 index 0000000..79faad1 --- /dev/null +++ b/core/twopc/Garbler.js @@ -0,0 +1,183 @@ +import {concatTA, assert, ba2int, expandRange} from './../utils.js'; + +export class Garbler{ + // class Garbler implements the role of the client as the garbler + s; + garbledC; + + constructor(parent){ + // this.s is the TWOPC class + this.s = parent; + // this.garbledC will contain truth table, output labels and input labels for each + // circuit after it is garbled + this.garbledC = []; + } + + async getAllB(allB){ + let fixedCount = 0; + let nonFixedCount = 0; + + for (let i = 1; i < this.s.cs.length; i++) { + if (i !== 6){ + fixedCount += this.s.cs[i].notaryFixedInputSize; + } + else { + fixedCount += 160 + this.s.C6Count * 128; + } + console.log('fixed count for ', i, ' is ', fixedCount); + nonFixedCount += this.s.cs[i].notaryNonFixedInputSize; + } + + console.log('in getAllB fixedCount, nonFixedCount', fixedCount, nonFixedCount); + const OT0PoolSize = Math.ceil(nonFixedCount/2 * 1.2); + const OT1PoolSize = Math.ceil(nonFixedCount/2 * 1.2); + + // 4000 OT for OT-ghash + const expectedLen = (OT0PoolSize + OT1PoolSize + fixedCount + 6000)*32; + assert(allB.length === expectedLen); + + const fixedBlob = allB.slice(0, fixedCount*32); + const nonFixedPoolBlob = allB.slice(fixedCount*32); + + const encLabels = []; + let fixedBlobIdx = 0; + for (let j = 1; j < this.s.cs.length; j++) { + const c = this.s.cs[j]; + let inputCount = c.notaryFixedInputSize; + if (j === 6){ + inputCount = 160 + this.s.C6Count * 128; + } + assert(inputCount*32 === this.garbledC[j].il.notaryFixed.length); + for (let i = 0; i < inputCount; i++) { + const m0 = this.garbledC[j].il.notaryFixed.slice(i*32, i*32+16); + const m1 = this.garbledC[j].il.notaryFixed.slice(i*32+16, i*32+32); + const B = fixedBlob.slice(fixedBlobIdx*32, fixedBlobIdx*32+32); + encLabels.push(this.s.ot.encrypt(m0, m1, B)); + fixedBlobIdx++; + } + } + assert(fixedBlobIdx*32 === fixedBlob.length); + + const arrOfB = []; + for ( let i = 0; i < nonFixedPoolBlob.length/32; i++) { + arrOfB[i] = nonFixedPoolBlob.slice(i*32, i*32+32); + } + await this.s.ot.prepareEncryptionKeys(arrOfB); + return concatTA(...encLabels); + } + + async garbleAll(){ + // first garble circuit 5 once, so that future invocations can reuse labels + const rv5 = await this.s.workers[5].garble(); + + // garble the rest of the circuits asyncronously + const allPromises = []; + for (let cNo =1; cNo < this.s.cs.length; cNo++){ + if (cNo === 5){ + allPromises.push(Promise.resolve('empty')); + continue; + } + const worker = this.s.workers[cNo]; + allPromises.push(worker.garble()); + } + + // reuse labels of c5 and garble in batches + const allTt = [new Uint8Array(rv5.tt)]; + const allOl = [new Uint8Array(rv5.ol)]; + const allIl = this.separateLabels(new Uint8Array(rv5.il), 5); + + const outputs = await this.s.workers[5].garbleBatch(this.s.C5Count-1, { + reuseLabels: concatTA(allIl.notaryFixed, allIl.clientNonFixed), + reuseIndexes: expandRange(0, 320), + reuseR: new Uint8Array(rv5.R) + }); + + for (let i=0; i < this.s.C5Count-1; i++){ + const out = outputs[i]; + allTt.push(new Uint8Array(out.tt)); + allOl.push(new Uint8Array(out.ol)); + const labels = this.separateLabels(new Uint8Array(out.il), 5); + allIl.clientFixed = concatTA(allIl.clientFixed, labels.clientFixed); + } + this.garbledC[5] = { + tt: concatTA(...allTt), + ol: concatTA(...allOl), + il: allIl}; + + // all the other circuits have been garbled by now + const allRv = await Promise.all(allPromises); + + for (let cNo=1; cNo < this.s.cs.length; cNo++){ + const rv = allRv[cNo-1]; + if (cNo === 5){ + // c5 already dealt with + continue; + } + this.garbledC[cNo] = { + tt: new Uint8Array(rv.tt), + ol: new Uint8Array(rv.ol), + il: this.separateLabels(new Uint8Array(rv.il), cNo)}; + } + } + + getNonFixedEncLabels(idxBlob, cNo){ + const nfis = this.s.cs[cNo].notaryNonFixedInputSize; + assert(nfis*2 === idxBlob.length); + + const encLabels = []; + console.time('encryptWithKeyAtIndex'); + for (let i=0; i < nfis; i++){ + const idx = ba2int(idxBlob.subarray(i*2, i*2+2)); + const m0 = this.garbledC[cNo].il.notaryNonFixed.subarray(i*32, i*32+16); + const m1 = this.garbledC[cNo].il.notaryNonFixed.subarray(i*32+16, i*32+32); + const encr = this.s.ot.encryptWithKeyAtIndex(m0, m1, idx); + encLabels.push(encr); + } + console.timeEnd('encryptWithKeyAtIndex'); + console.log('encryptWithKeyAtIndex for count:', nfis); + + return concatTA(...encLabels); + } + + getClientLabels(nonFixedBits, cNo){ + const fixedBits = this.s.cs[cNo].fixedInputs; + const clientInputs = [].concat(nonFixedBits, fixedBits); + const inputLabels = []; + const clientLabelBlob = concatTA( + this.garbledC[cNo].il.clientNonFixed, + this.garbledC[cNo].il.clientFixed); + assert(clientInputs.length*32 == clientLabelBlob.length); + + for (let i=0; i < clientInputs.length; i++){ + const bit = clientInputs[i]; + const label = clientLabelBlob.subarray(i*32+bit*16, i*32+bit*16+16); + inputLabels.push(label); + } + return concatTA(...inputLabels); + } + + // separate one continuous blob of input labels into 4 blobs as in Labels struct + separateLabels(blob, cNo) { + const c = this.s.cs[cNo]; + if (blob.length != (c.notaryInputSize+c.clientInputSize)*32) { + throw('in separateLabels'); + } + const labels = {}; + let offset = 0; + labels['notaryNonFixed'] = blob.slice(offset, offset+c.notaryNonFixedInputSize*32); + offset += c.notaryNonFixedInputSize * 32; + + labels['notaryFixed'] = blob.slice(offset, offset+c.notaryFixedInputSize*32); + offset += c.notaryFixedInputSize * 32; + + labels['clientNonFixed'] = blob.slice(offset, offset+c.clientNonFixedInputSize*32); + offset += c.clientNonFixedInputSize * 32; + + labels['clientFixed'] = blob.slice(offset, offset+c.clientFixedInputSize*32); + offset += c.clientFixedInputSize * 32; + assert(offset === blob.length); + return labels; + } +} + + diff --git a/core/twopc/OT.js b/core/twopc/OT.js new file mode 100644 index 0000000..363a768 --- /dev/null +++ b/core/twopc/OT.js @@ -0,0 +1,201 @@ +import {OTWorker} from './OTWorker.js'; +import {concatTA, int2ba, assert, encrypt_generic, decrypt_generic} from './../utils.js'; + +export class OT{ + // class OT implements oblivious transfer protocol based on + // [1] The Simplest Protocol for Oblivious Transfer + // as much pre-computation as possiblle is done in the offline phase + + constructor(){ + this.decryptionKeys = []; + this.notaryA = null; // A value of notary the sender + this.worker = new OTWorker(4); + + // pools are used to pre-compute in the offline phase the decryption key + // for a receiver's bit in the oblivious transfer + this.poolOf0 = []; // item format {k_R:, B:, idx:<>} + this.poolOf1 = []; // + + // OT for the sender + this.a = sodium.crypto_core_ristretto255_scalar_random(); + this.A = sodium.crypto_scalarmult_ristretto255_base(this.a); + this.encryptionKeys = []; + } + + setA(A){ + this.notaryA = A; + } + + getSenderA(){ + return this.A; + } + + // for each bit in bits pre-compute B and k_R (per [1]) + saveDecryptionKeysOld(bits){ + const receiverBs = []; + // we will reuse the same B to save time + // during release REUSE IS NOT ALLOWED - IT BREAKS SECURITY + const b0 = sodium.crypto_core_ristretto255_scalar_random(); + const B0 = sodium.crypto_scalarmult_ristretto255_base(b0); + const k0 = sodium.crypto_generichash(16, sodium.crypto_scalarmult_ristretto255(b0, this.notaryA)); + + const b1 = sodium.crypto_core_ristretto255_scalar_random(); + const gb1 = sodium.crypto_scalarmult_ristretto255_base(b1); + const B1 = sodium.crypto_core_ristretto255_add(this.notaryA, gb1); + const k1 = sodium.crypto_generichash(16, sodium.crypto_scalarmult_ristretto255(b1, this.notaryA)); + + for (let i=0; i < bits.length; i++){ + const bit = bits[i]; + this.decryptionKeys.push(bit === 0 ? k0 : k1); + receiverBs.push(bit === 0 ? B0 : B1); + } + console.log('saveDecryptionKeys for count:', bits.length); + return receiverBs; + } + + async saveDecryptionKeys(bits){ + const receiverBs = []; + const entries = await this.worker.saveDecryptionKeys(bits, this.notaryA); + for (const e of entries){ + this.decryptionKeys.push(e[0]); + receiverBs.push(e[1]); + } + return receiverBs; + } + + + // decrypts 1-of-2 ciphertexts for a bit "bit" with a key "key" at index "idx" + // returns the plaintext + decryptWithKeyFromIndex(ciphertext, bit, idx){ + assert(ciphertext.length == 32); + assert(bit === 0 || bit === 1); + assert(this.decryptionKeys[idx] != undefined); + const encMessage = ciphertext.slice(16*bit, 16*bit+16); + return decrypt_generic(encMessage, this.decryptionKeys[idx], 0); + } + + // decrypts 1-of-2 ciphertexts for a bit "bit" with a key from obj.k_R + decryptWithKey(ciphertext, bit, key){ + assert(ciphertext.length === 32 && key.length === 16); + assert(bit === 0 || bit === 1); + const encMessage = ciphertext.slice(16*bit, 16*bit+16); + return decrypt_generic(encMessage, key, 0); + } + + // we prepare B and k_R for 120% of the bits. The extra 20% is needed because we don't + // know in advance exactly how many 1s and 0s we'll need during the online phase + precomputePoolOld(numBits){ + // we will reuse the same B to save time + // during release REUSE IS NOT ALLOWED - IT BREAKS SECURITY + const b0 = sodium.crypto_core_ristretto255_scalar_random(); + const B0 = sodium.crypto_scalarmult_ristretto255_base(b0); + const k0 = sodium.crypto_generichash(16, sodium.crypto_scalarmult_ristretto255(b0, this.notaryA)); + + const b1 = sodium.crypto_core_ristretto255_scalar_random(); + const gb1 = sodium.crypto_scalarmult_ristretto255_base(b1); + const B1 = sodium.crypto_core_ristretto255_add(this.notaryA, gb1); + const k1 = sodium.crypto_generichash(16, sodium.crypto_scalarmult_ristretto255(b1, this.notaryA)); + + console.time('precomputePool'); + for (let i = 0; i < Math.ceil(numBits/2 * 1.2) ; i++){ + this.poolOf0.push({k_R:k0, B:B0}); + } + for (let i = 0; i < Math.ceil(numBits/2 * 1.2); i++){ + this.poolOf1.push({k_R:k1, B:B1}); + } + console.timeEnd('precomputePool'); + console.log('total bits', numBits); + } + + // we prepare B and k_R for 120% of the bits. The extra 20% is needed because we don't + // know in advance exactly how many 1s and 0s we'll need during the online phase + async precomputePool(numBits){ + const count = Math.ceil(numBits/2 * 1.2); // we need "count" zeroes and "count" ones + const entries = await this.worker.precomputePool(count, this.notaryA); + assert(entries.length === count*2); + for (const e of entries.slice(0, count)){ + this.poolOf0.push({k_R:e[0], B:e[1]}); + } + for (const e of entries.slice(count, count*2)){ + this.poolOf1.push({k_R:e[0], B:e[1]}); + } + } + + // given an array of bits, return the index for each bit in the pool + // and decryption keys for OT + getIndexesFromPool(bits){ + const idxArray = []; + const otKeys = []; + for (let i=0; i < bits.length; i++){ + const otbit = this.getFromPool(bits[i]); + idxArray.push(int2ba(otbit.idx, 2)); + otKeys.push(otbit.k_R); + } + return [concatTA(...idxArray), otKeys]; + } + + + // return an array of B values from poolOf0 and poolOf1 in random sequence + // and remember each B's index in that sequence. + getRandomizedPool(){ + function getRandomInt(min, max) { + min = Math.ceil(min); + max = Math.floor(max); + return Math.floor(Math.random() * (max - min + 1)) + min; + } + + const randomizedB = []; + const fullPool = [].concat(this.poolOf0, this.poolOf1); + const origLen = fullPool.length; + for (let i=0; i < origLen; i++){ + const randIdx = getRandomInt(0, fullPool.length-1); + const ot = fullPool.splice(randIdx, 1)[0]; + // modifying ot will be reflected in this.poolOf0/this.poolOf1 because of pass-by-reference + ot.idx = i; + randomizedB.push(ot.B); + } + return randomizedB; + } + + + // gets either 0 or 1 from pool + getFromPool(bit){ + assert(bit === 0 || bit === 1); + const pool = (bit === 0) ? this.poolOf0 : this.poolOf1; + const item = pool.pop(); + assert(this.poolOf0.length > 0 && this.poolOf0.length > 0); + return item; + } + + // given the receiver's B, encrypt m0 and m1 + // we don't parallelize this function because the amount of encryptions is small + encrypt(m0, m1, B){ + const k0 = sodium.crypto_generichash(16, sodium.crypto_scalarmult_ristretto255(this.a, B)); + const sub = sodium.crypto_core_ristretto255_sub(B, this.A); + const k1 = sodium.crypto_generichash(16, sodium.crypto_scalarmult_ristretto255(this.a, sub)); + const e0 = encrypt_generic(m0, k0, 0); + const e1 = encrypt_generic(m1, k1, 0); + return concatTA(e0, e1); + } + + encryptWithKeyAtIndex(m0, m1, idx){ + const k0 = this.encryptionKeys[idx][0]; + const k1 = this.encryptionKeys[idx][1]; + const e0 = encrypt_generic(m0, k0, 0); + const e1 = encrypt_generic(m1, k1, 0); + return concatTA(e0, e1); + } + + // (client as the sender) for each B in arrOfB save an encryption keypair [k0,k1] + async prepareEncryptionKeys(arrOfB){ + console.time('prepareEncryptionKeys'); + const entries = await this.worker.prepareEncryptionKeys(arrOfB, this.a, this.A); + assert(entries.length === arrOfB.length); + for (const e of entries){ + this.encryptionKeys.push([e[0], e[1]]); + } + console.timeEnd('prepareEncryptionKeys'); + console.log('prepareEncryptionKeys for count:', arrOfB.length); + } +} + \ No newline at end of file diff --git a/core/twopc/OTWorker.js b/core/twopc/OTWorker.js new file mode 100644 index 0000000..0714113 --- /dev/null +++ b/core/twopc/OTWorker.js @@ -0,0 +1,147 @@ +// note that unlike with GCWorker class, the caller of OTWorker's methods doesn't have +// to manage the worker pool. We manage them internally inside the class. +import {bitsToBytes, concatTA, assert} from './../utils.js'; + +import WorkerPool from './WorkerPool.js'; + +export class OTWorker extends WorkerPool{ + constructor(numWorkers){ + super(numWorkers, chrome.extension.getURL('core/twopc/webWorkers/otworker.js')); + } + + async saveDecryptionKeys(bits, A){ + let padCount = 0; + if (bits.length % 8 > 0){ + // make bits length a multiple of 8 + padCount = 8 - bits.length % 8; + bits.push(...Array(padCount).fill(0)); + } + const bytes = bitsToBytes(bits); + // put chunks of 128 bytes into a batch + const batch = []; + const chunkSize = 128; + for (let i=0; i < Math.ceil(bytes.length/chunkSize); i++){ + batch.push([bytes.slice(i*chunkSize, (i+1)*chunkSize), A]); + } + const outputs = await this.workerPool(batch, this.saveDecryptionKeysDoWork); + const arrOutput = []; + for (let i=0; i < batch.length; i++){ + arrOutput[i] = new Uint8Array(outputs[batch.length-1-i]); + } + const dataBlob = concatTA(...arrOutput); + assert(dataBlob.length === bits.length*48); + // deserialize data + const entries = []; + for (let i=0; i < bits.length; i++){ + const k = dataBlob.slice(i*48, i*48+16); + const B = dataBlob.slice(i*48+16, i*48+48); + entries.push([k,B]); + } + return entries.slice(0, entries.length-padCount); + } + + async precomputePool(count, A){ + // chunk up into 512 items and put chunks into a batch + const batch = []; + const chunkSize = 512; + const chunkCount = Math.ceil(count/chunkSize); + const lastChunkSize = count - (chunkSize * (chunkCount-1)); + for (let i=0; i < chunkCount; i++){ + if (i === chunkCount-1){ + batch.push([lastChunkSize, A]); + } + else{ + batch.push([chunkSize, A]); + } + } + const outputs = await this.workerPool(batch, this.precomputePoolDoWork); + const arrOutput = []; + for (let i=0; i < batch.length; i++){ + arrOutput[i] = new Uint8Array(outputs[i]); + } + // deserialize data + const entries0 = []; + const entries1 = []; + for (let i=0; i < arrOutput.length; i++){ + const size = (i < (chunkCount-1)) ? chunkSize : lastChunkSize; + const batch = arrOutput[i]; + for (let j=0; j < size*2; j++){ + const k = batch.slice(j*48, j*48+16); + const B = batch.slice(j*48+16, j*48+48); + if (j < size){ + entries0.push([k,B]); + } + else { + entries1.push([k,B]); + } + } + } + const allEntries = [].concat(entries0, entries1); + assert(allEntries.length === count*2); + return allEntries; + } + + async prepareEncryptionKeys(arrOfB, a, A){ + const batch = []; + const chunkSize = 1024; + const chunkCount = Math.ceil(arrOfB.length/chunkSize); + for (let i=0; i < chunkCount; i++){ + batch.push([concatTA(...arrOfB.slice(i*chunkSize, (i+1)*chunkSize)), a, A]); + } + const outputs = await this.workerPool(batch, this.prepareEncryptionKeysDoWork); + const arrOutput = []; + for (let i=0; i < batch.length; i++){ + arrOutput[i] = new Uint8Array(outputs[i]); + } + const dataBlob = concatTA(...arrOutput); + assert(dataBlob.length === arrOfB.length*32); + // deserialize data + const entries = []; + for (let i=0; i < arrOfB.length; i++){ + const k0 = dataBlob.slice(i*32, i*32+16); + const k1 = dataBlob.slice(i*32+16, i*32+32); + entries.push([k0,k1]); + } + return entries; + } + + prepareEncryptionKeysDoWork(batchItem, worker){ + const bytes = batchItem[0]; + const a = batchItem[1]; + const A = batchItem[2]; + return new Promise(function(resolve) { + worker.onmessage = function(event) { + worker['isResolved'] = true; + resolve(event.data.blob); + }; + const obj = {msg:'prepareEncryptionKeys', data:{bytes:bytes.buffer, a:a.buffer, A:A.buffer}}; + worker.postMessage(obj); + }); + } + + precomputePoolDoWork(batchItem, worker){ + const count = batchItem[0]; + const A = batchItem[1]; + return new Promise(function(resolve) { + worker.onmessage = function(event) { + worker['isResolved'] = true; + resolve(event.data.blob); + }; + const obj = {msg:'precomputePool', data:{count:count, A:A.buffer}}; + worker.postMessage(obj); + }); + } + + saveDecryptionKeysDoWork(batchItem, worker){ + const bytes = batchItem[0]; + const A = batchItem[1]; + return new Promise(function(resolve) { + worker.onmessage = function(event) { + worker['isResolved'] = true; + resolve(event.data.blob); + }; + const obj = {msg:'saveDecryptionKeys', data:{bytes:bytes.buffer, A:A.buffer}}; + worker.postMessage(obj); + }); + } +} \ No newline at end of file diff --git a/core/twopc/Paillier2PC.js b/core/twopc/Paillier2PC.js new file mode 100644 index 0000000..77a0659 --- /dev/null +++ b/core/twopc/Paillier2PC.js @@ -0,0 +1,297 @@ +/* eslint-disable no-console */ +/* eslint-disable max-classes-per-file */ + +import * as bcu from './../third-party/math.js'; +import {ba2str, concatTA, int2ba, str2ba, ba2hex, ba2int} from './../utils.js'; + +function pad(str) { + if (str.length % 2 === 1) { + return `0${str}`; + } + return str; +} + +// eslint-disable-next-line no-unused-vars +class PaillierPubkey { + constructor(n, g) { + this.n = n; + this.n2 = n ** 2n; + this.g = g; + } + + multiply(ciphertext, cleartext) { + return bcu.modPow(ciphertext, cleartext, this.n2); + } + + encrypt(m) { + let r; + do { + r = bcu.randBetween(this.n); + } while (bcu.gcd(r, this.n) !== 1n); + return (bcu.modPow(this.g, m, this.n2) * bcu.modPow(r, this.n, this.n2)) % this.n2; + } + + addCleartext(ciphertext, cleartext) { + return (ciphertext * bcu.modPow(this.g, cleartext, this.n2)) % this.n2; + } + + addCiphertext(ct1, ct2) { + return (ct1 * ct2) % this.n2; + } +} + +// Protocol to compute EC point addition in Paillier +// +// we need to find xr = lambda**2 - xp - xq, where +// lambda = (yq - yp)(xq - xp)**-1 +// (when p is prime then) a**-1 mod p == a**p-2 mod p +// Simplifying: +// xr == (yq**2 - 2yqyp + yp**2) (xq - xp)**2p-4 - xp - xq +// we have 3 terms +// A = (yq**2 - 2yqyp + yp**2) +// B = (xq - xp)**2p-4 +// C = - xp - xq +// +// class Paillier2PC is the client's side part of 2PC +// you should launch the notary side of 2PC with: +// go build -o notary2pc && ./notary2pc + +// TODO rename Paillier2PC into ECDH2PC + +// eslint-disable-next-line no-unused-vars +export class Paillier2PC { + // x and y are 32-byte long byte arrays: coordinates of server pubkey + constructor(parent, x_, y_, ) { + this.send = parent.send; + this.notary = parent.notary; + this.clientKey = parent.clientKey; + this.notaryKey = parent.notaryKey; + this.encryptToNotary = parent.encryptToNotary; + this.decryptFromNotary = parent.decryptFromNotary; + + this.uid = parent.uid; + // define secp256r1 curve + this.secp256r1 = new ECSimple.Curve( + 0xFFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFCn, + 0x5AC635D8AA3A93E7B3EBBD55769886BC651D06B0CC53B0F63BCE3C3E27D2604Bn, + 0xFFFFFFFF00000000FFFFFFFFFFFFFFFFBCE6FAADA7179E84F3B9CAC2FC632551n, + (2n ** 224n) * (2n ** 32n - 1n) + 2n ** 192n + 2n ** 96n - 1n, + new ECSimple.ModPoint( + 0x6B17D1F2E12C4247F8BCE6E563A440F277037D812DEB33A0F4A13945D898C296n, + 0x4FE342E2FE1A7F9B8EE7EB4A7C0F9E162BCE33576B315ECECBB6406837BF51F5n, + ), + ); + + const x = ba2int(x_); + const y = ba2int(y_); + + this.serverPubkey = new ECSimple.ModPoint(x, y); + + this.pPriv = bcu.randBetween(this.secp256r1.n - 1n, 1n); + // debug only delete priv by 2 so that the final client priv doesnt + // overflow 32 bytes - to make openssl happy + // remove in production + this.pPriv = this.pPriv / 2n; + this.pPrivG = this.secp256r1.multiply(this.secp256r1.g, this.pPriv); + + this.share1 = this.secp256r1.multiply(this.serverPubkey, this.pPriv); + + + // var ecPubKey = secp256r1.add(qPrivG, pPrivG) + // var pms = secp256r1.add(share1, share2) + // console.log('pms is', pms) + } + + // run 2PC computation with the notary + async run() { + const payload1 = str2ba(JSON.stringify({ + serverX: pad(this.serverPubkey.x.toString(16)), + serverY: pad(this.serverPubkey.y.toString(16)), + share1X: pad(this.share1.x.toString(16)), + share1Y: pad(this.share1.y.toString(16)), + })); + const step1 = JSON.parse(ba2str(await this.send('step1', payload1))); + const p = this.secp256r1.p; + + // (party1 is the notary, party2 is the client) + // -------- PHASE 1: computing term B + + // party1 provides P(xq) + // var Pxq = publicKey.encrypt(qPrivG.x) + // // negative xq + // // 5 - 3 mod 6 == 5 + (6 -3) mod 6 + // var Pnxq = publicKey.encrypt(secp256r1.p - qPrivG.x) + + // party2: + // 1) compute P(A) == P(xq - xp) + // 2) blind with B: P(AB) == P(A)^B + // 3) (to prevent factorizing AB) blind with C: P(AB+C) == P(AB)*C + // 4) send 1) P(AB+C) and 2) C mod p + + // if xp > xq then PA below is negative and we'd have to apply the mask C the size of + // n = 2048bits we don't want that. If we keep PA positive then the mask C size will be + // 256+256=512 bits for this reason we increase xp by prime (mod prime) + + const n = BigInt(`0x${step1.n}`, 16); + const g = BigInt(`0x${step1.g}`, 16); + const Pxq = BigInt(`0x${step1.Pxq}`, 16); + const Pnxq = BigInt(`0x${step1.Pnxq}`, 16); + + this.pubkey = new PaillierPubkey(n, g); + + const PA = this.pubkey.addCleartext(Pxq, p - this.share1.x); + const maskB = bcu.randBetween(2n ** 256n); + const PAB = this.pubkey.multiply(PA, maskB); + const maskC = bcu.randBetween(2n ** 512n); + const PABC = this.pubkey.addCleartext(PAB, maskC); + const Cmodp = maskC % p; + + const payload2 = str2ba(JSON.stringify({ + PABC: pad(PABC.toString(16)), + Cmodp: pad(Cmodp.toString(16)), + })); + const fetch2 = this.send('step2', payload2, true); + + // while fetching we can compute + + // -------- PHASE 2: computing term A + + // party1 provides: P(yq**2), P(-2yq) (was done in step1) + + // var Pyq2 = publicKey.encrypt(bcu.modPow(qPrivG.y, 2n, secp256r1.p)) + // var Pn2yq = publicKey.encrypt(2n * (secp256r1.p - qPrivG.y) % secp256r1.p) + + // party2 + // 1) computes P(term A) = P(yq**2) + P(-2yq)**yp + P(yp**2) + // 2) blind with c1 and c2 : d == P(termA * c1 mod c2) + // 3) send d and c2 mod p + + const Pyq2 = BigInt(`0x${step1.Pyq2}`, 16); + const Pn2yq = BigInt(`0x${step1.Pn2yq}`, 16); + + const PtermA = this.pubkey.addCleartext( + this.pubkey.addCiphertext(Pyq2, this.pubkey.multiply(Pn2yq, this.share1.y)), + bcu.modPow(this.share1.y, 2n, p), + ); + + const c1 = bcu.randBetween(2n ** 512n); + const c2 = bcu.randBetween(2n ** 1024n); + const d = this.pubkey.addCleartext(this.pubkey.multiply(PtermA, c1), c2); + const c2modp = c2 % p; + + const step2 = JSON.parse(ba2str(await fetch2)); + + // party1 + // computing term B continued + // 1) decrypt to get AB+C + // 2) reduce AB+C mod p + // 3) subtract C to get AB mod p + // 4) compute ABraised = (AB)**2p-4 mod p + // 5) send P(ABraised) + + // var DABC = privateKey.decrypt(PABC) + // var ABC = DABC % secp256r1.p + // var AB = (ABC + secp256r1.p - Cmodp) % secp256r1.p + // var ABraised = bcu.modPow(AB, 2n*secp256r1.p - 4n, secp256r1.p) + // var PABraised = publicKey.encrypt(ABraised) + + // party2 + // (remember that ABraised == (A**2p-4)(B**2p-4) + // in order to get (A**2p-4), we need to divide by (B**2p-4) or multiply by (B**2p-4)**-1) + // 1) compute P(term B) = P(ABraised) ** (B**2p-4)**-1 mod p + // 2) blind with a1 and a2 : b == P(termB * a1 + a2) + // 3) send b and a2 mod p + + const PABraised = BigInt(`0x${step2.PABraised}`, 16); + const Braised = bcu.modPow(maskB, p - 3n, p); + const Binv = bcu.modInv(Braised, p); + const PtermB = this.pubkey.multiply(PABraised, Binv); + const a1 = bcu.randBetween(2n ** 512n); + const a2 = bcu.randBetween(2n ** 1024n); + const b = this.pubkey.addCleartext(this.pubkey.multiply(PtermB, a1), a2); + const a2modp = a2 % p; + + const payload3 = str2ba(JSON.stringify({ + b: pad(b.toString(16)), + a2modp: pad(a2modp.toString(16)), + d: pad(d.toString(16)), + c2modp: pad(c2modp.toString(16)), + })); + const step3 = JSON.parse(ba2str(await this.send('step3', payload3))); + + // -------- PHASE 3: computing termA*termB and term C + + // party1 + // 1) compute termB*a1*termA*c2 + // 2) send P() + + // var termBa1 = (privateKey.decrypt(b) - a2modp) % secp256r1.p + // var termAc2 = (privateKey.decrypt(d) - c2modp) % secp256r1.p + // var PtermABmasked = publicKey.encrypt(termBa1 * termAc2 % secp256r1.p) + + // party2 + // 1) compute P(termAB) = P(termABmasked) * (a1*c2)**-1 + // 2) compute P(X) = P(termAB) + P(-xp) + P (-xq) + // 3) blind P(X) with x1: P(x2) = P(X+x1) + // 4) send P(x2) (unreduced) + + const PtermABmasked = BigInt(`0x${step3.PtermABmasked}`, 16); + const a1c1inv = bcu.modInv((a1 * c1) % p, p); + const PtermAB = this.pubkey.multiply(PtermABmasked, a1c1inv); + + // negative xp + const nxp = p - this.share1.x; + const PX = this.pubkey.addCleartext( + this.pubkey.addCiphertext(PtermAB, Pnxq), + nxp, + ); + // PX may be up to 1027 bits long + const x1unreduced = bcu.randBetween(2n ** 1027n); + const Px2unreduced = this.pubkey.addCleartext(PX, x1unreduced); + // negative x1 + const nx1 = p - (x1unreduced % p); + + const payload4 = str2ba(JSON.stringify({ + Px2unreduced: pad(Px2unreduced.toString(16)), + })); + const step4 = JSON.parse(ba2str(await this.send('step4', payload4))); + + // party1 + + // var x2 = privateKey.decrypt(Px2unreduced) % secp256r1.p + // // now both parties have additive shares of X: x1 and nx2 + // // x2 + nx1 == x2 - x1 == X + + const x2 = BigInt(`0x${step4.x2}`, 16); + const qPriv = BigInt(`0x${step4.qPriv}`, 16); + const qPrivG = this.secp256r1.multiply(this.secp256r1.g, qPriv); + const share2 = this.secp256r1.multiply(this.serverPubkey, qPriv); + + // TODO this must not be done here because qPriv (from which qPrivG is computed) + // is here only for debugging. notary should pass qPrivG after step1 + const clientPubkey = this.secp256r1.add(qPrivG, this.pPrivG); + const cpubBytes = concatTA( + int2ba(clientPubkey.x, 32), + int2ba(clientPubkey.y, 32)); + + const clientPrivkey = this.pPriv + qPriv; + console.log('priv sum len is ', int2ba(clientPrivkey).length); + // if privkey > 32 bytes, the result will still be correct + // the problem may arise when (during debugging) we feed >32 bytes + // into openssl. It expects 32 bytes + + // assert(bigint2ba(clientPrivkey).length <= 32) + + + const x = ((( + bcu.modPow(share2.y + p - this.share1.y, 2n, p) * + bcu.modPow(share2.x + p - this.share1.x, p - 3n, p)) % p) + + (p - this.share1.x) + (p - share2.x)) % p; + + const pms = (x2 + nx1) % p; + console.log('is sum larger than prime', (x2 + nx1) > p); + + const nx1Hex = int2ba(nx1, 32); // negative share x1 + return [nx1Hex, cpubBytes]; + } +} diff --git a/core/twopc/TWOPC.js b/core/twopc/TWOPC.js new file mode 100644 index 0000000..cdd19cc --- /dev/null +++ b/core/twopc/TWOPC.js @@ -0,0 +1,1369 @@ +/* eslint-disable no-bitwise */ +/* eslint-disable class-methods-use-this */ +/* eslint-disable max-len */ + +import {ba2hex, sortKeys, assert, getRandom, bytesToBits, concatTA, int2ba, + str2ba, innerHash, xor, blockMult, eq, sha256, getXTable, ba2int, splitIntoChunks, + bitsToBytes, pubkeyPEM2raw, checkExpiration, wait} from '../utils.js'; +import {Garbler} from './Garbler.js'; +import {Evaluator} from './Evaluator.js'; +import {OT} from './OT.js'; +import {Paillier2PC} from './Paillier2PC.js'; +import {GCWorker} from './GCWorker.js'; +import {global} from './../globals.js'; + + +// class C is initialized once and then it is a read-only struct +// accessed by both garbler and evaluator +class C{ + constructor( notaryInputSize, notaryNonFixedInputSize, + clientInputSize, clientNonFixedInputSize, circuitOutputSize, circuit, masks, fixedInputs){ + + this.notaryInputSize = notaryInputSize; + this.clientInputSize = clientInputSize; + this.circuitOutputSize = circuitOutputSize; + // nonFixedInputs are inputs the value of which is not known in the offline phase + // as opposed to fixed inputs like masks which can be chosen in an offline phase + // the order of inputs is: non-fixed inputs first, then fixed inputs + this.notaryNonFixedInputSize = notaryNonFixedInputSize; + this.clientNonFixedInputSize = clientNonFixedInputSize; + this.notaryFixedInputSize = this.notaryInputSize - this.notaryNonFixedInputSize; + this.clientFixedInputSize = this.clientInputSize - this.clientNonFixedInputSize; + // circuit is a serialized circuit with metadata + this.circuit = circuit; + // what each mask does for each circuit is explained in c*.casm files + this.masks = masks; + // fixedInputs is an array A of arrays B, where + // arrayA's length is equal to the amount of circuits + // arrayB consists of 0 and 1, item at idx==0 is the first input to the circuit + this.fixedInputs = fixedInputs; + } +} + + + +// eslint-disable-next-line no-unused-vars +export class TWOPC { + // notary is an object {'IP':, 'pubkeyPEM':} + notary; + // clientKey is a symmetric key used to encrypt messages to the notary + clientKey; + // notaryKey is a symmetric key used to decrypt messages from the notary + notaryKey; + constructor(notary, plaintextLen, circuits, progressMonitor) { + this.notary = notary; + // number of client request encr counter blocks to produce + const noOfAESBlocks = Math.ceil(plaintextLen/16); + // const noOfGctrBlocks = Math.ceil(noOfAESBlocks /8) + const noOfGctrBlocks = 1; + this.C5Count = noOfAESBlocks; + this.C6Count = noOfGctrBlocks; + this.cwkMaskedByNotary = null; + this.swkMaskedByNotary = null; + this.sivMaskedByNotary = null; + this.civMaskedByNotary = null; + this.innerState_MS = null; // HMAC inner sha256 state for MS + this.g = new Garbler(this); + this.e = new Evaluator(this); + this.ot = new OT(); + this.pm = progressMonitor; + // uid is used for communication with the notary + this.uid = Math.random().toString(36).slice(-10); + + const [masks, fixedInputs] = this.initInputs(); + this.cs = []; + this.cs[1] = new C(512, 256, 512, 256, 512, circuits[1], masks[1], fixedInputs[1]); + this.cs[2] = new C(512, 256, 640, 384, 512, circuits[2], masks[2], fixedInputs[2]); + this.cs[3] = new C(832, 256, 1568, 768, 800, circuits[3], masks[3], fixedInputs[3]); + this.cs[4] = new C(672, 416, 960, 480, 480, circuits[4], masks[4], fixedInputs[4]); + this.cs[5] = new C(160, 0, 308, 160, 128, circuits[5], masks[5], fixedInputs[5]); + this.cs[6] = new C(288, 0, 304, 160, 128, circuits[6], masks[6], fixedInputs[6]); + + // fixedLabels contains a label for each fixed input bit + this.fixedLabels = Array(this.cs.length); + // output is the output of the circuit as array of bytes + this.output = Array(this.cs.length); + // Commits are used to ensure malicious security of garbled circuits + // if client's and notary's commits match, then both parties can be assured + // that no malicious garbling took place. + // hisSaltedCommit is a salted hash of the circuit's output from the notary + this.hisSaltedCommit = Array(this.cs.length); + // myCommit is a (unsalted) hash of the circuit's output + this.myCommit = Array(this.cs.length); + // workers are GCWorker class for each circuit + this.workers = Array(this.cs.length); + + console.log('need to evaluate ', this.C5Count, ' c5 circuits'); + + this.preComputed = false; // will set to true after preCompute() was run + // powersOfH is an array of client's shares of powers of H, starting with H^1 at index 1 + this.powersOfH = []; + + // maxPowerNeeded is the maximum power of H that we'll need in order to compute the GHASH + // function. This doesn't mean that the parties will compute shares of this power. It just + // shows the upper bound of H. + this.maxPowerNeeded = Math.ceil(plaintextLen /16) + 2; + // maxOddPowerNeeded is the maximum odd power for which the parties must compute their shares + this.maxOddPowerNeeded = this.initMaxOddPower(this.maxPowerNeeded); + // ghashOTNeeded is how many bits the receiver of Oblivious Transfer will have + // in order to compute the GHASH function + this.ghashOTNeeded = this.initGhashOTNeeded(this.maxPowerNeeded, this.maxOddPowerNeeded); + + // ephemeralKey is an ephemeral key used by notary to sign this session + this.ephemeralKey = null; + // eValidFrom and eValidUntil are times from/until which the ephemeralKey is valid + this.eValidFrom = null; + this.eValidUntil = null; + // eSigByMasterKey is a signature (in p1363 format) made by notary's masterkey over + // eValidFrom|eValidUntil|ephemeralKey + this.eSigByMasterKey = null; + // clientPMSShare is Client's share of TLS the pre-master secret + this.clientPMSShare = null; + // client_random is a 32-byte random value from Client Hello + this.client_random = null; + // server_random is a 32-byte random value from Server Hellp + this.server_random = null; + // allHandshakes is a concatenation of all handshake messages up to this point. + // This is only data visible at the handshake layer and does not include record layer headers + this.allHandshakes = null; + // hs_hash is a sha256 hash of allHandshakes + this.hs_hash = null; + } + + // destroy de-registers listeners, terminates workers + destroy(){ + this.pm.destroy(); + for (let i=1; i < this.workers.length; i++){ + const gcworker = this.workers[i]; + for (let j=0; j < gcworker.workers.length; j++){ + gcworker.workers[j].terminate(); + } + } + for (const w of this.ot.worker.workers){ + w.terminate(); + } + } + + // compute how many bits need OT for ghash-OT method + initGhashOTNeeded(maxPowerNeeded, maxOddPowerNeeded){ + const strategies = { + 5: [4,1], + 7: [4,3], + 9: [8,1], + 11: [8,3], + 13: [12,1], + 15: [12,3], + 17: [16,1], + 19: [16,3], + 21: [17,4], + 23: [17,6], + 25: [17,8], + 27: [19,8], + 29: [17,12], + 31: [19,12], + 33: [17,16], + 35: [19,16]}; + + // add powers 1,2,3 which the client will already have + const allPowers = []; // all shares of powers which the client has + allPowers[1] = true; + allPowers[2] = true; + allPowers[3] = true; + + // will contain unique powers for which we compute shares directly + // each power requires the client to prepare 256 OT bits + const uniquePowers = []; + for (const k of sortKeys(strategies)){ + if (k <= maxOddPowerNeeded){ + allPowers[k] = true; + const v = strategies[k]; + if (! uniquePowers.includes(v[0])){ + uniquePowers.push(v[0]); + } + if (! uniquePowers.includes(v[1])){ + uniquePowers.push(v[1]); + } + } + } + + // and perform "free squaring" on all powers + for (let i=1; i < allPowers.length; i++){ + if (allPowers[i] == undefined){ + continue; + } + let power = i; + while (power <= maxPowerNeeded){ + power = power * 2; + if (allPowers[power] != undefined){ + continue; + } + allPowers[power] = true; + } + } + + // how many auxillary powers will be needed for the block aggregation method + // each aux power requires 128 OT bits from client + const auxPowers = []; + for (let i=1; i <= maxPowerNeeded; i++){ + if (allPowers[i] != undefined){ + // for this power the client has a share of H, no need for the block aggregation method + continue; + } + // a is the smaller power + const [a,b] = this.findSum(allPowers, i); + if (! auxPowers.includes(a)){ + auxPowers.push(a); + } + } + + return uniquePowers.length * 256 + auxPowers.length*128; + } + + initMaxOddPower(maxPowerNeeded){ + assert(maxPowerNeeded <= 1026); + + // maxHTable = {:}. shows (when using the block aggregation method) + // how many powers of H can be obtained if we: + // A) have all the sequential powers starting with 1 up to AND + // B) have performed OT with the notary on all those sequential powers. + // e.g. {5:29} means that if we have powers 1,2,3,4,5 then using the block aggregation method we can obtain + // up to and including H^29. + // max TLS record size of 16KB requires 1026 powers of H + const maxHTable = {0: 0, 3: 19, 5: 29, 7: 71, 9: 89, 11: 107, 13: 125, 15: 271, 17: 305, 19: 339, 21: 373, + 23: 407, 25: 441, 27: 475, 29: 509, 31: 1023, 33: 1025, 35: 1027}; + + let maxOddPowerNeeded = null; + for (const key of sortKeys(maxHTable)){ + const maxH = maxHTable[key]; + if (maxH >= maxPowerNeeded){ + maxOddPowerNeeded = key; + break; + } + } + return maxOddPowerNeeded; + } + + // set all masks and fixed inputs for each circuit + initInputs(){ + const masks = []; + const fixedInputs = []; + + masks[1] = []; + masks[1][1] = getRandom(32); + fixedInputs[1] = bytesToBits(masks[1][1]); + + masks[2] = []; + masks[2][1] = getRandom(32); + fixedInputs[2] = bytesToBits(masks[2][1]); + + masks[3] = []; + const maskSizes3 = [0,16,16,4,4,16,16,16,12]; + for (let i=1; i < maskSizes3.length; i++){ + masks[3][i] = getRandom(maskSizes3[i]); + } + fixedInputs[3] = bytesToBits(concatTA(...masks[3].slice(1).reverse())); + + masks[4] = []; + const maskSizes4 = [0,16,16,16,12]; + for (let i=1; i < maskSizes4.length; i++){ + masks[4][i] = getRandom(maskSizes4[i]); + } + fixedInputs[4] = bytesToBits(concatTA(...masks[4].slice(1).reverse())); + + masks[5] = []; + for (let i = 0; i < this.C5Count; i++) { + masks[5].push(getRandom(16)); + } + const totalBits = []; + // we only send 1 TLS record with a fixed nonce 2 + const nonce = 2; + for (let i = 0; i < this.C5Count; i++) { + const counter = 2 + i; + const counterBits = bytesToBits(int2ba(counter, 2)).slice(0, 10); + const nonceBits = bytesToBits(int2ba(nonce, 2)).slice(0, 10); + const maskBits = bytesToBits(masks[5][i]); + totalBits.push([].concat(maskBits, nonceBits, counterBits)); + } + fixedInputs[5] = [].concat(...totalBits); + + masks[6] = []; + for (let i = 0; i < this.C6Count; i++) { + masks[6].push(getRandom(16)); + } + // for gctr blocks + let totalParsed6 = []; + for (let i = 0; i < this.C6Count; i++) { + // nonce starts with 2 + const nonce = 2 + i; + const parsedNonce = bytesToBits(int2ba(nonce, 2)).slice(0, 16); + const mask = bytesToBits(masks[6][i]); + totalParsed6.push([].concat(mask, parsedNonce)); + } + fixedInputs[6] = [].concat(...totalParsed6); + + return [masks, fixedInputs]; + } + + async getECDHShare(x, y){ + const paillier = new Paillier2PC(this, x, y); + return await paillier.run(); + } + + + // pass client/server random, handshake (to derive verify_data), pms share + // returns encrypted Client Finished (CF), authentication tag for CF, verify_data for CF + async run(cr, sr, allHandshakes, pmsShare) { + this.clientPMSShare = pmsShare; + this.client_random = cr; + this.server_random = sr; + this.allHandshakes = allHandshakes; + this.hs_hash = await(sha256(allHandshakes)); + + // if pre-fetching / pre-computation was not done, now it's too late for that + if (! this.preComputed){ + console.log('pre-computation was not done before the session started'); + throw('pre-computation was not done before the session started'); + } + + const nonFixedBits = bytesToBits(this.clientPMSShare); + const c1Output = await this.runCircuit(nonFixedBits, 1); + + const c2_output = await this.phase2(c1Output); + const c3_output = await this.phase3(c2_output); + const [encFinished, tag, verify_data] = await this.phase4(c3_output); + return [encFinished, tag, verify_data]; + } + + // checkServerFinished takes encrypted Server Finished with nonce and authentication tag + // and checks its correctness in 2PC + async checkServerFinished(encSFWithNonceAndTag, allHandshakes) { + const sf_nonce = encSFWithNonceAndTag.slice(0, 8); + // sf_pure is encrypted SF without the nonce and without the tag + const sf_pure = encSFWithNonceAndTag.slice(8, -16); + const sf_tag = encSFWithNonceAndTag.slice(-16); + const hshash = await sha256(allHandshakes); + + const seed = concatTA(str2ba('server finished'), hshash); + const a0 = seed; + const a1inner = innerHash(this.innerState_MS, a0); + const a1 = await this.send('c4_pre1', a1inner); + const p1inner = innerHash(this.innerState_MS, concatTA(a1, seed)); + + const nonFixedBits = bytesToBits(concatTA( + new Uint8Array(sf_nonce), + new Uint8Array(this.sivMaskedByNotary), + new Uint8Array(this.swkMaskedByNotary), + p1inner)); + + const outArray = await this.runCircuit(nonFixedBits, 4); + const c4_output = outArray[0]; + console.log('c4Output.length', c4_output.length); + + let o = 0; // offset + const verify_dataMasked = c4_output.slice(o, o+=12); + const verify_data = xor(verify_dataMasked, this.cs[4].masks[4]); + const sf = concatTA(new Uint8Array([0x14, 0x00, 0x00, 0x0c]), verify_data); + + const encCounterMasked = c4_output.slice(o, o+=16); + const encCounter = xor(encCounterMasked, this.cs[4].masks[3]); + + const gctrSFMasked = c4_output.slice(o, o+=16); + const gctrShare = xor(gctrSFMasked, this.cs[4].masks[2]); + + const H1MaskedTwice = c4_output.slice(o, o+=16); + const H1 = xor(H1MaskedTwice, this.cs[4].masks[1]); + const H2 = blockMult(H1, H1); + const H1H2 = blockMult(H1, H2); + + // OT starts with the highest bit + const h1Bits = bytesToBits(H1).reverse(); + const [idxArray1, otKeys1] = this.ot.getIndexesFromPool(h1Bits); + const h2Bits = bytesToBits(H2).reverse(); + const [idxArray2, otKeys2] = this.ot.getIndexesFromPool(h2Bits); + + const encSF = xor(sf, encCounter); + assert(eq(sf_pure, encSF)); + + const step3resp = await this.send('c4_step3', concatTA(encSF, idxArray1, idxArray2)); + assert(step3resp.length === 16 + 128*32 + 128*32); + o = 0; + const Snotary = step3resp.slice(o, o+=16); + const encEntries1 = step3resp.slice(o, o+=(128*32)); + const encEntries2 = step3resp.slice(o, o+=(128*32)); + + let H3share = H1H2; + for (let i = 0; i < h1Bits.length; i += 1) { + const bit = h1Bits[i]; + const ct = encEntries2.slice(i * 32, (i+1) * 32); + const maskedEntry = this.ot.decryptWithKey(ct, bit, otKeys1[i]); + H3share = xor(H3share, maskedEntry); + } + for (let i = 0; i < h2Bits.length; i += 1) { + const bit = h2Bits[i]; + const ct = encEntries1.slice(i * 32, (i+1) * 32); + const maskedEntry = this.ot.decryptWithKey(ct, bit, otKeys2[i]); + H3share = xor(H3share, maskedEntry); + } + + const aad = new Uint8Array([0, 0, 0, 0, 0, 0, 0, 0, 22, 3, 3, 0, 16, 0, 0, 0]); + // lenA (before padding) == 13*8 == 104, lenC == 16*8 == 128 + const lenAlenC = new Uint8Array([0, 0, 0, 0, 0, 0, 0, 104, 0, 0, 0, 0, 0, 0, 0, 128]); + + const s1share = blockMult(aad, H3share); + const s2share = blockMult(encSF, H2); + const s3share = blockMult(lenAlenC, H1); + const Sclient = xor(xor(xor(s1share, s2share), s3share), gctrShare); + + const tagFromPowersOfH = xor(Snotary, Sclient); + assert (eq(sf_tag, tagFromPowersOfH)); + } + + async getEncryptedCounters() { + const nonFixedBits = bytesToBits(concatTA(this.civMaskedByNotary, this.cwkMaskedByNotary)); + const outArray = await this.runCircuit(nonFixedBits, 5); + const results = []; + for (let i=0; i < this.C5Count; i++){ + const encCounter = xor(outArray[i], this.cs[5].masks[i]); + results.push(encCounter); + } + return results; + } + + // note that getGctrBlocks does not actually output gctr function's output but only + // client's gctr share. The notary's gctr share is already xored into the output + // of getTagFromPowersOfH + async getGctrBlocks(){ + const nonFixedBits = bytesToBits(concatTA(this.civMaskedByNotary, this.cwkMaskedByNotary)); + const outArray = await this.runCircuit(nonFixedBits, 6); + + const c6CommitSalt = await this.send('checkC6Commit', this.myCommit[6]); + // the commit which notary computed on their side must be equal to our commit + const saltedCommit = await sha256(concatTA(this.myCommit[6], c6CommitSalt)); + assert (eq(saltedCommit, this.hisSaltedCommit[6])); + + const results = []; + for (let i=0; i < this.C6Count; i++){ + const gctrBlock = xor(outArray[i], this.cs[6].masks[i]); + results.push(gctrBlock); + } + return results; + } + + async getTagFromPowersOfH(encRequestBlocks){ + // prepare ghash inputs + const ghashInputs = []; + // last block may not be 16 bytes + const recordLen = (encRequestBlocks.length-1)*16+encRequestBlocks[encRequestBlocks.length-1].length; + const seqNum = int2ba(1, 8); + const recordLenBytes = int2ba(recordLen, 2); + const aad = concatTA(seqNum, new Uint8Array([23,3,3]), recordLenBytes); + // right-pad with zeroes if needed + let aadPadding = []; + if (aad.length % 16 > 0) { + aadPadding = Array(16-(aad.length%16)).fill(0); + } + ghashInputs.push(concatTA(aad, new Uint8Array(aadPadding))); + ghashInputs.push(...encRequestBlocks.slice(0,-1)); + let ctPadding = []; + if (encRequestBlocks[encRequestBlocks.length-1].length%16 > 0) { + ctPadding = Array(16-(encRequestBlocks[encRequestBlocks.length-1].length%16)).fill(0); + } + ghashInputs.push(concatTA(encRequestBlocks[encRequestBlocks.length-1], new Uint8Array(ctPadding))); + const lenA = int2ba(aad.length*8, 8); + const lenC = int2ba(recordLen*8, 8); + ghashInputs.push(concatTA(lenA, lenC)); + + // fill this.powersOfH with needed H shares + await this.getOddPowers(this.maxPowerNeeded); + const directSum = this.useDirectHShares(ghashInputs); + const indirectSum = await this.useIndirectHShares(ghashInputs); + return [[xor(directSum, indirectSum)], concatTA(...ghashInputs)]; + + } + + // multiply direct H shares with corresponding ciphertext blocks + useDirectHShares(ghashInputs){ + let res = int2ba(0, 16); + // this.powersOfH is a sparse array, its .length is the max index + for (let i=1; i < this.powersOfH.length; i++){ + if (i > ghashInputs.length){ + // we will have more powers than the input blocks + break; + } + if (this.powersOfH[i] == undefined){ + continue; + } + const h = this.powersOfH[i]; + const x = ghashInputs[ghashInputs.length-i]; + res = xor(res, blockMult(h,x)); + } + return res; + } + + // for those shares of powers which are not in powersOfH, we do not compute the shares of + // powers, but instead we compute the share of X*H + // e.g. if we need H^21*X and we have shares of H^19 and H^2, we compute it as follows: + // (H19_a + H19_b)(H2_a + H2_b)X == H19_aH2_aX + H19_aXH2_b + H19_bXH2_a + H19_bH2_bX + // only the 2 middle cross-terms need to be computed using OT + // A will send OT for H19_aX to B + // B will send OT for H19_bX to A + // all other powers where one of the factors is H^2 like eg H^25 == H^23*H^2 + // can be collapsed into the terms above e.g. H23_aX2 can be collapsed into H19_aX + + async useIndirectHShares(ghashInputs){ + let res = int2ba(0, 16); // this is the xor of all my X*H shares + let sumForPowers = {}; + for (let i=4; i < this.powersOfH.length; i++){ + if (i > ghashInputs.length){ + // we will have more powers than the input blocks + break; + } + if (this.powersOfH[i] != undefined){ + continue; + } + // found a hole in our sparse array, we need X*H for this missing power + // a is the smaller power + const [a,b] = this.findSum(this.powersOfH, i); + const x = ghashInputs[ghashInputs.length-i]; + const h_small = this.powersOfH[a]; + const h_big = this.powersOfH[b]; + res = xor(res, blockMult(blockMult(h_small, h_big), x)); + const hx = blockMult(h_big, x); + if (sumForPowers.hasOwnProperty(a)){ + sumForPowers[a] = xor(sumForPowers[a], hx); + } + else { + sumForPowers[a] = hx; + } + } + + // send OT for all sums in sumForPowers in ascending order + const sortedKeys = sortKeys(sumForPowers); + let allBits = []; + for (const key of sortedKeys){ + const bytes = sumForPowers[key]; + // OT starts with the highest bit + const bits = bytesToBits(new Uint8Array(bytes)).reverse(); + allBits = [].concat(allBits, bits); + } + const [idxArray, otKeys] = this.ot.getIndexesFromPool(allBits); + + const payload = concatTA(...ghashInputs, idxArray); + const step5resp = await this.send('ghash_step5', payload); + let o = 0; + const encEntries = step5resp.slice(o, o+idxArray.length/2 * 32); + o += idxArray.length/2 * 32; + const hisIndexes = step5resp.slice(o, o+idxArray.length); + o += idxArray.length; + assert(step5resp.length === o); + + for (let i = 0; i < allBits.length; i += 1) { + const bit = allBits[i]; + const ct = encEntries.slice(i * 32, (i+1) * 32); + const maskedEntry = this.ot.decryptWithKey(ct, bit, otKeys[i]); + res = xor(res, maskedEntry); + } + + // get his indexes and send his encrypted masked entries + let maskSum = int2ba(0, 16); + let totalOffset = 0; + const myEncEntries = []; + for (let i=0; i < sortedKeys.length; i++){ + const xTable = getXTable(this.powersOfH[sortedKeys[i]]); + for (let i=0; i < 128; i++){ + const idx = ba2int(hisIndexes.slice(totalOffset, totalOffset+2)); + totalOffset += 2; + const mask = getRandom(16); + maskSum = xor(maskSum, mask); + const m0 = mask; + const m1 = xor(xTable[i], mask); + myEncEntries.push(this.ot.encryptWithKeyAtIndex(m0, m1, idx)); + } + + } + res = xor(res, maskSum); + const hisTagShare = await this.send('ghash_step6', concatTA(...myEncEntries)); + return xor(res, hisTagShare); + } + + + // draw from the OT pool and send to notary OT step1 + getOTIndexArray(powersForOT, powersOfH){ + // prepare OT data for each bit of each power + const idxArrays = []; + for (const power of sortKeys(powersForOT)){ + const bits = bytesToBits(powersOfH[power]).reverse(); + powersForOT[power]['bits'] = bits; + const [idxArray, otKeys] = this.ot.getIndexesFromPool(bits); + powersForOT[power]['otKeys'] = otKeys; + idxArrays.push(idxArray); + } + return idxArrays; + } + + + // decrypt OT from notary and compute shares of powers listed in strategies + // modifies PowersOfH in-place + getPowerShares(strategies, powersForOT, encEntriesBlob, powersOfH){ + const stratKeys = sortKeys(strategies); + assert(encEntriesBlob.length === stratKeys.length*256*32); + + for (let j=0; j < stratKeys.length; j++){ + const oddPower = stratKeys[j]; + let xorSum = int2ba(0, 16); // start with 0 sum + for (let round=0; round < 2; round++){ + // first factor is always notary's, second factor is always client's + // on first round factor at strategies[key][0] is notary's + // on second round factor at strategies[key][1] is notary's + let f2 = round === 0 ? strategies[oddPower][1] : strategies[oddPower][0]; + const encEntries = encEntriesBlob.slice((j*256+round*128)*32, (j*256+(round+1)*128)*32); + for (let i = 0; i < 128; i += 1) { + const bit = powersForOT[f2].bits[i]; + const ct = encEntries.slice(i * 32, (i+1) * 32); + const maskedEntry = this.ot.decryptWithKey(ct, bit, powersForOT[f2].otKeys[i]); + xorSum = xor(xorSum, maskedEntry); + } + } + const Cx = powersOfH[strategies[oddPower][0]]; + const Cy = powersOfH[strategies[oddPower][1]]; + const CxCy = blockMult(Cx,Cy); + powersOfH[oddPower] = xor(xorSum, CxCy); + } + } + + + // Use oblivious transfer with the notary to compute the necessary amount of odd powers + // we will later call powersPlusOne with these odd powers to compute X*H. + // Note: when OT-extension is implemented, we're not gonna need all these optimizations. + // We will be able to compute all powers directly with OT-extenion. But for now, since + // we use base-OT which is expensive, we resort to optimizations. + + async getOddPowers(maxPowerNeeded){ + console.log('maxPowerNeeded is', maxPowerNeeded); + assert(maxPowerNeeded <= 1026); + + if (this.maxOddPowerNeeded === 3){ + return; // already have power 3 + } + + // perform free squaring of shares H^2 and H^3 which we have from client finished + this.freeSquare(this.powersOfH, maxPowerNeeded); + + // strategies shows what existing powers we will be multiplying to obtain other odd powers + // max sequential odd power that we can obtain on first round is 19 + // Note that "sequential" is a keyword here. We can't obtain 21 but we indeed can obtain + // 25==24+1, 33==32+1 etc. However with 21 missing, we will not be able to obtain more powers + // with the X*H method, even if we have 25,33,etc. + const strategies = { + 5: [4,1], + 7: [4,3], + 9: [8,1], + 11: [8,3], + 13: [12,1], + 15: [12,3], + 17: [16,1], + 19: [16,3]}; + const powersForOT1 = {1: {},3: {},4: {},8: {},12: {},16: {}}; + + // TODO send only those powers which we actually need + const idxArrays1 = this.getOTIndexArray(powersForOT1, this.powersOfH); + + const encEntries1 = await this.send('ghash_step1', concatTA(...idxArrays1, int2ba(maxPowerNeeded, 2))); + + this.getPowerShares(strategies, powersForOT1, encEntries1, this.powersOfH); + this.freeSquare(this.powersOfH, maxPowerNeeded); + + // we need to perform OT on all powers [1, maxOddPowerNeeded] which we havent performed OT + // for yet + const powersLeft = [2,5,6,7,9,10,11,13,14,15,17,18,19]; + const powersForOT2 = {}; + for (const power of powersLeft){ + if (power <= this.maxOddPowerNeeded){ + powersForOT2[power] = {}; + } + } + const idxArrays2 = this.getOTIndexArray(powersForOT2, this.powersOfH); + await this.send('ghash_step2', concatTA(...idxArrays2)); + + if (this.maxOddPowerNeeded <= 19){ + return; + } + // else we need more odd powers. The max that we'll ever need is 35 + // strategies2 should be canonical for both client and notary + // Eventually we will send OT for all powers from 1 to 35 + const strategies2 = { + 21: [17,4], + 23: [17,6], + 25: [17,8], + 27: [19,8], + 29: [17,12], + 31: [19,12], + 33: [17,16], + 35: [19,16]}; + + const powersForOT3 = {17: {},19: {}}; + const idxArrays3 = this.getOTIndexArray(powersForOT3, this.powersOfH); + const step3resp = await this.send('ghash_step3', concatTA(...idxArrays3)); + this.getPowerShares(strategies2, powersForOT3, step3resp, this.powersOfH); + this.freeSquare(this.powersOfH, maxPowerNeeded); + // we need to perform OT on all powers [1, maxOddPowerNeeded] which we havent performed OT + // for yet + const powersLeft2 = [20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35]; + const powersForOT4 = {}; + for (let i=0; i < powersLeft2.length; i++){ + if (powersLeft2[i] <= this.maxOddPowerNeeded){ + powersForOT4[i] = {}; + } + } + const idxArrays4 = this.getOTIndexArray(powersForOT4, this.powersOfH); + await this.send('ghash_step4', concatTA(...idxArrays4)); + } + + // those powers which were not set are undefined + findSum(powers, sumNeeded){ + for (let i=1; i < powers.length; i++){ + if (powers[i] == undefined){ + continue; + } + for (let j=1; j < powers.length; j++){ + if (powers[j] == undefined){ + continue; + } + if (i+j === sumNeeded){ + return [i,j]; + } + } + } + // this should never happen because we always call + // findSum() knowing that the sum can be found + throw('sum not found'); + } + + // Perform squaring of each share of odd power up to maxPower. + // "powers" is an array where idx is the power (or undefined if not set) and item at that idx + // if client's share of H^power + // modifies "powers" in-place + // e.g if "powers" contains 1,2,3 and maxPower==19, then upon return "powers" + // will contain 1,2,3,4,6,8,12,16 + freeSquare(powers, maxPower){ + for (let i=0; i < powers.length; i++){ + if (powers[i] == undefined || i % 2 === 0){ + continue; + } + if (i > maxPower){ + return; + } + let power = i; + while (power <= maxPower){ + power = power * 2; + if (powers.includes(power)){ + continue; + } + powers[power] = blockMult(powers[power/2], powers[power/2]); + } + } + } + + // send data to the notary + async send(cmd, data = new Uint8Array(0), returnPromise = false, willEncrypt = true){ + let to_be_sent; + if (willEncrypt){ + to_be_sent = await this.encryptToNotary(this.clientKey, data); + } + else { + to_be_sent = data; + } + + function timeout(ms, promise) { + return new Promise(function(resolve, reject) { + setTimeout(function() { + reject(new Error('Timed out while while transfering data.')); + }, ms); + promise.then(resolve, reject); + }); + } + + const fetchPromise = fetch( + 'http://'+this.notary.IP+':'+global.defaultNotaryPort+'/'+cmd+'?'+this.uid, + { + method: 'POST', + mode: 'cors', + cache: 'no-store', + // keepalive: true, <-- trips up chrome + body: to_be_sent.buffer + }); + const that = this; + + const promise = new Promise((resolve, reject) => { + timeout(20000, fetchPromise).then(function(resp){ + resp.arrayBuffer().then(function(ab){ + const payload = new Uint8Array(ab); + if (payload.length !== 0){ + if (willEncrypt){ + that.decryptFromNotary(that.notaryKey, payload).then(function(decrypted){ + resolve(decrypted); + }); + } + else { + resolve(payload); + } + } + else { + resolve(); + } + }); + }).catch(err =>{ + reject(err); + }); + }); + if (returnPromise === true){ + return promise; + } + else { + return await promise; + } + } + + async preComputeOT(){ + + const allFixedInputs = []; + let allNonFixedInputsCount = 0; + let allFixedInputsCount = 0; + for (let i=1; i < this.cs.length; i++){ + allFixedInputs.push(this.cs[i].fixedInputs); + allNonFixedInputsCount += this.cs[i].clientNonFixedInputSize; + } + allNonFixedInputsCount += (256 + 256); // for powers of H OT for ClFin and SerFin + allFixedInputsCount = [].concat(...allFixedInputs).length; + + console.log('allFixedInputs.length', allFixedInputsCount); + console.log('precomputePool size', allNonFixedInputsCount + this.ghashOTNeeded); + + this.pm.update('last_stage', {'current': 1, 'total': 10}); + const receiverBs = await this.ot.saveDecryptionKeys([].concat(...allFixedInputs)); + await this.ot.precomputePool(allNonFixedInputsCount + this.ghashOTNeeded); + + const OTpayload = concatTA(...receiverBs, ...this.ot.getRandomizedPool()); + console.log('sending payload of size', OTpayload.length); + const resp_ot_AllB = await this.send('ot_AllB', OTpayload); + console.log('returned from ot_AllB'); + const fixedOTBlob = resp_ot_AllB.slice(0, allFixedInputsCount*32); + const OTFromNotaryEval = resp_ot_AllB.slice(allFixedInputsCount*32); + console.time('getAllB'); + const encLabelsBlob = await this.g.getAllB(OTFromNotaryEval); + console.timeEnd('getAllB'); + this.send('ot_encLabelsForEval', encLabelsBlob); + + // get evaluator's fixed labels and keep them + let idx = 0; + for (let i=1; i < this.cs.length; i++){ + this.fixedLabels[i] = []; + for (let j=0; j < this.cs[i].fixedInputs.length; j++){ + const ct = fixedOTBlob.slice(idx*32, (idx+1)*32); + const bit = this.cs[i].fixedInputs[j]; + const inputLabel = this.ot.decryptWithKeyFromIndex(ct, bit, idx); + idx += 1; + this.fixedLabels[i].push(inputLabel); + } + } + assert(fixedOTBlob.length === idx*32); + this.pm.update('last_stage', {'current': 2, 'total': 10}); + } + + // preCompute() should be called before run() is called + // it does all fetching/pre-computation that can be done in 2PC offline phase + async preCompute() { + if (this.preComputed) { + return; + } + + const [pubBytes, privKey] = await this.generateECKeypair(); + + const preInitBlob = await this.send('preInit', concatTA( + pubBytes, + int2ba(this.C5Count, 2), + int2ba(this.C6Count, 2), + int2ba(this.ghashOTNeeded, 2), + this.ot.getSenderA()), false, false); + + let o = 0; + this.eValidFrom = preInitBlob.slice(o, o+=4); + this.eValidUntil = preInitBlob.slice(o, o+=4); + this.ephemeralKey = preInitBlob.slice(o, o+=65); + this.eSigByMasterKey = preInitBlob.slice(o, o+=64); + const encrypted = preInitBlob.slice(o); + + console.log(this.notary.pubkeyPEM); + const notaryKey = pubkeyPEM2raw(this.notary.pubkeyPEM); + const notaryCryptoKey = await crypto.subtle.importKey( + 'raw', notaryKey.buffer, {name: 'ECDSA', namedCurve: 'P-256'}, true, ['verify']); + const tbs = concatTA(this.eValidFrom, this.eValidUntil, this.ephemeralKey); + const result = await crypto.subtle.verify( + {'name': 'ECDSA', 'hash': 'SHA-256'}, + notaryCryptoKey, + this.eSigByMasterKey.buffer, + tbs.buffer); + assert(result === true, 'Error verifying ephemeral keys from notary.'); + assert(checkExpiration(this.eValidFrom, this.eValidUntil) === true, + 'Error verifying ephemeral key validity.'); + + // generate symmetric encryption keys for communication with the notary + const [ck, nk] = await this.generateSymmetricKeys(privKey, this.ephemeralKey); + this.clientKey = ck; + this.notaryKey = nk; + const notaryA = await this.decryptFromNotary(nk, encrypted); + this.ot.setA(notaryA); + + const that = this; + const getBlobPromise = new Promise((resolve) => { + this.getBlobFromNotary() + .then(function(hisBlob){ + that.blob = that.processBlob(hisBlob); + resolve(); + }); + }); + + await this.setupWorkers(); + await this.g.garbleAll(); + let blobOut = []; + for (let i=1; i < this.cs.length; i++){ + blobOut.push(this.g.garbledC[i].tt); + blobOut.push(this.g.garbledC[i].ol); + } + + // start blob upload as soon as download finishes + await getBlobPromise; + const sendBlobPromise = this.sendBlobToNotary(concatTA(...blobOut)); + await this.preComputeOT(); + await sendBlobPromise; + this.preComputed = true; + } + + // sendBlobToNotary uploads a blob to the notary and periodically publishes the download progress + // to the UI. Upload is in 1MB chunks. + async sendBlobToNotary(blob){ + const that = this; + let sentSoFar = 0; + let oneMB = 1024*1024; + let chunkCount = Math.ceil(blob.length / oneMB); + for (let i=0; i < chunkCount; i++){ + if (i % 10 == 0){ + // dont monopolize the upload bandwidth, allow preComputeOT to squeeze in some data + await wait(200); + } + let chunk = blob.slice(sentSoFar, sentSoFar + oneMB); + await that.send('setBlobChunk', chunk); + sentSoFar += chunk.length; + that.pm.update('upload', {'current': i+1, 'total': chunkCount}); + } + that.send('setBlobChunk', str2ba('magic: no more data')); + } + + // getNotaryBlob downloads a blob from notary in 1 MB chunks publishes the download progress + // to the UI. + async getBlobFromNotary (){ + const allChunks = []; + const totalBytes = ba2int(await this.send('init')); + console.log('totalBytes is', totalBytes); + + let soFarBytes = 0; + while (soFarBytes < totalBytes){ + let needBytes = 1024*1024; + if (needBytes + soFarBytes > totalBytes){ + needBytes = totalBytes - soFarBytes; + } + let chunk = await this.send('getBlobChunk', int2ba(needBytes, 4)); + allChunks.push(chunk); + soFarBytes += chunk.length; + this.pm.update('download', {'current': soFarBytes, 'total': totalBytes}); + } + const rv = concatTA(...allChunks); + assert(rv.length === totalBytes); + return rv; + } + + async decryptFromNotary (key, enc){ + try{ + const IV = enc.slice(0,12); + const ciphertext = enc.slice(12); + return new Uint8Array(await crypto.subtle.decrypt( + {name: 'AES-GCM', iv: IV.buffer}, + key, + ciphertext.buffer)); + } catch (err){ + throw('Error while decrypting data from the notary.'); + } + } + + async encryptToNotary(key, plaintext){ + try{ + const IV = getRandom(12); + const enc = await crypto.subtle.encrypt( + {name: 'AES-GCM', iv: IV.buffer}, + key, + plaintext.buffer); + return concatTA(IV, new Uint8Array(enc)); + } catch(err){ + throw('Error while encrypting data for the notary.'); + } + } + + async setupWorkers(){ + const maxWorkerCount = 3; // only needed for c5 + const workerCount = [0,1,1,1,1,maxWorkerCount,1]; + for (let i=1; i < this.cs.length; i++){ + this.workers[i] = new GCWorker(workerCount[i], this.pm); + this.workers[i].parse(this.cs[i].circuit); + } + } + + async phase2(outArray) { + console.log('reached phase2'); + const c1Output = outArray[0]; + const innerStateMasked = c1Output.slice(0, 32); + const innerStateUint8 = xor(innerStateMasked, this.cs[1].masks[1]); + + const innerState = new Int32Array(8); + for (let i = 0; i < 8; i++) { + var hex = ba2hex(innerStateUint8).slice(i * 8, (i + 1) * 8); + innerState[i] = `0x${hex}`; + } + + // python code for reference: + // seed = str.encode("master secret") + self.client_random + self.server_random + // a0 = seed + // a1 = hmac.new(secret , a0, hashlib.sha256).digest() + // a2 = hmac.new(secret , a1, hashlib.sha256).digest() + // p2 = hmac.new(secret, a2+seed, hashlib.sha256).digest() + // p1 = hmac.new(secret, a1+seed, hashlib.sha256).digest() + // ms = (p1+p2)[0:48] + + const seed = concatTA(str2ba('master secret'), this.client_random, this.server_random); + const a1inner = innerHash(innerState, seed); + const a1 = await this.send('c1_step3', a1inner); + const a2inner = innerHash(innerState, a1); + const a2 = await this.send('c1_step4', a2inner); + const p2inner = innerHash(innerState, concatTA(a2, seed)); + const p2 = await this.send('c1_step5', p2inner); + const p1inner = innerHash(innerState, concatTA(a1, seed)); + + const nonFixedBits = bytesToBits(concatTA(p2.subarray(0, 16), p1inner)); + return await this.runCircuit(nonFixedBits, 2); + } + + async phase3(outArray) { + const c2_output = outArray[0]; + const innerStateMasked = c2_output.slice(0, 32); + const innerStateUint8 = xor(innerStateMasked, this.cs[2].masks[1]); + + // hash state for MS + this.innerState_MS = new Int32Array(8); + for (var i = 0; i < 8; i++) { + var hex = ba2hex(innerStateUint8).slice(i * 8, (i + 1) * 8); + this.innerState_MS[i] = `0x${hex}`; + } + + // python code for reference + // seed = str.encode("key expansion") + self.server_random + self.client_random + // a0 = seed + // a1 = hmac.new(ms , a0, hashlib.sha256).digest() + // a2 = hmac.new(ms , a1, hashlib.sha256).digest() + // p1 = hmac.new(ms, a1+seed, hashlib.sha256).digest() + // p2 = hmac.new(ms, a2+seed, hashlib.sha256).digest() + // ek = (p1 + p2)[:40] + + const seed = concatTA(str2ba('key expansion'), this.server_random, this.client_random); + // at the same time also compute verify_data for Client Finished + const seed_vd = concatTA(str2ba('client finished'), this.hs_hash); + + const a1inner = innerHash(this.innerState_MS, seed); + const a1inner_vd = innerHash(this.innerState_MS, seed_vd); + const resp4 = await this.send('c2_step3', concatTA(a1inner, a1inner_vd)); + const a1 = resp4.subarray(0, 32); + const a1_vd = resp4.subarray(32, 64); + + const a2inner = innerHash(this.innerState_MS, a1); + const p1inner_vd = innerHash(this.innerState_MS, concatTA(a1_vd, seed_vd)); + const resp5 = await this.send('c2_step4', concatTA(a2inner, p1inner_vd)); + const a2 = resp5.subarray(0, 32); + + const p1inner = innerHash(this.innerState_MS, concatTA(a1, seed)); + const p2inner = innerHash(this.innerState_MS, concatTA(a2, seed)); + const nonFixedBits = bytesToBits(concatTA(p1inner_vd, p2inner, p1inner)); + return await this.runCircuit(nonFixedBits, 3); + } + + async phase4(outArray) { + const c3_output = outArray[0]; + let o = 0; // offset + const verify_dataMasked = c3_output.slice(o, o+=12); + const verify_data = xor(verify_dataMasked, this.cs[3].masks[8]); + const clientFinished = concatTA(new Uint8Array([0x14, 0x00, 0x00, 0x0c]), verify_data); + + const encCounterMasked = c3_output.slice(o, o+=16); + const encCounter = xor(encCounterMasked, this.cs[3].masks[7]); + + const gctrMaskedTwice = c3_output.slice(o, o+=16); + const myGctrShare = xor(gctrMaskedTwice, this.cs[3].masks[6]); + + const H1MaskedTwice = c3_output.slice(o, o+=16); + + const H1 = xor(H1MaskedTwice, this.cs[3].masks[5]); + this.powersOfH[1] = H1; + const H2 = blockMult(H1, H1); + this.powersOfH[2] = H2; + const H1H2 = blockMult(H1, H2); + + // OT starts with the highest bit + const h1Bits = bytesToBits(H1).reverse(); + const [idxArray1, otKeys1] = this.ot.getIndexesFromPool(h1Bits); + const h2Bits = bytesToBits(H2).reverse(); + const [idxArray2, otKeys2] = this.ot.getIndexesFromPool(h2Bits); + + const civMaskedTwice = c3_output.slice(o, o+=4); + this.civMaskedByNotary = xor(civMaskedTwice, this.cs[3].masks[4]); + const sivMaskedTwice = c3_output.slice(o, o+=4); + this.sivMaskedByNotary = xor(sivMaskedTwice, this.cs[3].masks[3]); + + const cwkMaskedTwice = c3_output.slice(o, o+=16); + const swkMaskedTwice = c3_output.slice(o, o+=16); + this.cwkMaskedByNotary = xor(cwkMaskedTwice, this.cs[3].masks[2]); + this.swkMaskedByNotary = xor(swkMaskedTwice, this.cs[3].masks[1]); + + const encCF = xor(clientFinished, encCounter); + const step3resp = await this.send('c3_step3', concatTA(encCF, idxArray1, idxArray2)); + assert(step3resp.length === 16 + 128*32 + 128*32); + + o = 0; + const Snotary = step3resp.slice(o, o+=16); + const encEntries1 = step3resp.slice(o, o+=(128*32)); + const encEntries2 = step3resp.slice(o, o+=(128*32)); + + let H3share = H1H2; + for (let i = 0; i < h1Bits.length; i += 1) { + const bit = h1Bits[i]; + const ct = encEntries2.slice(i * 32, (i+1) * 32); + const maskedEntry = this.ot.decryptWithKey(ct, bit, otKeys1[i]); + H3share = xor(H3share, maskedEntry); + } + for (let i = 0; i < h2Bits.length; i += 1) { + const bit = h2Bits[i]; + const ct = encEntries1.slice(i * 32, (i+1) * 32); + const maskedEntry = this.ot.decryptWithKey(ct, bit, otKeys2[i]); + H3share = xor(H3share, maskedEntry); + } + this.powersOfH[3] = H3share; + + const aad = new Uint8Array([0, 0, 0, 0, 0, 0, 0, 0, 22, 3, 3, 0, 16, 0, 0, 0]); + // lenA (before padding) == 13*8 == 104, lenC == 16*8 == 128 + const lenAlenC = new Uint8Array([0, 0, 0, 0, 0, 0, 0, 104, 0, 0, 0, 0, 0, 0, 0, 128]); + + const s1share = blockMult(aad, H3share); + const s2share = blockMult(encCF, H2); + const s3share = blockMult(lenAlenC, H1); + const Sclient = xor(xor(xor(s1share, s2share), s3share), myGctrShare); + const tagFromPowersOfH = xor(Sclient, Snotary); + + return [encCF, tagFromPowersOfH, verify_data]; + } + + // getClientFinishedResumed runs a circuit to obtain data needed to construct the + // Client Finished messages for cases when we need TLS session resumption + async getClientFinishedResumed(hs_hash){ + const seed = concatTA(str2ba('client finished'), hs_hash); + const a1inner = innerHash(this.innerState_MS, seed); + const a1 = await this.send('c7_step1', a1inner); + const p1inner = innerHash(this.innerState_MS, a1); + // p1inner is the client's input to c7 + const mask1 = getRandom(16) + const mask2 = getRandom(12) + const nonFixedBits = bytesToBits(concatTA( + mask2, mask2, this.civMaskedByNotary, this.cwkMaskedByNotary, p1inner)); + + } + + // getServerKeyShare returns client's xor share of server_write_key + // and server_write_iv + getKeyShares(){ + return [this.cwkMaskedByNotary, this.civMaskedByNotary, + this.swkMaskedByNotary, this.sivMaskedByNotary]; + } + + getEphemeralKey(){ + return [this.ephemeralKey, this.eValidFrom, this.eValidUntil, this.eSigByMasterKey]; + } + + // eslint-disable-next-line class-methods-use-this + // optionally send extra data + async runCircuit(nonFixedBits, cNo, extraData) { + console.log('in runCircuit', cNo); + if (extraData == undefined){ + extraData = new Uint8Array(); + } + const c = this.cs[cNo]; + const circuit = c.circuit; + // how many times to repeat evaluation (> 1 only for circuits 5&7 ) + const repeatCount = [0,1,1,1,1,this.C5Count,1,this.C6Count][cNo]; + const [idxArray, otKeys] = this.ot.getIndexesFromPool(nonFixedBits); + + // for circuit 1, there was no previous commit + const prevCommit = cNo > 1 ? this.myCommit[cNo-1] : new Uint8Array(); + + const blob1 = await this.send(`c${cNo}_step1`, concatTA(prevCommit, idxArray, extraData)); + + let offset = 0; + if (cNo > 1){ + const prevCommitSalt = blob1.slice(offset, offset + 32); + offset += 32; + // the hash to which the notary committed must be equal to our commit + const saltedCommit = await sha256(concatTA(this.myCommit[cNo-1], prevCommitSalt)); + assert (eq(saltedCommit, this.hisSaltedCommit[cNo-1])); + } + let notaryInputsCount = circuit.notaryInputSize; + if (cNo === 6){ + notaryInputsCount = 160 + 128 * this.C6Count; + } + const notaryInputsBlob = blob1.slice(offset, offset + notaryInputsCount*16); + offset += notaryInputsCount*16; + const encLabels = blob1.slice(offset, offset+nonFixedBits.length*32); + offset += nonFixedBits.length*32; + const nonFixedIndexes = blob1.slice(offset, offset+c.notaryNonFixedInputSize*2); + offset += c.notaryNonFixedInputSize*2; + assert(blob1.length === offset); + + const nonFixedEncLabels = this.g.getNonFixedEncLabels(nonFixedIndexes, cNo); + const clientLabels = this.g.getClientLabels(nonFixedBits, cNo); + const sendPromise = this.send(`c${cNo}_step2`, concatTA(nonFixedEncLabels, clientLabels), true); + const nonFixedLabels = this.e.getNonFixedLabels(encLabels, otKeys, nonFixedBits); + const allNotaryLabels = splitIntoChunks(notaryInputsBlob, 16); + + // collect batch of evaluation + const batch = []; + for (let r=0; r < repeatCount; r++){ + let fixedLabels = this.fixedLabels[cNo]; + let notaryLabels = allNotaryLabels; + if (cNo === 5){ + fixedLabels = this.fixedLabels[cNo].slice(r*148, r*148+148); + } + else if (cNo === 6){ + assert(this.fixedLabels[cNo].length === 144*repeatCount); + fixedLabels = this.fixedLabels[cNo].slice(r*144, r*144+144); + const commonNotary = allNotaryLabels.slice(0,160); + const uniqueNotary = allNotaryLabels.slice(160+r*128, 160+r*128+128); + notaryLabels = [].concat(commonNotary, uniqueNotary); + } + const garbledAssignment = concatTA(...notaryLabels, ...nonFixedLabels, ...fixedLabels); + const ttSize = circuit.andGateCount * 64; + const tt = this.blob[`c${cNo}_tt`].slice(r*ttSize, r*ttSize+ttSize); + batch.push([garbledAssignment, tt]); + } + + // perform evaluation + console.time('evaluateBatch'); + const batchOutputLabels = await this.e.evaluateBatch(batch, cNo); + console.timeEnd('evaluateBatch'); + const output = []; + + // process evaluation outputs + for (let r=0; r < repeatCount; r++){ + const outputLabelsBlob = batchOutputLabels[r]; + const outputLabels = splitIntoChunks(outputLabelsBlob, 16); + + const outputSize = circuit.outputSize * 32; + const allOutputLabelsBlob = this.blob[`c${cNo}_ol`].slice(r*outputSize, (r+1)*outputSize); + assert(allOutputLabelsBlob.length === circuit.outputSize*32); + const allOutputLabels = splitIntoChunks(allOutputLabelsBlob, 16); + + const bits = []; + for (let i = 0; i < circuit.outputSize; i++) { + const out = outputLabels[i]; + if (eq(out, allOutputLabels[i*2])) { + bits.push(0); + } else if (eq(out, allOutputLabels[i*2+1])) { + bits.push(1); + } else { + console.log('evaluator output does not match the garbled outputs'); + } + } + const out = bitsToBytes(bits); + this.output[cNo] = out; + output.push(out); + } + this.myCommit[cNo] = await sha256(concatTA(...output)); + + const cStep2Out = await sendPromise; + this.hisSaltedCommit[cNo] = cStep2Out.subarray(0,32); + const extraDataOut = cStep2Out.subarray(32); + output.push(extraDataOut); + return output; + } + + + // eslint-disable-next-line class-methods-use-this + processBlob(blob) { + // split up blob into [truth table + output labels] for each circuit + const obj = {}; + let offset = 0; + for (let i=1; i < this.cs.length; i++){ + let truthTableSize = this.cs[i].circuit.andGateCount *64; + let outputLabelsSize = this.cs[i].circuit.outputSize *32; + if (i === 5){ + truthTableSize = this.C5Count * truthTableSize; + outputLabelsSize = this.C5Count * outputLabelsSize; + } + else if ( i == 6 ){ + truthTableSize = this.C6Count * truthTableSize; + outputLabelsSize = this.C6Count * outputLabelsSize; + } + console.log('truthtable for ', i, ' is size: ', truthTableSize); + obj['c'+String(i)+'_tt'] = blob.subarray(offset, offset+truthTableSize); + offset += truthTableSize; + console.log('ol for ', i, ' is size: ', outputLabelsSize); + obj['c'+String(i)+'_ol'] = blob.subarray(offset, offset+outputLabelsSize); + offset += outputLabelsSize; + } + assert(blob.length === offset); + return obj; + } + + // generateSymmetricKeys generates ECDH shared secret given a raw pubkey of another party. + // Returns 2 symmetric keys in CryptoKey format: client_key and notary_key + // client_key is used to encrypt TO notary + // notary_key is used to decrypt FROM notary + async generateSymmetricKeys(privKeyCryptoKey, pubkeyRaw){ + const hisPubKey = await crypto.subtle.importKey( + 'raw', + pubkeyRaw.buffer, + {name: 'ECDH', namedCurve: 'P-256'}, + true, + []); + + const Secret = await crypto.subtle.deriveBits( + {'name': 'ECDH', 'public': hisPubKey }, + privKeyCryptoKey, + 256); + + const clientKey = await crypto.subtle.importKey( + 'raw', + Secret.slice(0,16), + 'AES-GCM', true, ['encrypt']); + + const notaryKey = await crypto.subtle.importKey( + 'raw', + Secret.slice(16,32), + 'AES-GCM', true, ['decrypt']); + + return [clientKey, notaryKey]; + } + + async generateECKeypair(){ + const keyPair = await crypto.subtle.generateKey( + {'name': 'ECDH', 'namedCurve': 'P-256'}, + true, + ['deriveBits']); + + const pubBytes = new Uint8Array( + await crypto.subtle.exportKey('raw', keyPair.publicKey)).slice(1); + return [pubBytes, keyPair.privateKey]; + } +} diff --git a/core/twopc/WorkerPool.js b/core/twopc/WorkerPool.js new file mode 100644 index 0000000..505a018 --- /dev/null +++ b/core/twopc/WorkerPool.js @@ -0,0 +1,78 @@ +// class WorkerPool assigns work from a batch to multiple Web Workers + +export default class WorkerPool{ + constructor(numWorkers, url){ + this.workers = []; + for (let i=0; i < numWorkers; i++){ + this.workers[i] = new Worker(url); + this.setIsResolved(i, true); + this.setRoundNo(i, -1); + } + } + // for each item in batch call the function doWork which has a signature + // doWork(batchItem, worker) where batchItem is the next item of batch + // and worker is a free worker from the pool. doWork must return a promise + // which resolves to the output + // optional arguments are: + // pm is in instance of ProgressMonitor + // pmtype is the type of progress monitoring. Can be either 'garbling' or 'evaluating' + async workerPool(batch, doWork, pm, pmtype){ + const promises = []; + const outputs = {}; + const workerCount = this.workers.length; + for (let c = 0; c < workerCount; c++){ + // start with Promises in resolved state + promises.push(Promise.resolve('empty')); + } + for (let i=0; i < batch.length; i++){ + console.log('round ', i); + // wait until we have a free worker + const out = await Promise.any(promises); + if (pm != undefined){ + pm.update(pmtype, {'current': i+1, 'total': batch.length}); + } + // find which worker resolved + let worker = null; + let idx = null; + for (idx = 0; idx < workerCount; idx++){ + if (this.getIsResolved(idx) === true){ + worker = this.workers[idx]; + break; + } + } + if (worker === null){ + throw('panic: no worker is marked as resolved'); + } + // save the worker's output + outputs[this.getRoundNo(idx)] = out; + // give the worker new work + this.setIsResolved(idx, false); + this.setRoundNo(idx, i); + const promise = doWork(batch[i], worker); + promises[idx] = promise; + } + // waiting for last "workerCount" workers to finish + const rv = await Promise.all(promises); + for (let idx = 0; idx < workerCount; idx++){ + outputs[this.getRoundNo(idx)] = rv[idx]; + } + return outputs; + } + + setIsResolved(idx, flag){ + this.workers[idx]['isResolved'] = flag; + } + + getIsResolved(idx){ + return this.workers[idx]['isResolved']; + } + + setRoundNo(idx, no){ + this.workers[idx]['roundNo'] = no; + } + + getRoundNo(idx){ + return this.workers[idx]['roundNo']; + } + +} diff --git a/core/twopc/circuits b/core/twopc/circuits new file mode 160000 index 0000000..cb87bc3 --- /dev/null +++ b/core/twopc/circuits @@ -0,0 +1 @@ +Subproject commit cb87bc30e7ee2b1913856e1eef4acd0fee9bf664 diff --git a/core/twopc/webWorkers/gcworker.js b/core/twopc/webWorkers/gcworker.js new file mode 100644 index 0000000..74ce297 --- /dev/null +++ b/core/twopc/webWorkers/gcworker.js @@ -0,0 +1,403 @@ +// gcworker.js is a WebWorker which performs garbling and evaluation +// of garbled circuits + +// eslint-disable-next-line no-undef +importScripts('./../../third-party/nacl-fast.js'); + +let circuit = null; +let truthTable = null; +let timeEvaluating = 0; + +// sha0 is used by randomOracle +const sha0 = new Uint8Array( hex2ba('da5698be17b9b46962335799779fbeca8ce5d491c0d26243bafef9ea1837a9d8')); +// byteArray is used by randomOracle +const byteArray = new Uint8Array(24); +// randomPool will be filled with data from getRandom +let randomPool; +// randomPoolOffset will be moved after data was read from randomPool +let randomPoolOffset = 0; +let garbledAssigment; + +self.onmessage = function(event) { + const msg = event.data.msg; + const data = event.data.data; + if (msg === 'parse'){ + circuit = data; + garbledAssigment = new Uint8Array(32*(circuit.wiresCount)); + // no need to respond to this message + } + else if (msg === 'setTruthTable'){ + assert(data.byteLength == circuit.andGateCount*64); + truthTable = new Uint8Array(data); + } + else if (msg === 'garble'){ + console.log('in garble with circuit', circuit); + if (circuit == null){ + console.log('error: need to parse circuit before garble'); + return; + } + console.time('garbling done in'); + const reuseLabels = (data == undefined) ? undefined : data.reuseLabels; + const reuseIndexes = (data == undefined) ? undefined : data.reuseIndexes; + const reuseR = (data == undefined) ? undefined : data.reuseR; + + const [truthTable, inputLabels, outputLabels, R] = garble(circuit, garbledAssigment, reuseLabels, reuseIndexes, reuseR); + assert (truthTable.length === circuit.andGateCount*64); + assert (inputLabels.length === circuit.clientInputSize*32 + circuit.notaryInputSize*32); + assert (outputLabels.length === circuit.outputSize*32); + const obj = {'tt': truthTable.buffer, 'il': inputLabels.buffer, 'ol': outputLabels.buffer, 'R': R}; + console.timeEnd('garbling done in'); + postMessage(obj, [truthTable.buffer, inputLabels.buffer, outputLabels.buffer]); + } + else if (msg === 'evaluate'){ + if (circuit == null || truthTable == null){ + console.log('error: need to parse circuit and set truth table before evaluate'); + return; + } + const garbledAssigment = new Uint8Array(16*(circuit.wiresCount)); + const inputLabels = new Uint8Array(data); + assert (inputLabels.length === circuit.clientInputSize*16 + circuit.notaryInputSize*16); + const outputLabels = evaluate(circuit, garbledAssigment, truthTable, inputLabels); + assert (outputLabels.length === circuit.outputSize*16); + postMessage(outputLabels.buffer); + } + else { + console.log('Error: unexpected message in worker'); + } +}; + +function newR(){ + const R = getRandom(16); + R[15] = R[15] | 0x01; + return R; +} + +function generateInputLabels(count, R){ + const newLabels = new Uint8Array(count*32); + for (let i=0; i < count; i++){ + const label1 = getRandom(16); + const label2 = xor(label1, R); + newLabels.set(label1, i*32); + newLabels.set(label2, i*32+16); + } + return newLabels; +} + +function garble(circuit, ga, reuseLabels = new Uint8Array(0) , reuseIndexes = [], R){ + + const inputCount = circuit.notaryInputSize + circuit.clientInputSize; + fillRandom((inputCount+1+circuit.andGateCount)*16); + R = R || newR(); + + // generate new labels + const newLabels = generateInputLabels(inputCount - reuseIndexes.length, R); + + // set both new and reused labels into ga + let reusedCount = 0; // how many reused inputs were already put into ga + let newInputsCount = 0; // how many new inputs were already put into ga + + for (let i = 0; i < inputCount; i++) { + if (reuseIndexes.includes(i)) { + ga.set(reuseLabels.subarray(reusedCount*32, reusedCount*32+32), i*32); + reusedCount += 1; + } + else { + ga.set(newLabels.subarray(newInputsCount*32, newInputsCount*32+32), i*32); + newInputsCount += 1; + } + } + + const truthTable = new Uint8Array(circuit.andGateCount*64); + let andGateIdx = 0; + // garble gates + for (let i = 0; i < circuit.gatesCount; i++) { + const gateBlob = circuit.gatesBlob.subarray(i*10, i*10+10); + const op = ['XOR', 'AND', 'INV'][gateBlob[0]]; + if (op === 'AND') { + garbleAnd(gateBlob, R, ga, truthTable, andGateIdx, i); + andGateIdx += 1; + } else if (op === 'XOR') { + garbleXor(gateBlob, R, ga); + } else if (op === 'NOT' || op === 'INV') { + garbleNot(gateBlob, ga); + } else { + throw new Error('Unrecognized gate: ' + op); + } + } + + return [truthTable, ga.slice(0, inputCount*32), ga.slice(-circuit.outputSize*32), R]; + +} + +const garbleAnd = function (gateBlob, R, ga, tt, andGateIdx, id) { + const in1 = threeBytesToInt(gateBlob.subarray(1,4)); + const in2 = threeBytesToInt(gateBlob.subarray(4,7)); + const out = threeBytesToInt(gateBlob.subarray(7,10)); + + const randomLabel = getRandom(16); + + gaSetIndexG(ga, out, 0, randomLabel); + gaSetIndexG(ga, out, 1, xor(randomLabel, R, true)); + + const in1_0 = gaGetIndexG(ga, in1, 0); + const in1_1 = gaGetIndexG(ga, in1, 1); + const in2_0 = gaGetIndexG(ga, in2, 0); + const in2_1 = gaGetIndexG(ga, in2, 1); + const out_0 = gaGetIndexG(ga, out, 0); + const out_1 = gaGetIndexG(ga, out, 1); + + const values = [ + encrypt(in1_0, in2_0, id, out_0), + encrypt(in1_0, in2_1, id, out_0), + encrypt(in1_1, in2_0, id, out_0), + encrypt(in1_1, in2_1, id, out_1) + ]; + + const points = [ + 2 * getPoint(in1_0) + getPoint(in2_0), + 2 * getPoint(in1_0) + getPoint(in2_1), + 2 * getPoint(in1_1) + getPoint(in2_0), + 2 * getPoint(in1_1) + getPoint(in2_1) + ]; + + tt.set(values[0], andGateIdx*64+16*points[0]); + tt.set(values[1], andGateIdx*64+16*points[1]); + tt.set(values[2], andGateIdx*64+16*points[2]); + tt.set(values[3], andGateIdx*64+16*points[3]); +}; + + +const garbleXor = function (gateBlob, R, ga) { + const in1 = threeBytesToInt(gateBlob.subarray(1,4)); + const in2 = threeBytesToInt(gateBlob.subarray(4,7)); + const out = threeBytesToInt(gateBlob.subarray(7,10)); + + const in1_0 = gaGetIndexG(ga, in1, 0); + const in1_1 = gaGetIndexG(ga, in1, 1); + const in2_0 = gaGetIndexG(ga, in2, 0); + const in2_1 = gaGetIndexG(ga, in2, 1); + + gaSetIndexG(ga, out, 0, xor(in1_0, in2_0)); + gaSetIndexG(ga, out, 1, xor(xor(in1_1, in2_1), R, true)); +}; + + +const garbleNot = function (gateBlob, ga) { + const in1 = threeBytesToInt(gateBlob.subarray(1,4)); + const out = threeBytesToInt(gateBlob.subarray(7,10)); + + const in1_0 = gaGetIndexG(ga, in1, 0); + const in1_1 = gaGetIndexG(ga, in1, 1); + // careful! don't put the reference back into ga, but a copy of it + gaSetIndexG(ga, out, 0, in1_1.slice()); + gaSetIndexG(ga, out, 1, in1_0.slice()); +}; + +function evaluate (circuit, ga, tt, inputLabels) { + // set input labels + ga.set(inputLabels); + + // evaluate one gate at a time + let numberOfANDGates = 0; + const t0 = performance.now(); + console.time('worker_evaluate'); + for (let i = 0; i < circuit.gatesCount; i++) { + const gateBlob = circuit.gatesBlob.subarray(i*10, i*10+10); + const op = ['XOR', 'AND', 'INV'][gateBlob[0]]; + if (op === 'AND') { + evaluateAnd(ga, tt, numberOfANDGates, gateBlob, i); + numberOfANDGates += 1; + } else if (op === 'XOR') { + evaluateXor(ga, gateBlob); + } else if (op === 'INV' || op === 'NOT') { + evaluateNot(ga, gateBlob); + } else { + throw new Error(`Unrecognized gate: ${op}`); + } + } + console.timeEnd('worker_evaluate'); + const t1 = performance.now(); + timeEvaluating += (t1 - t0); + + return ga.slice((circuit.wiresCount-circuit.outputSize)*16, circuit.wiresCount*16); +} + +const evaluateAnd = function (ga, tt, andGateIdx, gateBlob, id) { + const in1 = threeBytesToInt(gateBlob.subarray(1,4)); + const in2 = threeBytesToInt(gateBlob.subarray(4,7)); + const out = threeBytesToInt(gateBlob.subarray(7,10)); + + const label1 = gaGetIndexE(ga, in1); // ga[in1]; + const label2 = gaGetIndexE(ga, in2); // ga[in2]; + + const point = 2 * getPoint(label1) + getPoint(label2); + const offset = andGateIdx*64+16*point; + const cipher = tt.subarray(offset, offset+16); + + gaSetIndexE(ga, out, decrypt(label1, label2, id, cipher)); +}; + +const evaluateXor = function (ga, gateBlob) { + const in1 = threeBytesToInt(gateBlob.subarray(1,4)); + const in2 = threeBytesToInt(gateBlob.subarray(4,7)); + const out = threeBytesToInt(gateBlob.subarray(7,10)); + + const v1 = gaGetIndexE(ga, in1); + const v2 = gaGetIndexE(ga, in2); + gaSetIndexE(ga, out, xor(v1, v2)); +}; + +const evaluateNot = function (ga, gateBlob) { + const in1 = threeBytesToInt(gateBlob.subarray(1,4)); + const out = threeBytesToInt(gateBlob.subarray(7,10)); + gaSetIndexE(ga, out, gaGetIndexE(ga, in1)); +}; + +// get value at index in the garbled assignment when evaluating +function gaGetIndexE(ga, idx){ + return ga.subarray(idx*16, idx*16+16); +} + +// set value at index in the garbled assignment when evaluating +function gaSetIndexE(ga, idx, value){ + ga.set(value, idx*16); +} + +// get value at index in the garbled assignment when garbling +// pos is index within idx (either 0 or 1) +function gaGetIndexG(ga, idx, pos){ + return ga.subarray(idx*32+16*pos, idx*32+16*pos+16); +} + +// set value at index and (position in index) in the garbled assignment when garbling +// values is an array of two 16-byte values +function gaSetIndexG(ga, idx, pos, value){ + ga.set(value, idx*32+pos*16); +} + + +function xor(a, b, reuse) { + if (a.length !== b.length){ + console.log('a.length !== b.length'); + throw('a.length !== b.length'); + } + let bytes; + if (reuse === true){ + // in some cases the calling function will have no more use of "a" + // so we reuse it to return the value + // saving a few cycles on not allocating a new var + bytes = a; + } + else { + bytes = a.slice(); + } + for (let i = 0; i < a.length; i++) { + bytes[i] = a[i] ^ b[i]; + } + return bytes; +} + +function getPoint(arr) { + return arr[15] & 0x01; +} + +const decrypt = encrypt; + +let a2; +let b4; +function encrypt(a, b, t, m) { + // double a + a2 = a.slice(); + const leastbyte = a2[0]; + a2.copyWithin(0,1,15); // Logical left shift by 1 byte + a2[14] = leastbyte; // Restore old least byte as new greatest (non-pointer) byte + // quadruple b + b4 = b.slice(); + const leastbytes = [b4[0], b4[1]]; + b4.copyWithin(0,2,15); // Logical left shift by 2 byte + [b4[13], b4[14]] = leastbytes; // Restore old least two bytes as new greatest bytes + + const k = xor(a2, b4, true); + const ro = randomOracle(k, t); + const mXorK = xor(k, m, true); + return xor(ro, mXorK, true); +} + +function randomOracle(m, t) { + return self.nacl.secretbox( + m, + longToByteArray(t), + sha0, + ).subarray(0,16); +} + +function longToByteArray(long) { + // we want to represent the input as a 24-bytes array + for (let index = 0; index < byteArray.length; index++) { + const byte = long & 0xff; + byteArray[index] = byte; + long = (long - byte) / 256; + } + return byteArray; +} + +function threeBytesToInt(b){ + return b[2] + b[1]*256 + b[0]*65536; +} + +// convert a hex string into byte array +function hex2ba(str) { + var ba = []; + // pad with a leading 0 if necessary + if (str.length % 2) { + str = '0' + str; + } + for (var i = 0; i < str.length; i += 2) { + ba.push(parseInt('0x' + str.substr(i, 2))); + } + return ba; +} + + +function getRandom(count) { + const rand = randomPool.subarray(randomPoolOffset, randomPoolOffset+count); + randomPoolOffset += count; + return rand; +} + +// to save time we fill the randomPool in one call and then take +// randomness from that pool. Instead of making 1000s of calls to getRandomValues() +function fillRandom(count){ + // 65536 is the max that API supports + const randomChunks = []; + const chunkCount = Math.ceil(count/65536); + for (let i=0; i < chunkCount; i++){ + randomChunks.push(self.crypto.getRandomValues(new Uint8Array(65536))); + } + randomPool = concatTA(...randomChunks); + randomPoolOffset = 0; +} + + +function assert(condition, message) { + if (!condition) { + console.trace(); + throw message || 'Assertion failed'; + } +} + +// concatenate an array of typed arrays (specifically Uint8Array) +function concatTA (...arr){ + let newLen = 0; + for (const item of arr){ + assert(item instanceof Uint8Array); + newLen += item.length; + } + const newArray = new Uint8Array(newLen); + let offset = 0; + for (const item of arr){ + newArray.set(item, offset); + offset += item.length; + } + return newArray; +} \ No newline at end of file diff --git a/core/twopc/webWorkers/otworker.js b/core/twopc/webWorkers/otworker.js new file mode 100644 index 0000000..a9c4e6b --- /dev/null +++ b/core/twopc/webWorkers/otworker.js @@ -0,0 +1,124 @@ +// otworker.js is a WebWorker where most of the heavy computations for +// oblivious transfer happen + +importScripts('./../../third-party/sodium.js'); + +self.onmessage = function(event) { + const msg = event.data.msg; + const data = event.data.data; + if (msg === 'saveDecryptionKeys'){ + const bytes = new Uint8Array(data.bytes); + const A = new Uint8Array(data.A); + const rv = saveDecryptionKeys(bytes, A); + postMessage({'blob': rv.buffer}); + + } + else if (msg === 'precomputePool'){ + const count = data.count; + const A = new Uint8Array(data.A); + const rv = precomputePool(count, A); + postMessage({'blob': rv.buffer}); + } + else if (msg === 'prepareEncryptionKeys'){ + const bytes = new Uint8Array(data.bytes); + const a = new Uint8Array(data.a, data.A); + const A = new Uint8Array(data.A); + const rv = prepareEncryptionKeys(bytes, a, A); + postMessage({'blob': rv.buffer}); + } +}; + + +function prepareEncryptionKeys(bytes, a, A){ + const blob = []; + const Bcount = bytes.length/32; + for (let i=0; i < Bcount; i++){ + const B = bytes.slice(i*32, (i+1)*32); + const k0 = sodium.crypto_generichash(16, sodium.crypto_scalarmult_ristretto255(a, B)); + const sub = sodium.crypto_core_ristretto255_sub(B, A); + const k1 = sodium.crypto_generichash(16, sodium.crypto_scalarmult_ristretto255(a, sub)); + blob.push(k0); + blob.push(k1); + } + return concatTA(...blob); +} + +function saveDecryptionKeys(bytes, A){ + const bits = bytesToBits(bytes); + const blob = []; + for (const bit of bits){ + if (bit === 0){ + const b0 = sodium.crypto_core_ristretto255_scalar_random(); + const B0 = sodium.crypto_scalarmult_ristretto255_base(b0); + const k0 = sodium.crypto_generichash(16, sodium.crypto_scalarmult_ristretto255(b0, A)); + blob.push(k0); + blob.push(B0); + } + else { + const b1 = sodium.crypto_core_ristretto255_scalar_random(); + const gb1 = sodium.crypto_scalarmult_ristretto255_base(b1); + const B1 = sodium.crypto_core_ristretto255_add(A, gb1); + const k1 = sodium.crypto_generichash(16, sodium.crypto_scalarmult_ristretto255(b1, A)); + blob.push(k1); + blob.push(B1); + } + } + return concatTA(...blob); +} + +function precomputePool(count, A){ + const blob = []; + for (let i = 0; i < count ; i++){ + const b0 = sodium.crypto_core_ristretto255_scalar_random(); + const B0 = sodium.crypto_scalarmult_ristretto255_base(b0); + const k0 = sodium.crypto_generichash(16, sodium.crypto_scalarmult_ristretto255(b0, A)); + blob.push(k0); + blob.push(B0); + } + for (let i = 0; i < count; i++){ + const b1 = sodium.crypto_core_ristretto255_scalar_random(); + const gb1 = sodium.crypto_scalarmult_ristretto255_base(b1); + const B1 = sodium.crypto_core_ristretto255_add(A, gb1); + const k1 = sodium.crypto_generichash(16, sodium.crypto_scalarmult_ristretto255(b1, A)); + blob.push(k1); + blob.push(B1); + } + return concatTA(...blob); +} + +// convert Uint8Array into an array of 0/1 where least bit has index 0 +function bytesToBits (ba){ + assert(ba instanceof Uint8Array); + const bitArr = Array(ba.length*8); + let idx = 0; + for (let i=ba.length-1; i >= 0; i--){ + for (let j=0; j < 8; j++){ + bitArr[idx] = (ba[i] >> j) & 0x01; + idx++; + } + } + return bitArr; +} + +function assert(condition, message) { + if (!condition) { + console.trace(); + throw message || 'Assertion failed'; + } +} + +// concatenate an array of typed arrays (specifically Uint8Array) +function concatTA (...arr){ + let newLen = 0; + for (const item of arr){ + assert(item instanceof Uint8Array); + newLen += item.length; + } + const newArray = new Uint8Array(newLen); + let offset = 0; + for (const item of arr){ + newArray.set(item, offset); + offset += item.length; + } + return newArray; +} \ No newline at end of file diff --git a/core/twopc/webWorkers/serializeCircuits.js b/core/twopc/webWorkers/serializeCircuits.js new file mode 100644 index 0000000..5beabaa --- /dev/null +++ b/core/twopc/webWorkers/serializeCircuits.js @@ -0,0 +1,77 @@ +// Serializes the circuit into a compact representation + +self.onmessage = function(event) { + const text = event.data.text; + const [obj, blob] = serializeCircuit(text); + postMessage({'obj': obj, blob: blob.buffer}); +}; + +function serializeCircuit(text){ + const obj = {}; + // we don't do any sanity/formatting checks because the circuits + // were output by casm.js and have a well-defined structure + const rows = text.split('\n'); + obj['gatesCount'] = Number(rows[0].split(' ')[0]); + console.log('obj[\'gatesCount\']', obj['gatesCount']); + obj['wiresCount'] = Number(rows[0].split(' ')[1]); + obj['notaryInputSize'] = Number(rows[1].split(' ')[1]); + obj['clientInputSize'] = Number(rows[1].split(' ')[2]); + obj['outputSize'] = Number(rows[2].split(' ')[1]); + + // each gate is serialized as + // 1 byte: gate type XOR==0 AND==1 INV==2 + // 3 bytes: 1st input wire number + // 3 bytes: 2nd input wire number + // 3 bytes: output wire number + const gateByteSize = 10; + const opBytes = {'XOR': 0, 'AND': 1, 'INV': 2}; + // first 3 rows are not gates but metadata + const blob = new Uint8Array((rows.length-3)*gateByteSize); + let blobOffset = 0; + let andCount = 0; + for (let i=0; i < (rows.length-3); i++){ + const gate = rows[3+i]; + const tokens = gate.split(' '); + const op = tokens[tokens.length-1]; + const opByte = opBytes[op]; + blob.set([opByte], blobOffset); + blobOffset+=1; + if (op === 'XOR' || op === 'AND'){ + const in1 = intToThreeBytes(tokens[tokens.length-4]); + const in2 = intToThreeBytes(tokens[tokens.length-3]); + const out = intToThreeBytes(tokens[tokens.length-2]); + blob.set(in1, blobOffset); + blobOffset+=3; + blob.set(in2, blobOffset); + blobOffset+=3; + blob.set(out, blobOffset); + blobOffset+=3; + if (op == 'AND'){ + andCount+=1; + } + } + else if (op === 'INV'){ + const in1 = intToThreeBytes(tokens[tokens.length-3]); + const out = intToThreeBytes(tokens[tokens.length-2]); + blob.set(in1, blobOffset); + blobOffset+=3; + blob.set([0,0,0], blobOffset); + blobOffset+=3; + blob.set(out, blobOffset); + blobOffset+=3; + } + else { + throw('unknown op'); + } + } + obj['andGateCount'] = andCount; + return [obj, blob]; +} + +function intToThreeBytes(i){ + const byteArray = Array(3); + byteArray[0] = (i >> 16) & 0xFF; + byteArray[1] = (i >> 8) & 0xFF; + byteArray[2] = i & 0xFF; + return byteArray; +} diff --git a/core/utils.js b/core/utils.js new file mode 100644 index 0000000..ae7d380 --- /dev/null +++ b/core/utils.js @@ -0,0 +1,1343 @@ +import {verifyChain} from './verifychain.js'; +import * as asn1js from './third-party/pkijs/asn1.js'; +import Certificate from './third-party/pkijs/Certificate.js'; + +// returns an array of obj's keys converted to numbers sorted ascendingly +export function sortKeys(obj){ + const numArray = Object.keys(obj).map(function(x){return Number(x);}); + return numArray.sort(function(a, b){return a-b;}); +} + +// convert a byte array into a hex string +export function ba2hex(ba) { + assert(ba instanceof Uint8Array); + let hexstring = ''; + for (const b of ba) { + let hexchar = b.toString(16); + if (hexchar.length == 1) { + hexchar = '0' + hexchar; + } + hexstring += hexchar; + } + return hexstring; +} + +// convert a hex string into byte array +export function hex2ba(str) { + const ba = []; + // pad with a leading 0 if necessary + if (str.length % 2) { + str = '0' + str; + } + for (let i = 0; i < str.length; i += 2) { + ba.push(parseInt('0x' + str.substr(i, 2))); + } + return new Uint8Array(ba); +} + +// test a string against a string with a * wildcard +export function wildcardTest(wildStr, str) { + var index = wildStr.indexOf('*'); + if (index > -1){ + // if wildStr has an asterisk then we match from the end up to the asterisk + var substringAfterAsterisk = wildStr.slice(index+1); + return str.endsWith(substringAfterAsterisk); + } + else{ + // if it doesnt contain an asterisk then wildStr must be equal to str + return (wildStr == str); + } +} + +// ba2int converts a bit-endian byte array into a Number or BigInt +export function ba2int(ba){ + assert(ba instanceof Uint8Array); + if (ba.length <= 8){ + let retval = 0; + for (let i = 0; i < ba.length; i++) { + retval |= ba[ba.length - 1 - i] << 8 * i; + } + return retval; + } + else { + var hexstr = ''; + for (let byte of ba){ + let hexbyte = byte.toString(16); + if (hexbyte.length == 1) { + hexbyte = '0' + hexbyte; + } + hexstr += hexbyte; + } + return BigInt('0x'+hexstr); + } +} + + +// int2ba converts Number or BigInt into a byte array, +// optionally padding it to the desired length +export function int2ba(int, size){ + assert(typeof(int) == 'bigint' || typeof(int) == 'number', 'Only can convert Number or BigInt'); + let hexstr = int.toString(16); + if (hexstr.length % 2) { + hexstr = '0' + hexstr; } + const ba = []; + for (let i=0; i < hexstr.length/2; i++){ + ba.push(parseInt(hexstr.slice(2*i, 2*i+2), 16)); + } + if (size){ + const oldlen = ba.length; + for (let j = 0; j < (size - oldlen); j++) { + ba.unshift(0); + } + } + return new Uint8Array(ba); +} + + +// converts string to byte array +export function str2ba(str) { + if (typeof(str) !== 'string') { + throw ('Only type string is allowed in str2ba'); + } + const ba = new Uint8Array(str.length); + for (let i = 0; i < str.length; i++) { + ba[i] = str.charCodeAt(i); + } + return ba; +} + +export function ba2str(ba) { + assert(ba instanceof Uint8Array); + let result = ''; + for (const b of ba) { + result += String.fromCharCode(b); + } + return result; +} + +// xor 2 byte arrays of equal length +export function xor (a,b){ + assert(a instanceof Uint8Array && b instanceof Uint8Array); + assert(a.length === b.length); + var c = new Uint8Array(a.length); + for (var i=0; i< a.length; i++){ + c[i] = a[i]^b[i]; + } + return c; +} + + +export async function sha256(ba) { + assert(ba instanceof Uint8Array); + return new Uint8Array(await crypto.subtle.digest('SHA-256', ba.buffer)); +} + +export function assert(condition, message) { + if (!condition) { + console.trace(); + throw message || 'Assertion failed'; + } +} + +export function getRandom(number) { + return crypto.getRandomValues(new Uint8Array(number)); +} + +// verifySig verifies a signature in p1363 format against a +// pubkey in raw format. The signature is over "signed_digest". +export async function verifySig(pubkeyRaw, sig_p1363, signed_digest){ + try { + const pubkey = await crypto.subtle.importKey( + 'raw', + pubkeyRaw.buffer, + {name: 'ECDSA', namedCurve: 'P-256'}, + true, + ['verify']); + var result = await crypto.subtle.verify( + {'name': 'ECDSA', 'hash': 'SHA-256'}, + pubkey, + sig_p1363.buffer, + signed_digest.buffer); + } catch (e) { + console.log(e, e.name); + throw(e); + } + return result; +} + +// input is Uint8Array +export async function verifyAttestationDoc(doc){ + // extract x,y from EC pubkey + const decoded = window.CBOR.decode(doc.buffer); + const payload = decoded[2].slice(); // need to copy otherwise .buffer will access ab + const doc_obj = window.CBOR.decode(payload.buffer); + const leafCertDer = doc_obj.certificate.slice(); + const cert_asn1 = asn1js.fromBER(leafCertDer.buffer); + const leafCert = new Certificate({ schema: cert_asn1.result }); + const x = new Uint8Array(leafCert.subjectPublicKeyInfo.parsedKey.x); + const y = new Uint8Array(leafCert.subjectPublicKeyInfo.parsedKey.y); + // verify the signature + COSE.verify(x, y, doc.buffer); + + // verify certificate chain + + // this is a sha256 hash of root cert from https://aws-nitro-enclaves.amazonaws.com/AWS_NitroEnclaves_Root-G1.zip + // root.pem must be converted to der with pem2ab() + const rootCertDer = doc_obj.cabundle[0].slice(); + const rootCertHash = '641a0321a3e244efe456463195d606317ed7cdcc3c1756e09893f3c68f79bb5b'; + assert(ba2hex(await sha256(rootCertDer)) === rootCertHash); + const rootCert = new Certificate({ schema: asn1js.fromBER(rootCertDer.buffer).result}); + + // reverse cabundle ordering + const certChain = [leafCertDer]; + for (let i=doc_obj.cabundle.length-1; i >=0; i--){ + certChain.push(doc_obj.cabundle[i].slice()); + } + // verifying against the time when the attestation doc was retrieved + var vcrv = await verifyChain(certChain, leafCert.notBefore.value, [rootCert]); + assert (vcrv.result == true); + console.log('cert chain verification successful'); + + // return user_data and PCRs + return [doc_obj.user_data, doc_obj.pcrs[0], doc_obj.pcrs[1], doc_obj.pcrs[2]]; +} + + +export function b64encode(ba) { + assert(ba instanceof Uint8Array); + if (typeof window === 'undefined') { + // running in nodejs + return Buffer.from(ba).toString('base64'); + } + else { + // if aBytes is too large > ~100 KB, we may get an error + // RangeError: Maximum call stack size exceeded + // therefore we split the input into chunks + var strings = ''; + var chunksize = 4096; + for (var i = 0; i * chunksize < ba.length; i++){ + strings += String.fromCharCode.apply(null, ba.slice(i * chunksize, (i + 1) * chunksize)); + } + return btoa(strings); + } +} + + +export function b64decode(str) { + if (typeof window === 'undefined') { + // running in nodejs + return Buffer.from(str, 'base64').toJSON().data; + } + else { + const arr = atob(str).split('').map(function(c) { + return c.charCodeAt(0); + }); + return new Uint8Array(arr); + } +} + +// conform to base64url format replace +/= with -_ +export function b64urlencode (ba){ + assert(ba instanceof Uint8Array); + let str; + if (typeof window === 'undefined') { + // running in nodejs + str = Buffer.from(ba).toString('base64'); + } + else { + str = b64encode(ba); + } + return str.split('+').join('-').split('/').join('_').split('=').join(''); +} + + +export function buildChunkMetadata(plaintextArr){ + let http_data = ''; + for (const pt of plaintextArr){ + http_data += ba2str(pt); + } + + const chunkMetadata = []; + // '''Dechunk only if http_data is chunked otherwise return http_data unmodified''' + const http_header = http_data.slice(0, http_data.search('\r\n\r\n') + '\r\n\r\n'.length); + // #\s* below means any amount of whitespaces + if (http_header.search(/transfer-encoding:\s*chunked/i) === -1) { + return []; // #nothing to dechunk + } + + // all offsets are relative to the beginning of the HTTP response + let cur_offset = http_header.length; + let chunk_len = -1; // #initialize with a non-zero value + while (true) { + var new_offset = http_data.slice(cur_offset).search('\r\n'); + if (new_offset === -1) { // #pre-caution against endless looping + // #pinterest.com is known to not send the last 0 chunk when HTTP gzip is disabled + break; + } + var chunk_len_hex = http_data.slice(cur_offset, cur_offset + new_offset); + chunk_len = parseInt(chunk_len_hex, 16); + if (chunk_len === 0) { + chunkMetadata.push(cur_offset-2); + chunkMetadata.push(cur_offset+ '0\r\n\r\n'.length - 1); + break; // #for properly-formed ml we should break here + } + if (cur_offset == http_header.length){ + chunkMetadata.push(http_header.length); + } + else { + chunkMetadata.push(cur_offset-2); + } + cur_offset += new_offset + '\r\n'.length; + chunkMetadata.push(cur_offset-1); + cur_offset += chunk_len + '\r\n'.length; + } + return chunkMetadata; +} + + +// HTTP chunking metadata may be present in records. Strip the records of it. +// return the array of records with dechunked info removed +export function dechunk_http(decrRecords) { + var http_data = ''; + for (const ct of decrRecords){ + http_data += ba2str(ct); + } + + // '''Dechunk only if http_data is chunked otherwise return http_data unmodified''' + const http_header = http_data.slice(0, http_data.search('\r\n\r\n') + '\r\n\r\n'.length); + // #\s* below means any amount of whitespaces + var stopat = 0; + if (http_header.search(/transfer-encoding:\s*chunked/i) === -1) { + return decrRecords; // #nothing to dechunk + } + + var chunkMetadata = buildChunkMetadata(decrRecords); + var dechunkedPlaintexts = []; + var totalOffset = -1; // an offset at which the last byte is found of plaintexts processed so far + var shrinkNextRecordBy = 0; // used when chunking metadata spans 2 TLS records + var shrinkThisRecordBy = 0; + for (var i=0; i < decrRecords.length; i++){ + shrinkThisRecordBy = shrinkNextRecordBy; + shrinkNextRecordBy = 0; + var ct = decrRecords[i]; + totalOffset += ct.length; + if (stopat){ + if (stopat < [].concat.apply([], dechunkedPlaintexts).length - 500){ + var s = true; + } + } + var metadataInThisRecord = []; + var tmpArray = [...chunkMetadata]; + // every even index contains the start of metadata + for (var j=0; j < tmpArray.length; j+=2){ + if (tmpArray[j] > totalOffset) break; + // else + if (tmpArray[j+1] > totalOffset){ + // chunking metadata spans 2 TLS records + if (shrinkNextRecordBy) { + // already was spanning 2 TLS records + throw('chunking metadata spans 3 TLS records. Please report to the developers for investigation'); + } + shrinkNextRecordBy = tmpArray[j+1] - totalOffset; + } + metadataInThisRecord.push(tmpArray[j]- (totalOffset+1 - ct.length)); + metadataInThisRecord.push(tmpArray[j+1] - (totalOffset+1 - ct.length)); + chunkMetadata.shift(); + chunkMetadata.shift(); + } + + const dechunkedRecord = []; + // if we need to shrink the record but the record itself consists only of partial metadata + // and its size is less than the amount we need to shrink + if (shrinkThisRecordBy && (ct.length < shrinkThisRecordBy)){ + assert(shrinkNextRecordBy == 0); + shrinkNextRecordBy = shrinkThisRecordBy - ct.length; + dechunkedPlaintexts.push([]); + continue; + } + + var fromPos = shrinkThisRecordBy; // set to 0 when metadata doesnt span 2 records + for (var k=0; k < metadataInThisRecord.length; k+=2){ + // offsets in metadataInThisRecord relative to this record + if (k+2 == metadataInThisRecord.length && i+1 == decrRecords.length){ + // set breakpoint here + var s = true; + } + var startOffset = metadataInThisRecord[k]; + var slice = ct.slice(fromPos, startOffset); + dechunkedRecord.push(slice); + fromPos = metadataInThisRecord[k+1]+1; + } + var lastSlice = ct.slice(fromPos); + dechunkedRecord.push(lastSlice); + dechunkedPlaintexts.push(concatTA(...dechunkedRecord)); + } + return dechunkedPlaintexts; +} + + + + +export function gunzip_http(dechunkedRecords) { + var http_data = ''; + for (let rec of dechunkedRecords){ + http_data += rec; + } + + var http_header = http_data.slice(0, http_data.search('\r\n\r\n') + '\r\n\r\n'.length); + // #\s* below means any amount of whitespaces + if (http_header.search(/content-encoding:\s*deflate/i) > -1) { + // #TODO manually resend the request with compression disabled + throw ('please disable compression and rerun the notarization'); + } + if (http_header.search(/content-encoding:\s.*gzip/i) === -1) { + console.log('nothing to gunzip'); + return dechunkedRecords; // #nothing to gunzip + } + throw ('gzip enabled'); + var http_body = http_data.slice(http_header.length); + var ungzipped = http_header; + if (!http_body) { + // HTTP 304 Not Modified has no body + return [ungzipped]; + } + var inflated = pako.inflate(http_body); + ungzipped += ba2str(inflated); + return [ungzipped]; +} + +export function getTime() { + var today = new Date(); + var time = today.getFullYear() + '-' + + ('00' + (today.getMonth() + 1)).slice(-2) + '-' + + ('00' + today.getDate()).slice(-2) + '-' + + ('00' + today.getHours()).slice(-2) + '-' + + ('00' + today.getMinutes()).slice(-2) + '-' + + ('00' + today.getSeconds()).slice(-2); + return time; +} + +// PEM certificate/pubkey to byte array +export function pem2ba(pem) { + var lines = pem.split('\n'); + var encoded = ''; + for(let line of lines){ + if (line.trim().length > 0 && + line.indexOf('-BEGIN CERTIFICATE-') < 0 && + line.indexOf('-BEGIN PUBLIC KEY-') < 0 && + line.indexOf('-END PUBLIC KEY-') < 0 && + line.indexOf('-END CERTIFICATE-') < 0 ) { + encoded += line.trim(); + } + } + return b64decode(encoded); +} + + +// compare bytes in 2 arrays. a or b can be either Array or Uint8Array +export function eq(a, b) { + assert(Array.isArray(a) || a instanceof Uint8Array); + assert(Array.isArray(b) || b instanceof Uint8Array); + return a.length === b.length && + a.every((val, index) => val === b[index]); +} + + +// expand the range [min:max) into array of ints 1,2,3,4... up to but not including max +export function expandRange(min, max){ + const arr = []; + for (let i=0; i < max-min; i++){ + arr.push(min + i); + } + return arr; +} + + +// split Array or Uint8Array into an array array of chunks +export function splitIntoChunks(ba, chunkSize) { + assert(ba instanceof Uint8Array); + assert(ba.length % chunkSize === 0); + const newArray = []; + const chunkCount = ba.length / chunkSize; + for (let i=0; i < chunkCount; i++){ + newArray.push(ba.slice(i*chunkSize, (i+1)*chunkSize)); + } + return newArray; +} + +// perform GCM Galois Field block multiplication +// x,y are byte arrays +export function blockMult(x_,y_){ + // casting to BigInt just in case if ba2int returns a Number + let x = BigInt(ba2int(x_)); + const y = BigInt(ba2int(y_)); + let res = 0n; + for (let i=127n; i >= 0n; i--){ + res ^= x * ((y >> i) & 1n); + x = (x >> 1n) ^ ((x & 1n) * BigInt(0xE1000000000000000000000000000000)); + } + return int2ba(res, 16); +} + +// x is Uint8Array +export function getXTable(x_){ + let x = ba2int(x_); + const table = []; + for (let i=0; i < 128; i++){ + table[i] = int2ba(x, 16); + x = (x >> 1n) ^ ((x & 1n) * BigInt(0xE1000000000000000000000000000000)); + } + return table; +} + + +// convert Uint8Array into an array of 0/1 where least bit has index 0 +export function bytesToBits (ba){ + assert(ba instanceof Uint8Array); + const bitArr = Array(ba.length*8); + let idx = 0; + for (let i=ba.length-1; i >= 0; i--){ + for (let j=0; j < 8; j++){ + bitArr[idx] = (ba[i] >> j) & 0x01; + idx++; + } + } + return bitArr; +} + +// convert an array of 0/1 (with least bit at index 0) to Uint8Array +export function bitsToBytes(arr){ + assert(arr.length % 8 === 0); + const ba = new Uint8Array(arr.length/8); + for (let i=0; i < ba.length; i++){ + let sum = 0; + for (let j=0; j < 8; j++){ + sum += arr[i*8+j] * (2**j); + } + ba[ba.length-1-i] = sum; + } + return ba; +} + + +// convert OpenSSL's signature format (asn1 DER) into WebCrypto's IEEE P1363 format +export function sigDER2p1363(sigDER){ + var o = 0; + assert(eq(sigDER.slice(o,o+=1), [0x30])); + var total_len = ba2int(sigDER.slice(o,o+=1)); + assert(sigDER.length == total_len+2); + assert(eq(sigDER.slice(o,o+=1), [0x02])); + var r_len = ba2int(sigDER.slice(o,o+=1)); + assert(r_len === 32 || r_len === 33); + var r = sigDER.slice(o,o+=r_len); + assert(eq(sigDER.slice(o,o+=1), [0x02])); + var s_len = ba2int(sigDER.slice(o,o+=1)); + assert(s_len >= 31 && s_len <= 33); + var s = sigDER.slice(o,o+=s_len); + if (s.length === 31){ + s = concatTA(new Uint8Array([0x00]), s); + } + if (r_len === 33){ + assert(eq(r.slice(0,1), [0x00])); + r = r.slice(1); + } + if (s_len == 33){ + assert(eq(s.slice(0,1), [0x00])); + s = s.slice(1); + } + var sig_p1363 = concatTA(r,s); + return sig_p1363; +} + + +// we can import chrome:// and file:// URL +export async function import_resource(filename) { + var path = chrome.extension.getURL(filename); + var resp = await fetch(path); + var data = await resp.text(); + return data; +} + +// take PEM EC pubkey and output a "raw" pubkey with all asn1 data stripped +export function pubkeyPEM2raw(pkPEM){ + // prepended asn1 data for ECpubkey prime256v1 + const preasn1 = [0x30, 0x59, 0x30, 0x13, 0x06, 0x07, 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x02, 0x01, 0x06,0x08, 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x03, 0x01, 0x07, 0x03, 0x42, 0x00]; + const pk = pem2ba(pkPEM); + assert(eq(pk.slice(0, preasn1.length), preasn1)); + return pk.slice(preasn1.length); +} + + + +function bin2hex(bin) { + const table2 = { + '0000': '0', '0001': '1', '0010': '2', '0011': '3', + '0100': '4', '0101': '5', '0110': '6', '0111': '7', + '1000': '8', '1001': '9', '1010': 'A', '1011': 'B', + '1100': 'C', '1101': 'D', '1110': 'E', '1111': 'F' + }; + + let hex = ''; + bin = (new Array((4-(bin.length%4))%4)).fill('0').join('') + bin; + for (let i = 0; i < bin.length; i+=4) { + hex += table2[bin.substr(i, 4)]; + } + return hex; +} + +// states are Int32Array just lke fastsha expects +// msg and output are byte arrays +export function finishHMAC(innerState, outerState, msg) { + const ihasher = new fastsha256.Hash(); + const ohasher = new fastsha256.Hash(); + ihasher._restoreState(innerState, 64); + ihasher.update(msg); + const iHash = ihasher.digest(); + ohasher._restoreState(outerState, 64); + ohasher.update(iHash); + return ohasher.digest(); +} + +// state is Int32Array just lke fastsha expects +// msg and output are byte arrays +export function innerHash(innerState, msg) { + assert (innerState instanceof Int32Array); + assert (msg instanceof Uint8Array); + + const ihasher = new fastsha256.Hash(); + ihasher._restoreState(innerState, 64); + ihasher.update(msg); + return ihasher.digest(); +} + +export function encrypt_generic(plaintext, key, nonce) { + const ro = randomOracle(key, nonce); + const tmp = xor(plaintext, key); + return xor(tmp, ro); +} + +const byteArray = new Uint8Array(24); +const sha0 = hex2ba('da5698be17b9b46962335799779fbeca8ce5d491c0d26243bafef9ea1837a9d8'); + +// class PRF is initialized once and then it is a read-only + +export function longToByteArray(long) { + // we want to represent the input as a 24-bytes array + for (let index = 0; index < byteArray.length; index++) { + const byte = long & 0xff; + byteArray[index] = byte; + long = (long - byte) / 256; + } + return byteArray; +} + + +export function randomOracle(m, t) { + const nonce = longToByteArray(t); + return nacl.secretbox( + m, + nonce, // Nonce 24 bytes because this sodium uses 192 bit blocks. + sha0, + ).slice(0,16); +} + +export const decrypt_generic = encrypt_generic; + +export async function wait(timeout) { + return await new Promise((resolve) => { + setTimeout(function(){ + resolve('wait'); + }, timeout); + }); +} + +export const fetchTimeout = (url, ms, { signal, ...options } = {}) => { + const controller = new AbortController(); + const promise = fetch(url, { signal: controller.signal, ...options }); + if (signal) signal.addEventListener('abort', () => controller.abort()); + const timeout = setTimeout(() => controller.abort(), ms); + return promise.finally(() => clearTimeout(timeout)); +}; + +// concatTA concatenates typed arrays of type Uint8Array +export function concatTA(...arr){ + let newLen = 0; + for (const item of arr){ + assert(item instanceof Uint8Array); + newLen += item.length; + } + const newArray = new Uint8Array(newLen); + let offset = 0; + for (const item of arr){ + newArray.set(item, offset); + offset += item.length; + } + return newArray; +} + +async function gcmEncrypt(key, plaintext, IV, aad){ + const cryptoKey = await crypto.subtle.importKey( + 'raw', + key.buffer, + 'AES-GCM', + true, + ['encrypt', 'decrypt']); + + const ciphertext = await crypto.subtle.encrypt({ + name: 'AES-GCM', + iv: IV.buffer, + additionalData: aad.buffer}, + cryptoKey, + plaintext.buffer, + ); + + const counter = concatTA(IV, int2ba(2, 4)); + const encCounter = await AESECBencrypt(key, counter); + const ct = xor(encCounter, plaintext); + + const gctrCounter = concatTA(IV, int2ba(1, 4)); + const gctrBlock = await AESECBencrypt(key, gctrCounter); + + const H = ba2int(await AESECBencrypt(key, int2ba(0, 16))); + const H2 = times_auth_key(H, H); + const H3 = times_auth_key(H2, H); + + const lenAlenC = new Uint8Array([0, 0, 0, 0, 0, 0, 0, 128, 0, 0, 0, 0, 0, 0, 0, 128]); + + const s1 = int2ba(times_auth_key(ba2int(aad), H3), 16); + const s2 = int2ba(times_auth_key(ba2int(ct), H2), 16); + const s3 = int2ba(times_auth_key(ba2int(lenAlenC), H), 16); + const tag = xor(xor(xor(s1, s2), s3), gctrBlock); + + const H1a = ba2int(getRandom(16)); + const H1b = H ^ H1a; + + const H2a = times_auth_key(H1a, H1a); + const H2b = times_auth_key(H1b, H1b); + + const X1 = ba2int(aad); + const X2 = ba2int(ct); + const X3 = ba2int(lenAlenC); + + const H3X1 = times_auth_key(times_auth_key(H2a, H1a), X1) ^ + times_auth_key(times_auth_key(H2a, H1b), X1) ^ + times_auth_key(times_auth_key(H2b, H1a), X1) ^ + times_auth_key(times_auth_key(H2b, H1b), X1); + + const res = times_auth_key(X3, H1a) ^ times_auth_key(X3, H1b) ^ + times_auth_key(X2, H2a) ^ times_auth_key(X2, H2b) ^ + H3X1 ^ ba2int(gctrBlock); +} + +// WebCrypto doesn't provide AES-ECB encryption. We achieve it by using +// the CTR mode and setting CTR's counter to what we want to AES-encrypt and setting CTR's +// data to encrypt to zero, because in CTR ciphertext = AES(counter) XOR plaintext +// +export async function AESECBencrypt(key, data){ + const cryptoKey = await crypto.subtle.importKey( + 'raw', + key.buffer, + 'AES-CTR', + true, + ['encrypt', 'decrypt']); + + const zeroes = int2ba(0, 16); + return new Uint8Array (await crypto.subtle.encrypt({ + name: 'AES-CTR', + counter: data.buffer, length: 16}, + cryptoKey, + zeroes.buffer)); +} + +function bestPathNew(num){ + const mainPowers = []; + const auxPowers = []; // aux powers + const auxIncrements = []; // by how much we increment main powers + for (let i=0; i<10; i++){ + mainPowers.push(2**i); + } + mainPowers.sort(function(a, b){return a-b;}); + const primes = [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]; + let paths = []; + paths.push([mainPowers, auxPowers, auxIncrements]); + for (let i=3; i < num; i++){ + // take each path and see if sum is found. discard paths where it was not found + const emptyIndexes = []; + for (let pathIdx=0; pathIdx < paths.length; pathIdx++ ){ + const mainPowers = paths[pathIdx][0]; + const auxPowers = paths[pathIdx][1]; + if (! isSumFound(mainPowers, auxPowers, i)){ + emptyIndexes.push(pathIdx); + } + } + if (paths.length !== emptyIndexes.length){ + // discard paths where no sums were found (if any) + // TODO: do we want to discard, or maybe to add primes? + for (let i=0; i < emptyIndexes.length; i++){ + // console.log('discarding path with index ', i) + paths.splice(i,1); + } + } + else { // sum was not found in any path + const newPaths = []; + // add the next prime to main powers and check if sum is found + for (let pathIdx=0; pathIdx < paths.length; pathIdx++ ){ + const mainPowers = paths[pathIdx][0]; + const auxPowers = paths[pathIdx][1]; + const auxIncrements = paths[pathIdx][2]; + + for (let p=0; p < primes.length; p++){ + const prime = primes[p]; + if (mainPowers.includes(prime)){ + continue; + } + const mainPowersCopy = [].concat(mainPowers, allPrimeMultiples(prime)); + mainPowersCopy.sort(function(a, b){return a-b;}); + const auxPowersCopy = incrementPowers(mainPowersCopy, auxIncrements); + + // check if after adding, this path became a duplicate of another path + if (isDuplicatePath([mainPowersCopy, auxPowersCopy], paths)){ + continue; + } + if (! isSumFound(mainPowersCopy, auxPowersCopy, i)){ + continue; + } + newPaths.push([mainPowersCopy, auxPowers, auxIncrements]); + } + + // add new numbers to auxPowers + // this can be any number - prime or non-prime that is already + // available in mainPowers + for (let p=0; p < mainPowers.length; p++){ + const num = mainPowers[p]; + if (auxPowers.includes(num)){ + // power already present in auxPowers + continue; + } + if (num > i){ + // adding number larger than the power we need makes no sense + continue; + } + const auxIncrementsCopy = [].concat(auxIncrements, [num]); + auxIncrementsCopy.sort(function(a, b){return a-b;}); + const auxPowersCopy = incrementPowers(mainPowers, auxIncrementsCopy); + // check if after adding, this path became a duplicate of another path + if (isDuplicatePath([mainPowers, auxPowersCopy], paths)){ + continue; + } + if (! isSumFound(mainPowers, auxPowersCopy, i)){ + continue; + } + newPaths.push([mainPowers, auxPowersCopy, auxIncrementsCopy]); + } + } + paths = newPaths; + } + } + const onlyPrimes = []; + for (let i=0; i < paths.length; i++){ + const mPrimes = []; + const mp = paths[i][0]; + const increments = paths[i][2]; + for (let j=0; j< primes.length; j++){ + if (mp.includes(primes[j])){ + mPrimes.push(primes[j]); + } + } + onlyPrimes.push([mPrimes, increments]); + console.log(mPrimes, increments); + } + + return onlyPrimes; +} + +function bestPathNewer(num){ + let mainPowers = []; + const auxIncrements = [1]; // by how much we increment main powers + for (let i=0; i<10; i++){ + mainPowers.push(2**i); + } + // mainPowers = [].concat(mainPowers, allPrimeMultiples(7)) + // mainPowers = [].concat(mainPowers, allPrimeMultiples(15)) + // mainPowers = [].concat(mainPowers, allPrimeMultiples(17)) + + mainPowers.sort(function(a, b){return a-b;}); + const auxPowers = incrementPowers(mainPowers, auxIncrements); + + let paths = []; + paths.push([mainPowers, auxPowers, auxIncrements, true, 0]); + for (let i=3; i <= num; i++){ + // if there are too many paths, we will hang the machine + // keep random 1000 paths + // const sampleSize = 100 + // if (paths.length > sampleSize){ + // for (let i=0; i < paths.length-sampleSize; i++){ + // const randIdx = Math.ceil(Math.random()*paths.length) + // paths.splice(randIdx, 1) + // } + // } + + // take each path and see if sum is found. + // if found at least in one path, advance to the next number + let foundAtLeastOnce = false; + for (let pathIdx=0; pathIdx < paths.length; pathIdx++ ){ + const mainPowers = paths[pathIdx][0]; + const auxPowers = paths[pathIdx][1]; + const wasPrevFound = paths[pathIdx][3]; + if (! wasPrevFound){ + continue; + } + const sumFound = isSumFound(mainPowers, auxPowers, i); + if (sumFound){ + paths[pathIdx][3] = true; // set wasFound flag + foundAtLeastOnce = true; + } + else { + paths[pathIdx][3] = false; // set wasFound flag + paths[pathIdx][4] = i; // keep index on which it was not found + } + } + if (foundAtLeastOnce){ + // continue to the next number + continue; + } + // if not found in any path + const newPaths = []; + // add the next num to main powers and check if sum is found + for (let pathIdx=0; pathIdx < paths.length; pathIdx++ ){ + const mainPowers = paths[pathIdx][0]; + const auxIncrements = paths[pathIdx][2]; + + for (let p=0; p <= i; p++){ + if (p%2 === 0 || mainPowers.includes(p)){ + // only odd numbers that we haven't had + continue; + } + const mainPowersCopy = [].concat(mainPowers, allPrimeMultiples(p)); + mainPowersCopy.sort(function(a, b){return a-b;}); + const auxPowers = incrementPowers(mainPowersCopy, auxIncrements); + auxPowers.sort(function(a, b){return a-b;}); + + // check if after adding, this path became a duplicate of another path + if (isDuplicatePath([mainPowersCopy, auxPowers], paths)){ + continue; + } + if (! isSumFound(mainPowersCopy, auxPowers, i)){ + continue; + } + // also need to check any possible previous indexes which we may have skipped + const notFoundOn = paths[pathIdx][4]; + if (notFoundOn > 0 || notFoundOn !== i){ + let sawNoSum = false; + for (let k=notFoundOn; k < i-notFoundOn; k++){ + if (! isSumFound(mainPowersCopy, auxPowers, k)){ + sawNoSum = true; + break; + } + } + if (sawNoSum){ + continue; + } + } + newPaths.push([mainPowersCopy, auxPowers, auxIncrements, true, 0] ); + } + } + paths = newPaths; + } + + const numFreq = {}; + let minLen = paths[0][0].length; + for (let i=0; i < paths.length; i++){ + if (paths[i][3] !== true){ + continue; + } + const nums = []; + // if (paths[i][0].length < minLen){ + // minLen = paths[i][0].length + // } + // if (paths[i][0].length > minLen){ + // continue + // } + for (let j=0; j < paths[i][0].length; j ++){ + const next = paths[i][0][j]; + if (next % 2 === 0 || next === 1){ + continue; + } + nums.push(next); + if (next in numFreq){ + numFreq[next] += 1; + } + else { + numFreq[next] = 1; + } + } + console.log(nums.sort(function(a, b){return a-b;})); + } + console.log(numFreq); +} + +function findMax(powers){ + let mainPowers = []; + for (let i=0; i<10; i++){ + mainPowers.push(2**i); + } + for (let p=0; p < powers.length; p++){ + mainPowers = [].concat(mainPowers, allPrimeMultiples(powers[p])); + } + mainPowers.sort(function(a, b){return a-b;}); + + function isFound(main, aux, num){ + if (main.includes(num)){ + return true; + } + for (let k=0; k time || time > ba2int(validUntil)){ + return false; + } + return true; +} + +// computes AES GCM authentication tag +// all 4 inputs arrays of bytes +// aad: additional_data, ct: ciphertext +// encZero = E(0) +// encIV = E( IV(4bytes) + nonce(8bytes) + 1 (4 bytes) ) +// return byte array of 16 bytes +function getAuthTag(aad, ct, encZero, encIV, precompute){ + if (precompute == undefined){ + // precompute takes ~400ms + // only in cases of a lot of data it may be worth precomputing + precompute = false; + } + + let aadPadBytes = aad.length%16 == 0 ? new Uint8Array() : int2ba(0, 16 - (aad.length%16)); + let ctPadBytes = ct.length%16 == 0 ? new Uint8Array() : int2ba(0, 16 - (ct.length%16)); + let lenAlenC = concatTA(int2ba(aad.length*8, 8), int2ba(ct.length*8, 8)); + let inputs = concatTA(aad, aadPadBytes, ct, ctPadBytes, lenAlenC); + + let table; + if (precompute){ + table = preComputeTable(encZero); + } + let S = 0n; + let enczBI = ba2int(encZero); + for(let i=0; i < inputs.length/16; i++){ + const X = ba2int(inputs.slice(i*16, i*16+16)); + if (precompute){ + S = times_auth_key(X ^ S, table); + } + else { + S = times_auth_key2(X ^ S, enczBI); + } + + } + let ret = (S ^ ba2int(encIV)); + return int2ba(ret); + + + function times_auth_key(val, table){ + let res = 0n; + for (let i=0n; i < 16n; i++){ + res ^= table[i][val & BigInt(0xFF)]; + val >>= 8n; + } + return res; + } + + function times_auth_key2(val, encZero){ + let res = 0n; + for (let i=0n; i < 16n; i++){ + let j = val & BigInt(0xFF); + res ^= gf_2_128_mul(encZero, j << (8n*i)); + val >>= 8n; + } + return res; + } +} + + +if (typeof module !== 'undefined'){ // we are in node.js environment + module.exports={ + assert, + ba2ab, + ba2bigint, + ba2str, + bi2ba, + ab2ba, + ba2int, + buildChunkMetadata, + b64encode, + b64decode, + b64urlencode, + dechunk_http, + gunzip_http, + eq, + getTime, + pem2ba, + pubkeyPEM2raw, + sha256, + sigDER2p1363, + str2ba, + xor + }; +} \ No newline at end of file diff --git a/core/verifychain.js b/core/verifychain.js new file mode 100644 index 0000000..08ca181 --- /dev/null +++ b/core/verifychain.js @@ -0,0 +1,178 @@ +import {pem2ba, eq, import_resource} from './utils.js'; +import * as asn1js from './third-party/pkijs/asn1.js'; +import Certificate from './third-party/pkijs/Certificate.js'; +import CertificateChainValidationEngine from './third-party/pkijs/CertificateChainValidationEngine.js'; + + +var trustedCertificates = []; + + +// extract PEMs from Mozilla's CA store and convert into asn1js's Certificate object +export async function parse_certs(){ + // wait for pkijs module to load + while (typeof(asn1js) == 'undefined'){ + console.log('waiting for pkijs'); + await new Promise(function(resolve) { + setTimeout(function(){ + resolve(); + }, 100); + }); + } + + const text = await import_resource('core/third-party/certs.txt'); + const lines = text.split('"\n"').slice(1); // discard the first line - headers + for (const line of lines){ + const fields = line.split('","'); + const pem = fields[32].slice(1,-1); + const asn1cert = asn1js.fromBER(pem2ba(pem).buffer); + trustedCertificates.push(new Certificate({ schema: asn1cert.result })); + } +} + + +function getPubkey(c){ + return new Uint8Array(c.subjectPublicKeyInfo.subjectPublicKey.valueBlock.valueHex); +} + + +// Verify that the common name in the Certificate is the name of the server we are sending to +// Otherwise an attacker can send us his CA-issued certificate for evildomain.com +export function checkCertSubjName(cert, serverName){ + let commonName = getCommonName(cert); + let alternativeNames = getAltNames(cert); + let allNames = alternativeNames; + allNames.push(commonName); + + // test a string against a string with a wildcard + function wildTest(wildcardStr, str) { + var index = wildcardStr.indexOf('*'); + if (index > -1){ + // if wildcard has an asterisk then we match from the end up to the asterisk + var substringAfterAsterisk = wildcardStr.slice(index+1); + return str.endsWith(substringAfterAsterisk); + } + else{ + // if it doesnt contain an asterisk then wildcard must be equal to str + return (wildcardStr == str); + } + } + + for (let nameInCert of allNames){ + if (wildTest(nameInCert, serverName) == true) + return true; + } + throw 'Server name is not the same as the certificate\'s subject name(s)'; +} + + +export function getCommonName(cert) { + for (let type of cert.subject.typesAndValues){ + if (type.type == '2.5.4.3') { + return type.value.valueBlock.value; + } + } +} + + +export function getAltNames(cert) { + let altNames = []; + if (cert.extensions){ + for (let ext of cert.extensions){ + if (ext.extnID != '2.5.29.17') continue; + for (let name of ext.parsedValue.altNames){ + altNames.push(name.value); + } + } + } + return altNames; +} + + + + +// verifyChain verifies a certificate chain "chain_der" against the time "date". If "date" is not +// given, verifies againt the current time. +// Returns true on success or throws if verification failed. +// Sometimes servers do not put intermediate certs into the chain. In such case we +// fetch the missing cert from a URL embedded in the leaf cert. We return the fetched cert. +export async function verifyChain(chain_der, date, trustedCerts) { + if (trustedCerts == undefined){ + trustedCerts = trustedCertificates; + } + if (chain_der.length > 7){ + // prevent DOS from having to parse large chains + throw ('Error: cannot parse an unusually large certificate chain.'); + } + // convert each der certificate into a Certificate object + const chain = []; + for (const cert_der of chain_der){ + const cert_asn1 = asn1js.fromBER(cert_der.buffer); + const cert = new Certificate({ schema: cert_asn1.result }); + chain.push(cert); + } + + + async function do_verify(chain, date, trustedCerts){ + // CertificateChainValidationEngine will fail the verification if the root cert is + // included in the chain. To prevent this, we remove the root CA from the chain. + // Check by pubkey if the last cert is a root CA known to us. + + var pubkeyToFind = new Uint8Array(chain.slice(-1)[0].subjectPublicKeyInfo.subjectPublicKey.valueBlock.valueHex); + for (let cert of trustedCerts){ + if (eq(new Uint8Array(cert.subjectPublicKeyInfo.subjectPublicKey.valueBlock.valueHex), pubkeyToFind)){ + chain = chain.slice(0,-1); + break; + } + } + + // pkijs requires that the leaf cert is last in the array + // if not, the verification will still succeed, but the returned certificatePath + // will be incomplete + var leafCert = chain.splice(0,1)[0]; + chain.push(leafCert); + const ccve = new CertificateChainValidationEngine({ + trustedCerts: trustedCerts, + certs: chain, + checkDate: date ? date : new Date() + }); + let rv = await ccve.verify(); + return rv; + } + + let rv = await do_verify(chain, date, trustedCerts); + if (chain.length == 1 && rv.result == false && chain[0].extensions != undefined){ + for (let ext of chain[0].extensions){ + if (ext.extnID != '1.3.6.1.5.5.7.1.1') continue; + for (let ad of ext.parsedValue.accessDescriptions){ + if (ad.accessMethod != '1.3.6.1.5.5.7.48.2') continue; + let cert_url = ad.accessLocation.value; + let resp = await fetch(cert_url, { + method: 'POST', + mode: 'cors', + cache: 'no-store', + }); + let blob = await resp.blob(); + let certDER = await blob.arrayBuffer(); + let cert_asn1 = asn1js.fromBER(certDER); + let cert = new Certificate({ schema: cert_asn1.result }); + chain.push(cert); + rv = await do_verify(chain); + } + } + } + if (rv.result == false){ + throw ('Could not notarize because the website presented an untrusted certificate'); + } + return rv; +} + + +if (typeof module !== 'undefined'){ // we are in node.js environment + module.exports={ + checkCertSubjName, + getCommonName, + getModulus, + parse_certs, + verifyChain + }; +} \ No newline at end of file diff --git a/manifest.json b/manifest.json index e5478ae..74ab435 100644 --- a/manifest.json +++ b/manifest.json @@ -3,26 +3,27 @@ "name": "PageSigner", "description": "PageSigner - a cryptographically secure webpage screenshot tool", - "version": "2.1.0.1", + "version": "3.0", "author": "TLSNotary Group", "permissions": [ "webRequest", - "activeTab" + "activeTab", + "https://tlsnotary.org/backup_oracle" ], - "icons": { - "64": "icon.png" + "64": "ui/img/icon64.png" }, "browser_action": { - "default_icon": "webextension/content/icon.png", - "default_popup": "webextension/content/popup.html" + "default_icon": "ui/img/icon.png", + "default_popup": "ui/html/popup.html" }, "background": { - "page": "webextension/content/background.html" - } + "page": "background.html" + }, + "content_security_policy": "script-src 'self' 'unsafe-eval' 'wasm-eval'; object-src 'self'" } diff --git a/pagesigner.py b/pagesigner.py new file mode 100644 index 0000000..35973e4 --- /dev/null +++ b/pagesigner.py @@ -0,0 +1,60 @@ +import socket, threading, json, base64, time, datetime +connections = {} #uid:{buffer:, socketId:} +httpRespStr = 'HTTP/1.0 200 OK\r\nAccess-Control-Allow-Origin: *\r\n\r\n' + +def handler(sock): + raw = sock.recv(10000) + payload = raw.decode().split('\r\n\r\n')[1] + if len(payload) == 0: #Maybe HTTP POST body arrived late. Trying again + raw += sock.recv(10000) + payload = raw.decode().split('\r\n\r\n')[1] + j = json.loads(payload) + + if j['command'] == 'connect': + if j['args']['port'] == -1: + sock.send((httpRespStr + json.dumps({'retval':'active'})).encode()) + sock.close() + return + clientSock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + clientSock.settimeout(None) + clientSock.connect((j['args']['name'], j['args']['port'])) + print( datetime.datetime.now().strftime("%H:%M:%S"), ' connected to ',j['args']['name']) + connections[j['uid']] = {'buffer':b'', 'socket': clientSock} + sock.send((httpRespStr + json.dumps({'retval':'success'})).encode()) + sock.close() + while True: + data = clientSock.recv(1000000) + if len(data) == 0: + break #the blocking socket returns 0 when it was closed + connections[j['uid']]['buffer'] += data + + if j['command'] == 'send': + clientSock = connections[j['uid']]['socket'] + clientSock.send(base64.b64decode(j['args']['data'])) + #if we don't send a response back then there will be an error on the console + sock.send((httpRespStr).encode()) + sock.close() + + if j['command'] == 'close': + connections[j['uid']]['socket'].close() + del connections[j['uid']] + sock.send((httpRespStr).encode()) + sock.close() + + if j['command'] == 'recv': + tmp = connections[j['uid']]['buffer'] + connections[j['uid']]['buffer'] = b'' + sock.send((httpRespStr + json.dumps({'data':base64.b64encode(tmp).decode()})).encode()) + sock.close() + +sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) +sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) +sock.bind(('0.0.0.0', 20022)) +sock.listen(100) #as many as possible +print("PageSigner helper app is running. You can now perform notarizations in your browser. This window must remain open.") +while True: + try: + connection, client_address = sock.accept() + threading.Thread(target=handler, args=(connection,)).start() + except Exception as e: + print('Exception caught', e) \ No newline at end of file diff --git a/ui/FileChooser.js b/ui/FileChooser.js new file mode 100644 index 0000000..a219e68 --- /dev/null +++ b/ui/FileChooser.js @@ -0,0 +1,35 @@ +// FileChooser create a "choose file" button and sends the chosen file +// to the extension + +export class FileChooser{ + // show is called by extension's Main.openFileChooser() + show(){ + const label = document.getElementById('import_label'); + label.style.display = ''; + const that = this; + document.getElementById('import').addEventListener('change', function(evt) { + const f = evt.target.files[0]; + if (f) { + const reader = new FileReader(); + reader.onload = that.onload; + reader.readAsArrayBuffer(f); + } + }); + } + + onload(e) { + const loader = document.getElementById('loader'); + loader.classList.toggle('m-fadeIn'); + loader.removeAttribute('hidden'); + const import_label = document.getElementById('import_label'); + import_label.classList.toggle('m-fadeOut'); + chrome.runtime.sendMessage({ + 'destination': 'extension', + 'message': 'import', + 'args': { + 'data': Array.from(new Uint8Array(e.target.result)) + } + }); + // don't close the window, we reuse it to display html + } +} \ No newline at end of file diff --git a/ui/Manager.js b/ui/Manager.js new file mode 100644 index 0000000..57a93ee --- /dev/null +++ b/ui/Manager.js @@ -0,0 +1,279 @@ +import {str2ba} from './utils.js'; + +document.addEventListener('load', onload); +window.addEventListener('load', onload); + +class Manager{ + constructor(){ + window.tabid = null; + window.isManager = true; + // isReady will be se to true after message listener is installed + window.isReady = false; + + } + + main() { + const that = this; + chrome.runtime.onMessage.addListener(function(data) { + if (data.destination != 'manager') return; + if (data.command == 'payload'){ + console.log('data.payload', data.payload); + that.processData(data.payload); + } + else if (data.command == 'export'){ + // .payload contains {pgsg: json, name: session_name} + const exportedBlobUrl = URL.createObjectURL(new Blob([str2ba(data.payload.pgsg)]), { + type: 'application/octet-stream' + }); + var fauxLink = document.createElement('a'); + fauxLink.href = exportedBlobUrl; + fauxLink.setAttribute('download', data.payload.name+'.pgsg'); + document.body.appendChild(fauxLink); + fauxLink.click(); + } + }); + window.isReady = true; + chrome.runtime.sendMessage({ + 'destination': 'extension', + 'message': 'refresh' + }); + } + + processData(rows) { + const tb = document.getElementsByTagName('tbody')[0]; + const initial_row_length = tb.rows.length; + for (let j = 0; j < initial_row_length; j++) { + tb.deleteRow(0); + } + // create descending sort order based on creation time + rows.sort(function(a, b) { + return Date.parse(a.creationTime) < Date.parse(b.creationTime) ? 1 : -1; + }); + + for (const r of rows) { + this.addRow({ + 'sessionName': r.sessionName, + 'serverName': r.serverName, + 'isImported': r.isImported, + 'isEdited': r.isEdited, + 'creationTime': r.creationTime, + 'version': r.version + }); + } + } + + + addRow(args) { + const that = this; + const session = args.creationTime; + const tb = document.getElementById('tableBody'); + const row = tb.insertRow(tb.rows.length); + + const td_session = document.createElement('td'); + if (args.isImported){ + const importedIcon = document.createElement('img'); + importedIcon.src = '../img/import.svg'; + importedIcon.width = 16; + importedIcon.height = 16; + importedIcon.style.marginLeft = 5; + importedIcon.style.marginRight = 5; + importedIcon.title = 'This notarization session was imported'; + td_session.appendChild(importedIcon); + } + if (args.isEdited){ + const editedIcon = document.createElement('img'); + editedIcon.src = '../img/edited.svg'; + editedIcon.width = 16; + editedIcon.height = 16; + editedIcon.style.marginLeft = 5; + editedIcon.style.marginRight = 5; + editedIcon.title = 'This notarization session was edited'; + td_session.appendChild(editedIcon); + } + td_session.appendChild(document.createTextNode(args.sessionName)); + + const iconDiv = document.createElement('div'); + + const imgExp = document.createElement('img'); + imgExp.classList.add('icon'); + imgExp.src = '../img/export.svg'; + imgExp.width = 20; + imgExp.height = 20; + imgExp.style.marginLeft = 10; + imgExp.title = 'Export the session so you can transfer it to others'; + imgExp.onclick = function(event) { + console.log('export clicked'); + swal({ + title: 'You MUST LOG OUT before exporting', + text: 'Before exporting you MUST LOG OUT of any sessions associated with the data you are about to export. Please LOG OUT NOW if you have any active sessions running and press OK to proceed', + type: 'warning' + }, + function() { + chrome.runtime.sendMessage({ + 'destination': 'extension', + 'message': 'export', + 'args': { + 'dir': session + } + }); + }); + }; + imgExp.value = 'Export'; + iconDiv.appendChild(imgExp); + + const imgRen = document.createElement('img'); + imgRen.classList.add('icon'); + imgRen.src = '../img/rename.svg'; + imgRen.width = 20; + imgRen.height = 20; + imgRen.style.marginLeft = 10; + imgRen.title = 'Give the session a more memorable name'; + imgRen.onclick = function(event) { + that.doRename(event.target, session); + }; + iconDiv.appendChild(imgRen); + + const imgDel = document.createElement('img'); + imgDel.classList.add('icon'); + imgDel.src = '../img/delete.svg'; + imgDel.width = 20; + imgDel.height = 20; + imgDel.style.marginLeft = 10; + imgDel.title = 'Permanently remove this session from disk'; + imgDel.onclick = function() { + swal({ + title: 'Removing notarization data', + text: 'This will remove the selected session: ' + args.sessionName + '. Are you sure?', + type: 'warning' + }, + function() { + chrome.runtime.sendMessage({ + 'destination': 'extension', + 'message': 'delete', + 'args': { + 'dir': session + } + }); + }); + }; + imgDel.value = 'Delete'; + iconDiv.appendChild(imgDel); + + iconDiv.style.position = 'absolute'; + iconDiv.style.top = 2; + iconDiv.style.right = 4; + + td_session.style.position = 'relative'; + td_session.appendChild(iconDiv); + row.appendChild(td_session); + + const td_time = document.createElement('td'); + td_time.style.textAlign = 'center'; + td_time.textContent = args.creationTime; + row.appendChild(td_time); + + const buttonDiv = document.createElement('div'); + + const input1 = document.createElement('input'); + input1.type = 'button'; + input1.className = 'btn'; + input1.onclick = function() { + chrome.runtime.sendMessage({ + 'destination': 'extension', + 'message': 'viewdata', + 'args': { + 'dir': session + } + }); + }; + input1.value = 'HTML'; + buttonDiv.appendChild(input1); + + const input2 = document.createElement('input'); + input2.type = 'button'; + input2.className = 'btn'; + input2.onclick = function() { + chrome.runtime.sendMessage({ + 'destination': 'extension', + 'message': 'viewraw', + 'args': { + 'dir': session + } + }); + }; + input2.value = 'Details'; + buttonDiv.appendChild(input2); + + const input3 = document.createElement('input'); + input3.type = 'button'; + input3.className = 'btn'; + input3.onclick = function() { + chrome.runtime.sendMessage({ + 'destination': 'extension', + 'message': 'raw editor', + 'args': { + 'dir': session + } + }); + }; + input3.value = 'Edit'; + // Edit button will be used in fututre versions + input3.style.visibility = "hidden"; + if (args.isImported || args.isEdited || (args.version < 5)){ + input3.style.opacity = '0.3'; + input3.onclick = null; + input3.title='You cannot edit sessions which were already edited or which were imported.'; + if (args.version < 5){ + input3.title='This session has an old version which cannot be edited'; + } + } + buttonDiv.appendChild(input3); + + const td3 = document.createElement('td'); + td3.style.textAlign = 'center'; + td3.appendChild(buttonDiv); + row.appendChild(td3); + } + + doRename(t, dir) { + var isValid = (function() { + var rg1 = /^[^\\/:\*\?"<>\|]+$/; // forbidden characters \ / : * ? " < > | + var rg2 = /^\./; // cannot start with dot (.) + var rg3 = /^(nul|prn|con|lpt[0-9]|com[0-9])(\.|$)/i; // forbidden file names + return function isValid(fname) { + if (typeof(fname) !== 'string') return false; + return rg1.test(fname) && !rg2.test(fname) && !rg3.test(fname); + }; + })(); + swal({ + title: 'Enter a new name for the notarization file', + type: 'input', + inputPlaceholder: 'e.g. my profile' + }, + function(new_name) { + if (!(isValid(new_name))) { + console.log('detected invalid name', new_name); + // swal glitch - need a timeout + setTimeout(function() { + swal({ + title: 'Invalid filename', + text: 'Please only use alphanumerical characters', + type: 'warning' + }); + }, 200); + } else if (new_name === null) return; // escape pressed + else { + chrome.runtime.sendMessage({ + 'destination': 'extension', + 'message': 'rename', + 'args': { + 'dir': dir, + 'newname': new_name + } + }); + } + }); + } +} + +new Manager().main(); diff --git a/ui/NotificationBar.js b/ui/NotificationBar.js new file mode 100644 index 0000000..4b5b374 --- /dev/null +++ b/ui/NotificationBar.js @@ -0,0 +1,76 @@ +export class NotificationBar{ + constructor(){} + + show(sessionId, serverName, hideButton) { + hideButton = hideButton || false; + + const table = document.createElement('table'); + table.style.position = 'fixed'; + table.style.top = '0px'; + table.style.left = '100px'; + table.style.background = 'rgba(242, 241, 240, 0.9)'; + table.style.width = '80%'; + table.style.height = '32px'; + table.style.visibility = 'hidden'; + table.style.opacity = '0'; + table.style.transition = 'visibility 0s 2s, opacity 2s linear'; + const row = document.createElement('tr'); + + const cell1 = document.createElement('td'); + const cell2 = document.createElement('td'); + const cell3 = document.createElement('td'); + const cell4 = document.createElement('td'); + + cell3.style.align = 'right'; + cell4.style.align = 'right'; + const img = document.createElement('img'); + img.src = '../img/icon.svg'; + img.height = 24; + img.width = 24; + const text = document.createElement('text'); + text.textContent = 'PageSigner verified that this page was received from '; + const domain = document.createElement('text'); + domain.id = 'domainName'; + domain.textContent = serverName; + const button = document.createElement('button'); + button.id = 'viewRaw'; + button.textContent = 'Details'; + button.style.MozBorderRadius = '4px'; + button.style.WebkitBorderRadius = '4px'; + button.style.borderRadius = '4px'; + button.onclick = function() { + chrome.runtime.sendMessage({ + destination: 'extension', + message: 'viewraw', + args: { + dir: sessionId + } + }); + }; + if (hideButton) { + button.hidden = true; + } + + cell3.appendChild(button); + cell2.appendChild(text); + cell2.appendChild(domain); + cell1.appendChild(img); + row.appendChild(cell1); + row.appendChild(cell2); + row.appendChild(cell3); + row.appendChild(cell4); + table.appendChild(row); + const tablediv = document.createElement('div'); + tablediv.appendChild(table); + tablediv.id = 'tablediv'; + document.body.appendChild(tablediv); + + setTimeout(function() { + // make a transition to visible + table.style.visibility = 'visible'; + table.style.opacity = '1'; + table.style.transition = 'opacity 2s linear'; + }, 0); + + } +} diff --git a/ui/Popup.js b/ui/Popup.js new file mode 100644 index 0000000..2aae2db --- /dev/null +++ b/ui/Popup.js @@ -0,0 +1,220 @@ +// import {ProgressBar} from './progressbar.min.js'; + +class Popup{ + constructor(){ + window.tabid = 1; // to distinguish this view during .getViews() + this.currentUrl; // the url at the time when the user clicks notarize + this.hasPermission; // shows whether currentUrl has already been allowed in Firefox + this.is_chrome = window.navigator.userAgent.match('Chrome') ? true : false; + this.is_edge = window.navigator.userAgent.match('Edg') ? true : false; + this.is_firefox = window.navigator.userAgent.match('Firefox') ? true : false; + this.is_opera = window.navigator.userAgent.match('OPR') ? true : false; + + // in Firefox we need to know the current URL before the user clicks notarize + // to pass it to the click event listener so that it could run synchronously. + // document.getElementById("notarize").addEventListener("mouseover", + // function() { + // chrome.tabs.query({active: true}, async function(t) { + // currentUrl = t[0].url + // hasPermission = await browser.permissions.contains({origins: [currentUrl]}) + // }) + // }) + + const that = this; + document.getElementById('notarize').addEventListener('click', function(){ + that.notarizeClicked(false); + }); + document.getElementById('notarizeAfter').addEventListener('click', function(){ + that.notarizeClicked(true); + }); + + document.getElementById('manage').addEventListener('click', function() { + chrome.runtime.sendMessage({ + destination: 'extension', + message: 'manage' + }); + window.close(); + }); + + document.getElementById('import').addEventListener('click', function() { + chrome.runtime.sendMessage({ + destination: 'extension', + message: 'file picker' + }); + window.close(); + }); + + document.getElementById('about').addEventListener('click', function() { + document.getElementById('menu').hidden = true; + document.getElementById('aboutWindow').hidden = false; + }); + + document.getElementById('app_disabled').addEventListener('click', function() { + chrome.runtime.sendMessage({ + destination: 'extension', + message: 'openChromeExtensions' + }); + window.close(); + }); + + chrome.runtime.onMessage.addListener(function(data) { + that.processMessages(data); + }); + + chrome.runtime.sendMessage({ + destination: 'extension', + message: 'popup active' + }); + } + + // notarizeClicked is triggered when Notarize of Notariza after click was pressed + notarizeClicked(isAfterClick){ + isAfterClick = isAfterClick || false; + const msg = isAfterClick ? 'notarizeAfter' : 'notarize'; + if (this.is_firefox && ! this.hasPermission && this.currentUrl.startsWith('https://')){ + // in Firefox we give a temporary permission just for the current tab's URL + // also no async/await/callback here, otherwise Firefox will complain + for (let el of document.getElementsByTagName('div')){ + el.setAttribute('hidden', ''); + } + document.getElementById('grantPermission').removeAttribute('hidden'); + chrome.runtime.sendMessage({ + destination: 'extension', + message: 'pendingAction', + args: msg + }); + browser.permissions.request({origins: [this.currentUrl]}); + } + else { + chrome.runtime.sendMessage({ + destination: 'extension', + message: msg + }); + } + if (isAfterClick){ + window.close(); + } + } + + processMessages(data) { + console.log('popup got message', data); + if (data.destination !== 'popup') return; + if (data.message === 'app_not_installed') { + document.getElementById('menu').removeAttribute('hidden'); + var notarize = document.getElementById('notarize'); + notarize.setAttribute('hidden', true); + var notarizeAfter = document.getElementById('notarizeAfter'); + notarizeAfter.setAttribute('hidden', true); + if (this.is_edge || this.is_firefox || this.is_opera){ + const appNotInstalledFirefox = document.getElementById('appNotInstalledFirefox'); + appNotInstalledFirefox.removeAttribute('hidden'); + var showScript = document.getElementById('showPythonScript'); + showScript.onclick = function(){ + chrome.runtime.sendMessage({ + destination: 'extension', + message: 'open python script' + }); + window.close(); + }; + } + else { + document.getElementById('appNotInstalledChrome').removeAttribute('hidden'); + var openWebStore = document.getElementById('openWebStore'); + openWebStore.onclick = function(){ + chrome.tabs.create({url: 'https://chrome.google.com/webstore/detail/pagesigner-helper-app/oclohfdjoojomkfddjclanpogcnjhemd'}); + }; + } + } else if (data.message === 'app_disabled') { + document.getElementById('app_disabled').removeAttribute('hidden'); + } else if (data.message === 'show_menu') { + document.getElementById('menu').removeAttribute('hidden'); + } else if (data.message === 'notarization_in_progress') { + this.showInProgressDiv(data.firstTime); + } else if (data.message === 'waiting_for_click') { + document.getElementById('waiting_for_click').removeAttribute('hidden'); + } else if (data.message === 'popup error') { + console.log('got popup error with', data); + const error_div = document.getElementById('popup_error'); + error_div.removeAttribute('hidden'); + const error_text = document.getElementById('popup_error_text'); + error_text.textContent = data.data.title + ' ' +data.data.text; + } else { + console.log('popup received unexpected message ' + data.message); + } + } + + // showInProgressDiv show the

with progress info and listens for + // progress updates + showInProgressDiv(isFirstTimeSetup){ + document.getElementById('menu').setAttribute('hidden', ''); + document.getElementById('in_progress').removeAttribute('hidden'); + + const progressBars = {}; + const types = ['download', 'upload', 'garbling', 'last_stage']; + if (isFirstTimeSetup){ + types.push('first_time'); + document.getElementById('first_time_progress_div').removeAttribute('hidden'); + } + for (const type of types){ + const bar = document.getElementById(type+'_progress_bar'); + progressBars[type] = bar; + } + + const that = this; + chrome.runtime.onMessage.addListener(function(data) { + if (data.destination != 'progress listeners') return; + for (const type of types){ + const obj = data.progress[type]; + if (obj == undefined) continue; + const value = Math.ceil((obj.current / obj.total)*100); + if (isNaN(value)) continue; + that.moveBar(progressBars[type], value); + if (type === 'download'){ + const mbCount = Math.floor(obj.total / (1024*1024)); + document.getElementById('download_MB').textContent = String(mbCount); + document.getElementById('upload_MB').textContent = String(mbCount); + } + } + }); + + // ask for an initial update, all future updates will arrive only + // when there is actually stuff to update + chrome.runtime.sendMessage({ + destination: 'progress monitor' + }); + } + + + moveBar(bar, goalWidth) { + const curWidth = Number(bar.style.width.slice(0,-1)); + if (curWidth === goalWidth){ + return; // no update needed + } + bar.style.width = String(goalWidth) + '%'; + bar.innerHTML = String(goalWidth) + '%'; + } +} + +new Popup(); + + + + + + + + + + + + + + + + + + + + + + diff --git a/ui/RawViewer.js b/ui/RawViewer.js new file mode 100644 index 0000000..fea299d --- /dev/null +++ b/ui/RawViewer.js @@ -0,0 +1,28 @@ +import {decode_str} from './utils.js'; + +class RawViewer{ + constructor(){ + window.tabid = null; // allow the extension to put the id of the tab which opened this page + window.isRawViewer = true; + // isReady will be se to true after message listener is installed + window.isReady = false; + } + + main(){ + chrome.runtime.onMessage.addListener(function(obj) { + if (obj.destination !== 'rawviewer') return; + console.log('got obj', obj); + if (obj.tabId != window.tabid) return; + const request = decode_str(obj.data.request); + const response = decode_str(obj.data.response); + document.getElementById('request').textContent = request; + document.getElementById('response').textContent = response; + document.getElementById('notarization_time').textContent = obj.data.sessionId; + }); + window.isReady = true; + } +} + +window.rawViewer = new RawViewer(); +window.rawViewer.main(); + diff --git a/ui/Viewer.js b/ui/Viewer.js new file mode 100644 index 0000000..60e34e0 --- /dev/null +++ b/ui/Viewer.js @@ -0,0 +1,117 @@ +import {NotificationBar} from './NotificationBar.js'; +import {FileChooser} from './FileChooser.js'; +import {decode_str, str2ba } from './utils.js'; + +class Viewer{ + constructor(){ + window.tabid = null; // allow the extension to put the id of the tab which opened this page + window.isViewer = true; + // isFileChooser will be toggled to true if extension calls Main.openFileChooser() + window.isFileChooser = false; + // isReady will be se to true after message listener is installed + window.isReady = false; + } + + main(){ + console.log('in viewer main'); + const that = this; + chrome.runtime.onMessage.addListener(function(msg) { + console.log('got msg', msg); + if (msg.destination === 'fileChooser' && window.isFileChooser) { + if (msg.message === 'duplicate'){ + that.showDuplicateNotice(msg.date, msg.name); + return; + } + else { + throw 'unexpected message'; + } + } + if (msg.destination !== 'viewer') return; + if (msg.tabId != window.tabid) return; + if (msg.message != 'show'){ + throw 'unexpected message'; + } + console.log('got data in viewer'); + var hideButton = false; + var text = msg.data.response; + console.log('text size is', text.length); + // remove the HTTP headers + var http_body = text.split('\r\n\r\n').splice(1).join('\r\n\r\n'); + + let type = that.getType(text); + if (['html', 'json', 'xml', 'txt'].indexOf(type) > -1) { + // add CSP to prevent loading any resources from the page + const csp = '\r\n'; + document.write(csp + decode_str(http_body)); + } + else { + // a file which cannot be shown but has to be downloaded like e.g. PDF + document.getElementById('type').textContent = type; + document.getElementById('view file button').onclick = function() { + that.view_file(str2ba(http_body), msg.serverName + '.' + type);}; + document.getElementById('view file').removeAttribute('hidden'); + } + setTimeout(function(){ + // we need timeout because the body may not yet be available + new NotificationBar().show(msg.data.sessionId, msg.data.serverName, hideButton); + document.body.style.marginTop = '30px'; + }, 1000); + }); + window.isReady = true; + } + + + getType (data_with_headers){ + const headers = data_with_headers.split('\r\n\r\n')[0]; + const header_lines = headers.split('\r\n'); + for (const line of header_lines) { + if (line.search(/content-type:\s*/i) < 0) continue; + if (line.match('application/pdf')){ + return 'pdf'; + } + else if (line.match('image/jpeg')){ + return 'jpg'; + } + return 'html'; + } + } + + view_file(data, filename){ + console.log('view file button clicked'); + // create an invisible download link + var exportedBlobUrl = URL.createObjectURL(new Blob([data]), { + type: 'application/octet-stream' + }); + var fauxLink = document.createElement('a'); + fauxLink.href = exportedBlobUrl; + fauxLink.setAttribute('download', filename); + document.body.appendChild(fauxLink); + fauxLink.click(); + } + + showFileChooser(){ + console.log('in showFileChooser'); + window.isFileChooser = true; + const fc = new FileChooser(); + fc.show(); + } + + showDuplicateNotice(date, name){ + document.getElementById('loader').setAttribute('hidden', true); + document.getElementById('duplicate notice').removeAttribute('hidden'); + document.getElementById('dup name').textContent = name; + document.getElementById('dup date').textContent = date; + document.getElementById('dup open manager').addEventListener('click', function() { + chrome.runtime.sendMessage({ + 'destination': 'extension', + 'message': 'viewdata', + 'args': { + 'dir': date + } + }); + }); + } +} + +window.viewer = new Viewer(); +window.viewer.main(); \ No newline at end of file diff --git a/ui/css/manager.css b/ui/css/manager.css new file mode 100644 index 0000000..7930828 --- /dev/null +++ b/ui/css/manager.css @@ -0,0 +1,32 @@ +body{ + background-image: linear-gradient(to right bottom, #d1d1d1, #d8d8d8, #dfdfdf, #e7e7e7, #eeeeee); + margin-top: 20px; + margin-bottom: 20px; + margin-left: 60px; + margin-right: 60px; + font-family: 'Lucida Grande', 'Segoe UI', Tahoma, 'DejaVu Sans', Arial, sans-serif; + font-size: 75%; +} + +.btn { + box-shadow: 0px 0px 0px 2px #9fb4f2; + background-color:#475bbf; + border-radius:10px; + border:1px solid #4e6096; + cursor:pointer; + color:#ffffff; + font-family:Arial; + font-size:12px; + text-decoration:none; + text-shadow:0px 1px 0px #283966; + margin-left: 20px; +} + + +.icon:hover{ + cursor:pointer; +} + + + + diff --git a/ui/css/sweetalert.css b/ui/css/sweetalert.css new file mode 100644 index 0000000..f390a2f --- /dev/null +++ b/ui/css/sweetalert.css @@ -0,0 +1,961 @@ +body.stop-scrolling { + height: 100%; + overflow: hidden; +} + +.sweet-overlay { + background-color: black; + /* IE8 */ + -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=40)"; + /* IE8 */ + background-color: rgba(0, 0, 0, 0.4); + position: fixed; + left: 0; + right: 0; + top: 0; + bottom: 0; + display: none; + z-index: 10000; +} + +.sweet-alert { + background-color: white; + font-family: 'Open Sans', 'Helvetica Neue', Helvetica, Arial, sans-serif; + width: 478px; + padding: 17px; + border-radius: 5px; + text-align: center; + position: fixed; + left: 50%; + top: 50%; + margin-left: -256px; + margin-top: -200px; + overflow: hidden; + display: none; + z-index: 99999; +} + +@media all and (max-width: 540px) { + .sweet-alert { + width: auto; + margin-left: 0; + margin-right: 0; + left: 15px; + right: 15px; + } +} + +.sweet-alert h2 { + color: #575757; + font-size: 30px; + text-align: center; + font-weight: 600; + text-transform: none; + position: relative; + margin: 25px 0; + padding: 0; + line-height: 40px; + display: block; +} + +.sweet-alert p { + color: #797979; + font-size: 16px; + text-align: center; + font-weight: 300; + position: relative; + text-align: inherit; + float: none; + margin: 0; + padding: 0; + line-height: normal; +} + +.sweet-alert fieldset { + border: none; + position: relative; +} + +.sweet-alert .sa-error-container { + background-color: #f1f1f1; + margin-left: -17px; + margin-right: -17px; + overflow: hidden; + padding: 0 10px; + max-height: 0; + webkit-transition: padding 0.15s, max-height 0.15s; + transition: padding 0.15s, max-height 0.15s; +} + +.sweet-alert .sa-error-container.show { + padding: 10px 0; + max-height: 100px; + webkit-transition: padding 0.2s, max-height 0.2s; + transition: padding 0.25s, max-height 0.25s; +} + +.sweet-alert .sa-error-container .icon { + display: inline-block; + width: 24px; + height: 24px; + border-radius: 50%; + background-color: #ea7d7d; + color: white; + line-height: 24px; + text-align: center; + margin-right: 3px; +} + +.sweet-alert .sa-error-container p { + display: inline-block; +} + +.sweet-alert .sa-input-error { + position: absolute; + top: 29px; + right: 26px; + width: 20px; + height: 20px; + opacity: 0; + -webkit-transform: scale(0.5); + transform: scale(0.5); + -webkit-transform-origin: 50% 50%; + transform-origin: 50% 50%; + -webkit-transition: all 0.1s; + transition: all 0.1s; +} + +.sweet-alert .sa-input-error::before, .sweet-alert .sa-input-error::after { + content: ""; + width: 20px; + height: 6px; + background-color: #f06e57; + border-radius: 3px; + position: absolute; + top: 50%; + margin-top: -4px; + left: 50%; + margin-left: -9px; +} + +.sweet-alert .sa-input-error::before { + -webkit-transform: rotate(-45deg); + transform: rotate(-45deg); +} + +.sweet-alert .sa-input-error::after { + -webkit-transform: rotate(45deg); + transform: rotate(45deg); +} + +.sweet-alert .sa-input-error.show { + opacity: 1; + -webkit-transform: scale(1); + transform: scale(1); +} + +.sweet-alert input { + width: 100%; + box-sizing: border-box; + border-radius: 3px; + border: 1px solid #d7d7d7; + height: 43px; + margin-top: 10px; + margin-bottom: 17px; + font-size: 18px; + box-shadow: inset 0px 1px 1px rgba(0, 0, 0, 0.06); + padding: 0 12px; + display: none; + -webkit-transition: all 0.3s; + transition: all 0.3s; +} + +.sweet-alert input:focus { + outline: none; + box-shadow: 0px 0px 3px #c4e6f5; + border: 1px solid #b4dbed; +} + +.sweet-alert input:focus::-moz-placeholder { + transition: opacity 0.3s 0.03s ease; + opacity: 0.5; +} + +.sweet-alert input:focus:-ms-input-placeholder { + transition: opacity 0.3s 0.03s ease; + opacity: 0.5; +} + +.sweet-alert input:focus::-webkit-input-placeholder { + transition: opacity 0.3s 0.03s ease; + opacity: 0.5; +} + +.sweet-alert input::-moz-placeholder { + color: #bdbdbd; +} + +.sweet-alert input:-ms-input-placeholder { + color: #bdbdbd; +} + +.sweet-alert input::-webkit-input-placeholder { + color: #bdbdbd; +} + +.sweet-alert.show-input input { + display: block; +} + +.sweet-alert button { + background-color: #AEDEF4; + color: white; + border: none; + box-shadow: none; + font-size: 17px; + font-weight: 500; + -webkit-border-radius: 4px; + border-radius: 5px; + padding: 10px 32px; + margin: 26px 5px 0 5px; + cursor: pointer; +} + +.sweet-alert button:focus { + outline: none; + box-shadow: 0 0 2px rgba(128, 179, 235, 0.5), inset 0 0 0 1px rgba(0, 0, 0, 0.05); +} + +.sweet-alert button:hover { + background-color: #a1d9f2; +} + +.sweet-alert button:active { + background-color: #81ccee; +} + +.sweet-alert button.cancel { + background-color: #D0D0D0; +} + +.sweet-alert button.cancel:hover { + background-color: #c8c8c8; +} + +.sweet-alert button.cancel:active { + background-color: #b6b6b6; +} + +.sweet-alert button.cancel:focus { + box-shadow: rgba(197, 205, 211, 0.8) 0px 0px 2px, rgba(0, 0, 0, 0.0470588) 0px 0px 0px 1px inset !important; +} + +.sweet-alert button::-moz-focus-inner { + border: 0; +} + +.sweet-alert[data-has-cancel-button=false] button { + box-shadow: none !important; +} + +.sweet-alert[data-has-confirm-button=false][data-has-cancel-button=false] { + padding-bottom: 40px; +} + +.sweet-alert .sa-icon { + width: 80px; + height: 80px; + border: 4px solid gray; + -webkit-border-radius: 40px; + border-radius: 40px; + border-radius: 50%; + margin: 20px auto; + padding: 0; + position: relative; + box-sizing: content-box; +} + +.sweet-alert .sa-icon.sa-error { + border-color: #F27474; +} + +.sweet-alert .sa-icon.sa-error .sa-x-mark { + position: relative; + display: block; +} + +.sweet-alert .sa-icon.sa-error .sa-line { + position: absolute; + height: 5px; + width: 47px; + background-color: #F27474; + display: block; + top: 37px; + border-radius: 2px; +} + +.sweet-alert .sa-icon.sa-error .sa-line.sa-left { + -webkit-transform: rotate(45deg); + transform: rotate(45deg); + left: 17px; +} + +.sweet-alert .sa-icon.sa-error .sa-line.sa-right { + -webkit-transform: rotate(-45deg); + transform: rotate(-45deg); + right: 16px; +} + +.sweet-alert .sa-icon.sa-warning { + border-color: #F8BB86; +} + +.sweet-alert .sa-icon.sa-warning .sa-body { + position: absolute; + width: 5px; + height: 47px; + left: 50%; + top: 10px; + -webkit-border-radius: 2px; + border-radius: 2px; + margin-left: -2px; + background-color: #F8BB86; +} + +.sweet-alert .sa-icon.sa-warning .sa-dot { + position: absolute; + width: 7px; + height: 7px; + -webkit-border-radius: 50%; + border-radius: 50%; + margin-left: -3px; + left: 50%; + bottom: 10px; + background-color: #F8BB86; +} + +.sweet-alert .sa-icon.sa-info { + border-color: #C9DAE1; +} + +.sweet-alert .sa-icon.sa-info::before { + content: ""; + position: absolute; + width: 5px; + height: 29px; + left: 50%; + bottom: 17px; + border-radius: 2px; + margin-left: -2px; + background-color: #C9DAE1; +} + +.sweet-alert .sa-icon.sa-info::after { + content: ""; + position: absolute; + width: 7px; + height: 7px; + border-radius: 50%; + margin-left: -3px; + top: 19px; + background-color: #C9DAE1; +} + +.sweet-alert .sa-icon.sa-success { + border-color: #A5DC86; +} + +.sweet-alert .sa-icon.sa-success::before, .sweet-alert .sa-icon.sa-success::after { + content: ''; + -webkit-border-radius: 40px; + border-radius: 40px; + border-radius: 50%; + position: absolute; + width: 60px; + height: 120px; + background: white; + -webkit-transform: rotate(45deg); + transform: rotate(45deg); +} + +.sweet-alert .sa-icon.sa-success::before { + -webkit-border-radius: 120px 0 0 120px; + border-radius: 120px 0 0 120px; + top: -7px; + left: -33px; + -webkit-transform: rotate(-45deg); + transform: rotate(-45deg); + -webkit-transform-origin: 60px 60px; + transform-origin: 60px 60px; +} + +.sweet-alert .sa-icon.sa-success::after { + -webkit-border-radius: 0 120px 120px 0; + border-radius: 0 120px 120px 0; + top: -11px; + left: 30px; + -webkit-transform: rotate(-45deg); + transform: rotate(-45deg); + -webkit-transform-origin: 0px 60px; + transform-origin: 0px 60px; +} + +.sweet-alert .sa-icon.sa-success .sa-placeholder { + width: 80px; + height: 80px; + border: 4px solid rgba(165, 220, 134, 0.2); + -webkit-border-radius: 40px; + border-radius: 40px; + border-radius: 50%; + box-sizing: content-box; + position: absolute; + left: -4px; + top: -4px; + z-index: 2; +} + +.sweet-alert .sa-icon.sa-success .sa-fix { + width: 5px; + height: 90px; + background-color: white; + position: absolute; + left: 28px; + top: 8px; + z-index: 1; + -webkit-transform: rotate(-45deg); + transform: rotate(-45deg); +} + +.sweet-alert .sa-icon.sa-success .sa-line { + height: 5px; + background-color: #A5DC86; + display: block; + border-radius: 2px; + position: absolute; + z-index: 2; +} + +.sweet-alert .sa-icon.sa-success .sa-line.sa-tip { + width: 25px; + left: 14px; + top: 46px; + -webkit-transform: rotate(45deg); + transform: rotate(45deg); +} + +.sweet-alert .sa-icon.sa-success .sa-line.sa-long { + width: 47px; + right: 8px; + top: 38px; + -webkit-transform: rotate(-45deg); + transform: rotate(-45deg); +} + +.sweet-alert .sa-icon.sa-custom { + background-size: contain; + border-radius: 0; + border: none; + background-position: center center; + background-repeat: no-repeat; +} + + +/* + * Animations + */ + +@-webkit-keyframes showSweetAlert { + 0% { + transform: scale(0.7); + -webkit-transform: scale(0.7); + } + 45% { + transform: scale(1.05); + -webkit-transform: scale(1.05); + } + 80% { + transform: scale(0.95); + -webkit-transform: scale(0.95); + } + 100% { + transform: scale(1); + -webkit-transform: scale(1); + } +} + +@keyframes showSweetAlert { + 0% { + transform: scale(0.7); + -webkit-transform: scale(0.7); + } + 45% { + transform: scale(1.05); + -webkit-transform: scale(1.05); + } + 80% { + transform: scale(0.95); + -webkit-transform: scale(0.95); + } + 100% { + transform: scale(1); + -webkit-transform: scale(1); + } +} + +@-webkit-keyframes hideSweetAlert { + 0% { + transform: scale(1); + -webkit-transform: scale(1); + } + 100% { + transform: scale(0.5); + -webkit-transform: scale(0.5); + } +} + +@keyframes hideSweetAlert { + 0% { + transform: scale(1); + -webkit-transform: scale(1); + } + 100% { + transform: scale(0.5); + -webkit-transform: scale(0.5); + } +} + +@-webkit-keyframes slideFromTop { + 0% { + top: 0%; + } + 100% { + top: 50%; + } +} + +@keyframes slideFromTop { + 0% { + top: 0%; + } + 100% { + top: 50%; + } +} + +@-webkit-keyframes slideToTop { + 0% { + top: 50%; + } + 100% { + top: 0%; + } +} + +@keyframes slideToTop { + 0% { + top: 50%; + } + 100% { + top: 0%; + } +} + +@-webkit-keyframes slideFromBottom { + 0% { + top: 70%; + } + 100% { + top: 50%; + } +} + +@keyframes slideFromBottom { + 0% { + top: 70%; + } + 100% { + top: 50%; + } +} + +@-webkit-keyframes slideToBottom { + 0% { + top: 50%; + } + 100% { + top: 70%; + } +} + +@keyframes slideToBottom { + 0% { + top: 50%; + } + 100% { + top: 70%; + } +} + +.showSweetAlert[data-animation=pop] { + -webkit-animation: showSweetAlert 0.3s; + animation: showSweetAlert 0.3s; +} + +.showSweetAlert[data-animation=none] { + -webkit-animation: none; + animation: none; +} + +.showSweetAlert[data-animation=slide-from-top] { + -webkit-animation: slideFromTop 0.3s; + animation: slideFromTop 0.3s; +} + +.showSweetAlert[data-animation=slide-from-bottom] { + -webkit-animation: slideFromBottom 0.3s; + animation: slideFromBottom 0.3s; +} + +.hideSweetAlert[data-animation=pop] { + -webkit-animation: hideSweetAlert 0.2s; + animation: hideSweetAlert 0.2s; +} + +.hideSweetAlert[data-animation=none] { + -webkit-animation: none; + animation: none; +} + +.hideSweetAlert[data-animation=slide-from-top] { + -webkit-animation: slideToTop 0.4s; + animation: slideToTop 0.4s; +} + +.hideSweetAlert[data-animation=slide-from-bottom] { + -webkit-animation: slideToBottom 0.3s; + animation: slideToBottom 0.3s; +} + +@-webkit-keyframes animateSuccessTip { + 0% { + width: 0; + left: 1px; + top: 19px; + } + 54% { + width: 0; + left: 1px; + top: 19px; + } + 70% { + width: 50px; + left: -8px; + top: 37px; + } + 84% { + width: 17px; + left: 21px; + top: 48px; + } + 100% { + width: 25px; + left: 14px; + top: 45px; + } +} + +@keyframes animateSuccessTip { + 0% { + width: 0; + left: 1px; + top: 19px; + } + 54% { + width: 0; + left: 1px; + top: 19px; + } + 70% { + width: 50px; + left: -8px; + top: 37px; + } + 84% { + width: 17px; + left: 21px; + top: 48px; + } + 100% { + width: 25px; + left: 14px; + top: 45px; + } +} + +@-webkit-keyframes animateSuccessLong { + 0% { + width: 0; + right: 46px; + top: 54px; + } + 65% { + width: 0; + right: 46px; + top: 54px; + } + 84% { + width: 55px; + right: 0px; + top: 35px; + } + 100% { + width: 47px; + right: 8px; + top: 38px; + } +} + +@keyframes animateSuccessLong { + 0% { + width: 0; + right: 46px; + top: 54px; + } + 65% { + width: 0; + right: 46px; + top: 54px; + } + 84% { + width: 55px; + right: 0px; + top: 35px; + } + 100% { + width: 47px; + right: 8px; + top: 38px; + } +} + +@-webkit-keyframes rotatePlaceholder { + 0% { + transform: rotate(-45deg); + -webkit-transform: rotate(-45deg); + } + 5% { + transform: rotate(-45deg); + -webkit-transform: rotate(-45deg); + } + 12% { + transform: rotate(-405deg); + -webkit-transform: rotate(-405deg); + } + 100% { + transform: rotate(-405deg); + -webkit-transform: rotate(-405deg); + } +} + +@keyframes rotatePlaceholder { + 0% { + transform: rotate(-45deg); + -webkit-transform: rotate(-45deg); + } + 5% { + transform: rotate(-45deg); + -webkit-transform: rotate(-45deg); + } + 12% { + transform: rotate(-405deg); + -webkit-transform: rotate(-405deg); + } + 100% { + transform: rotate(-405deg); + -webkit-transform: rotate(-405deg); + } +} + +.animateSuccessTip { + -webkit-animation: animateSuccessTip 0.75s; + animation: animateSuccessTip 0.75s; +} + +.animateSuccessLong { + -webkit-animation: animateSuccessLong 0.75s; + animation: animateSuccessLong 0.75s; +} + +.sa-icon.sa-success.animate::after { + -webkit-animation: rotatePlaceholder 4.25s ease-in; + animation: rotatePlaceholder 4.25s ease-in; +} + +@-webkit-keyframes animateErrorIcon { + 0% { + transform: rotateX(100deg); + -webkit-transform: rotateX(100deg); + opacity: 0; + } + 100% { + transform: rotateX(0deg); + -webkit-transform: rotateX(0deg); + opacity: 1; + } +} + +@keyframes animateErrorIcon { + 0% { + transform: rotateX(100deg); + -webkit-transform: rotateX(100deg); + opacity: 0; + } + 100% { + transform: rotateX(0deg); + -webkit-transform: rotateX(0deg); + opacity: 1; + } +} + +.animateErrorIcon { + -webkit-animation: animateErrorIcon 0.5s; + animation: animateErrorIcon 0.5s; +} + +@-webkit-keyframes animateXMark { + 0% { + transform: scale(0.4); + -webkit-transform: scale(0.4); + margin-top: 26px; + opacity: 0; + } + 50% { + transform: scale(0.4); + -webkit-transform: scale(0.4); + margin-top: 26px; + opacity: 0; + } + 80% { + transform: scale(1.15); + -webkit-transform: scale(1.15); + margin-top: -6px; + } + 100% { + transform: scale(1); + -webkit-transform: scale(1); + margin-top: 0; + opacity: 1; + } +} + +@keyframes animateXMark { + 0% { + transform: scale(0.4); + -webkit-transform: scale(0.4); + margin-top: 26px; + opacity: 0; + } + 50% { + transform: scale(0.4); + -webkit-transform: scale(0.4); + margin-top: 26px; + opacity: 0; + } + 80% { + transform: scale(1.15); + -webkit-transform: scale(1.15); + margin-top: -6px; + } + 100% { + transform: scale(1); + -webkit-transform: scale(1); + margin-top: 0; + opacity: 1; + } +} + +.animateXMark { + -webkit-animation: animateXMark 0.5s; + animation: animateXMark 0.5s; +} + +@-webkit-keyframes pulseWarning { + 0% { + border-color: #F8D486; + } + 100% { + border-color: #F8BB86; + } +} + +@keyframes pulseWarning { + 0% { + border-color: #F8D486; + } + 100% { + border-color: #F8BB86; + } +} + +.pulseWarning { + -webkit-animation: pulseWarning 0.75s infinite alternate; + animation: pulseWarning 0.75s infinite alternate; +} + +@-webkit-keyframes pulseWarningIns { + 0% { + background-color: #F8D486; + } + 100% { + background-color: #F8BB86; + } +} + +@keyframes pulseWarningIns { + 0% { + background-color: #F8D486; + } + 100% { + background-color: #F8BB86; + } +} + +.pulseWarningIns { + -webkit-animation: pulseWarningIns 0.75s infinite alternate; + animation: pulseWarningIns 0.75s infinite alternate; +} + + +/* Internet Explorer 9 has some special quirks that are fixed here */ + + +/* The icons are not animated. */ + + +/* This file is automatically merged into sweet-alert.min.js through Gulp */ + + +/* Error icon */ + +.sweet-alert .sa-icon.sa-error .sa-line.sa-left { + -ms-transform: rotate(45deg) \9; +} + +.sweet-alert .sa-icon.sa-error .sa-line.sa-right { + -ms-transform: rotate(-45deg) \9; +} + + +/* Success icon */ + +.sweet-alert .sa-icon.sa-success { + border-color: transparent\9; +} + +.sweet-alert .sa-icon.sa-success .sa-line.sa-tip { + -ms-transform: rotate(45deg) \9; +} + +.sweet-alert .sa-icon.sa-success .sa-line.sa-long { + -ms-transform: rotate(-45deg) \9; +} diff --git a/ui/css/table.css b/ui/css/table.css new file mode 100644 index 0000000..51676ea --- /dev/null +++ b/ui/css/table.css @@ -0,0 +1,59 @@ +table.blueTable { + border: 1px solid #1C6EA4; + background-color: #476BBD; + width: 100%; + text-align: left; + border-collapse: collapse; +} +table.blueTable td, table.blueTable th { + border: 1px solid #AAAAAA; + padding: 3px 2px; + padding-top: 1em; + padding-bottom: 1em; +} +table.blueTable tbody td { + font-size: 13px; +} +table.blueTable tr:nth-child(even) { + background: #D0E4F5; +} +table.blueTable thead { + background: #476BBD; + background: -moz-linear-gradient(top, #7590cd 0%, #5979c3 66%, #476BBD 100%); + background: -webkit-linear-gradient(top, #7590cd 0%, #5979c3 66%, #476BBD 100%); + background: linear-gradient(to bottom, #7590cd 0%, #5979c3 66%, #476BBD 100%); + border-bottom: 2px solid #444444; +} +table.blueTable thead th { + font-size: 15px; + font-weight: bold; + color: #FFFFFF; + border-left: 2px solid #D0E4F5; +} +table.blueTable thead th:first-child { + border-left: none; +} + +table.blueTable tfoot { + font-size: 14px; + font-weight: bold; + color: #FFFFFF; + background: #D0E4F5; + background: -moz-linear-gradient(top, #dcebf7 0%, #d4e6f6 66%, #D0E4F5 100%); + background: -webkit-linear-gradient(top, #dcebf7 0%, #d4e6f6 66%, #D0E4F5 100%); + background: linear-gradient(to bottom, #dcebf7 0%, #d4e6f6 66%, #D0E4F5 100%); + border-top: 2px solid #444444; +} +table.blueTable tfoot td { + font-size: 14px; +} +table.blueTable tfoot .links { + text-align: right; +} +table.blueTable tfoot .links a{ + display: inline-block; + background: #1C6EA4; + color: #FFFFFF; + padding: 2px 8px; + border-radius: 5px; +} \ No newline at end of file diff --git a/ui/html/manager.html b/ui/html/manager.html new file mode 100644 index 0000000..92f2be8 --- /dev/null +++ b/ui/html/manager.html @@ -0,0 +1,32 @@ + + Manage your PageSigner notarization sessions. + + + + + + + + + + +
+ + + + + + + + + + +
Session nameNotarization timeView session
+
+ + + + + + + diff --git a/ui/html/popup.html b/ui/html/popup.html new file mode 100644 index 0000000..105ed30 --- /dev/null +++ b/ui/html/popup.html @@ -0,0 +1,202 @@ + + + + + + + + + + + +
+ + + +
+ + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + diff --git a/ui/html/rawviewer.html b/ui/html/rawviewer.html new file mode 100644 index 0000000..8dc8aeb --- /dev/null +++ b/ui/html/rawviewer.html @@ -0,0 +1,31 @@ + + + + + + +
+

-------------------Notarization time-------------------

+ +

-------------------Client request:---------------------

+ +

-------------------Server response:--------------------

+ +
+ +