From 47df39467c15fa321d4628310e7b6bde75bbdf5e Mon Sep 17 00:00:00 2001 From: Balazs Komuves Date: Wed, 21 Jan 2026 14:36:11 +0100 Subject: [PATCH] add Griffin permutation --- bench/.gitignore | 3 ++ bench/bench_griffin.nim | 51 +++++++++++++++++++ bench/bench_perm.nim | 19 +------ bench/shared.nim | 23 +++++++++ griffin/compress.nim | 10 ++++ griffin/permutation.nim | 106 ++++++++++++++++++++++++++++++++++++++++ griffin/roundconst.nim | 41 ++++++++++++++++ poseidon2.nimble | 13 +++-- poseidon2/types.nim | 28 +++++++++++ 9 files changed, 272 insertions(+), 22 deletions(-) create mode 100644 bench/.gitignore create mode 100644 bench/bench_griffin.nim create mode 100644 bench/shared.nim create mode 100644 griffin/compress.nim create mode 100644 griffin/permutation.nim create mode 100644 griffin/roundconst.nim diff --git a/bench/.gitignore b/bench/.gitignore new file mode 100644 index 0000000..335a144 --- /dev/null +++ b/bench/.gitignore @@ -0,0 +1,3 @@ +.DS_Store +bench_perm +bench_griffin diff --git a/bench/bench_griffin.nim b/bench/bench_griffin.nim new file mode 100644 index 0000000..e97e0ca --- /dev/null +++ b/bench/bench_griffin.nim @@ -0,0 +1,51 @@ + +# +# nimble build -d:release +# + +import strformat +# import strutils + +import constantine/math/arithmetic +import constantine/math/io/io_fields +import constantine/math/io/io_bigints + +import poseidon2/types +import poseidon2/io +import griffin/permutation + +import ./shared + +#------------------------------------------------------------------------------- + +proc iteratePerm(n: int) = + + var x: F = toF(0) + var y: F = toF(1) + var z: F = toF(2) + + for i in 0.. 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) + +#------------------------------------------------------------------------------- diff --git a/griffin/roundconst.nim b/griffin/roundconst.nim new file mode 100644 index 0000000..8049c17 --- /dev/null +++ b/griffin/roundconst.nim @@ -0,0 +1,41 @@ + +#------------------------------------------------------------------------------- + +const roundConstStr* : array[33, string] = + [ "0x2fb30cafdb1f76156dfabf0cd0af4b895e764ac2a84386c9d0d7aed6a7f4eac9" + , "0x282927892ce324572f19abb14871d2b539a80d8a5800cdb87a81e1697a94b6c9" + , "0x03d0f3f2711dd59e3d97fc797261300cd3fee33b95cf710a32edf42aa2bc0905" + , "0x036a8b3eb9ef35c74ea5a367ed279ee6d043d4ff69817f192c7251b91dcbb03d" + , "0x2a626d396e7fa8ce8d6339bb37bd48491d56db0c7ac0afb5008a7464d5776a26" + , "0x0cc9dfabbeaef7982543453ea3ac37ef2bfefd35a7e7070aa39b021035852d5b" + , "0x2a1951149e2568ab28e972a2ceddc49eff0cae8e1cddcf4b0684a73a1b4ef61b" + , "0x2d0ff8e9158b2fd7ae3afe01cf09d4ce9ff81e6127e441eb6cbc79d21f22be9e" + , "0x1cc315b7ea0c1efb538f0c3248a7da062309a9e41af5a555c9ea9e8a10930cb5" + , "0x03cb10093ea62fb3f6e5680a128d07112ee566f1b424558f2ec9d86892e13a80" + , "0x12e7bb50ae7e9e90f1765c073eb61c4be4956c424930233ce497d2722a458868" + , "0x006b1367547937ae71e2e9b55d2f90c90131f9e6784ce3de0eb314ec748871e7" + , "0x1ffff572c53442c58809aeca02287839b11df1420deb0e99fde2baad8b86fa9c" + , "0x13aefd685e7739f9a8b4ccdbfc5ef9e566149af4d54d6b746058ea44cb422840" + , "0x1ea6c3ea93fe6f4ed0186941650de76ff94ab0e6e8a583996b67ba026dd2b7a5" + , "0x288f120288f9225643de833c5c15e22aadd358132bbdc12c75109048a158c9f4" + , "0x0f638114cd7c781ab299e5233338b00cf2996df962347a00146a22103d9ad91a" + , "0x14eeca5fa2c18999ea25ddf44237d6ac3cb8757ea452f67e2590a46f7d5b1e4f" + , "0x102d1a099e8cd107dc056e72370e340b0316d237b72d99ef6261761f7eb2d61c" + , "0x0ef741fc2fcda50f207c759dbd844a4d630cc0e4062ca80f3ffba2cce2d3f51d" + , "0x0989b9f642485692a1f91a4b207db64f38ae545bf3e0622f3862967d27f563db" + , "0x1eb4d812c80ce04784a80c89fbcc5aab89db274c62602bdd30f3223655e6cf8a" + , "0x0124a9400253731facd46e21f41016aed69a79087f81665bc5d29a34e4e924dd" + , "0x2520bfa6b70e6ba7ad380aaf9015b71983868a9c53e66e685ed6e48692c185a8" + , "0x1bd62b5bfa02667ac08d51d9e77bb3ab8dbd19e7a701442a20e23f7d3d6b28b4" + , "0x1ae2f0d09fffc6bb869ebc639484a7c2084cfa3c1f88a7440713b1b154e5f952" + , "0x0cd06e16a0d570c3799d800d92a25efbd44a795ed5b9114a28f5f869a57d9ba1" + , "0x00691740e313922521fe8c4843355eff8de0f93d4f62df0fe48755b897881c39" + , "0x19903aa449fe9c27ee9c8320e6915b50c2822e61ce894be72b47a449c5705762" + , "0x126e801aae44016a35deceaa3eba6ccc341fa3c2a65ab3d021fcd39abd170e1b" + , "0x1b0a98be27b54ac9d5d72b94187c991c1872cb2c7777c0e880f439c133971e8d" + , "0x1e10a35afda2e5a173d4f3edecf29dacf51d8fac33d6bfb4088cc787ec647605" + , "0x1793cda85abe2782ea8e911ce92bab59a8c68e0dd561a57b064bb233f109cc57" + ] + +#------------------------------------------------------------------------------- + diff --git a/poseidon2.nimble b/poseidon2.nimble index 3d61dd6..9896cf8 100644 --- a/poseidon2.nimble +++ b/poseidon2.nimble @@ -1,8 +1,11 @@ -version = "0.1.0" -author = "nim-poseidon2 authors" +version = "0.1.0" +author = "nim-poseidon2 authors" description = "Poseidon2 hash function" -license = "MIT" +license = "MIT" -requires "https://github.com/mratsim/constantine#bc3845aa492b52f7fef047503b1592e830d1a774" +installExt = @["nim"] -bin = @["bench/bench_perm"] \ No newline at end of file +#requires "https://github.com/mratsim/constantine#bc3845aa492b52f7fef047503b1592e830d1a774" +requires "https://github.com/mratsim/constantine#782d838e7a073262750eff593af6dfff3ff832dd" + +bin = @["bench/bench_perm", "bench/bench_griffin"] \ No newline at end of file diff --git a/poseidon2/types.nim b/poseidon2/types.nim index 98d567d..0a24f41 100644 --- a/poseidon2/types.nim +++ b/poseidon2/types.nim @@ -22,6 +22,7 @@ func getZero*() : F = const zero* : F = getZero() const one* : F = fromHex(F,"0x01") # note: `fromUint()` does not work at compile time +const two* : F = fromHex(F,"0x02") const twoToThe64* : F = fromHex(F,"0x10000000000000000") @@ -39,5 +40,32 @@ func arrayFromHex*[N]( tmp[i] = hexToF(inp[i], endian) return tmp +#------------------------------------------------------------------------------- + +func `+`*(x, y: F): F = ( var z: F = x ; z += y ; return z ) +func `-`*(x, y: F): F = ( var z: F = x ; z -= y ; return z ) +func `*`*(x, y: F): F = ( var z: F = x ; z *= y ; return z ) + func `==`*(a, b: F): bool = bool(arithmetic.`==`(a, b)) + +func sqr*(x : F): F = + var y = x + y.square() + return y + +#------------------------------------------------------------------------------- + +func fastPow*(base: F, expo: B): F = + var s : F = base + var a : F = one + var e : B = expo + for i in 0..<254: + if bool(isOdd(e)): + a *= s + s.square() + e.div2() + return a + +#------------------------------------------------------------------------------- +