nim-poseidon2/griffin/permutation.nim
2026-01-21 14:36:11 +01:00

107 lines
2.8 KiB
Nim

import
constantine/math/arithmetic,
constantine/math/io/io_fields,
constantine/math/io/io_bigints
import ../poseidon2/types
import ./roundconst
#-------------------------------------------------------------------------------
const expo_inv : B = fromHex(B,"0x26b6a528b427b35493736af8679aad17535cb9d394945a0dcfe7f7a98ccccccd")
const alpha : F = fromHex(F,"0x146ecffb34a66316fae66609f78d1310bc14ad7208082ca7943afebb1da4aa4a")
const beta : F = fromHex(F,"0x2b568115d544c7e941eff6ccc935384619b0fb7d2c5ba6c078c34cf81697ee1c")
const roundConstArray : array[33, F] = arrayFromHex( roundConstStr )
#-------------------------------------------------------------------------------
# inplace sbox, x => x^5
proc pow5(x: var F) : void =
var y = x
square(y)
square(y)
x *= y
# inplace sbox, x => x^(1/5)
proc powInv5(x: var F) : void =
x = fastPow(x, expo_inv)
#-------------------------------------------------------------------------------
proc sbox(x, y, z: var F) =
x.powInv5()
y.pow5()
let u : F = x + y
var m = beta
m += sqr(u)
m += alpha * u # m = u^2 + alpha*u + beta
z *= m
proc addRC(round: int, x, y, z: var F) =
if (round > 0):
let j = (round-1) * 3
x += roundConstArray[ j ]
y += roundConstArray[ j+1 ]
z += roundConstArray[ j+2 ]
proc linear(x, y, z : var F) =
var s = x ; s += y ; s += z
x += s
y += s
z += s
proc roundFun(round: int, x, y, z: var F) =
addRC(round,x,y,z)
sbox(x,y,z)
linear(x,y,z)
#-------------------------------------------------------------------------------
# the Griffin permutation (mutable, in-place version)
proc permInPlace*(x, y, z : var F) =
linear(x, y, z)
for j in 0..<12:
roundFun(j, x, y, z)
# the Griffin permutation (pure version)
func perm*(xyz: S) : S =
var (x,y,z) = xyz
permInPlace(x, y, z)
return (x,y,z)
#-------------------------------------------------------------------------------
# known-answer test: the expected permutation of (0,1,2)
const kat: S =
( F.fromHex("0x2311cdb3076c3a7ee37fd5a271e0f3a8a3cc38057d0cea37b78951f43b1b6ff6")
, F.fromHex("0x1d3aaed9ea361e899e667abd18e5328555b97b5c3890d52b261f940d6ab4df58")
, F.fromHex("0x22614a0ac719cb623a636adac3bac1b85b5a7a418fcf8ab3a3ae0787fb4bed9d")
)
proc sanityCheckExpoInv*() =
let x0 : F = F.fromHex("0x666")
var x : F = x0
x.pow5()
x.powInv5()
echo "sanity check /a = " & $(x == x0)
let y0 : F = F.fromHex("0x777017")
var y : F = y0
y.powInv5()
y.pow5()
echo "sanity check /b = " & $(y == y0)
proc testGriffin*() =
sanityCheckExpoInv()
let inp: S = (zero,one,two)
let candidate = perm(inp)
let (x,y,z) = candidate
echo "x = " & $x.toDecimal()
echo "y = " & $y.toDecimal()
echo "z = " & $z.toDecimal()
echo "KAT ok = " & $(candidate == kat)
#-------------------------------------------------------------------------------