From d94184d471e9b1aa7463efbbef8ee9639fc04b48 Mon Sep 17 00:00:00 2001 From: Shandar Denys Date: Thu, 26 Oct 2023 22:42:19 +0300 Subject: [PATCH 1/7] add subtree.mjs --- subtree.mjs | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 subtree.mjs diff --git a/subtree.mjs b/subtree.mjs new file mode 100644 index 0000000..e69de29 From 08cc31843ab28de9ebb0f46c0b54ae1933397224 Mon Sep 17 00:00:00 2001 From: Shandar Denys Date: Thu, 26 Oct 2023 23:41:45 +0300 Subject: [PATCH 2/7] highestOne256 --- subtree.mjs | 71 +++++++++++++++++++++++++++++++++++++++++++++++++++++ test.mjs | 44 +++++++++++++++++++++++++++++++++ 2 files changed, 115 insertions(+) diff --git a/subtree.mjs b/subtree.mjs index e69de29..a4e4550 100644 --- a/subtree.mjs +++ b/subtree.mjs @@ -0,0 +1,71 @@ +import digest256 from './digest256.mjs' +const { merge } = digest256 + +/** + * @typedef {readonly [bigint, bigint, bigint]} Node + */ + +const nodeRoot = 0 +const nodeLast = 1 +const nodeHeight = 2 + +/** @typedef {Node[]} State */ + +/** + * @template T + * @typedef {null | T} Nullable + */ + +/** @type {(bu256: bigint) => bigint} */ +const highestOne256 = bu256 => { + let result = 0n + let index = 256n + while (bu256 !== 0n) { + if (index === 0n) { + return result + 1n + } + index >>= 1n + const high = bu256 >> index + if (high === 0n) { + bu256 &= (1n << index) - 1n + } else { + bu256 = high + result += index + } + } + return result +} + +/** @type {(bu256: bigint) => bigint} */ +const leadingZero256 = bu256 => 256n - highestOne256(bu256) + +/** @type {(a: bigint) => (b: bigint) => bigint} */ +const height = a => b => { + let v = a ^ b + return leadingZero256(v) +} + +/** @type {(state: State) => (last0: bigint) => Nullable} */ +const end = state => last0 => { + throw 'not implemented' +} + +/** @type {(state: State) => (last0: bigint) => Nullable} */ +const push = state => last0Last => { + let height10 = 0n + let last1 = state.pop() + if (last1 !== undefined) { + if (last0Last >= last1[nodeLast]) { + return end(state)(merge(last1[nodeRoot])(last0Last)) + } + //height10 = + } + throw 'not implemented' + //state.push([last0, height10]) + return null + +} + +export default { + highestOne256 +} \ No newline at end of file diff --git a/test.mjs b/test.mjs index b705817..0e23d6a 100644 --- a/test.mjs +++ b/test.mjs @@ -1,9 +1,11 @@ import index from './index.mjs' import sha224 from './sha224.mjs' import digest256 from './digest256.mjs' +import subtree from './subtree.mjs' const { getParityBit } = index const { compress } = sha224 const { merge, byteToDigest, len } = digest256 +const { highestOne256 } = subtree console.log(`test start`) @@ -58,4 +60,46 @@ console.log(`test start`) const result = merge(0n)(a) if (result !== a) { throw result } } +} + +{ + { + const result = highestOne256(0n) + if (result !== 0n) { throw result } + } + + { + const result = highestOne256(1n) + if (result !== 1n) { throw result } + } + + { + const result = highestOne256(2n) + if (result !== 2n) { throw result } + } + + { + const result = highestOne256(3n) + if (result !== 2n) { throw result } + } + + { + const result = highestOne256(4n) + if (result !== 3n) { throw result } + } + + { + const result = highestOne256(8n) + if (result !== 4n) { throw result } + } + + { + const result = highestOne256(8n) + if (result !== 4n) { throw result } + } + + { + const result = highestOne256(0x8000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000n) + if (result !== 256n) { throw result } + } } \ No newline at end of file From 95099c94eaf24e8948ed347a693c6382f18c4c8e Mon Sep 17 00:00:00 2001 From: Shandar Denys Date: Thu, 26 Oct 2023 23:45:37 +0300 Subject: [PATCH 3/7] optimization --- subtree.mjs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/subtree.mjs b/subtree.mjs index a4e4550..623d64b 100644 --- a/subtree.mjs +++ b/subtree.mjs @@ -21,10 +21,10 @@ const highestOne256 = bu256 => { let result = 0n let index = 256n while (bu256 !== 0n) { + index >>= 1n if (index === 0n) { return result + 1n } - index >>= 1n const high = bu256 >> index if (high === 0n) { bu256 &= (1n << index) - 1n From 51df32fa799b773665de1cec6d1486c29d3cf43c Mon Sep 17 00:00:00 2001 From: Shandar Denys Date: Fri, 27 Oct 2023 00:04:17 +0300 Subject: [PATCH 4/7] implement height function --- subtree.mjs | 34 +++++++++++++++++++++++++--------- test.mjs | 52 +++++++++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 76 insertions(+), 10 deletions(-) diff --git a/subtree.mjs b/subtree.mjs index 623d64b..f212d2d 100644 --- a/subtree.mjs +++ b/subtree.mjs @@ -47,25 +47,41 @@ const height = a => b => { /** @type {(state: State) => (last0: bigint) => Nullable} */ const end = state => last0 => { - throw 'not implemented' + while (true) { + let last1 = state.pop() + if (last1 === undefined) { + return last0 + } + last0 = merge(last1[nodeRoot])(last0) + } } /** @type {(state: State) => (last0: bigint) => Nullable} */ -const push = state => last0Last => { +const push = state => last0 => { let height10 = 0n let last1 = state.pop() if (last1 !== undefined) { - if (last0Last >= last1[nodeLast]) { - return end(state)(merge(last1[nodeRoot])(last0Last)) + if (last0 >= last1[nodeLast]) { + return end(state)(merge(last1[nodeRoot])(last0)) } - //height10 = + height10 = height(last1[nodeLast])(last0) + while (last1[nodeHeight] > height10) { + let last2 = state.pop() + if (last2 === undefined) throw 'invalid state' + last1 = [ + merge(last2[nodeRoot])(last1[nodeRoot]), + last1[nodeLast], + last2[nodeHeight] + ] + } + state.push(last1) } - throw 'not implemented' - //state.push([last0, height10]) + state.push([last0, last0, height10]) return null - } export default { - highestOne256 + highestOne256, + height, + push } \ No newline at end of file diff --git a/test.mjs b/test.mjs index 0e23d6a..f941872 100644 --- a/test.mjs +++ b/test.mjs @@ -5,7 +5,7 @@ import subtree from './subtree.mjs' const { getParityBit } = index const { compress } = sha224 const { merge, byteToDigest, len } = digest256 -const { highestOne256 } = subtree +const { highestOne256, height, push } = subtree console.log(`test start`) @@ -102,4 +102,54 @@ console.log(`test start`) const result = highestOne256(0x8000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000n) if (result !== 256n) { throw result } } + + { + const result = height(0n)(0n) + if (result !== 256n) { throw result } + } + + { + const result = height(0n)(1n) + if (result !== 255n) { throw result } + } + + { + const result = height(1n)(0n) + if (result !== 255n) { throw result } + } + + { + const result = height(0n)(0x1_0000_0000_0000_0000_0000_0000_0000_0000n) + if (result !== 127n) { throw result } + } + + { + const result = height(0x1_0000_0000_0000_0000_0000_0000_0000_0000n)(0x1_0000_0000_0000_0000_0000_0000_0000_0000n) + if (result !== 256n) { throw result } + } + + { + const result = height(1n)(1n) + if (result !== 256n) { throw result } + } + + { + const result = height(0n)(0x1_0000_0000_0000_0000_0000_0000_0000_01can) + if (result !== 127n) { throw result } + } + + { + const result = height(0n)(0x1ca_0000_0000_0000_0000_0000_0000_0000_0001n) + if (result !== 119n) { throw result } + } + + { + const result = height(0x7_0000_0000_0000_0000_0000_0000_0000_0000n)(0x4_0000_0000_0000_0000_0000_0000_0000_01can) + if (result !== 126n) { throw result } + } + + { + const result = height(0n)(0x8000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_01can) + if (result !== 0n) { throw result } + } } \ No newline at end of file From de13f41dd0af23f1617cd3c3403d52a3096f9c98 Mon Sep 17 00:00:00 2001 From: Shandar Denys Date: Fri, 27 Oct 2023 00:25:54 +0300 Subject: [PATCH 5/7] tests --- test.mjs | 38 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/test.mjs b/test.mjs index f941872..3461f53 100644 --- a/test.mjs +++ b/test.mjs @@ -2,6 +2,8 @@ import index from './index.mjs' import sha224 from './sha224.mjs' import digest256 from './digest256.mjs' import subtree from './subtree.mjs' +import { stat } from 'fs' + /** @typedef {import('./subtree.mjs').State} State */ const { getParityBit } = index const { compress } = sha224 const { merge, byteToDigest, len } = digest256 @@ -152,4 +154,40 @@ console.log(`test start`) const result = height(0n)(0x8000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_01can) if (result !== 0n) { throw result } } + + { + let a = byteToDigest(0b01) + let b = byteToDigest(0b10) + let c = byteToDigest(0b11) + { + /** @type {State} */ + let state = [] + push(state)(a) + if (state.length !== 1) { throw state.length } + const state0 = state[0] + if (state0[0] !== a) { throw state0[0] } + if (state0[1] !== a) { throw state0[1] } + if (state0[2] !== 0n) { throw state0[2] } + const ab = push(state)(b) + const mergeAB = merge(a)(b) + if (ab !== mergeAB) { throw ab } + state = state + if (state.length !== 0) { throw state.length } + } + { + /** @type {State} */ + let state = [] + let result = push(state)(c) + if (result !== null) { throw result } + result = push(state)(b) + if (result !== null) { throw result } + if (state.length !== 2 ) { throw state.length } + result = push(state)(a) + if (result !== null) { throw result } + if (state.length !== 2 ) { throw state.length } + result = push(state)(a) + const mergeCB_AA = merge(merge(c)(b))(merge(a)(a)) + if (result != mergeCB_AA) { throw result } + } + } } \ No newline at end of file From 00be6bf6ff811e51a7fdd00bf09471cf6d53211d Mon Sep 17 00:00:00 2001 From: Shandar Denys Date: Fri, 27 Oct 2023 00:28:48 +0300 Subject: [PATCH 6/7] minor --- subtree.mjs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/subtree.mjs b/subtree.mjs index f212d2d..b5b3b11 100644 --- a/subtree.mjs +++ b/subtree.mjs @@ -45,7 +45,7 @@ const height = a => b => { return leadingZero256(v) } -/** @type {(state: State) => (last0: bigint) => Nullable} */ +/** @type {(state: State) => (last0: bigint) => bigint} */ const end = state => last0 => { while (true) { let last1 = state.pop() From 9e29921125bd23a187239545910ecac36eda9ada Mon Sep 17 00:00:00 2001 From: Shandar Denys Date: Fri, 27 Oct 2023 00:31:55 +0300 Subject: [PATCH 7/7] remove garbage --- test.mjs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/test.mjs b/test.mjs index 3461f53..6ed9850 100644 --- a/test.mjs +++ b/test.mjs @@ -2,8 +2,7 @@ import index from './index.mjs' import sha224 from './sha224.mjs' import digest256 from './digest256.mjs' import subtree from './subtree.mjs' -import { stat } from 'fs' - /** @typedef {import('./subtree.mjs').State} State */ +/** @typedef {import('./subtree.mjs').State} State */ const { getParityBit } = index const { compress } = sha224 const { merge, byteToDigest, len } = digest256