Skip to content

Commit

Permalink
renaming for name consistency (#70)
Browse files Browse the repository at this point in the history
* renaming

* fix naming

* version 0.3.2
  • Loading branch information
Trinidadec authored Nov 14, 2023
1 parent b22b20c commit 0349cc0
Show file tree
Hide file tree
Showing 12 changed files with 252 additions and 254 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ on:
branches: [ "main" ]

env:
VERSION: 0.3.1
VERSION: 0.3.2

jobs:
node:
Expand Down
24 changes: 12 additions & 12 deletions tree.mjs → cdt/main-tree.mjs
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import digest256 from './digest256.mjs'
import subtree from './subtree.mjs'
import sha224 from './sha224.mjs'
/** @typedef {import('./subtree.mjs').State} SubTreeState */
const { byteToDigest } = digest256
const { newState: newSubTree, push: pushSubTree, end: endSubTree } = subtree
import nodeId from './node-id.mjs'
import subTree from './sub-tree.mjs'
import sha224 from '../crypto/sha224.mjs'
/** @typedef {import('./sub-tree.mjs').State} SubTreeState */
const { byteToNodeId } = nodeId
const { newState: newSubTree, push: pushSubTree, end: endSubTree } = subTree
const { compress } = sha224

/**
Expand All @@ -13,10 +13,10 @@ const { compress } = sha224
const mask224 = ((1n << 224n) - 1n)

/** @type {(state: State) => (nu8: number) => void} */
const push = state => nu8 => pushDigest(state)(byteToDigest(nu8))
const push = state => nu8 => pushNodeId(state)(byteToNodeId(nu8))

/** @type {(state: State) => (bu256: bigint) => void} */
const pushDigest = state => last0 => {
const pushNodeId = state => last0 => {
let i = 0
while (true) {
let subTree = state[i]
Expand All @@ -38,11 +38,11 @@ const end = state => compress(internalEnd(state)) & mask224

/** @type {(state: State) => bigint | null} */
const partialEnd = state => {
let digest256 = internalEnd(state)
if (digest256 >> 224n !== 0xffff_ffffn) {
let nodeId = internalEnd(state)
if (nodeId >> 224n !== 0xffff_ffffn) {
return null
}
return digest256 & mask224
return nodeId & mask224
}

/** @type {(state: State) => bigint} */
Expand All @@ -56,7 +56,7 @@ const internalEnd = state => {

export default {
push,
pushDigest,
pushNodeId,
end,
partialEnd
}
14 changes: 6 additions & 8 deletions digest256.mjs → cdt/node-id.mjs
Original file line number Diff line number Diff line change
@@ -1,12 +1,10 @@
import sha224 from './sha224.mjs'
import sha224 from '../crypto/sha224.mjs'
const { compress2 } = sha224

const maxLength = 248n

const u32Mask = 0xffff_ffffn

const hashMask = u32Mask << 224n;

const byteMask = 0x08n << maxLength

const dataMask = (1n << 248n) - 1n
Expand All @@ -17,7 +15,7 @@ const dataMask = (1n << 248n) - 1n
const len = bu256 => (bu256 >> maxLength) & u32Mask

/** @type {(nu8: number) => bigint} */
const byteToDigest = nu8 => BigInt(nu8) | byteMask
const byteToNodeId = nu8 => BigInt(nu8) | byteMask

/** @type {(bu256: bigint) => bigint} */
const getData = bu256 => bu256 & dataMask
Expand All @@ -42,20 +40,20 @@ const merge = a => b => {


/** @type {(tail: Uint8Array) => bigint} */
const tailToDigest = tail => {
const tailToNodeId = tail => {
if (tail.length > 31) {
throw 'invalid tail'
}
let result = 0n
for(let byte of tail) {
result = merge(result)(byteToDigest(byte))
result = merge(result)(byteToNodeId(byte))
}
return result
}

export default {
merge,
byteToDigest,
tailToDigest,
byteToNodeId,
tailToNodeId,
len
}
4 changes: 2 additions & 2 deletions subtree.mjs → cdt/sub-tree.mjs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import digest256 from './digest256.mjs'
const { merge } = digest256
import nodeId from './node-id.mjs'
const { merge } = nodeId

/**
* @typedef {readonly [bigint, bigint, bigint]} Node
Expand Down
10 changes: 5 additions & 5 deletions base32.mjs → crypto/base32.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -15,21 +15,21 @@ const getParityBit = uint256 => {
}

/** @type {(bu224: bigint) => string} */
const toAddress = bu224 => {
let address = ''
const toBase32Hash = bu224 => {
let result = ''
const parity = getParityBit(bu224)
for (let j = 0; j < 45; j++) {
let uint5 = Number(bu224 & 0b11111n)
if (j == 44) {
uint5 += parity << 4
}
address += toBase32(uint5)
result += toBase32(uint5)
bu224 >>= 5n
}
return address
return result
}

export default {
toAddress,
toBase32Hash,
getParityBit
}
File renamed without changes.
188 changes: 188 additions & 0 deletions forest/index.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,188 @@
import base32 from '../crypto/base32.mjs'
import mainTree from '../cdt/main-tree.mjs'
import nodeId from '../cdt/node-id.mjs'
/** @typedef {import('../cdt/main-tree.mjs').State} StateTree */
/**
* @template T
* @typedef {import('../cdt/sub-tree.mjs').Nullable<T>} Nullable
*/
const { toBase32Hash } = base32
const { push: pushTree, end: endTree, partialEnd: partialEndTree, pushNodeId } = mainTree
const { tailToNodeId } = nodeId

/**
* second element is root flag
* @typedef {readonly [string, boolean]} ForestNodeId
*/

/**
* @typedef {[ForestNodeId, Uint8Array]} ForestNode
*/

/**
* @template T
* @typedef {readonly['ok', T]} Ok
*/

/**
* @template E
* @typedef {readonly['error', E]} Error
*/

/**
* @template T
* @template E
* @typedef {Ok<T>|Error<E>} Result
*/

/**
* @typedef {readonly Uint8Array[]} OkOutput
*/

/**
* @typedef { Result<OkOutput,string> } Output
*/

/**
* @typedef { Uint8Array } ReadonlyUint8Array
*/

/**
* @typedef {[ForestNodeId, Nullable<ReadonlyUint8Array>]} ForestNodeState
*/

/**
* @typedef { ForestNodeState[] } State
*/

/**
* @typedef {{
* readonly read: (address: ForestNodeId) => Promise<Uint8Array>,
* readonly write: (buffer: Uint8Array) => Promise<void>,
* }} Provider
*/

/** @type {(state: State) => (forestNode: ForestNode) => void} */
const insertForestNode = state => forestNode => {
for (let i = 0; i < state.length; i++) {
if (state[i][0][0] === forestNode[0][0]) {
state[i][1] = forestNode[1]
}
}
}

/** @type {(state: State) => Output} */
const nextState = state => {
/** @type {Uint8Array[]} */
let resultBuffer = []

while (true) {
const forestNodeLast = state.at(-1)
if (forestNodeLast === undefined) {
return ['ok', resultBuffer]
}

const forestNodeData = forestNodeLast[1]
if (forestNodeData === null) {
return ['ok', resultBuffer]
}

state.pop()

if (forestNodeLast[0][0] === '') {
resultBuffer.push(forestNodeData)
continue
}

/** @type {StateTree} */
let verificationTree = []
const tailLength = forestNodeData[0]
if (tailLength === 32) {
const data = forestNodeData.subarray(1)
for (let byte of data) {
pushTree(verificationTree)(byte)
}
resultBuffer.push(data)
} else {
const tail = forestNodeData.subarray(1, tailLength + 1)
if (tail.length !== 0) {
state.push([['', false], tail])
}
/** @type {ForestNodeId[]} */
let children = []
for (let i = tailLength + 1; i < forestNodeData.length; i += 28) {
let forestNodeHash = 0n
for (let j = 0; j < 28; j++) {
forestNodeHash += BigInt(forestNodeData[i + j]) << BigInt(8 * j)
}
pushNodeId(verificationTree)(forestNodeHash | (0xffff_ffffn << 224n))
const childBase32Hash = toBase32Hash(forestNodeHash)
children.push([childBase32Hash, false])
}
pushNodeId(verificationTree)(tailToNodeId(tail))
const forestNodeHash = forestNodeLast[0][1] ? endTree(verificationTree) : partialEndTree(verificationTree)
if (forestNodeHash === null || toBase32Hash(forestNodeHash) !== forestNodeLast[0][0]) {
return ['error', `verification failed ${forestNodeLast[0][0]}`]
}

for (let i = children.length - 1; i >= 0; i--) {
state.push([children[i], null])
}
}
}
}

/** @type {(provider: Provider) => (root: string) => Promise<string | null>} */
const get = ({ read, write }) => async (root) => {
/** @type {State} */
let state = [[[root, true], null]]
/** @type {[ForestNodeId, Promise<Uint8Array>] | null} */
let readPromise = null
/** @type {Promise<void> | null} */
let writePromise = null
try {
while (true) {
const nodeStateLast = state.at(-1)
if (nodeStateLast === undefined) {
if (writePromise === null) {
return 'unexpected behaviour'
}
await writePromise
return null
}

if (readPromise !== null) {
const data = await readPromise[1]
insertForestNode(state)([readPromise[0], data])
}

for (let i = state.length - 1; i >= 0; i--) {
const nodeStateLastI = state[i]
if (nodeStateLastI[1] === null) {
const nodeId = nodeStateLastI[0]
readPromise = [nodeId, read(nodeId)]
break
}
}

const next = nextState(state)
if (next[0] === 'error') {
return `${next[1]}`
}

const writeData = next[1]
for (let buffer of writeData) {
if (writePromise === null) {
writePromise = Promise.resolve()
}
writePromise = writePromise.then(() => write(buffer))
}
}
} catch (err) {
return `${err}`
}
}

export default {
get
}
Loading

0 comments on commit 0349cc0

Please sign in to comment.