keccak JS implementation
This commit is contained in:
		| @@ -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) | ||||
|   | ||||
		Reference in New Issue
	
	Block a user