mirror of
https://github.com/logos-storage/nim-poseidon2.git
synced 2026-01-07 16:13:10 +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
|
import constantine/math/arithmetic
|
||||||
constantine/math/arithmetic,
|
|
||||||
constantine/math/config/curves
|
|
||||||
|
|
||||||
import poseidon2/types
|
import poseidon2/types
|
||||||
import poseidon2/roundconst
|
import poseidon2/roundfun
|
||||||
import poseidon2/io
|
import poseidon2/io
|
||||||
|
|
||||||
export toBytes
|
export toBytes
|
||||||
|
|
||||||
#-------------------------------------------------------------------------------
|
#-------------------------------------------------------------------------------
|
||||||
|
|
||||||
const zero : F = getZero()
|
# the Poseidon2 permutation (mutable, in-place version)
|
||||||
|
proc permInplace*(x, y, z : var F) =
|
||||||
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) =
|
|
||||||
linearLayer(x, y, z);
|
linearLayer(x, y, z);
|
||||||
for j in 0..3:
|
for j in 0..3:
|
||||||
externalRound(j, x, y, z)
|
externalRound(j, x, y, z)
|
||||||
@ -58,6 +18,7 @@ func permInplace*(x, y, z : var F) =
|
|||||||
for j in 4..7:
|
for j in 4..7:
|
||||||
externalRound(j, x, y, z)
|
externalRound(j, x, y, z)
|
||||||
|
|
||||||
|
# the Poseidon2 permutation
|
||||||
func perm*(xyz: S) : S =
|
func perm*(xyz: S) : S =
|
||||||
var (x,y,z) = xyz
|
var (x,y,z) = xyz
|
||||||
permInplace(x, y, z)
|
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 =
|
func compress*(a, b : F) : F =
|
||||||
var x = a
|
var x = a
|
||||||
var y = b
|
var y = b
|
||||||
@ -101,3 +112,5 @@ func merkleRoot*(xs: openArray[F]) : F =
|
|||||||
|
|
||||||
func merkleRoot*(bytes: openArray[byte]): F =
|
func merkleRoot*(bytes: openArray[byte]): F =
|
||||||
merkleRoot(seq[F].fromBytes(bytes))
|
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
|
import
|
||||||
|
constantine/math/arithmetic,
|
||||||
constantine/math/io/io_fields,
|
constantine/math/io/io_fields,
|
||||||
constantine/math/io/io_bigints,
|
constantine/math/io/io_bigints,
|
||||||
constantine/math/arithmetic,
|
|
||||||
constantine/math/config/curves
|
constantine/math/config/curves
|
||||||
|
|
||||||
#-------------------------------------------------------------------------------
|
#-------------------------------------------------------------------------------
|
||||||
@ -18,9 +18,17 @@ func getZero*() : F =
|
|||||||
setZero(z)
|
setZero(z)
|
||||||
return 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 =
|
func toF*(a: int) : F =
|
||||||
var y : F
|
var y : F
|
||||||
fromInt(y, a);
|
y.fromInt(a)
|
||||||
return y
|
return y
|
||||||
|
|
||||||
func hexToF*(s : string, endian: static Endianness = bigEndian) : F =
|
func hexToF*(s : string, endian: static Endianness = bigEndian) : F =
|
||||||
|
|||||||
@ -10,6 +10,36 @@ import constantine/serialization/codecs
|
|||||||
import poseidon2/types
|
import poseidon2/types
|
||||||
import poseidon2
|
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":
|
suite "poseidon2":
|
||||||
|
|
||||||
test "permutation in place":
|
test "permutation in place":
|
||||||
@ -23,6 +53,24 @@ suite "poseidon2":
|
|||||||
check toDecimal(y) == "09030699330013392132529464674294378792132780497765201297316864012141442630280"
|
check toDecimal(y) == "09030699330013392132529464674294378792132780497765201297316864012141442630280"
|
||||||
check toDecimal(z) == "09137931384593657624554037900714196568304064431583163402259937475584578975855"
|
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":
|
test "merkle root of field elements":
|
||||||
let m = 17
|
let m = 17
|
||||||
let n = 2^m
|
let n = 2^m
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user