mirror of
https://github.com/logos-storage/nim-poseidon2.git
synced 2026-01-02 13:43:08 +00:00
add sponge construction
This commit is contained in:
parent
573a77f14f
commit
acbc92dac7
101
poseidon2.nim
101
poseidon2.nim
@ -1,55 +1,15 @@
|
||||
import
|
||||
constantine/math/arithmetic,
|
||||
constantine/math/config/curves
|
||||
import constantine/math/arithmetic
|
||||
|
||||
import poseidon2/types
|
||||
import poseidon2/roundconst
|
||||
import poseidon2/roundfun
|
||||
import poseidon2/io
|
||||
|
||||
export toBytes
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
|
||||
const zero : F = getZero()
|
||||
|
||||
const externalRoundConst : array[24, F] = arrayFromHex( externalRoundConstStr )
|
||||
const internalRoundConst : array[56, F] = arrayFromHex( internalRoundConstStr )
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
|
||||
# inplace sbox, x => x^5
|
||||
func sbox(x: var F) : void =
|
||||
var y = x
|
||||
square(y)
|
||||
square(y)
|
||||
x *= y
|
||||
|
||||
func linearLayer(x, y, z : var F) =
|
||||
var s = x ; s += y ; s += z
|
||||
x += s
|
||||
y += s
|
||||
z += s
|
||||
|
||||
func internalRound(j: int; x, y, z: var F) =
|
||||
x += internalRoundConst[j]
|
||||
sbox(x)
|
||||
var s = x ; s += y ; s += z
|
||||
double(z)
|
||||
x += s
|
||||
y += s
|
||||
z += s
|
||||
|
||||
func externalRound(j: int; x, y, z : var F) =
|
||||
x += externalRoundConst[3*j+0]
|
||||
y += externalRoundConst[3*j+1]
|
||||
z += externalRoundConst[3*j+2]
|
||||
sbox(x) ; sbox(y) ; sbox(z)
|
||||
var s = x ; s += y ; s += z
|
||||
x += s
|
||||
y += s
|
||||
z += s
|
||||
|
||||
func permInplace*(x, y, z : var F) =
|
||||
# the Poseidon2 permutation (mutable, in-place version)
|
||||
proc permInplace*(x, y, z : var F) =
|
||||
linearLayer(x, y, z);
|
||||
for j in 0..3:
|
||||
externalRound(j, x, y, z)
|
||||
@ -58,6 +18,7 @@ func permInplace*(x, y, z : var F) =
|
||||
for j in 4..7:
|
||||
externalRound(j, x, y, z)
|
||||
|
||||
# the Poseidon2 permutation
|
||||
func perm*(xyz: S) : S =
|
||||
var (x,y,z) = xyz
|
||||
permInplace(x, y, z)
|
||||
@ -65,6 +26,56 @@ func perm*(xyz: S) : S =
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
|
||||
# sponge with rate=1 (capacity=2)
|
||||
func spongeWithRate1*(xs: openArray[F]) : F =
|
||||
let a = low(xs)
|
||||
let b = high(xs)
|
||||
let n = b-a+1
|
||||
|
||||
var s0 : F = zero
|
||||
var s1 : F = zero
|
||||
var s2 : F = zero
|
||||
|
||||
for i in 0..<n:
|
||||
s0 += xs[a+i]
|
||||
permInplace(s0,s1,s2)
|
||||
|
||||
# padding
|
||||
s0 += one;
|
||||
permInplace(s0,s1,s2)
|
||||
return s0
|
||||
|
||||
# sponge with rate=2 (capacity=1)
|
||||
func spongeWithRate2*(xs: openArray[F]) : F =
|
||||
let a = low(xs)
|
||||
let b = high(xs)
|
||||
let n = b-a+1
|
||||
let halfn : int = n div 2
|
||||
|
||||
var s0 : F = zero
|
||||
var s1 : F = zero
|
||||
var s2 : F = zero
|
||||
|
||||
for i in 0..<halfn:
|
||||
s0 += xs[a+2*i ]
|
||||
s1 += xs[a+2*i+1]
|
||||
permInplace(s0,s1,s2)
|
||||
|
||||
if (2*halfn == n):
|
||||
# padding even input
|
||||
s0 += one
|
||||
s1 += zero
|
||||
else:
|
||||
# padding odd input
|
||||
s0 += xs[b]
|
||||
s1 += one
|
||||
|
||||
permInplace(s0,s1,s2)
|
||||
return s0
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
|
||||
# 2-to-1 compression
|
||||
func compress*(a, b : F) : F =
|
||||
var x = a
|
||||
var y = b
|
||||
@ -101,3 +112,5 @@ func merkleRoot*(xs: openArray[F]) : F =
|
||||
|
||||
func merkleRoot*(bytes: openArray[byte]): F =
|
||||
merkleRoot(seq[F].fromBytes(bytes))
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
|
||||
51
poseidon2/roundfun.nim
Normal file
51
poseidon2/roundfun.nim
Normal file
@ -0,0 +1,51 @@
|
||||
import
|
||||
constantine/math/arithmetic,
|
||||
constantine/math/config/curves
|
||||
|
||||
import ./types
|
||||
import ./roundconst
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
|
||||
const zero* : F = getZero()
|
||||
const one* : F = getOne()
|
||||
|
||||
const externalRoundConst : array[24, F] = arrayFromHex( externalRoundConstStr )
|
||||
const internalRoundConst : array[56, F] = arrayFromHex( internalRoundConstStr )
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
|
||||
# inplace sbox, x => x^5
|
||||
func sbox*(x: var F) : void =
|
||||
var y = x
|
||||
square(y)
|
||||
square(y)
|
||||
x *= y
|
||||
|
||||
func linearLayer*(x, y, z : var F) =
|
||||
var s = x ; s += y ; s += z
|
||||
x += s
|
||||
y += s
|
||||
z += s
|
||||
|
||||
func internalRound*(j: int; x, y, z: var F) =
|
||||
x += internalRoundConst[j]
|
||||
sbox(x)
|
||||
var s = x ; s += y ; s += z
|
||||
double(z)
|
||||
x += s
|
||||
y += s
|
||||
z += s
|
||||
|
||||
func externalRound*(j: int; x, y, z : var F) =
|
||||
x += externalRoundConst[3*j+0]
|
||||
y += externalRoundConst[3*j+1]
|
||||
z += externalRoundConst[3*j+2]
|
||||
sbox(x) ; sbox(y) ; sbox(z)
|
||||
var s = x ; s += y ; s += z
|
||||
x += s
|
||||
y += s
|
||||
z += s
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
|
||||
@ -1,8 +1,8 @@
|
||||
|
||||
import
|
||||
constantine/math/arithmetic,
|
||||
constantine/math/io/io_fields,
|
||||
constantine/math/io/io_bigints,
|
||||
constantine/math/arithmetic,
|
||||
constantine/math/config/curves
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
@ -18,9 +18,17 @@ func getZero*() : F =
|
||||
setZero(z)
|
||||
return z
|
||||
|
||||
func getOne*() : F =
|
||||
var y : F
|
||||
# y.fromUint(1'u32) # WTF, why does this not compile ???
|
||||
y.fromHex("0x01")
|
||||
return y
|
||||
|
||||
# for some reason this one does not compile... ???
|
||||
# (when actually called)
|
||||
func toF*(a: int) : F =
|
||||
var y : F
|
||||
fromInt(y, a);
|
||||
y.fromInt(a)
|
||||
return y
|
||||
|
||||
func hexToF*(s : string, endian: static Endianness = bigEndian) : F =
|
||||
|
||||
@ -10,6 +10,36 @@ import constantine/serialization/codecs
|
||||
import poseidon2/types
|
||||
import poseidon2
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
|
||||
const expectedSpongeResultsRate1 : array[8, string] =
|
||||
[ "12363515589665961836680709257448433057869762330741639517836048636244832188495"
|
||||
, "10755250120808789043370150604836786069442045362641800439807384337872752972068"
|
||||
, "04842014531366721455661330916203255410159059117951668762867230544004815370337"
|
||||
, "13502515636936876459766686836354199651004594178376827739246669803080321705927"
|
||||
, "19312121576697000598919845239663673946550934099828684806027699882665482322097"
|
||||
, "21509595983900483103260021285060939918324350560398732346653142062765920502059"
|
||||
, "11892726572958426459775026381831352388154613015696290329810000571844227402585"
|
||||
, "10284126944232604349630438079200913190801781418325975675236599364113149409058"
|
||||
]
|
||||
|
||||
# TODO: add domain separation between rate=1 and rate=2, so that the empty input
|
||||
# gives different results. But this has to be done in all the other Poseidon2 libraries
|
||||
# too (circom, Haskell, C...)
|
||||
|
||||
const expectedSpongeResultsRate2 : array[8, string] =
|
||||
[ "12363515589665961836680709257448433057869762330741639517836048636244832188495"
|
||||
, "00899009032366875286186953183805404053380636995610127460025486428583509745414"
|
||||
, "16500906802543951227422597869354004883060519121579073949799015758201044544012"
|
||||
, "05275430613748165078459451567241807462288293965310307668712900802458919462965"
|
||||
, "13763559248248167400098483085605230840597893317332127197498651878933380690961"
|
||||
, "14871143128308815290845020646262475973102494373985615216162863857354721038367"
|
||||
, "02746725081632011689597680224823496636241961292066939394613880404914874634920"
|
||||
, "02290144245981244996669076598332792758523446545263085369617640761875376727694"
|
||||
]
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
|
||||
suite "poseidon2":
|
||||
|
||||
test "permutation in place":
|
||||
@ -23,6 +53,24 @@ suite "poseidon2":
|
||||
check toDecimal(y) == "09030699330013392132529464674294378792132780497765201297316864012141442630280"
|
||||
check toDecimal(z) == "09137931384593657624554037900714196568304064431583163402259937475584578975855"
|
||||
|
||||
test "sponge with rate=1":
|
||||
for n in 0..7:
|
||||
var xs: seq[F]
|
||||
for i in 1..n:
|
||||
xs.add( toF(i) )
|
||||
let h = spongeWithRate1(xs)
|
||||
# echo(toDecimal(h))
|
||||
check toDecimal(h) == expectedSpongeResultsRate1[n]
|
||||
|
||||
test "sponge with rate=2":
|
||||
for n in 0..7:
|
||||
var xs: seq[F]
|
||||
for i in 1..n:
|
||||
xs.add( toF(i) )
|
||||
let h = spongeWithRate2(xs)
|
||||
# echo(toDecimal(h))
|
||||
check toDecimal(h) == expectedSpongeResultsRate2[n]
|
||||
|
||||
test "merkle root of field elements":
|
||||
let m = 17
|
||||
let n = 2^m
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user