feat(bch-wallet): complete Bitcoin Cash wallet migration
Implemented full wallet functionality for Bitcoin Cash: - Balance Checking: Real-time balance fetching via redundant APIs (Blockchain.com, Blockcypher, FullStack.cash). - Address Compatibility: Full support for both CashAddr (Bech32) and Legacy formats with automatic bidirectional conversion. - Transaction Signing: Implemented BIP-143 signature hashing with SIGHASH_FORKID (0x41) for replay protection. - Transaction History: Robust fetching from multi-provider APIs with detailed transaction formatting. - Sending Functionality: Secure BCH transfers with dynamic fee estimation and manual ECDSA signing. - UI Integration: Updated currency selectors and address management modals for Bitcoin Cash specifics.
This commit is contained in:
parent
4e474003ae
commit
b9d76ea9f0
1342
css/main.css
Normal file
1342
css/main.css
Normal file
File diff suppressed because it is too large
Load Diff
1
css/main.min.css
vendored
Normal file
1
css/main.min.css
vendored
Normal file
File diff suppressed because one or more lines are too long
1466
css/main.scss
Normal file
1466
css/main.scss
Normal file
File diff suppressed because it is too large
Load Diff
3
favicon.svg
Normal file
3
favicon.svg
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
<svg width="128" height="128" viewBox="0 0 128 128" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M75.9466 56.32C74.2933 62.9333 64 59.5733 60.8 58.6667L63.7333 47.04C67.04 48 77.6533 49.3867 75.9466 56.32ZM59.36 64.64L56.16 77.4933C60.1066 78.5067 72.32 82.4 74.1333 75.1467C76.0533 67.5733 63.3066 65.6 59.36 64.64ZM115.733 76.9067C108.587 105.493 79.68 122.88 51.0933 115.733C22.5066 108.587 5.13597 79.68 12.2666 51.0933C19.4133 22.5067 48.32 5.14133 76.9066 12.2667C105.44 19.4133 122.827 48.32 115.733 76.9067ZM75.7866 42.9333L78.1866 33.3333L72.32 32L69.9733 41.2267C68.4266 40.8533 66.88 40.48 65.28 40.16L67.6266 30.72L61.8133 29.3333L59.4133 38.88C58.1333 38.56 56.8533 38.2933 55.68 37.9733L47.6266 35.9467L46.0266 42.1867C46.0266 42.1867 50.4 43.2 50.2933 43.2533C52.6933 43.84 53.12 45.3333 53.0133 46.6667L46.4533 72.96C46.1866 73.7067 45.3333 74.6667 43.7866 74.4C43.84 74.4533 39.52 73.3333 39.52 73.3333L36.64 80L44.2133 81.92C45.6533 82.2933 47.04 82.6667 48.4266 82.9867L45.9733 92.6933L51.84 94.1867L54.24 84.5333C55.84 84.96 57.3866 85.3333 58.88 85.76L56.48 95.3067L62.3466 96.8L64.8 87.0933C74.6666 88.96 82.24 88.2133 85.3333 79.2C88 72 85.3333 67.7333 80 65.0133C83.84 64 86.72 61.6 87.52 56.3733C88.5866 49.28 83.1466 45.4933 75.7866 42.9333Z" fill="#8DC351"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 1.3 KiB |
2268
index.html
Normal file
2268
index.html
Normal file
File diff suppressed because one or more lines are too long
1221
scripts/bchOperator.js
Normal file
1221
scripts/bchOperator.js
Normal file
File diff suppressed because it is too large
Load Diff
1503
scripts/btcOperator.js
Normal file
1503
scripts/btcOperator.js
Normal file
File diff suppressed because it is too large
Load Diff
1
scripts/btcOperator.min.js
vendored
Normal file
1
scripts/btcOperator.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
12
scripts/components.js
Normal file
12
scripts/components.js
Normal file
File diff suppressed because one or more lines are too long
1
scripts/components.min.js
vendored
Normal file
1
scripts/components.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
530
scripts/floCrypto.js
Normal file
530
scripts/floCrypto.js
Normal file
@ -0,0 +1,530 @@
|
|||||||
|
(function (EXPORTS) { //floCrypto v2.3.6a
|
||||||
|
/* FLO Crypto Operators */
|
||||||
|
'use strict';
|
||||||
|
const floCrypto = EXPORTS;
|
||||||
|
|
||||||
|
const p = BigInteger("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F", 16);
|
||||||
|
const ecparams = EllipticCurve.getSECCurveByName("secp256k1");
|
||||||
|
const ascii_alternatives = `‘ '\n’ '\n“ "\n” "\n– --\n— ---\n≥ >=\n≤ <=\n≠ !=\n× *\n÷ /\n← <-\n→ ->\n↔ <->\n⇒ =>\n⇐ <=\n⇔ <=>`;
|
||||||
|
const exponent1 = () => p.add(BigInteger.ONE).divide(BigInteger("4"));
|
||||||
|
coinjs.compressed = true; //defaulting coinjs compressed to true;
|
||||||
|
|
||||||
|
function calculateY(x) {
|
||||||
|
let exp = exponent1();
|
||||||
|
// x is x value of public key in BigInteger format without 02 or 03 or 04 prefix
|
||||||
|
return x.modPow(BigInteger("3"), p).add(BigInteger("7")).mod(p).modPow(exp, p)
|
||||||
|
}
|
||||||
|
|
||||||
|
function getUncompressedPublicKey(compressedPublicKey) {
|
||||||
|
// Fetch x from compressedPublicKey
|
||||||
|
let pubKeyBytes = Crypto.util.hexToBytes(compressedPublicKey);
|
||||||
|
const prefix = pubKeyBytes.shift() // remove prefix
|
||||||
|
let prefix_modulus = prefix % 2;
|
||||||
|
pubKeyBytes.unshift(0) // add prefix 0
|
||||||
|
let x = new BigInteger(pubKeyBytes)
|
||||||
|
let xDecimalValue = x.toString()
|
||||||
|
// Fetch y
|
||||||
|
let y = calculateY(x);
|
||||||
|
let yDecimalValue = y.toString();
|
||||||
|
// verify y value
|
||||||
|
let resultBigInt = y.mod(BigInteger("2"));
|
||||||
|
let check = resultBigInt.toString() % 2;
|
||||||
|
if (prefix_modulus !== check)
|
||||||
|
yDecimalValue = y.negate().mod(p).toString();
|
||||||
|
return {
|
||||||
|
x: xDecimalValue,
|
||||||
|
y: yDecimalValue
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function getSenderPublicKeyString() {
|
||||||
|
let privateKey = ellipticCurveEncryption.senderRandom();
|
||||||
|
var senderPublicKeyString = ellipticCurveEncryption.senderPublicString(privateKey);
|
||||||
|
return {
|
||||||
|
privateKey: privateKey,
|
||||||
|
senderPublicKeyString: senderPublicKeyString
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function deriveSharedKeySender(receiverPublicKeyHex, senderPrivateKey) {
|
||||||
|
let receiverPublicKeyString = getUncompressedPublicKey(receiverPublicKeyHex);
|
||||||
|
var senderDerivedKey = ellipticCurveEncryption.senderSharedKeyDerivation(
|
||||||
|
receiverPublicKeyString.x, receiverPublicKeyString.y, senderPrivateKey);
|
||||||
|
return senderDerivedKey;
|
||||||
|
}
|
||||||
|
|
||||||
|
function deriveSharedKeyReceiver(senderPublicKeyString, receiverPrivateKey) {
|
||||||
|
return ellipticCurveEncryption.receiverSharedKeyDerivation(
|
||||||
|
senderPublicKeyString.XValuePublicString, senderPublicKeyString.YValuePublicString, receiverPrivateKey);
|
||||||
|
}
|
||||||
|
|
||||||
|
function getReceiverPublicKeyString(privateKey) {
|
||||||
|
return ellipticCurveEncryption.receiverPublicString(privateKey);
|
||||||
|
}
|
||||||
|
|
||||||
|
function wifToDecimal(pk_wif, isPubKeyCompressed = false) {
|
||||||
|
let pk = Bitcoin.Base58.decode(pk_wif)
|
||||||
|
pk.shift()
|
||||||
|
pk.splice(-4, 4)
|
||||||
|
//If the private key corresponded to a compressed public key, also drop the last byte (it should be 0x01).
|
||||||
|
if (isPubKeyCompressed == true) pk.pop()
|
||||||
|
pk.unshift(0)
|
||||||
|
let privateKeyDecimal = BigInteger(pk).toString()
|
||||||
|
let privateKeyHex = Crypto.util.bytesToHex(pk)
|
||||||
|
return {
|
||||||
|
privateKeyDecimal: privateKeyDecimal,
|
||||||
|
privateKeyHex: privateKeyHex
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//generate a random Interger within range
|
||||||
|
floCrypto.randInt = function (min, max) {
|
||||||
|
min = Math.ceil(min);
|
||||||
|
max = Math.floor(max);
|
||||||
|
return Math.floor(securedMathRandom() * (max - min + 1)) + min;
|
||||||
|
}
|
||||||
|
|
||||||
|
//generate a random String within length (options : alphaNumeric chars only)
|
||||||
|
floCrypto.randString = function (length, alphaNumeric = true) {
|
||||||
|
var result = '';
|
||||||
|
var characters = alphaNumeric ? 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789' :
|
||||||
|
'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_+-./*?@#&$<>=[]{}():';
|
||||||
|
for (var i = 0; i < length; i++)
|
||||||
|
result += characters.charAt(Math.floor(securedMathRandom() * characters.length));
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Encrypt Data using public-key
|
||||||
|
floCrypto.encryptData = function (data, receiverPublicKeyHex) {
|
||||||
|
var senderECKeyData = getSenderPublicKeyString();
|
||||||
|
var senderDerivedKey = deriveSharedKeySender(receiverPublicKeyHex, senderECKeyData.privateKey);
|
||||||
|
let senderKey = senderDerivedKey.XValue + senderDerivedKey.YValue;
|
||||||
|
let secret = Crypto.AES.encrypt(data, senderKey);
|
||||||
|
return {
|
||||||
|
secret: secret,
|
||||||
|
senderPublicKeyString: senderECKeyData.senderPublicKeyString
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
//Decrypt Data using private-key
|
||||||
|
floCrypto.decryptData = function (data, privateKeyHex) {
|
||||||
|
var receiverECKeyData = {};
|
||||||
|
if (typeof privateKeyHex !== "string") throw new Error("No private key found.");
|
||||||
|
let privateKey = wifToDecimal(privateKeyHex, true);
|
||||||
|
if (typeof privateKey.privateKeyDecimal !== "string") throw new Error("Failed to detremine your private key.");
|
||||||
|
receiverECKeyData.privateKey = privateKey.privateKeyDecimal;
|
||||||
|
var receiverDerivedKey = deriveSharedKeyReceiver(data.senderPublicKeyString, receiverECKeyData.privateKey);
|
||||||
|
let receiverKey = receiverDerivedKey.XValue + receiverDerivedKey.YValue;
|
||||||
|
let decryptMsg = Crypto.AES.decrypt(data.secret, receiverKey);
|
||||||
|
return decryptMsg;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Sign data using private-key
|
||||||
|
floCrypto.signData = function (data, privateKeyHex) {
|
||||||
|
var key = new Bitcoin.ECKey(privateKeyHex);
|
||||||
|
var messageHash = Crypto.SHA256(data);
|
||||||
|
var messageSign = Bitcoin.ECDSA.sign(messageHash, key.priv);
|
||||||
|
var sighex = Crypto.util.bytesToHex(messageSign);
|
||||||
|
return sighex;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Verify signatue of the data using public-key
|
||||||
|
floCrypto.verifySign = function (data, signatureHex, publicKeyHex) {
|
||||||
|
var msgHash = Crypto.SHA256(data);
|
||||||
|
var sigBytes = Crypto.util.hexToBytes(signatureHex);
|
||||||
|
var publicKeyPoint = ecparams.getCurve().decodePointHex(publicKeyHex);
|
||||||
|
var verify = Bitcoin.ECDSA.verify(msgHash, sigBytes, publicKeyPoint);
|
||||||
|
return verify;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Generates a new flo ID and returns private-key, public-key and floID
|
||||||
|
const generateNewID = floCrypto.generateNewID = function () {
|
||||||
|
var key = new Bitcoin.ECKey(false);
|
||||||
|
key.setCompressed(true);
|
||||||
|
return {
|
||||||
|
floID: key.getBitcoinAddress(),
|
||||||
|
pubKey: key.getPubKeyHex(),
|
||||||
|
privKey: key.getBitcoinWalletImportFormat()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Object.defineProperties(floCrypto, {
|
||||||
|
newID: {
|
||||||
|
get: () => generateNewID()
|
||||||
|
},
|
||||||
|
hashID: {
|
||||||
|
value: (str) => {
|
||||||
|
let bytes = ripemd160(Crypto.SHA256(str, { asBytes: true }), { asBytes: true });
|
||||||
|
bytes.unshift(bitjs.pub);
|
||||||
|
var hash = Crypto.SHA256(Crypto.SHA256(bytes, {
|
||||||
|
asBytes: true
|
||||||
|
}), {
|
||||||
|
asBytes: true
|
||||||
|
});
|
||||||
|
var checksum = hash.slice(0, 4);
|
||||||
|
return bitjs.Base58.encode(bytes.concat(checksum));
|
||||||
|
}
|
||||||
|
},
|
||||||
|
tmpID: {
|
||||||
|
get: () => {
|
||||||
|
let bytes = Crypto.util.randomBytes(20);
|
||||||
|
bytes.unshift(bitjs.pub);
|
||||||
|
var hash = Crypto.SHA256(Crypto.SHA256(bytes, {
|
||||||
|
asBytes: true
|
||||||
|
}), {
|
||||||
|
asBytes: true
|
||||||
|
});
|
||||||
|
var checksum = hash.slice(0, 4);
|
||||||
|
return bitjs.Base58.encode(bytes.concat(checksum));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
//Returns public-key from private-key
|
||||||
|
floCrypto.getPubKeyHex = function (privateKeyHex) {
|
||||||
|
if (!privateKeyHex)
|
||||||
|
return null;
|
||||||
|
var key = new Bitcoin.ECKey(privateKeyHex);
|
||||||
|
if (key.priv == null)
|
||||||
|
return null;
|
||||||
|
key.setCompressed(true);
|
||||||
|
return key.getPubKeyHex();
|
||||||
|
}
|
||||||
|
|
||||||
|
//Returns flo-ID from public-key or private-key
|
||||||
|
floCrypto.getFloID = function (keyHex) {
|
||||||
|
if (!keyHex)
|
||||||
|
return null;
|
||||||
|
try {
|
||||||
|
var key = new Bitcoin.ECKey(keyHex);
|
||||||
|
if (key.priv == null)
|
||||||
|
key.setPub(keyHex);
|
||||||
|
return key.getBitcoinAddress();
|
||||||
|
} catch {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
floCrypto.getAddress = function (privateKeyHex, strict = false) {
|
||||||
|
if (!privateKeyHex)
|
||||||
|
return;
|
||||||
|
var key = new Bitcoin.ECKey(privateKeyHex);
|
||||||
|
if (key.priv == null)
|
||||||
|
return null;
|
||||||
|
key.setCompressed(true);
|
||||||
|
let pubKey = key.getPubKeyHex(),
|
||||||
|
version = bitjs.Base58.decode(privateKeyHex)[0];
|
||||||
|
switch (version) {
|
||||||
|
case coinjs.priv: //BTC
|
||||||
|
return coinjs.bech32Address(pubKey).address;
|
||||||
|
case bitjs.priv: //FLO
|
||||||
|
return bitjs.pubkey2address(pubKey);
|
||||||
|
default:
|
||||||
|
return strict ? false : bitjs.pubkey2address(pubKey); //default to FLO address (if strict=false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//Verify the private-key for the given public-key or flo-ID
|
||||||
|
floCrypto.verifyPrivKey = function (privateKeyHex, pubKey_floID, isfloID = true) {
|
||||||
|
if (!privateKeyHex || !pubKey_floID)
|
||||||
|
return false;
|
||||||
|
try {
|
||||||
|
var key = new Bitcoin.ECKey(privateKeyHex);
|
||||||
|
if (key.priv == null)
|
||||||
|
return false;
|
||||||
|
key.setCompressed(true);
|
||||||
|
if (isfloID && pubKey_floID == key.getBitcoinAddress())
|
||||||
|
return true;
|
||||||
|
else if (!isfloID && pubKey_floID.toUpperCase() == key.getPubKeyHex().toUpperCase())
|
||||||
|
return true;
|
||||||
|
else
|
||||||
|
return false;
|
||||||
|
} catch {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
floCrypto.getMultisigAddress = function (publicKeyList, requiredSignatures) {
|
||||||
|
if (!Array.isArray(publicKeyList) || !publicKeyList.length)
|
||||||
|
return null;
|
||||||
|
if (!Number.isInteger(requiredSignatures) || requiredSignatures < 1 || requiredSignatures > publicKeyList.length)
|
||||||
|
return null;
|
||||||
|
try {
|
||||||
|
var multisig = bitjs.pubkeys2multisig(publicKeyList, requiredSignatures);
|
||||||
|
return multisig;
|
||||||
|
} catch {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
floCrypto.decodeRedeemScript = function (redeemScript) {
|
||||||
|
try {
|
||||||
|
var decoded = bitjs.transaction().decodeRedeemScript(redeemScript);
|
||||||
|
return decoded;
|
||||||
|
} catch {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//Check if the given flo-id is valid or not
|
||||||
|
floCrypto.validateFloID = function (floID, regularOnly = false) {
|
||||||
|
if (!floID)
|
||||||
|
return false;
|
||||||
|
try {
|
||||||
|
let addr = new Bitcoin.Address(floID);
|
||||||
|
if (regularOnly && addr.version != Bitcoin.Address.standardVersion)
|
||||||
|
return false;
|
||||||
|
return true;
|
||||||
|
} catch {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//Check if the given address (any blockchain) is valid or not
|
||||||
|
floCrypto.validateAddr = function (address, std = true, bech = true) {
|
||||||
|
let raw = decodeAddress(address);
|
||||||
|
if (!raw)
|
||||||
|
return false;
|
||||||
|
if (typeof raw.version !== 'undefined') { //legacy or segwit
|
||||||
|
if (std == false)
|
||||||
|
return false;
|
||||||
|
else if (std === true || (!Array.isArray(std) && std === raw.version) || (Array.isArray(std) && std.includes(raw.version)))
|
||||||
|
return true;
|
||||||
|
else
|
||||||
|
return false;
|
||||||
|
} else if (typeof raw.bech_version !== 'undefined') { //bech32
|
||||||
|
if (bech === false)
|
||||||
|
return false;
|
||||||
|
else if (bech === true || (!Array.isArray(bech) && bech === raw.bech_version) || (Array.isArray(bech) && bech.includes(raw.bech_version)))
|
||||||
|
return true;
|
||||||
|
else
|
||||||
|
return false;
|
||||||
|
} else //unknown
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Check the public-key (or redeem-script) for the address (any blockchain)
|
||||||
|
floCrypto.verifyPubKey = function (pubKeyHex, address) {
|
||||||
|
let raw = decodeAddress(address);
|
||||||
|
if (!raw)
|
||||||
|
return;
|
||||||
|
let pub_hash = Crypto.util.bytesToHex(ripemd160(Crypto.SHA256(Crypto.util.hexToBytes(pubKeyHex), { asBytes: true })));
|
||||||
|
if (typeof raw.bech_version !== 'undefined' && raw.bytes.length == 32) //bech32-multisig
|
||||||
|
raw.hex = Crypto.util.bytesToHex(ripemd160(raw.bytes, { asBytes: true }));
|
||||||
|
return pub_hash === raw.hex;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Convert the given address (any blockchain) to equivalent floID
|
||||||
|
floCrypto.toFloID = function (address, options = null) {
|
||||||
|
if (!address)
|
||||||
|
return;
|
||||||
|
let raw = decodeAddress(address);
|
||||||
|
if (!raw)
|
||||||
|
return;
|
||||||
|
else if (options) { //if (optional) version check is passed
|
||||||
|
if (typeof raw.version !== 'undefined' && (!options.std || !options.std.includes(raw.version)))
|
||||||
|
return;
|
||||||
|
if (typeof raw.bech_version !== 'undefined' && (!options.bech || !options.bech.includes(raw.bech_version)))
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
raw.bytes.unshift(bitjs.pub);
|
||||||
|
let hash = Crypto.SHA256(Crypto.SHA256(raw.bytes, {
|
||||||
|
asBytes: true
|
||||||
|
}), {
|
||||||
|
asBytes: true
|
||||||
|
});
|
||||||
|
return bitjs.Base58.encode(raw.bytes.concat(hash.slice(0, 4)));
|
||||||
|
}
|
||||||
|
|
||||||
|
//Convert raw address bytes to floID
|
||||||
|
floCrypto.rawToFloID = function (raw_bytes) {
|
||||||
|
if (typeof raw_bytes === 'string')
|
||||||
|
raw_bytes = Crypto.util.hexToBytes(raw_bytes);
|
||||||
|
if (raw_bytes.length != 20)
|
||||||
|
return null;
|
||||||
|
raw_bytes.unshift(bitjs.pub);
|
||||||
|
let hash = Crypto.SHA256(Crypto.SHA256(raw_bytes, {
|
||||||
|
asBytes: true
|
||||||
|
}), {
|
||||||
|
asBytes: true
|
||||||
|
});
|
||||||
|
return bitjs.Base58.encode(raw_bytes.concat(hash.slice(0, 4)));
|
||||||
|
}
|
||||||
|
|
||||||
|
//Convert the given multisig address (any blockchain) to equivalent multisig floID
|
||||||
|
floCrypto.toMultisigFloID = function (address, options = null) {
|
||||||
|
if (!address)
|
||||||
|
return;
|
||||||
|
let raw = decodeAddress(address);
|
||||||
|
if (!raw)
|
||||||
|
return;
|
||||||
|
else if (options) { //if (optional) version check is passed
|
||||||
|
if (typeof raw.version !== 'undefined' && (!options.std || !options.std.includes(raw.version)))
|
||||||
|
return;
|
||||||
|
if (typeof raw.bech_version !== 'undefined' && (!options.bech || !options.bech.includes(raw.bech_version)))
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (typeof raw.bech_version !== 'undefined') {
|
||||||
|
if (raw.bytes.length != 32) return; //multisig bech address have 32 bytes
|
||||||
|
//multisig-bech:hash=SHA256 whereas multisig:hash=r160(SHA265), thus ripemd160 the bytes from multisig-bech
|
||||||
|
raw.bytes = ripemd160(raw.bytes, {
|
||||||
|
asBytes: true
|
||||||
|
});
|
||||||
|
}
|
||||||
|
raw.bytes.unshift(bitjs.multisig);
|
||||||
|
let hash = Crypto.SHA256(Crypto.SHA256(raw.bytes, {
|
||||||
|
asBytes: true
|
||||||
|
}), {
|
||||||
|
asBytes: true
|
||||||
|
});
|
||||||
|
return bitjs.Base58.encode(raw.bytes.concat(hash.slice(0, 4)));
|
||||||
|
}
|
||||||
|
|
||||||
|
//Checks if the given addresses (any blockchain) are same (w.r.t keys)
|
||||||
|
floCrypto.isSameAddr = function (addr1, addr2) {
|
||||||
|
if (!addr1 || !addr2)
|
||||||
|
return;
|
||||||
|
let raw1 = decodeAddress(addr1),
|
||||||
|
raw2 = decodeAddress(addr2);
|
||||||
|
if (!raw1 || !raw2)
|
||||||
|
return false;
|
||||||
|
else {
|
||||||
|
if (typeof raw1.bech_version !== 'undefined' && raw1.bytes.length == 32) //bech32-multisig
|
||||||
|
raw1.hex = Crypto.util.bytesToHex(ripemd160(raw1.bytes, { asBytes: true }));
|
||||||
|
if (typeof raw2.bech_version !== 'undefined' && raw2.bytes.length == 32) //bech32-multisig
|
||||||
|
raw2.hex = Crypto.util.bytesToHex(ripemd160(raw2.bytes, { asBytes: true }));
|
||||||
|
return raw1.hex === raw2.hex;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const decodeAddress = floCrypto.decodeAddr = function (address) {
|
||||||
|
if (!address)
|
||||||
|
return;
|
||||||
|
else if (address.length == 33 || address.length == 34) { //legacy encoding
|
||||||
|
let decode = bitjs.Base58.decode(address);
|
||||||
|
let bytes = decode.slice(0, decode.length - 4);
|
||||||
|
let checksum = decode.slice(decode.length - 4),
|
||||||
|
hash = Crypto.SHA256(Crypto.SHA256(bytes, {
|
||||||
|
asBytes: true
|
||||||
|
}), {
|
||||||
|
asBytes: true
|
||||||
|
});
|
||||||
|
return (hash[0] != checksum[0] || hash[1] != checksum[1] || hash[2] != checksum[2] || hash[3] != checksum[3]) ? null : {
|
||||||
|
version: bytes.shift(),
|
||||||
|
hex: Crypto.util.bytesToHex(bytes),
|
||||||
|
bytes
|
||||||
|
}
|
||||||
|
} else if (address.length == 42 || address.length == 62) { //bech encoding
|
||||||
|
let decode = coinjs.bech32_decode(address);
|
||||||
|
if (decode) {
|
||||||
|
let bytes = decode.data;
|
||||||
|
let bech_version = bytes.shift();
|
||||||
|
bytes = coinjs.bech32_convert(bytes, 5, 8, false);
|
||||||
|
return {
|
||||||
|
bech_version,
|
||||||
|
hrp: decode.hrp,
|
||||||
|
hex: Crypto.util.bytesToHex(bytes),
|
||||||
|
bytes
|
||||||
|
}
|
||||||
|
} else
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//Split the str using shamir's Secret and Returns the shares
|
||||||
|
floCrypto.createShamirsSecretShares = function (str, total_shares, threshold_limit) {
|
||||||
|
try {
|
||||||
|
if (str.length > 0) {
|
||||||
|
var strHex = shamirSecretShare.str2hex(str);
|
||||||
|
var shares = shamirSecretShare.share(strHex, total_shares, threshold_limit);
|
||||||
|
return shares;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
} catch {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//Returns the retrived secret by combining the shamirs shares
|
||||||
|
const retrieveShamirSecret = floCrypto.retrieveShamirSecret = function (sharesArray) {
|
||||||
|
try {
|
||||||
|
if (sharesArray.length > 0) {
|
||||||
|
var comb = shamirSecretShare.combine(sharesArray.slice(0, sharesArray.length));
|
||||||
|
comb = shamirSecretShare.hex2str(comb);
|
||||||
|
return comb;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
} catch {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//Verifies the shares and str
|
||||||
|
floCrypto.verifyShamirsSecret = function (sharesArray, str) {
|
||||||
|
if (!str)
|
||||||
|
return null;
|
||||||
|
else if (retrieveShamirSecret(sharesArray) === str)
|
||||||
|
return true;
|
||||||
|
else
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const validateASCII = floCrypto.validateASCII = function (string, bool = true) {
|
||||||
|
if (typeof string !== "string")
|
||||||
|
return null;
|
||||||
|
if (bool) {
|
||||||
|
let x;
|
||||||
|
for (let i = 0; i < string.length; i++) {
|
||||||
|
x = string.charCodeAt(i);
|
||||||
|
if (x < 32 || x > 127)
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
let x, invalids = {};
|
||||||
|
for (let i = 0; i < string.length; i++) {
|
||||||
|
x = string.charCodeAt(i);
|
||||||
|
if (x < 32 || x > 127)
|
||||||
|
if (x in invalids)
|
||||||
|
invalids[string[i]].push(i)
|
||||||
|
else
|
||||||
|
invalids[string[i]] = [i];
|
||||||
|
}
|
||||||
|
if (Object.keys(invalids).length)
|
||||||
|
return invalids;
|
||||||
|
else
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
floCrypto.convertToASCII = function (string, mode = 'soft-remove') {
|
||||||
|
let chars = validateASCII(string, false);
|
||||||
|
if (chars === true)
|
||||||
|
return string;
|
||||||
|
else if (chars === null)
|
||||||
|
return null;
|
||||||
|
let convertor, result = string,
|
||||||
|
refAlt = {};
|
||||||
|
ascii_alternatives.split('\n').forEach(a => refAlt[a[0]] = a.slice(2));
|
||||||
|
mode = mode.toLowerCase();
|
||||||
|
if (mode === "hard-unicode")
|
||||||
|
convertor = (c) => `\\u${('000' + c.charCodeAt().toString(16)).slice(-4)}`;
|
||||||
|
else if (mode === "soft-unicode")
|
||||||
|
convertor = (c) => refAlt[c] || `\\u${('000' + c.charCodeAt().toString(16)).slice(-4)}`;
|
||||||
|
else if (mode === "hard-remove")
|
||||||
|
convertor = c => "";
|
||||||
|
else if (mode === "soft-remove")
|
||||||
|
convertor = c => refAlt[c] || "";
|
||||||
|
else
|
||||||
|
return null;
|
||||||
|
for (let c in chars)
|
||||||
|
result = result.replaceAll(c, convertor(c));
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
floCrypto.revertUnicode = function (string) {
|
||||||
|
return string.replace(/\\u[\dA-F]{4}/gi,
|
||||||
|
m => String.fromCharCode(parseInt(m.replace(/\\u/g, ''), 16)));
|
||||||
|
}
|
||||||
|
|
||||||
|
})('object' === typeof module ? module.exports : window.floCrypto = {});
|
||||||
46
scripts/floEthereum.js
Normal file
46
scripts/floEthereum.js
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
(function (EXPORTS) { //floEthereum v1.0.1a
|
||||||
|
/* FLO Ethereum Operators */
|
||||||
|
/* Make sure you added Taproot, Keccak, FLO and BTC Libraries before */
|
||||||
|
'use strict';
|
||||||
|
const floEthereum = EXPORTS;
|
||||||
|
|
||||||
|
const ethPrivateKeyFromWif = floEthereum.ethPrivateKeyFromWif = function (privateKey,) {
|
||||||
|
return coinjs.wif2privkey(privateKey).privkey;
|
||||||
|
}
|
||||||
|
|
||||||
|
const ethAddressFromPrivateKey = floEthereum.ethAddressFromPrivateKey = function (privateKey, onlyEvenY = false) {
|
||||||
|
var t1, t1_x, t1_y, t1_y_BigInt, t2, t3, t4;
|
||||||
|
var groupOrder = BigInt("0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F");
|
||||||
|
|
||||||
|
t1 = bitjs.newPubkey(privateKey);
|
||||||
|
t1_x = t1.slice(2, 66); t1_y = t1.slice(-64);
|
||||||
|
if (onlyEvenY) {
|
||||||
|
t1_y_BigInt = BigInt("0x" + t1_y);
|
||||||
|
if (t1_y_BigInt % 2n !== 0n) { t1_y_BigInt = (groupOrder - t1_y_BigInt) % groupOrder; t1_y = t1_y_BigInt.toString(16) }
|
||||||
|
};
|
||||||
|
|
||||||
|
t2 = t1_x.toString(16) + t1_y.toString(16);
|
||||||
|
t3 = keccak.keccak_256(Crypto.util.hexToBytes(t2));
|
||||||
|
t4 = keccak.extractLast20Bytes(t3);
|
||||||
|
return "0x" + t4;
|
||||||
|
}
|
||||||
|
|
||||||
|
const ethAddressFromCompressedPublicKey = floEthereum.ethAddressFromCompressedPublicKey = function (compressedPublicKey) {
|
||||||
|
var t1, t2, t3, t4;
|
||||||
|
t1 = coinjs.compressedToUncompressed(compressedPublicKey);
|
||||||
|
t2 = t1.slice(2);
|
||||||
|
t3 = keccak.keccak_256(Crypto.util.hexToBytes(t2));
|
||||||
|
t4 = keccak.extractLast20Bytes(t3);
|
||||||
|
return "0x" + t4;
|
||||||
|
}
|
||||||
|
|
||||||
|
const ethAddressFromUncompressedPublicKey = floEthereum.ethAddressFromUncompressedPublicKey = function (unCompressedPublicKey) {
|
||||||
|
var t1, t2, t3, t4;
|
||||||
|
t1 = unCompressedPublicKey;
|
||||||
|
t2 = t1.slice(2);
|
||||||
|
t3 = keccak.keccak_256(Crypto.util.hexToBytes(t2));
|
||||||
|
t4 = keccak.extractLast20Bytes(t3);
|
||||||
|
return "0x" + t4;
|
||||||
|
}
|
||||||
|
|
||||||
|
})('object' === typeof module ? module.exports : window.floEthereum = {});
|
||||||
1
scripts/floEthereum.min.js
vendored
Normal file
1
scripts/floEthereum.min.js
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
!function(EXPORTS){"use strict";const floEthereum="object"===typeof module?module.exports:window.floEthereum={};floEthereum.ethPrivateKeyFromWif=function(privateKey){return coinjs.wif2privkey(privateKey).privkey},floEthereum.ethAddressFromPrivateKey=function(privateKey,onlyEvenY=!1){var t1,t1_x,t1_y,t1_y_BigInt,t2,t3,groupOrder=BigInt("0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F");return t1_x=(t1=bitjs.newPubkey(privateKey)).slice(2,66),t1_y=t1.slice(-64),onlyEvenY&&(t1_y_BigInt=BigInt("0x"+t1_y))%2n!==0n&&(t1_y=(t1_y_BigInt=(groupOrder-t1_y_BigInt)%groupOrder).toString(16)),t2=t1_x.toString(16)+t1_y.toString(16),t3=keccak.keccak_256(Crypto.util.hexToBytes(t2)),"0x"+keccak.extractLast20Bytes(t3)},floEthereum.ethAddressFromCompressedPublicKey=function(compressedPublicKey){var t2,t3;return t2=coinjs.compressedToUncompressed(compressedPublicKey).slice(2),t3=keccak.keccak_256(Crypto.util.hexToBytes(t2)),"0x"+keccak.extractLast20Bytes(t3)},floEthereum.ethAddressFromUncompressedPublicKey=function(unCompressedPublicKey){var t2,t3;return t2=unCompressedPublicKey.slice(2),t3=keccak.keccak_256(Crypto.util.hexToBytes(t2)),"0x"+keccak.extractLast20Bytes(t3)}}();
|
||||||
673
scripts/keccak.js
Normal file
673
scripts/keccak.js
Normal file
@ -0,0 +1,673 @@
|
|||||||
|
(function () {
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
var INPUT_ERROR = 'input is invalid type';
|
||||||
|
var FINALIZE_ERROR = 'finalize already called';
|
||||||
|
var WINDOW = typeof window === 'object';
|
||||||
|
var root = WINDOW ? (window.keccak = window.keccak || {}) : {};
|
||||||
|
if (root.JS_SHA3_NO_WINDOW) {
|
||||||
|
WINDOW = false;
|
||||||
|
}
|
||||||
|
var WEB_WORKER = !WINDOW && typeof self === 'object';
|
||||||
|
var NODE_JS = !root.JS_SHA3_NO_NODE_JS && typeof process === 'object' && process.versions && process.versions.node;
|
||||||
|
if (NODE_JS) {
|
||||||
|
root = global;
|
||||||
|
} else if (WEB_WORKER) {
|
||||||
|
root = self;
|
||||||
|
}
|
||||||
|
var COMMON_JS = !root.JS_SHA3_NO_COMMON_JS && typeof module === 'object' && module.exports;
|
||||||
|
var AMD = typeof define === 'function' && define.amd;
|
||||||
|
var ARRAY_BUFFER = !root.JS_SHA3_NO_ARRAY_BUFFER && typeof ArrayBuffer !== 'undefined';
|
||||||
|
var HEX_CHARS = '0123456789abcdef'.split('');
|
||||||
|
var SHAKE_PADDING = [31, 7936, 2031616, 520093696];
|
||||||
|
var CSHAKE_PADDING = [4, 1024, 262144, 67108864];
|
||||||
|
var KECCAK_PADDING = [1, 256, 65536, 16777216];
|
||||||
|
var PADDING = [6, 1536, 393216, 100663296];
|
||||||
|
var SHIFT = [0, 8, 16, 24];
|
||||||
|
var RC = [1, 0, 32898, 0, 32906, 2147483648, 2147516416, 2147483648, 32907, 0, 2147483649,
|
||||||
|
0, 2147516545, 2147483648, 32777, 2147483648, 138, 0, 136, 0, 2147516425, 0,
|
||||||
|
2147483658, 0, 2147516555, 0, 139, 2147483648, 32905, 2147483648, 32771,
|
||||||
|
2147483648, 32770, 2147483648, 128, 2147483648, 32778, 0, 2147483658, 2147483648,
|
||||||
|
2147516545, 2147483648, 32896, 2147483648, 2147483649, 0, 2147516424, 2147483648];
|
||||||
|
var BITS = [224, 256, 384, 512];
|
||||||
|
var SHAKE_BITS = [128, 256];
|
||||||
|
var OUTPUT_TYPES = ['hex', 'buffer', 'arrayBuffer', 'array', 'digest'];
|
||||||
|
var CSHAKE_BYTEPAD = {
|
||||||
|
'128': 168,
|
||||||
|
'256': 136
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
var isArray = root.JS_SHA3_NO_NODE_JS || !Array.isArray
|
||||||
|
? function (obj) {
|
||||||
|
return Object.prototype.toString.call(obj) === '[object Array]';
|
||||||
|
}
|
||||||
|
: Array.isArray;
|
||||||
|
|
||||||
|
var isView = (ARRAY_BUFFER && (root.JS_SHA3_NO_ARRAY_BUFFER_IS_VIEW || !ArrayBuffer.isView))
|
||||||
|
? function (obj) {
|
||||||
|
return typeof obj === 'object' && obj.buffer && obj.buffer.constructor === ArrayBuffer;
|
||||||
|
}
|
||||||
|
: ArrayBuffer.isView;
|
||||||
|
|
||||||
|
// [message: string, isString: bool]
|
||||||
|
var formatMessage = function (message) {
|
||||||
|
var type = typeof message;
|
||||||
|
if (type === 'string') {
|
||||||
|
return [message, true];
|
||||||
|
}
|
||||||
|
if (type !== 'object' || message === null) {
|
||||||
|
throw new Error(INPUT_ERROR);
|
||||||
|
}
|
||||||
|
if (ARRAY_BUFFER && message.constructor === ArrayBuffer) {
|
||||||
|
return [new Uint8Array(message), false];
|
||||||
|
}
|
||||||
|
if (!isArray(message) && !isView(message)) {
|
||||||
|
throw new Error(INPUT_ERROR);
|
||||||
|
}
|
||||||
|
return [message, false];
|
||||||
|
}
|
||||||
|
|
||||||
|
var empty = function (message) {
|
||||||
|
return formatMessage(message)[0].length === 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
var createOutputMethod = function (bits, padding, outputType) {
|
||||||
|
return function (message) {
|
||||||
|
return new Keccak(bits, padding, bits).update(message)[outputType]();
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
var createShakeOutputMethod = function (bits, padding, outputType) {
|
||||||
|
return function (message, outputBits) {
|
||||||
|
return new Keccak(bits, padding, outputBits).update(message)[outputType]();
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
var createCshakeOutputMethod = function (bits, padding, outputType) {
|
||||||
|
return function (message, outputBits, n, s) {
|
||||||
|
return methods['cshake' + bits].update(message, outputBits, n, s)[outputType]();
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
var createKmacOutputMethod = function (bits, padding, outputType) {
|
||||||
|
return function (key, message, outputBits, s) {
|
||||||
|
return methods['kmac' + bits].update(key, message, outputBits, s)[outputType]();
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
var createOutputMethods = function (method, createMethod, bits, padding) {
|
||||||
|
for (var i = 0; i < OUTPUT_TYPES.length; ++i) {
|
||||||
|
var type = OUTPUT_TYPES[i];
|
||||||
|
method[type] = createMethod(bits, padding, type);
|
||||||
|
}
|
||||||
|
return method;
|
||||||
|
};
|
||||||
|
|
||||||
|
var createMethod = function (bits, padding) {
|
||||||
|
var method = createOutputMethod(bits, padding, 'hex');
|
||||||
|
method.create = function () {
|
||||||
|
return new Keccak(bits, padding, bits);
|
||||||
|
};
|
||||||
|
method.update = function (message) {
|
||||||
|
return method.create().update(message);
|
||||||
|
};
|
||||||
|
return createOutputMethods(method, createOutputMethod, bits, padding);
|
||||||
|
};
|
||||||
|
|
||||||
|
var createShakeMethod = function (bits, padding) {
|
||||||
|
var method = createShakeOutputMethod(bits, padding, 'hex');
|
||||||
|
method.create = function (outputBits) {
|
||||||
|
return new Keccak(bits, padding, outputBits);
|
||||||
|
};
|
||||||
|
method.update = function (message, outputBits) {
|
||||||
|
return method.create(outputBits).update(message);
|
||||||
|
};
|
||||||
|
return createOutputMethods(method, createShakeOutputMethod, bits, padding);
|
||||||
|
};
|
||||||
|
|
||||||
|
var createCshakeMethod = function (bits, padding) {
|
||||||
|
var w = CSHAKE_BYTEPAD[bits];
|
||||||
|
var method = createCshakeOutputMethod(bits, padding, 'hex');
|
||||||
|
method.create = function (outputBits, n, s) {
|
||||||
|
if (empty(n) && empty(s)) {
|
||||||
|
return methods['shake' + bits].create(outputBits);
|
||||||
|
} else {
|
||||||
|
return new Keccak(bits, padding, outputBits).bytepad([n, s], w);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
method.update = function (message, outputBits, n, s) {
|
||||||
|
return method.create(outputBits, n, s).update(message);
|
||||||
|
};
|
||||||
|
return createOutputMethods(method, createCshakeOutputMethod, bits, padding);
|
||||||
|
};
|
||||||
|
|
||||||
|
var createKmacMethod = function (bits, padding) {
|
||||||
|
var w = CSHAKE_BYTEPAD[bits];
|
||||||
|
var method = createKmacOutputMethod(bits, padding, 'hex');
|
||||||
|
method.create = function (key, outputBits, s) {
|
||||||
|
return new Kmac(bits, padding, outputBits).bytepad(['KMAC', s], w).bytepad([key], w);
|
||||||
|
};
|
||||||
|
method.update = function (key, message, outputBits, s) {
|
||||||
|
return method.create(key, outputBits, s).update(message);
|
||||||
|
};
|
||||||
|
return createOutputMethods(method, createKmacOutputMethod, bits, padding);
|
||||||
|
};
|
||||||
|
|
||||||
|
var algorithms = [
|
||||||
|
{ name: 'keccak', padding: KECCAK_PADDING, bits: BITS, createMethod: createMethod },
|
||||||
|
{ name: 'sha3', padding: PADDING, bits: BITS, createMethod: createMethod },
|
||||||
|
{ name: 'shake', padding: SHAKE_PADDING, bits: SHAKE_BITS, createMethod: createShakeMethod },
|
||||||
|
{ name: 'cshake', padding: CSHAKE_PADDING, bits: SHAKE_BITS, createMethod: createCshakeMethod },
|
||||||
|
{ name: 'kmac', padding: CSHAKE_PADDING, bits: SHAKE_BITS, createMethod: createKmacMethod }
|
||||||
|
];
|
||||||
|
|
||||||
|
var methods = {}, methodNames = [];
|
||||||
|
|
||||||
|
for (var i = 0; i < algorithms.length; ++i) {
|
||||||
|
var algorithm = algorithms[i];
|
||||||
|
var bits = algorithm.bits;
|
||||||
|
for (var j = 0; j < bits.length; ++j) {
|
||||||
|
var methodName = algorithm.name + '_' + bits[j];
|
||||||
|
methodNames.push(methodName);
|
||||||
|
methods[methodName] = algorithm.createMethod(bits[j], algorithm.padding);
|
||||||
|
if (algorithm.name !== 'sha3') {
|
||||||
|
var newMethodName = algorithm.name + bits[j];
|
||||||
|
methodNames.push(newMethodName);
|
||||||
|
methods[newMethodName] = methods[methodName];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
methodNames.push("extractLast20Bytes");
|
||||||
|
methods["extractLast20Bytes"] = extractLast20Bytes;
|
||||||
|
|
||||||
|
|
||||||
|
function Keccak(bits, padding, outputBits) {
|
||||||
|
this.blocks = [];
|
||||||
|
this.s = [];
|
||||||
|
this.padding = padding;
|
||||||
|
this.outputBits = outputBits;
|
||||||
|
this.reset = true;
|
||||||
|
this.finalized = false;
|
||||||
|
this.block = 0;
|
||||||
|
this.start = 0;
|
||||||
|
this.blockCount = (1600 - (bits << 1)) >> 5;
|
||||||
|
this.byteCount = this.blockCount << 2;
|
||||||
|
this.outputBlocks = outputBits >> 5;
|
||||||
|
this.extraBytes = (outputBits & 31) >> 3;
|
||||||
|
|
||||||
|
for (var i = 0; i < 50; ++i) {
|
||||||
|
this.s[i] = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Keccak.prototype.update = function (message) {
|
||||||
|
if (this.finalized) {
|
||||||
|
throw new Error(FINALIZE_ERROR);
|
||||||
|
}
|
||||||
|
var result = formatMessage(message);
|
||||||
|
message = result[0];
|
||||||
|
var isString = result[1];
|
||||||
|
var blocks = this.blocks, byteCount = this.byteCount, length = message.length,
|
||||||
|
blockCount = this.blockCount, index = 0, s = this.s, i, code;
|
||||||
|
|
||||||
|
while (index < length) {
|
||||||
|
if (this.reset) {
|
||||||
|
this.reset = false;
|
||||||
|
blocks[0] = this.block;
|
||||||
|
for (i = 1; i < blockCount + 1; ++i) {
|
||||||
|
blocks[i] = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (isString) {
|
||||||
|
for (i = this.start; index < length && i < byteCount; ++index) {
|
||||||
|
code = message.charCodeAt(index);
|
||||||
|
if (code < 0x80) {
|
||||||
|
blocks[i >> 2] |= code << SHIFT[i++ & 3];
|
||||||
|
} else if (code < 0x800) {
|
||||||
|
blocks[i >> 2] |= (0xc0 | (code >> 6)) << SHIFT[i++ & 3];
|
||||||
|
blocks[i >> 2] |= (0x80 | (code & 0x3f)) << SHIFT[i++ & 3];
|
||||||
|
} else if (code < 0xd800 || code >= 0xe000) {
|
||||||
|
blocks[i >> 2] |= (0xe0 | (code >> 12)) << SHIFT[i++ & 3];
|
||||||
|
blocks[i >> 2] |= (0x80 | ((code >> 6) & 0x3f)) << SHIFT[i++ & 3];
|
||||||
|
blocks[i >> 2] |= (0x80 | (code & 0x3f)) << SHIFT[i++ & 3];
|
||||||
|
} else {
|
||||||
|
code = 0x10000 + (((code & 0x3ff) << 10) | (message.charCodeAt(++index) & 0x3ff));
|
||||||
|
blocks[i >> 2] |= (0xf0 | (code >> 18)) << SHIFT[i++ & 3];
|
||||||
|
blocks[i >> 2] |= (0x80 | ((code >> 12) & 0x3f)) << SHIFT[i++ & 3];
|
||||||
|
blocks[i >> 2] |= (0x80 | ((code >> 6) & 0x3f)) << SHIFT[i++ & 3];
|
||||||
|
blocks[i >> 2] |= (0x80 | (code & 0x3f)) << SHIFT[i++ & 3];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for (i = this.start; index < length && i < byteCount; ++index) {
|
||||||
|
blocks[i >> 2] |= message[index] << SHIFT[i++ & 3];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.lastByteIndex = i;
|
||||||
|
if (i >= byteCount) {
|
||||||
|
this.start = i - byteCount;
|
||||||
|
this.block = blocks[blockCount];
|
||||||
|
for (i = 0; i < blockCount; ++i) {
|
||||||
|
s[i] ^= blocks[i];
|
||||||
|
}
|
||||||
|
f(s);
|
||||||
|
this.reset = true;
|
||||||
|
} else {
|
||||||
|
this.start = i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
};
|
||||||
|
|
||||||
|
Keccak.prototype.encode = function (x, right) {
|
||||||
|
var o = x & 255, n = 1;
|
||||||
|
var bytes = [o];
|
||||||
|
x = x >> 8;
|
||||||
|
o = x & 255;
|
||||||
|
while (o > 0) {
|
||||||
|
bytes.unshift(o);
|
||||||
|
x = x >> 8;
|
||||||
|
o = x & 255;
|
||||||
|
++n;
|
||||||
|
}
|
||||||
|
if (right) {
|
||||||
|
bytes.push(n);
|
||||||
|
} else {
|
||||||
|
bytes.unshift(n);
|
||||||
|
}
|
||||||
|
this.update(bytes);
|
||||||
|
return bytes.length;
|
||||||
|
};
|
||||||
|
|
||||||
|
Keccak.prototype.encodeString = function (str) {
|
||||||
|
var result = formatMessage(str);
|
||||||
|
str = result[0];
|
||||||
|
var isString = result[1];
|
||||||
|
var bytes = 0, length = str.length;
|
||||||
|
if (isString) {
|
||||||
|
for (var i = 0; i < str.length; ++i) {
|
||||||
|
var code = str.charCodeAt(i);
|
||||||
|
if (code < 0x80) {
|
||||||
|
bytes += 1;
|
||||||
|
} else if (code < 0x800) {
|
||||||
|
bytes += 2;
|
||||||
|
} else if (code < 0xd800 || code >= 0xe000) {
|
||||||
|
bytes += 3;
|
||||||
|
} else {
|
||||||
|
code = 0x10000 + (((code & 0x3ff) << 10) | (str.charCodeAt(++i) & 0x3ff));
|
||||||
|
bytes += 4;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
bytes = length;
|
||||||
|
}
|
||||||
|
bytes += this.encode(bytes * 8);
|
||||||
|
this.update(str);
|
||||||
|
return bytes;
|
||||||
|
};
|
||||||
|
|
||||||
|
Keccak.prototype.bytepad = function (strs, w) {
|
||||||
|
var bytes = this.encode(w);
|
||||||
|
for (var i = 0; i < strs.length; ++i) {
|
||||||
|
bytes += this.encodeString(strs[i]);
|
||||||
|
}
|
||||||
|
var paddingBytes = (w - bytes % w) % w;
|
||||||
|
var zeros = [];
|
||||||
|
zeros.length = paddingBytes;
|
||||||
|
this.update(zeros);
|
||||||
|
return this;
|
||||||
|
};
|
||||||
|
|
||||||
|
Keccak.prototype.finalize = function () {
|
||||||
|
if (this.finalized) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.finalized = true;
|
||||||
|
var blocks = this.blocks, i = this.lastByteIndex, blockCount = this.blockCount, s = this.s;
|
||||||
|
blocks[i >> 2] |= this.padding[i & 3];
|
||||||
|
if (this.lastByteIndex === this.byteCount) {
|
||||||
|
blocks[0] = blocks[blockCount];
|
||||||
|
for (i = 1; i < blockCount + 1; ++i) {
|
||||||
|
blocks[i] = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
blocks[blockCount - 1] |= 0x80000000;
|
||||||
|
for (i = 0; i < blockCount; ++i) {
|
||||||
|
s[i] ^= blocks[i];
|
||||||
|
}
|
||||||
|
f(s);
|
||||||
|
};
|
||||||
|
|
||||||
|
Keccak.prototype.toString = Keccak.prototype.hex = function () {
|
||||||
|
this.finalize();
|
||||||
|
|
||||||
|
var blockCount = this.blockCount, s = this.s, outputBlocks = this.outputBlocks,
|
||||||
|
extraBytes = this.extraBytes, i = 0, j = 0;
|
||||||
|
var hex = '', block;
|
||||||
|
while (j < outputBlocks) {
|
||||||
|
for (i = 0; i < blockCount && j < outputBlocks; ++i, ++j) {
|
||||||
|
block = s[i];
|
||||||
|
hex += HEX_CHARS[(block >> 4) & 0x0F] + HEX_CHARS[block & 0x0F] +
|
||||||
|
HEX_CHARS[(block >> 12) & 0x0F] + HEX_CHARS[(block >> 8) & 0x0F] +
|
||||||
|
HEX_CHARS[(block >> 20) & 0x0F] + HEX_CHARS[(block >> 16) & 0x0F] +
|
||||||
|
HEX_CHARS[(block >> 28) & 0x0F] + HEX_CHARS[(block >> 24) & 0x0F];
|
||||||
|
}
|
||||||
|
if (j % blockCount === 0) {
|
||||||
|
f(s);
|
||||||
|
i = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (extraBytes) {
|
||||||
|
block = s[i];
|
||||||
|
hex += HEX_CHARS[(block >> 4) & 0x0F] + HEX_CHARS[block & 0x0F];
|
||||||
|
if (extraBytes > 1) {
|
||||||
|
hex += HEX_CHARS[(block >> 12) & 0x0F] + HEX_CHARS[(block >> 8) & 0x0F];
|
||||||
|
}
|
||||||
|
if (extraBytes > 2) {
|
||||||
|
hex += HEX_CHARS[(block >> 20) & 0x0F] + HEX_CHARS[(block >> 16) & 0x0F];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return hex;
|
||||||
|
};
|
||||||
|
|
||||||
|
Keccak.prototype.arrayBuffer = function () {
|
||||||
|
this.finalize();
|
||||||
|
|
||||||
|
var blockCount = this.blockCount, s = this.s, outputBlocks = this.outputBlocks,
|
||||||
|
extraBytes = this.extraBytes, i = 0, j = 0;
|
||||||
|
var bytes = this.outputBits >> 3;
|
||||||
|
var buffer;
|
||||||
|
if (extraBytes) {
|
||||||
|
buffer = new ArrayBuffer((outputBlocks + 1) << 2);
|
||||||
|
} else {
|
||||||
|
buffer = new ArrayBuffer(bytes);
|
||||||
|
}
|
||||||
|
var array = new Uint32Array(buffer);
|
||||||
|
while (j < outputBlocks) {
|
||||||
|
for (i = 0; i < blockCount && j < outputBlocks; ++i, ++j) {
|
||||||
|
array[j] = s[i];
|
||||||
|
}
|
||||||
|
if (j % blockCount === 0) {
|
||||||
|
f(s);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (extraBytes) {
|
||||||
|
array[i] = s[i];
|
||||||
|
buffer = buffer.slice(0, bytes);
|
||||||
|
}
|
||||||
|
return buffer;
|
||||||
|
};
|
||||||
|
|
||||||
|
Keccak.prototype.buffer = Keccak.prototype.arrayBuffer;
|
||||||
|
|
||||||
|
Keccak.prototype.digest = Keccak.prototype.array = function () {
|
||||||
|
this.finalize();
|
||||||
|
|
||||||
|
var blockCount = this.blockCount, s = this.s, outputBlocks = this.outputBlocks,
|
||||||
|
extraBytes = this.extraBytes, i = 0, j = 0;
|
||||||
|
var array = [], offset, block;
|
||||||
|
while (j < outputBlocks) {
|
||||||
|
for (i = 0; i < blockCount && j < outputBlocks; ++i, ++j) {
|
||||||
|
offset = j << 2;
|
||||||
|
block = s[i];
|
||||||
|
array[offset] = block & 0xFF;
|
||||||
|
array[offset + 1] = (block >> 8) & 0xFF;
|
||||||
|
array[offset + 2] = (block >> 16) & 0xFF;
|
||||||
|
array[offset + 3] = (block >> 24) & 0xFF;
|
||||||
|
}
|
||||||
|
if (j % blockCount === 0) {
|
||||||
|
f(s);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (extraBytes) {
|
||||||
|
offset = j << 2;
|
||||||
|
block = s[i];
|
||||||
|
array[offset] = block & 0xFF;
|
||||||
|
if (extraBytes > 1) {
|
||||||
|
array[offset + 1] = (block >> 8) & 0xFF;
|
||||||
|
}
|
||||||
|
if (extraBytes > 2) {
|
||||||
|
array[offset + 2] = (block >> 16) & 0xFF;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return array;
|
||||||
|
};
|
||||||
|
|
||||||
|
function Kmac(bits, padding, outputBits) {
|
||||||
|
Keccak.call(this, bits, padding, outputBits);
|
||||||
|
}
|
||||||
|
|
||||||
|
Kmac.prototype = new Keccak();
|
||||||
|
|
||||||
|
Kmac.prototype.finalize = function () {
|
||||||
|
this.encode(this.outputBits, true);
|
||||||
|
return Keccak.prototype.finalize.call(this);
|
||||||
|
};
|
||||||
|
|
||||||
|
var f = function (s) {
|
||||||
|
var h, l, n, c0, c1, c2, c3, c4, c5, c6, c7, c8, c9,
|
||||||
|
b0, b1, b2, b3, b4, b5, b6, b7, b8, b9, b10, b11, b12, b13, b14, b15, b16, b17,
|
||||||
|
b18, b19, b20, b21, b22, b23, b24, b25, b26, b27, b28, b29, b30, b31, b32, b33,
|
||||||
|
b34, b35, b36, b37, b38, b39, b40, b41, b42, b43, b44, b45, b46, b47, b48, b49;
|
||||||
|
for (n = 0; n < 48; n += 2) {
|
||||||
|
c0 = s[0] ^ s[10] ^ s[20] ^ s[30] ^ s[40];
|
||||||
|
c1 = s[1] ^ s[11] ^ s[21] ^ s[31] ^ s[41];
|
||||||
|
c2 = s[2] ^ s[12] ^ s[22] ^ s[32] ^ s[42];
|
||||||
|
c3 = s[3] ^ s[13] ^ s[23] ^ s[33] ^ s[43];
|
||||||
|
c4 = s[4] ^ s[14] ^ s[24] ^ s[34] ^ s[44];
|
||||||
|
c5 = s[5] ^ s[15] ^ s[25] ^ s[35] ^ s[45];
|
||||||
|
c6 = s[6] ^ s[16] ^ s[26] ^ s[36] ^ s[46];
|
||||||
|
c7 = s[7] ^ s[17] ^ s[27] ^ s[37] ^ s[47];
|
||||||
|
c8 = s[8] ^ s[18] ^ s[28] ^ s[38] ^ s[48];
|
||||||
|
c9 = s[9] ^ s[19] ^ s[29] ^ s[39] ^ s[49];
|
||||||
|
|
||||||
|
h = c8 ^ ((c2 << 1) | (c3 >>> 31));
|
||||||
|
l = c9 ^ ((c3 << 1) | (c2 >>> 31));
|
||||||
|
s[0] ^= h;
|
||||||
|
s[1] ^= l;
|
||||||
|
s[10] ^= h;
|
||||||
|
s[11] ^= l;
|
||||||
|
s[20] ^= h;
|
||||||
|
s[21] ^= l;
|
||||||
|
s[30] ^= h;
|
||||||
|
s[31] ^= l;
|
||||||
|
s[40] ^= h;
|
||||||
|
s[41] ^= l;
|
||||||
|
h = c0 ^ ((c4 << 1) | (c5 >>> 31));
|
||||||
|
l = c1 ^ ((c5 << 1) | (c4 >>> 31));
|
||||||
|
s[2] ^= h;
|
||||||
|
s[3] ^= l;
|
||||||
|
s[12] ^= h;
|
||||||
|
s[13] ^= l;
|
||||||
|
s[22] ^= h;
|
||||||
|
s[23] ^= l;
|
||||||
|
s[32] ^= h;
|
||||||
|
s[33] ^= l;
|
||||||
|
s[42] ^= h;
|
||||||
|
s[43] ^= l;
|
||||||
|
h = c2 ^ ((c6 << 1) | (c7 >>> 31));
|
||||||
|
l = c3 ^ ((c7 << 1) | (c6 >>> 31));
|
||||||
|
s[4] ^= h;
|
||||||
|
s[5] ^= l;
|
||||||
|
s[14] ^= h;
|
||||||
|
s[15] ^= l;
|
||||||
|
s[24] ^= h;
|
||||||
|
s[25] ^= l;
|
||||||
|
s[34] ^= h;
|
||||||
|
s[35] ^= l;
|
||||||
|
s[44] ^= h;
|
||||||
|
s[45] ^= l;
|
||||||
|
h = c4 ^ ((c8 << 1) | (c9 >>> 31));
|
||||||
|
l = c5 ^ ((c9 << 1) | (c8 >>> 31));
|
||||||
|
s[6] ^= h;
|
||||||
|
s[7] ^= l;
|
||||||
|
s[16] ^= h;
|
||||||
|
s[17] ^= l;
|
||||||
|
s[26] ^= h;
|
||||||
|
s[27] ^= l;
|
||||||
|
s[36] ^= h;
|
||||||
|
s[37] ^= l;
|
||||||
|
s[46] ^= h;
|
||||||
|
s[47] ^= l;
|
||||||
|
h = c6 ^ ((c0 << 1) | (c1 >>> 31));
|
||||||
|
l = c7 ^ ((c1 << 1) | (c0 >>> 31));
|
||||||
|
s[8] ^= h;
|
||||||
|
s[9] ^= l;
|
||||||
|
s[18] ^= h;
|
||||||
|
s[19] ^= l;
|
||||||
|
s[28] ^= h;
|
||||||
|
s[29] ^= l;
|
||||||
|
s[38] ^= h;
|
||||||
|
s[39] ^= l;
|
||||||
|
s[48] ^= h;
|
||||||
|
s[49] ^= l;
|
||||||
|
|
||||||
|
b0 = s[0];
|
||||||
|
b1 = s[1];
|
||||||
|
b32 = (s[11] << 4) | (s[10] >>> 28);
|
||||||
|
b33 = (s[10] << 4) | (s[11] >>> 28);
|
||||||
|
b14 = (s[20] << 3) | (s[21] >>> 29);
|
||||||
|
b15 = (s[21] << 3) | (s[20] >>> 29);
|
||||||
|
b46 = (s[31] << 9) | (s[30] >>> 23);
|
||||||
|
b47 = (s[30] << 9) | (s[31] >>> 23);
|
||||||
|
b28 = (s[40] << 18) | (s[41] >>> 14);
|
||||||
|
b29 = (s[41] << 18) | (s[40] >>> 14);
|
||||||
|
b20 = (s[2] << 1) | (s[3] >>> 31);
|
||||||
|
b21 = (s[3] << 1) | (s[2] >>> 31);
|
||||||
|
b2 = (s[13] << 12) | (s[12] >>> 20);
|
||||||
|
b3 = (s[12] << 12) | (s[13] >>> 20);
|
||||||
|
b34 = (s[22] << 10) | (s[23] >>> 22);
|
||||||
|
b35 = (s[23] << 10) | (s[22] >>> 22);
|
||||||
|
b16 = (s[33] << 13) | (s[32] >>> 19);
|
||||||
|
b17 = (s[32] << 13) | (s[33] >>> 19);
|
||||||
|
b48 = (s[42] << 2) | (s[43] >>> 30);
|
||||||
|
b49 = (s[43] << 2) | (s[42] >>> 30);
|
||||||
|
b40 = (s[5] << 30) | (s[4] >>> 2);
|
||||||
|
b41 = (s[4] << 30) | (s[5] >>> 2);
|
||||||
|
b22 = (s[14] << 6) | (s[15] >>> 26);
|
||||||
|
b23 = (s[15] << 6) | (s[14] >>> 26);
|
||||||
|
b4 = (s[25] << 11) | (s[24] >>> 21);
|
||||||
|
b5 = (s[24] << 11) | (s[25] >>> 21);
|
||||||
|
b36 = (s[34] << 15) | (s[35] >>> 17);
|
||||||
|
b37 = (s[35] << 15) | (s[34] >>> 17);
|
||||||
|
b18 = (s[45] << 29) | (s[44] >>> 3);
|
||||||
|
b19 = (s[44] << 29) | (s[45] >>> 3);
|
||||||
|
b10 = (s[6] << 28) | (s[7] >>> 4);
|
||||||
|
b11 = (s[7] << 28) | (s[6] >>> 4);
|
||||||
|
b42 = (s[17] << 23) | (s[16] >>> 9);
|
||||||
|
b43 = (s[16] << 23) | (s[17] >>> 9);
|
||||||
|
b24 = (s[26] << 25) | (s[27] >>> 7);
|
||||||
|
b25 = (s[27] << 25) | (s[26] >>> 7);
|
||||||
|
b6 = (s[36] << 21) | (s[37] >>> 11);
|
||||||
|
b7 = (s[37] << 21) | (s[36] >>> 11);
|
||||||
|
b38 = (s[47] << 24) | (s[46] >>> 8);
|
||||||
|
b39 = (s[46] << 24) | (s[47] >>> 8);
|
||||||
|
b30 = (s[8] << 27) | (s[9] >>> 5);
|
||||||
|
b31 = (s[9] << 27) | (s[8] >>> 5);
|
||||||
|
b12 = (s[18] << 20) | (s[19] >>> 12);
|
||||||
|
b13 = (s[19] << 20) | (s[18] >>> 12);
|
||||||
|
b44 = (s[29] << 7) | (s[28] >>> 25);
|
||||||
|
b45 = (s[28] << 7) | (s[29] >>> 25);
|
||||||
|
b26 = (s[38] << 8) | (s[39] >>> 24);
|
||||||
|
b27 = (s[39] << 8) | (s[38] >>> 24);
|
||||||
|
b8 = (s[48] << 14) | (s[49] >>> 18);
|
||||||
|
b9 = (s[49] << 14) | (s[48] >>> 18);
|
||||||
|
|
||||||
|
s[0] = b0 ^ (~b2 & b4);
|
||||||
|
s[1] = b1 ^ (~b3 & b5);
|
||||||
|
s[10] = b10 ^ (~b12 & b14);
|
||||||
|
s[11] = b11 ^ (~b13 & b15);
|
||||||
|
s[20] = b20 ^ (~b22 & b24);
|
||||||
|
s[21] = b21 ^ (~b23 & b25);
|
||||||
|
s[30] = b30 ^ (~b32 & b34);
|
||||||
|
s[31] = b31 ^ (~b33 & b35);
|
||||||
|
s[40] = b40 ^ (~b42 & b44);
|
||||||
|
s[41] = b41 ^ (~b43 & b45);
|
||||||
|
s[2] = b2 ^ (~b4 & b6);
|
||||||
|
s[3] = b3 ^ (~b5 & b7);
|
||||||
|
s[12] = b12 ^ (~b14 & b16);
|
||||||
|
s[13] = b13 ^ (~b15 & b17);
|
||||||
|
s[22] = b22 ^ (~b24 & b26);
|
||||||
|
s[23] = b23 ^ (~b25 & b27);
|
||||||
|
s[32] = b32 ^ (~b34 & b36);
|
||||||
|
s[33] = b33 ^ (~b35 & b37);
|
||||||
|
s[42] = b42 ^ (~b44 & b46);
|
||||||
|
s[43] = b43 ^ (~b45 & b47);
|
||||||
|
s[4] = b4 ^ (~b6 & b8);
|
||||||
|
s[5] = b5 ^ (~b7 & b9);
|
||||||
|
s[14] = b14 ^ (~b16 & b18);
|
||||||
|
s[15] = b15 ^ (~b17 & b19);
|
||||||
|
s[24] = b24 ^ (~b26 & b28);
|
||||||
|
s[25] = b25 ^ (~b27 & b29);
|
||||||
|
s[34] = b34 ^ (~b36 & b38);
|
||||||
|
s[35] = b35 ^ (~b37 & b39);
|
||||||
|
s[44] = b44 ^ (~b46 & b48);
|
||||||
|
s[45] = b45 ^ (~b47 & b49);
|
||||||
|
s[6] = b6 ^ (~b8 & b0);
|
||||||
|
s[7] = b7 ^ (~b9 & b1);
|
||||||
|
s[16] = b16 ^ (~b18 & b10);
|
||||||
|
s[17] = b17 ^ (~b19 & b11);
|
||||||
|
s[26] = b26 ^ (~b28 & b20);
|
||||||
|
s[27] = b27 ^ (~b29 & b21);
|
||||||
|
s[36] = b36 ^ (~b38 & b30);
|
||||||
|
s[37] = b37 ^ (~b39 & b31);
|
||||||
|
s[46] = b46 ^ (~b48 & b40);
|
||||||
|
s[47] = b47 ^ (~b49 & b41);
|
||||||
|
s[8] = b8 ^ (~b0 & b2);
|
||||||
|
s[9] = b9 ^ (~b1 & b3);
|
||||||
|
s[18] = b18 ^ (~b10 & b12);
|
||||||
|
s[19] = b19 ^ (~b11 & b13);
|
||||||
|
s[28] = b28 ^ (~b20 & b22);
|
||||||
|
s[29] = b29 ^ (~b21 & b23);
|
||||||
|
s[38] = b38 ^ (~b30 & b32);
|
||||||
|
s[39] = b39 ^ (~b31 & b33);
|
||||||
|
s[48] = b48 ^ (~b40 & b42);
|
||||||
|
s[49] = b49 ^ (~b41 & b43);
|
||||||
|
|
||||||
|
s[0] ^= RC[n];
|
||||||
|
s[1] ^= RC[n + 1];
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
function extractLast20Bytes(hexString, addPrefix) {
|
||||||
|
// Ensure the input hexString has '0x' prefix
|
||||||
|
if (!hexString.startsWith('0x')) {
|
||||||
|
hexString = '0x' + hexString;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove '0x' prefix and parse the hex string to a BigInt
|
||||||
|
var bigIntValue = BigInt(hexString);
|
||||||
|
|
||||||
|
// Extract the last 20 bytes (160 bits) from the BigInt
|
||||||
|
var last20Bytes = bigIntValue & BigInt('0x' + 'f'.repeat(40)); // 0xf is 4 bits in hexadecimal, repeated 40 times for 160 bits
|
||||||
|
|
||||||
|
// Convert the result back to a hexadecimal string
|
||||||
|
var result = last20Bytes.toString(16).padStart(40, '0'); // 40 characters for 160 bits
|
||||||
|
|
||||||
|
// Add '0x' prefix if addPrefix is truthy
|
||||||
|
if (addPrefix) {
|
||||||
|
result = '0x' + result;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof root.keccak === 'object') {
|
||||||
|
Object.assign(root.keccak, methods);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (COMMON_JS) {
|
||||||
|
module.exports = methods;
|
||||||
|
} else {
|
||||||
|
for (i = 0; i < methodNames.length; ++i) {
|
||||||
|
root[methodNames[i]] = methods[methodNames[i]];
|
||||||
|
}
|
||||||
|
if (AMD) {
|
||||||
|
define(function () {
|
||||||
|
return methods;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})();
|
||||||
10243
scripts/lib.js
Normal file
10243
scripts/lib.js
Normal file
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user