2023-11-23 14:29:28 +01:00

66 lines
1.9 KiB
Nim

import constantine/math/arithmetic
import constantine/math/io/io_fields
import ./types
import ./io
import ./compress
const KeyNone = F.fromHex("0x0")
const KeyBottomLayer = F.fromHex("0x1")
const KeyOdd = F.fromHex("0x2")
const KeyOddAndBottomLayer = F.fromhex("0x3")
type Merkle* = object
todo: seq[F] # nodes that haven't been combined yet
width: int # width of the current subtree
leafs: int # amount of leafs processed
func init*(_: type Merkle): Merkle =
Merkle(width: 2)
func compress(merkle: var Merkle, odd: static bool) =
when odd:
let a = merkle.todo.pop()
let b = zero
let key = if merkle.width == 2: KeyOddAndBottomLayer else: KeyOdd
merkle.todo.add(compress(a, b, key = key))
merkle.leafs += merkle.width div 2 # zero node represents this many leafs
else:
let b = merkle.todo.pop()
let a = merkle.todo.pop()
let key = if merkle.width == 2: KeyBottomLayer else: KeyNone
merkle.todo.add(compress(a, b, key = key))
merkle.width *= 2
func update*(merkle: var Merkle, element: F) =
merkle.todo.add(element)
inc merkle.leafs
merkle.width = 2
while merkle.width <= merkle.leafs and merkle.leafs mod merkle.width == 0:
merkle.compress(odd = false)
func finish*(merkle: var Merkle): F =
assert merkle.todo.len > 0, "merkle root of empty sequence is not defined"
if merkle.leafs == 1:
merkle.compress(odd = true)
while merkle.todo.len > 1:
if merkle.leafs mod merkle.width == 0:
merkle.compress(odd = false)
else:
merkle.compress(odd = true)
return merkle.todo[0]
func digest*(_: type Merkle, elements: openArray[F]): F =
var merkle = Merkle.init()
for element in elements:
merkle.update(element)
return merkle.finish()
func digest*(_: type Merkle, bytes: openArray[byte]): F =
var merkle = Merkle.init()
for element in bytes.elements(F):
merkle.update(element)
return merkle.finish()