From ba4ea177e9b1aa34ad96f1512b2acc9022978633 Mon Sep 17 00:00:00 2001 From: Shandar Denys Date: Wed, 25 Oct 2023 23:38:27 +0300 Subject: [PATCH] add digest256 --- digest256.mjs | 41 +++++++++++++++++++++++++++++++++++++++++ package.json | 2 +- test.mjs | 39 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 81 insertions(+), 1 deletion(-) create mode 100644 digest256.mjs diff --git a/digest256.mjs b/digest256.mjs new file mode 100644 index 0000000..7e584fa --- /dev/null +++ b/digest256.mjs @@ -0,0 +1,41 @@ +import sha224 from './sha224.mjs' +const { compress } = sha224 + +const maxLength = 248n + +const u32Mask = 0xffff_ffffn + +const hashMask = u32Mask << 224n; + +const byteMask = 0x08n << maxLength + +const dataMask = (1n << 248n) - 1n + +// a length of the sequence in bits. +// The function returns 255 if the digest is a hash. +/** @type {(bu256: bigint) => bigint} */ +const len = bu256 => (bu256 >> maxLength) & u32Mask + +/** @type {(nu8: number) => bigint} */ +const byteToDigest = nu8 => BigInt(nu8) | byteMask + +/** @type {(bu256: bigint) => bigint} */ +const getData = bu256 => bu256 & dataMask + +/** @type {(a: bigint) => (b: bigint) => bigint} */ +const merge = a => b => { + const lenA = len(a) + const lenB = len(b) + const lenAB = lenA + lenB + if (lenAB <= maxLength) { + const data = getData(a) | (getData(b) << lenA); + return data | (lenAB << maxLength) + } + return compress(a | (b << 256n)) +} + +export default { + merge, + byteToDigest, + len +} \ No newline at end of file diff --git a/package.json b/package.json index f5f4c7e..e2ac415 100644 --- a/package.json +++ b/package.json @@ -5,7 +5,7 @@ "main": "index.mjs", "scripts": { "tsc": "tsc", - "test": "tsc & node test.mjs" + "test": "tsc & node --trace-uncaught test.mjs" }, "repository": { "type": "git", diff --git a/test.mjs b/test.mjs index 2f9d767..cf08b8a 100644 --- a/test.mjs +++ b/test.mjs @@ -1,7 +1,9 @@ import index from './index.mjs' import sha224 from './sha224.mjs' +import digest256 from './digest256.mjs' const { getParityBit } = index const { compress } = sha224 +const { merge, byteToDigest, len } = digest256 { const parity = getParityBit(0n) @@ -17,4 +19,41 @@ const { compress } = sha224 const hash = compress(0x8000_0000n) const result = hash.toString(16) if (result !== 'ffffffffc5b3e42f828ea62a15a2b01f288234c4476102bb2a3a2bc9d14a028c') { throw result } +} + +{ + const a = byteToDigest(0x12) + if (a !== 0x0800_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0012n) { throw a.toString(16) } + const b = byteToDigest(0x34) + if (b !== 0x0800_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0034n) { throw b.toString(16) } + const lenA = len(a) + if (lenA !== 8n) { throw lenA.toString(16) } + + const c = merge(a)(b) + if (c !== 0x1000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_3412n) { throw c.toString(16) } + + const c2 = merge(c)(c) + if (c2 !== 0x2000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_3412_3412n) { throw c2.toString(16) } + + const c4 = merge(c2)(c2) + if (c4 !== 0x4000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_3412_3412_3412_3412n) { throw c4.toString(16) } + + const c8 = merge(c4)(c4) + if (c8 !== 0x8000_0000_0000_0000_0000_0000_0000_0000_3412_3412_3412_3412_3412_3412_3412_3412n) { throw c8.toString(16) } + + const c12 = merge(c8)(c4) + if (c12 !== 0xc000_0000_0000_0000_3412_3412_3412_3412_3412_3412_3412_3412_3412_3412_3412_3412n) { throw c12.toString(16) } + + const c16 = merge(c8)(c8) + if (len(c16) !== 0xffn) { throw c16.toString(16) } + + { + const result = merge(a)(0n) + if (result !== a) { throw result } + } + + { + const result = merge(0n)(a) + if (result !== a) { throw result } + } } \ No newline at end of file