2023-07-28 22:10:14 +02:00
|
|
|
|
|
|
|
# import std/sugar
|
|
|
|
|
2023-10-24 13:54:39 +02:00
|
|
|
import
|
|
|
|
constantine/math/arithmetic,
|
2023-10-26 14:39:27 +02:00
|
|
|
constantine/math/io/io_bigints,
|
2023-10-24 13:54:39 +02:00
|
|
|
constantine/math/config/curves
|
2023-07-28 22:10:14 +02:00
|
|
|
|
2023-10-24 13:57:47 +02:00
|
|
|
import poseidon2/types
|
|
|
|
import poseidon2/roundconst
|
2023-07-28 22:10:14 +02:00
|
|
|
|
|
|
|
#-------------------------------------------------------------------------------
|
|
|
|
|
|
|
|
let zero : F = getZero()
|
|
|
|
|
2023-10-24 14:21:37 +02:00
|
|
|
const externalRoundConst : array[24, F] = arrayFromHex( externalRoundConstStr )
|
|
|
|
const internalRoundConst : array[56, F] = arrayFromHex( internalRoundConstStr )
|
2023-07-28 22:10:14 +02:00
|
|
|
|
|
|
|
#-------------------------------------------------------------------------------
|
|
|
|
|
|
|
|
# inplace sbox, x => x^5
|
|
|
|
proc sbox(x: var F) : void =
|
|
|
|
var y = x
|
|
|
|
square(y)
|
|
|
|
square(y)
|
|
|
|
x *= y
|
|
|
|
|
2023-10-24 14:16:54 +02:00
|
|
|
proc linearLayer(x, y, z : var F) =
|
2023-07-28 22:10:14 +02:00
|
|
|
var s = x ; s += y ; s += z
|
|
|
|
x += s
|
|
|
|
y += s
|
|
|
|
z += s
|
|
|
|
|
2023-10-24 14:16:54 +02:00
|
|
|
proc internalRound(j: int; x, y, z: var F) =
|
|
|
|
x += internalRoundConst[j]
|
2023-07-28 22:10:14 +02:00
|
|
|
sbox(x)
|
|
|
|
var s = x ; s += y ; s += z
|
|
|
|
double(z)
|
2023-10-24 13:55:04 +02:00
|
|
|
x += s
|
2023-07-28 22:10:14 +02:00
|
|
|
y += s
|
|
|
|
z += s
|
|
|
|
|
2023-10-24 14:16:54 +02:00
|
|
|
proc externalRound(j: int; x, y, z : var F) =
|
|
|
|
x += externalRoundConst[3*j+0]
|
|
|
|
y += externalRoundConst[3*j+1]
|
|
|
|
z += externalRoundConst[3*j+2]
|
2023-07-28 22:10:14 +02:00
|
|
|
sbox(x) ; sbox(y) ; sbox(z)
|
|
|
|
var s = x ; s += y ; s += z
|
|
|
|
x += s
|
|
|
|
y += s
|
|
|
|
z += s
|
|
|
|
|
2023-10-24 14:16:54 +02:00
|
|
|
proc permInplace*(x, y, z : var F) =
|
|
|
|
linearLayer(x, y, z);
|
2023-07-28 22:10:14 +02:00
|
|
|
for j in 0..3:
|
2023-10-24 14:16:54 +02:00
|
|
|
externalRound(j, x, y, z)
|
2023-07-28 22:10:14 +02:00
|
|
|
for j in 0..55:
|
2023-10-24 14:16:54 +02:00
|
|
|
internalRound(j, x, y, z)
|
2023-07-28 22:10:14 +02:00
|
|
|
for j in 4..7:
|
2023-10-24 14:16:54 +02:00
|
|
|
externalRound(j, x, y, z)
|
2023-07-28 22:10:14 +02:00
|
|
|
|
|
|
|
proc perm*(xyz: S) : S =
|
|
|
|
var (x,y,z) = xyz
|
2023-10-24 14:16:54 +02:00
|
|
|
permInplace(x, y, z)
|
2023-07-28 22:10:14 +02:00
|
|
|
return (x,y,z)
|
|
|
|
|
|
|
|
#-------------------------------------------------------------------------------
|
|
|
|
|
|
|
|
proc compress*(a, b : F) : F =
|
|
|
|
var x = a
|
|
|
|
var y = b
|
|
|
|
var z : F ; setZero(z)
|
2023-10-24 14:16:54 +02:00
|
|
|
permInplace(x, y, z)
|
2023-07-28 22:10:14 +02:00
|
|
|
return x
|
|
|
|
|
2023-10-24 14:16:54 +02:00
|
|
|
proc merkleRoot*(xs: openArray[F]) : F =
|
2023-07-28 22:10:14 +02:00
|
|
|
let a = low(xs)
|
|
|
|
let b = high(xs)
|
|
|
|
let m = b-a+1
|
|
|
|
|
|
|
|
if m==1:
|
|
|
|
return xs[a]
|
|
|
|
|
|
|
|
else:
|
|
|
|
let halfn : int = m div 2
|
|
|
|
let n : int = 2*halfn
|
2023-10-24 14:16:54 +02:00
|
|
|
let isOdd : bool = (n != m)
|
2023-10-24 13:55:04 +02:00
|
|
|
|
2023-07-28 22:10:14 +02:00
|
|
|
var ys : seq[F] = newSeq[F](halfn)
|
|
|
|
|
2023-10-24 14:16:54 +02:00
|
|
|
if not isOdd:
|
2023-07-28 22:10:14 +02:00
|
|
|
for i in 0..<halfn:
|
|
|
|
ys[i] = compress( xs[a+2*i], xs[a+2*i+1] )
|
|
|
|
|
|
|
|
else:
|
|
|
|
for i in 0..<halfn-1:
|
|
|
|
ys[i] = compress( xs[a+2*i], xs[a+2*i+1] )
|
|
|
|
# and the last one:
|
|
|
|
ys[halfn-1] = compress( xs[a+n-2], zero )
|
|
|
|
|
2023-10-24 14:16:54 +02:00
|
|
|
return merkleRoot(ys)
|
2023-07-28 22:10:14 +02:00
|
|
|
|
2023-10-26 14:39:27 +02:00
|
|
|
proc unmarshal(
|
|
|
|
_: type F,
|
|
|
|
bytes: openArray[byte],
|
|
|
|
endian: static Endianness): seq[F] =
|
|
|
|
const chunkLen = 31
|
|
|
|
var elements: seq[F]
|
|
|
|
var i = 0
|
|
|
|
while i < bytes.len:
|
|
|
|
let chunk = bytes[i..<min(i + chunkLen, bytes.len)]
|
|
|
|
let bigint = B.unmarshal(chunk, endian)
|
|
|
|
let element = F.fromBig(bigint)
|
|
|
|
elements.add(element)
|
|
|
|
i += chunkLen
|
|
|
|
return elements
|
|
|
|
|
|
|
|
proc merkleRoot*(bytes: openArray[byte]): F =
|
|
|
|
merkleRoot(F.unmarshal(bytes, littleEndian))
|