forked from Qortal/qortal
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
789 lines
27 KiB
789 lines
27 KiB
<!DOCTYPE html> |
|
<html> |
|
<head> |
|
<title>Block Explorer</title> |
|
<style> |
|
body { color: #404040; font-family: sans-serif; } |
|
table { width: 100%; border-collapse: collapse; border: 1px solid #dddddd; margin-bottom: 40px; } |
|
tr:nth-child(odd) { background-color: #eeeeee; } |
|
th { background-color: #eeeeee; } |
|
td { text-align: center; } |
|
.sig { font-size: 60%; color: #405906; } |
|
.ref { font-size: 60%; color: #609040; } |
|
</style> |
|
<script> |
|
// USEFUL CODE STARTS HERE |
|
|
|
function publicKeyToAddress(publicKey) { |
|
var ADDRESS_VERSION = 58; // For normal user accounts starting with "Q" |
|
// var ADDRESS_VERSION = 23; // For Automated Transaction accounts starting with "A" |
|
|
|
var publicKeyHashSHA256 = SHA256.digest(publicKey); |
|
|
|
var ripemd160 = new RIPEMD160(); // 'Grandfathered' broken implementation of MD160 |
|
|
|
var publicKeyHash = ripemd160.digest(publicKeyHashSHA256); |
|
|
|
var addressArray = new Uint8Array(); |
|
|
|
addressArray = appendBuffer(addressArray, [ADDRESS_VERSION]); |
|
addressArray = appendBuffer(addressArray, publicKeyHash); |
|
|
|
var checkSum = SHA256.digest(SHA256.digest(addressArray)); |
|
|
|
addressArray = appendBuffer(addressArray, checkSum.subarray(0, 4)); |
|
|
|
return Base58.encode(addressArray); |
|
} |
|
|
|
function renderAddressTransactions(e) { |
|
var transactions = e.target.response; |
|
|
|
var address = this.responseURL.split("/")[5]; |
|
|
|
if (transactions.length == 0) { |
|
document.body.innerHTML += 'No transactions involving address'; |
|
return; |
|
} |
|
|
|
var html = '<table id="transactions"><tr><th>Type</th><th>Timestamp</th><th>Creator</th><th>Fee</th><th>Signature</th><th>Reference</th></tr>'; |
|
|
|
for (var i=0; i<transactions.length; ++i) { |
|
var tx = transactions[i]; |
|
var txTimestamp = new Date(tx.timestamp).toUTCString(); |
|
var txCreatorAddress = publicKeyToAddress(base64ToArray(tx.creatorPublicKey)); // currently base64 but likely to be base58 in the future |
|
|
|
var row = '<tr><td>' + tx.type + '</td>' + |
|
'<td>' + txTimestamp + '</td>' + |
|
'<td class="addr">' + addressAsLink(txCreatorAddress) + '</td>' + |
|
'<td>' + tx.fee + ' QORA</td>' + |
|
'<td class="sig">' + Base58.encode(base64ToArray(tx.signature)) + '</td>' + |
|
'<td class="ref">' + Base58.encode(base64ToArray(tx.reference)) + '</td></tr>'; |
|
|
|
html += row; |
|
} |
|
|
|
html += '</table>'; |
|
|
|
document.body.innerHTML += html; |
|
} |
|
|
|
function renderAddressInfo(e) { |
|
var balances = e.target.response; |
|
|
|
var address = this.responseURL.split("/")[5]; |
|
|
|
var html = '<h1>Address ' + address + '</h1>'; |
|
|
|
html += '<table><tr><th>Asset ID</th><th>Balance</th></tr>'; |
|
|
|
for (var i=0; i<balances.length; ++i) { |
|
var balanceInfo = balances[i]; |
|
|
|
html += '<tr><td>' + balanceInfo.assetId + '</td><td>' + balanceInfo.balance + '</td></tr>'; |
|
} |
|
|
|
html += '</table>'; |
|
|
|
document.body.innerHTML = html; |
|
|
|
XHR({ |
|
url: "/transactions/search?address=" + address, |
|
onload: renderAddressTransactions, |
|
responseType: "json" |
|
}); |
|
} |
|
|
|
function fetchAddressInfo(address) { |
|
XHR({ |
|
url: "/addresses/assets/" + address, |
|
onload: renderAddressInfo, |
|
responseType: "json" |
|
}); |
|
} |
|
|
|
function addressAsLink(address) { |
|
return '<a href="#" onclick="fetchAddressInfo(' + "'" + address + "'" + ')">' + address + '</a>'; |
|
} |
|
|
|
function renderBlockTransactions(e) { |
|
var transactions = e.target.response; |
|
|
|
if (transactions.length == 0) { |
|
document.body.innerHTML += 'No transactions in block'; |
|
return; |
|
} |
|
|
|
var html = '<table id="transactions"><tr><th>Type</th><th>Timestamp</th><th>Creator</th><th>Fee</th><th>Signature</th><th>Reference</th></tr>'; |
|
|
|
for (var i=0; i<transactions.length; ++i) { |
|
var tx = transactions[i]; |
|
var txTimestamp = new Date(tx.timestamp).toUTCString(); |
|
var txCreatorAddress = publicKeyToAddress(base64ToArray(tx.creatorPublicKey)); // currently base64 but likely to be base58 in the future |
|
|
|
var row = '<tr><td>' + tx.type + '</td>' + |
|
'<td>' + txTimestamp + '</td>' + |
|
'<td class="addr">' + addressAsLink(txCreatorAddress) + '</td>' + |
|
'<td>' + tx.fee + ' QORA</td>' + |
|
'<td class="sig">' + Base58.encode(base64ToArray(tx.signature)) + '</td>' + |
|
'<td class="ref">' + Base58.encode(base64ToArray(tx.reference)) + '</td></tr>'; |
|
|
|
html += row; |
|
} |
|
|
|
html += '</table>'; |
|
|
|
document.body.innerHTML += html; |
|
} |
|
|
|
function renderBlockInfo(e) { |
|
var blockData = e.target.response.block; |
|
|
|
// These properties are currently emitted as base64 by API but likely to be base58 in the future, so convert them |
|
var props = [ "signature", "reference", "transactionsSignature", "generatorPublicKey", "generatorSignature" ]; |
|
for (var i=0; i<props.length; ++i) { |
|
var p = props[i]; |
|
blockData[p] = Base58.encode(base64ToArray(blockData[p])); |
|
} |
|
|
|
// convert generator public key into address |
|
blockData.generator = publicKeyToAddress(base64ToArray(blockData.generatorPublicKey)); // currently base64 but likely to be base58 in the future |
|
|
|
var html = '<h1>Block ' + blockData.height + '</h1>'; |
|
html += '<table id="block"><tr><th>Property</th><th>Value</th></tr>'; |
|
|
|
for (var p in blockData) { |
|
html += '<tr><td>' + p + '</td>'; |
|
|
|
if (p.indexOf("ignature") != -1) { |
|
html += '<td class="sig">'; |
|
} else if (p.indexOf("eference") != -1) { |
|
html += '<td class="ref">'; |
|
} else { |
|
html += '<td>'; |
|
} |
|
|
|
if (p == "generator") { |
|
html += addressAsLink(blockData[p]); |
|
} else { |
|
html += blockData[p]; |
|
} |
|
|
|
if (p.indexOf("ees") != -1) |
|
html += " QORA"; |
|
|
|
html += '</td></tr>'; |
|
} |
|
|
|
html += '</table>'; |
|
|
|
document.body.innerHTML = html; |
|
|
|
// Fetch block's transactions |
|
XHR({ |
|
url: "/transactions/block/" + blockData.signature, |
|
onload: renderBlockTransactions, |
|
responseType: "json" |
|
}); |
|
} |
|
|
|
function fetchBlockInfo(height) { |
|
XHR({ |
|
url: "/blocks/byheight/" + height, |
|
onload: renderBlockInfo, |
|
responseType: "json" |
|
}); |
|
} |
|
|
|
function listBlock(e) { |
|
var blockData = e.target.response.block; |
|
|
|
var ourHeight = blockData.height; |
|
var blockTimestamp = new Date(blockData.timestamp).toUTCString(); |
|
var blockGeneratorAddress = publicKeyToAddress(base64ToArray(blockData.generatorPublicKey)); // currently base64 but likely to be base58 in the future |
|
|
|
var ourRow = document.createElement('TR'); |
|
ourRow.innerHTML = '<td><a href="#" onclick="fetchBlockInfo(' + ourHeight + ')">' + ourHeight + '</a></td>' + |
|
'<td>' + blockTimestamp + '</td>' + |
|
'<td class="addr">' + addressAsLink(blockGeneratorAddress) + '</td>' + |
|
'<td>' + blockData.generatingBalance + '</td>' + |
|
'<td>' + blockData.transactionCount + '</td>' + |
|
'<td>' + blockData.totalFees + ' QORA</td>'; |
|
|
|
var table = document.getElementById('blocks'); |
|
var rows = table.getElementsByTagName('TR'); |
|
for (var r = 1; r < rows.length; ++r) |
|
if (ourHeight > rows[r].cells[0].innerText) { |
|
table.insertBefore(ourRow, rows[r]); |
|
return; |
|
} |
|
|
|
table.appendChild(ourRow); |
|
} |
|
|
|
function showShutdown() { |
|
document.body.innerHTML = '<h1>Shutdown</h1>'; |
|
} |
|
|
|
function shutdownAPI() { |
|
XHR({ |
|
url: "/admin/stop", |
|
onload: showShutdown, |
|
responseType: "json" |
|
}); |
|
} |
|
|
|
function listBlocksFrom(height) { |
|
document.body.innerHTML = '<h1>Blocks</h1>'; |
|
|
|
document.body.innerHTML += '<table id="blocks"><tr><th>Height</th><th>Time</th><th>Generator</th><th>Gen.Balance</th><th>TX</th><th>Fees</th></tr></table>'; |
|
|
|
if (height > 20) |
|
document.body.innerHTML += '<a href="#" onclick="listBlocksFrom(' + (height - 20) + ')">Previous blocks...</a>'; |
|
|
|
document.body.innerHTML += '<p><a href="#" onclick="fetchBlockInfo(356928)">Block with lots of transactions</a>'; |
|
|
|
document.body.innerHTML += '<p><a href="#" onclick="shutdownAPI()">Shutdown</a>'; |
|
|
|
for (var h = height; h > 0 && h >= height - 20; --h) |
|
XHR({ |
|
url: "/blocks/byheight/" + h, |
|
onload: listBlock, |
|
responseType: "json" |
|
}); |
|
|
|
return false; |
|
} |
|
|
|
function initialBlocks(e) { |
|
var height = e.target.response; |
|
console.log("initial block height: " + height); |
|
|
|
listBlocksFrom(height); |
|
} |
|
|
|
function windowOnLoad() { |
|
XHR({ |
|
url: "/blocks/height", |
|
onload: initialBlocks, |
|
responseType: "json" |
|
}); |
|
} |
|
|
|
window.addEventListener('load', windowOnLoad, false); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// UTILITY FUNCTIONS BELOW (Base64, Base58, SHA256, etc.) |
|
|
|
function base64ToArray(base64) { |
|
var raw = window.atob(base64); |
|
var rawLength = raw.length; |
|
var array = new Uint8Array(new ArrayBuffer(rawLength)); |
|
|
|
for(i = 0; i < rawLength; i++) { |
|
array[i] = raw.charCodeAt(i); |
|
} |
|
return array; |
|
} |
|
|
|
function appendBuffer (buffer1, buffer2) { |
|
buffer1 = new Uint8Array(buffer1); |
|
buffer2 = new Uint8Array(buffer2); |
|
var tmp = new Uint8Array(buffer1.byteLength + buffer2.byteLength); |
|
tmp.set(buffer1, 0); |
|
tmp.set(buffer2, buffer1.byteLength); |
|
return tmp; |
|
} |
|
|
|
|
|
|
|
|
|
// BASE58 |
|
|
|
(function() { |
|
var ALPHABET, ALPHABET_MAP, Base58, i; |
|
|
|
Base58 = (typeof module !== "undefined" && module !== null ? module.exports : void 0) || (window.Base58 = {}); |
|
|
|
ALPHABET = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"; |
|
|
|
ALPHABET_MAP = {}; |
|
|
|
i = 0; |
|
|
|
while (i < ALPHABET.length) { |
|
ALPHABET_MAP[ALPHABET.charAt(i)] = i; |
|
i++; |
|
} |
|
|
|
Base58.encode = function(buffer) { |
|
var carry, digits, j; |
|
if (buffer.length === 0) { |
|
return ""; |
|
} |
|
i = void 0; |
|
j = void 0; |
|
digits = [0]; |
|
i = 0; |
|
while (i < buffer.length) { |
|
j = 0; |
|
while (j < digits.length) { |
|
digits[j] <<= 8; |
|
j++; |
|
} |
|
digits[0] += buffer[i]; |
|
carry = 0; |
|
j = 0; |
|
while (j < digits.length) { |
|
digits[j] += carry; |
|
carry = (digits[j] / 58) | 0; |
|
digits[j] %= 58; |
|
++j; |
|
} |
|
while (carry) { |
|
digits.push(carry % 58); |
|
carry = (carry / 58) | 0; |
|
} |
|
i++; |
|
} |
|
i = 0; |
|
while (buffer[i] === 0 && i < buffer.length - 1) { |
|
digits.push(0); |
|
i++; |
|
} |
|
return digits.reverse().map(function(digit) { |
|
return ALPHABET[digit]; |
|
}).join(""); |
|
}; |
|
|
|
Base58.decode = function(string) { |
|
var bytes, c, carry, j; |
|
if (string.length === 0) { |
|
return new (typeof Uint8Array !== "undefined" && Uint8Array !== null ? Uint8Array : Buffer)(0); |
|
} |
|
i = void 0; |
|
j = void 0; |
|
bytes = [0]; |
|
i = 0; |
|
while (i < string.length) { |
|
c = string[i]; |
|
if (!(c in ALPHABET_MAP)) { |
|
throw "Base58.decode received unacceptable input. Character '" + c + "' is not in the Base58 alphabet."; |
|
} |
|
j = 0; |
|
while (j < bytes.length) { |
|
bytes[j] *= 58; |
|
j++; |
|
} |
|
bytes[0] += ALPHABET_MAP[c]; |
|
carry = 0; |
|
j = 0; |
|
while (j < bytes.length) { |
|
bytes[j] += carry; |
|
carry = bytes[j] >> 8; |
|
bytes[j] &= 0xff; |
|
++j; |
|
} |
|
while (carry) { |
|
bytes.push(carry & 0xff); |
|
carry >>= 8; |
|
} |
|
i++; |
|
} |
|
i = 0; |
|
while (string[i] === "1" && i < string.length - 1) { |
|
bytes.push(0); |
|
i++; |
|
} |
|
return new (typeof Uint8Array !== "undefined" && Uint8Array !== null ? Uint8Array : Buffer)(bytes.reverse()); |
|
}; |
|
|
|
}).call(this); |
|
|
|
|
|
|
|
|
|
|
|
// SHA256 |
|
|
|
SHA256 = {}; |
|
|
|
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]; |
|
|
|
// The digest function returns the hash value (digest) |
|
// as a 32 byte (typed) array. |
|
// message: the string or byte array to hash |
|
SHA256.digest = function(message) { |
|
var h0 = 0x6a09e667; |
|
var h1 = 0xbb67ae85; |
|
var h2 = 0x3c6ef372; |
|
var h3 = 0xa54ff53a; |
|
var h4 = 0x510e527f; |
|
var h5 = 0x9b05688c; |
|
var h6 = 0x1f83d9ab; |
|
var h7 = 0x5be0cd19; |
|
var K = SHA256.K; |
|
if (typeof message == 'string') { |
|
var s = unescape(encodeURIComponent(message)); // UTF-8 |
|
message = new Uint8Array(s.length); |
|
for (var i = 0; i < s.length; i++) { |
|
message[i] = s.charCodeAt(i) & 0xff; |
|
} |
|
} |
|
var length = message.length; |
|
var byteLength = Math.floor((length + 72) / 64) * 64; |
|
var wordLength = byteLength / 4; |
|
var bitLength = length * 8; |
|
var m = new Uint8Array(byteLength); |
|
m.set(message); |
|
m[length] = 0x80; |
|
m[byteLength - 4] = bitLength >>> 24; |
|
m[byteLength - 3] = (bitLength >>> 16) & 0xff; |
|
m[byteLength - 2] = (bitLength >>> 8) & 0xff; |
|
m[byteLength - 1] = bitLength & 0xff; |
|
var words = new Int32Array(wordLength); |
|
var byteIndex = 0; |
|
for (var i = 0; i < words.length; i++) { |
|
var word = m[byteIndex++] << 24; |
|
word |= m[byteIndex++] << 16; |
|
word |= m[byteIndex++] << 8; |
|
word |= m[byteIndex++]; |
|
words[i] = word; |
|
} |
|
var w = new Int32Array(64); |
|
for (var j = 0; j < wordLength; j += 16) { |
|
for (i = 0; i < 16; i++) { |
|
w[i] = words[j + i]; |
|
} |
|
for (i = 16; i < 64; i++) { |
|
var v = w[i - 15]; |
|
var s0 = (v >>> 7) | (v << 25); |
|
s0 ^= (v >>> 18) | (v << 14); |
|
s0 ^= (v >>> 3); |
|
v = w[i - 2]; |
|
var s1 = (v >>> 17) | (v << 15); |
|
s1 ^= (v >>> 19) | (v << 13); |
|
s1 ^= (v >>> 10); |
|
w[i] = (w[i - 16] + s0 + w[i - 7] + s1) & 0xffffffff; |
|
} |
|
var a = h0; |
|
var b = h1; |
|
var c = h2; |
|
var d = h3; |
|
var e = h4; |
|
var f = h5; |
|
var g = h6; |
|
var h = h7; |
|
for (i = 0; i < 64; i++) { |
|
s1 = (e >>> 6) | (e << 26); |
|
s1 ^= (e >>> 11) | (e << 21); |
|
s1 ^= (e >>> 25) | (e << 7); |
|
var ch = (e & f) ^ (~e & g); |
|
var temp1 = (h + s1 + ch + K[i] + w[i]) & 0xffffffff; |
|
s0 = (a >>> 2) | (a << 30); |
|
s0 ^= (a >>> 13) | (a << 19); |
|
s0 ^= (a >>> 22) | (a << 10); |
|
var maj = (a & b) ^ (a & c) ^ (b & c); |
|
var temp2 = (s0 + maj) & 0xffffffff; |
|
h = g |
|
g = f |
|
f = e |
|
e = (d + temp1) & 0xffffffff; |
|
d = c; |
|
c = b; |
|
b = a; |
|
a = (temp1 + temp2) & 0xffffffff; |
|
} |
|
h0 = (h0 + a) & 0xffffffff; |
|
h1 = (h1 + b) & 0xffffffff; |
|
h2 = (h2 + c) & 0xffffffff; |
|
h3 = (h3 + d) & 0xffffffff; |
|
h4 = (h4 + e) & 0xffffffff; |
|
h5 = (h5 + f) & 0xffffffff; |
|
h6 = (h6 + g) & 0xffffffff; |
|
h7 = (h7 + h) & 0xffffffff; |
|
} |
|
var hash = new Uint8Array(32); |
|
for (i = 0; i < 4; i++) { |
|
hash[i] = (h0 >>> (8 * (3 - i))) & 0xff; |
|
hash[i + 4] = (h1 >>> (8 * (3 - i))) & 0xff; |
|
hash[i + 8] = (h2 >>> (8 * (3 - i))) & 0xff; |
|
hash[i + 12] = (h3 >>> (8 * (3 - i))) & 0xff; |
|
hash[i + 16] = (h4 >>> (8 * (3 - i))) & 0xff; |
|
hash[i + 20] = (h5 >>> (8 * (3 - i))) & 0xff; |
|
hash[i + 24] = (h6 >>> (8 * (3 - i))) & 0xff; |
|
hash[i + 28] = (h7 >>> (8 * (3 - i))) & 0xff; |
|
} |
|
return hash; |
|
} |
|
|
|
// The hash function returns the hash value as a hex string. |
|
// message: the string or byte array to hash |
|
SHA256.hash = function(message) { |
|
var digest = SHA256.digest(message); |
|
var hex = ''; |
|
for (i = 0; i < digest.length; i++) { |
|
var s = '0' + digest[i].toString(16); |
|
hex += s.length > 2 ? s.substring(1) : s; |
|
} |
|
return hex; |
|
} |
|
|
|
|
|
|
|
|
|
|
|
function XHR(options) { |
|
var xhr = new XMLHttpRequest(); |
|
|
|
if ("form" in options) { |
|
options.data = new FormData(options.form); |
|
|
|
if ( !("url" in options) ) |
|
options.url = options.form.action; |
|
|
|
if ( !("method" in options) && ("method" in options.form) ) |
|
options.method = options.form.method; |
|
} |
|
|
|
if ("json" in options) { |
|
options.data = JSON.stringify(options.json); |
|
options.method = "POST"; |
|
options.responseType = "json"; |
|
} |
|
|
|
if ( !("method" in options) ) |
|
options.method = "GET"; |
|
|
|
if ("responseType" in options) |
|
try { |
|
xhr.responseType = options.responseType; |
|
} catch(e) { |
|
console.log("XMLHttpRequest doesn't support responseType of '" + options.responseType + "'"); |
|
xhr.bodgeJSON = true; |
|
} |
|
|
|
if ("onload" in options) { |
|
if (options.responseType == "json" && xhr.bodgeJSON) |
|
xhr.addEventListener("load", function(e) { var e = { target: { response: JSON.parse(e.target.response) } }; options.onload(e) }, false); |
|
else |
|
xhr.addEventListener("load", options.onload, false); |
|
} |
|
|
|
xhr.open(options.method, options.url); |
|
|
|
if ("json" in options) |
|
xhr.setRequestHeader( "Content-Type", "application/json" ); |
|
|
|
if ("contentType" in options) |
|
xhr.setRequestHeader( "Content-Type", options.contentType ); |
|
|
|
xhr.send(options.data); |
|
|
|
return xhr; |
|
} |
|
|
|
|
|
// RIPEMD160 |
|
|
|
|
|
var RIPEMD160 = (function () { |
|
function RIPEMD160() { |
|
this.MDbuf = []; |
|
this.MDbuf[0] = 1732584193; |
|
this.MDbuf[1] = -271733879; |
|
this.MDbuf[2] = -1732584194; |
|
this.MDbuf[3] = 271733878; |
|
this.MDbuf[4] = -1009589776; |
|
this.working = new Int32Array(16); |
|
|
|
this.working_ptr = 0; |
|
this.msglen = 0; |
|
} |
|
RIPEMD160.prototype.reset = function () { |
|
this.MDbuf = []; |
|
this.MDbuf[0] = 1732584193; |
|
this.MDbuf[1] = -271733879; |
|
this.MDbuf[2] = -1732584194; |
|
this.MDbuf[3] = 271733878; |
|
this.MDbuf[4] = -1009589776; |
|
this.working = new Int32Array(16); |
|
this.working_ptr = 0; |
|
this.msglen = 0; |
|
}; |
|
RIPEMD160.prototype.compress = function (X) { |
|
var index = 0; |
|
var a; |
|
var b; |
|
var c; |
|
var d; |
|
var e; |
|
var A; |
|
var B; |
|
var C; |
|
var D; |
|
var E; |
|
var temp; |
|
var s; |
|
A = a = this.MDbuf[0]; |
|
B = b = this.MDbuf[1]; |
|
C = c = this.MDbuf[2]; |
|
D = d = this.MDbuf[3]; |
|
E = e = this.MDbuf[4]; |
|
for (; index < 16; index++) { |
|
temp = a + (b ^ c ^ d) + X[RIPEMD160.IndexArray[0][index]]; |
|
a = e; |
|
e = d; |
|
d = (c << 10) | (c >>> 22); |
|
c = b; |
|
s = RIPEMD160.ArgArray[0][index]; |
|
b = ((temp << s) | (temp >>> (32 - s))) + a; |
|
temp = A + (B ^ (C | ~D)) + X[RIPEMD160.IndexArray[1][index]] + 1352829926; |
|
A = E; |
|
E = D; |
|
D = (C << 10) | (C >>> 22); |
|
C = B; |
|
s = RIPEMD160.ArgArray[1][index]; |
|
B = ((temp << s) | (temp >>> (32 - s))) + A; |
|
} |
|
for (; index < 32; index++) { |
|
temp = a + ((b & c) | (~b & d)) + X[RIPEMD160.IndexArray[0][index]] + 1518500249; |
|
a = e; |
|
e = d; |
|
d = (c << 10) | (c >>> 22); |
|
c = b; |
|
s = RIPEMD160.ArgArray[0][index]; |
|
b = ((temp << s) | (temp >>> (32 - s))) + a; |
|
temp = A + ((B & D) | (C & ~D)) + X[RIPEMD160.IndexArray[1][index]] + 1548603684; |
|
A = E; |
|
E = D; |
|
D = (C << 10) | (C >>> 22); |
|
C = B; |
|
s = RIPEMD160.ArgArray[1][index]; |
|
B = ((temp << s) | (temp >>> (32 - s))) + A; |
|
} |
|
for (; index < 48; index++) { |
|
temp = a + ((b | ~c) ^ d) + X[RIPEMD160.IndexArray[0][index]] + 1859775393; |
|
a = e; |
|
e = d; |
|
d = (c << 10) | (c >>> 22); |
|
c = b; |
|
s = RIPEMD160.ArgArray[0][index]; |
|
b = ((temp << s) | (temp >>> (32 - s))) + a; |
|
temp = A + ((B | ~C) ^ D) + X[RIPEMD160.IndexArray[1][index]] + 1836072691; |
|
A = E; |
|
E = D; |
|
D = (C << 10) | (C >>> 22); |
|
C = B; |
|
s = RIPEMD160.ArgArray[1][index]; |
|
B = ((temp << s) | (temp >>> (32 - s))) + A; |
|
} |
|
for (; index < 64; index++) { |
|
temp = a + ((b & d) | (c & ~d)) + X[RIPEMD160.IndexArray[0][index]] + -1894007588; |
|
a = e; |
|
e = d; |
|
d = (c << 10) | (c >>> 22); |
|
c = b; |
|
s = RIPEMD160.ArgArray[0][index]; |
|
b = ((temp << s) | (temp >>> (32 - s))) + a; |
|
temp = A + ((B & C) | (~B & D)) + X[RIPEMD160.IndexArray[1][index]] + 2053994217; |
|
A = E; |
|
E = D; |
|
D = (C << 10) | (C >>> 22); |
|
C = B; |
|
s = RIPEMD160.ArgArray[1][index]; |
|
B = ((temp << s) | (temp >>> (32 - s))) + A; |
|
} |
|
for (; index < 80; index++) { |
|
temp = a + (b ^ (c | ~d)) + X[RIPEMD160.IndexArray[0][index]] + -1454113458; |
|
a = e; |
|
e = d; |
|
d = (c << 10) | (c >>> 22); |
|
c = b; |
|
s = RIPEMD160.ArgArray[0][index]; |
|
b = ((temp << s) | (temp >>> (32 - s))) + a; |
|
temp = A + (B ^ C ^ D) + X[RIPEMD160.IndexArray[1][index]]; |
|
A = E; |
|
E = D; |
|
D = (C << 10) | (C >>> 22); |
|
C = B; |
|
s = RIPEMD160.ArgArray[1][index]; |
|
B = ((temp << s) | (temp >>> (32 - s))) + A; |
|
} |
|
D += c + this.MDbuf[1]; |
|
this.MDbuf[1] = this.MDbuf[2] + d + E; |
|
this.MDbuf[2] = this.MDbuf[3] + e + A; |
|
this.MDbuf[3] = this.MDbuf[4] + a + B; |
|
this.MDbuf[4] = this.MDbuf[0] + b + C; |
|
this.MDbuf[0] = D; |
|
}; |
|
RIPEMD160.prototype.MDfinish = function (array, lswlen, mswlen) { |
|
var X = array; |
|
X[(lswlen >> 2) & 15] ^= 1 << (((lswlen & 3) << 3) + 7); |
|
if (((lswlen & 63) > 55)) { |
|
this.compress(X); |
|
for (var i = 0; i < 14; i++) { |
|
X[i] = 0; |
|
} |
|
} |
|
X[14] = lswlen << 3; |
|
X[15] = (lswlen >> 29) | (mswlen << 3); |
|
this.compress(X); |
|
}; |
|
RIPEMD160.prototype.update = function (input) { |
|
for (var i = 0; i < input.length; i++) { |
|
this.working[this.working_ptr >> 2] ^= input[i] << ((this.working_ptr & 3) << 3); |
|
this.working_ptr++; |
|
if ((this.working_ptr == 64)) { |
|
this.compress(this.working); |
|
for (var j = 0; j < 16; j++) { |
|
this.working[j] = 0; |
|
} |
|
this.working_ptr = 0; |
|
} |
|
} |
|
this.msglen += input.length; |
|
}; |
|
RIPEMD160.prototype.digestBin = function () { |
|
this.MDfinish(this.working, this.msglen, 0); |
|
//var res = new Int8Array(); |
|
var res = []; |
|
for (var i = 0; i < 20; i++) { |
|
res[i] = ((this.MDbuf[i >> 2] >>> ((i & 3) << 3)) & 255); |
|
} |
|
return new Uint8Array(res); |
|
}; |
|
RIPEMD160.prototype.digest = function (input) { |
|
this.update(new Int8Array(input)); |
|
return this.digestBin(); |
|
}; |
|
RIPEMD160.ArgArray = [[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], [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]]; |
|
RIPEMD160.IndexArray = [[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], [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]]; |
|
return RIPEMD160; |
|
})(); |
|
</script> |
|
</head> |
|
<body> |
|
Making initial call to API... |
|
<p> |
|
If nothing happens then check API is running! |
|
</body> |
|
</html> |