mirror of
https://github.com/codex-storage/nim-poseidon2.git
synced 2025-02-23 16:28:07 +00:00
66 lines
1.9 KiB
Nim
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()
|