keccak JS implementation
This commit is contained in:
parent
1816cd3cf1
commit
035aaaaca6
@ -0,0 +1 @@
|
||||
|
@ -16,6 +16,9 @@ const mainController = {
|
||||
ecc: (req, res) => {
|
||||
res.sendFile(path.resolve(__dirname + '/../public/ecc.js'));
|
||||
},
|
||||
ecdh: (req, res) => {
|
||||
res.sendFile(path.resolve(__dirname + '/../public/ecdh.js'));
|
||||
},
|
||||
popups: (req, res) => {
|
||||
res.sendFile(path.resolve(__dirname + '/../public/popups.js'));
|
||||
},
|
||||
|
172
src/keccak.js
Normal file
172
src/keccak.js
Normal file
@ -0,0 +1,172 @@
|
||||
// referencse:
|
||||
// https://github.com/XKCP/XKCP/blob/master/Standalone/CompactFIPS202/Python/CompactFIPS202.py (official python implementation)
|
||||
// https://keccak.team/keccak_specs_summary.html (pseudo code and description)
|
||||
|
||||
function ROL64(a, n) {
|
||||
const shift = BigInt(n) % 64n;
|
||||
if (shift === 0n) return a;
|
||||
const part1 = (a >> (64n - shift)) & ((1n << shift) - 1n);
|
||||
const part2 = (a << shift) & 0xffffffffffffffffn;
|
||||
return (part1 + part2) & 0xffffffffffffffffn;
|
||||
}
|
||||
|
||||
function KeccakF1600onLanes(lanes) {
|
||||
let R = 1n;
|
||||
for (let round = 0; round < 24; round++) {
|
||||
// θ step
|
||||
const C = new Array(5);
|
||||
for (let x = 0; x < 5; x++) {
|
||||
C[x] = lanes[x][0] ^ lanes[x][1] ^ lanes[x][2] ^ lanes[x][3] ^ lanes[x][4];
|
||||
}
|
||||
const D = new Array(5);
|
||||
for (let x = 0; x < 5; x++) {
|
||||
D[x] = C[(x + 4) % 5] ^ ROL64(C[(x + 1) % 5], 1);
|
||||
}
|
||||
for (let x = 0; x < 5; x++) {
|
||||
for (let y = 0; y < 5; y++) {
|
||||
lanes[x][y] ^= D[x];
|
||||
}
|
||||
}
|
||||
|
||||
// ρ and π steps
|
||||
let x = 1, y = 0;
|
||||
let current = lanes[x][y];
|
||||
for (let t = 0; t < 24; t++) {
|
||||
const nextY = (2 * x + 3 * y) % 5;
|
||||
[x, y] = [y, nextY];
|
||||
const temp = lanes[x][y];
|
||||
const rotate = (t + 1) * (t + 2) / 2;
|
||||
lanes[x][y] = ROL64(current, rotate);
|
||||
current = temp;
|
||||
}
|
||||
|
||||
// χ step
|
||||
for (let y = 0; y < 5; y++) {
|
||||
const T = new Array(5);
|
||||
for (let x = 0; x < 5; x++) {
|
||||
T[x] = lanes[x][y];
|
||||
}
|
||||
for (let x = 0; x < 5; x++) {
|
||||
lanes[x][y] = T[x] ^ ((~T[(x + 1) % 5]) & T[(x + 2) % 5]);
|
||||
}
|
||||
}
|
||||
|
||||
// ι step
|
||||
for (let j = 0; j < 7; j++) {
|
||||
const R_top = R >> 7n;
|
||||
R = ((R << 1n) ^ (R_top * 0x71n)) & 0xffn;
|
||||
if ((R & 2n) !== 0n) {
|
||||
const shift = (1n << BigInt(j)) - 1n;
|
||||
lanes[0][0] ^= 1n << shift;
|
||||
}
|
||||
}
|
||||
}
|
||||
return lanes;
|
||||
}
|
||||
|
||||
function load64(state, offset) {
|
||||
let result = 0n;
|
||||
for (let i = 0; i < 8; i++) {
|
||||
result |= BigInt(state[offset + i]) << (8n * BigInt(i));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
function store64(a, state, offset) {
|
||||
a = BigInt(a);
|
||||
for (let i = 0; i < 8; i++) {
|
||||
state[offset + i] = Number((a >> (8n * BigInt(i))) & 0xffn);
|
||||
}
|
||||
}
|
||||
|
||||
function KeccakF1600(state) {
|
||||
const lanes = Array.from({ length: 5 }, () => new Array(5).fill(0n));
|
||||
for (let x = 0; x < 5; x++) {
|
||||
for (let y = 0; y < 5; y++) {
|
||||
const offset = 8 * (x + 5 * y);
|
||||
lanes[x][y] = load64(state, offset);
|
||||
}
|
||||
}
|
||||
const processedLanes = KeccakF1600onLanes(lanes);
|
||||
const newState = new Uint8Array(200);
|
||||
for (let x = 0; x < 5; x++) {
|
||||
for (let y = 0; y < 5; y++) {
|
||||
const offset = 8 * (x + 5 * y);
|
||||
store64(processedLanes[x][y], newState, offset);
|
||||
}
|
||||
}
|
||||
return newState;
|
||||
}
|
||||
|
||||
function Keccak(rate, capacity, inputBytes, delimitedSuffix, outputByteLen) {
|
||||
if (rate + capacity !== 1600 || rate % 8 !== 0) {
|
||||
throw new Error("Invalid parameters");
|
||||
}
|
||||
|
||||
let state = new Uint8Array(200);
|
||||
const rateInBytes = rate / 8;
|
||||
let inputOffset = 0;
|
||||
let blockSize = 0;
|
||||
|
||||
// Absorb phase
|
||||
while (inputOffset < inputBytes.length) {
|
||||
blockSize = Math.min(inputBytes.length - inputOffset, rateInBytes);
|
||||
for (let i = 0; i < blockSize; i++) {
|
||||
state[i] ^= inputBytes[inputOffset + i];
|
||||
}
|
||||
inputOffset += blockSize;
|
||||
if (blockSize === rateInBytes) {
|
||||
state = KeccakF1600(state);
|
||||
blockSize = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// Padding
|
||||
state[blockSize] ^= delimitedSuffix;
|
||||
if ((delimitedSuffix & 0x80) !== 0 && blockSize === rateInBytes - 1) {
|
||||
state = KeccakF1600(state);
|
||||
}
|
||||
state[rateInBytes - 1] ^= 0x80;
|
||||
state = KeccakF1600(state);
|
||||
|
||||
// Squeeze phase
|
||||
const output = [];
|
||||
let remaining = outputByteLen;
|
||||
while (remaining > 0) {
|
||||
const blockSize = Math.min(remaining, rateInBytes);
|
||||
for (let i = 0; i < blockSize; i++) {
|
||||
output.push(state[i]);
|
||||
}
|
||||
remaining -= blockSize;
|
||||
if (remaining > 0) {
|
||||
state = KeccakF1600(state);
|
||||
}
|
||||
}
|
||||
|
||||
return new Uint8Array(output);
|
||||
}
|
||||
|
||||
// SHAKE and SHA3 functions
|
||||
function SHAKE128(inputBytes, outputByteLen) {
|
||||
return Keccak(1344, 256, inputBytes, 0x1f, outputByteLen);
|
||||
}
|
||||
|
||||
function SHAKE256(inputBytes, outputByteLen) {
|
||||
return Keccak(1088, 512, inputBytes, 0x1f, outputByteLen);
|
||||
}
|
||||
|
||||
function SHA3_224(inputBytes) {
|
||||
return Keccak(1152, 448, inputBytes, 0x06, 224 / 8);
|
||||
}
|
||||
|
||||
function SHA3_256(inputBytes) {
|
||||
return Keccak(1088, 512, inputBytes, 0x06, 256 / 8);
|
||||
}
|
||||
|
||||
function SHA3_384(inputBytes) {
|
||||
return Keccak(832, 768, inputBytes, 0x06, 384 / 8);
|
||||
}
|
||||
|
||||
function SHA3_512(inputBytes) {
|
||||
return Keccak(576, 1024, inputBytes, 0x06, 512 / 8);
|
||||
}
|
0
src/public/ecdh.js
Normal file
0
src/public/ecdh.js
Normal file
@ -0,0 +1,5 @@
|
||||
// const express = require("express");
|
||||
// const chatController = require("../controllers/chat");
|
||||
// const router = express.Router();
|
||||
//
|
||||
// module.exports = router;
|
@ -1,9 +1,11 @@
|
||||
const express = require("express");
|
||||
const rootRoutes = require('./root');
|
||||
const accountRoutes = require('./account.js');
|
||||
// const chatRoutes = require('./chat.js');
|
||||
const router = express.Router();
|
||||
|
||||
router.use("/", rootRoutes);
|
||||
router.use("/account", accountRoutes);
|
||||
// router.use("/chat", chatRoutes);
|
||||
|
||||
module.exports = router;
|
||||
|
@ -18,6 +18,10 @@ router
|
||||
.route("/ecc.js")
|
||||
.get(mainController.ecc);
|
||||
|
||||
router
|
||||
.route("/ecdh.js")
|
||||
.get(mainController.ecdh);
|
||||
|
||||
router
|
||||
.route("/popups.js")
|
||||
.get(mainController.popups);
|
||||
|
@ -10,6 +10,7 @@ html(lang="en-US")
|
||||
script(type="module", src="/ecc.js", defer)
|
||||
if isLoggedIn
|
||||
script(src="/chat.js", defer)
|
||||
script(src="/ecdh.js", defer)
|
||||
else
|
||||
script(type="module", src="/popups.js", defer)
|
||||
script(type="module", src="/register.js", defer)
|
||||
|
Loading…
x
Reference in New Issue
Block a user