Merge pull request #806 from Zokrates/poseidon
Add poseidon hashing algorithm
This commit is contained in:
commit
6cfaedb70b
15 changed files with 2308 additions and 0 deletions
1
changelogs/unreleased/806-dark64
Normal file
1
changelogs/unreleased/806-dark64
Normal file
|
@ -0,0 +1 @@
|
|||
Add [poseidon](https://www.poseidon-hash.info/) zk-friendly hashing algorithm to stdlib
|
2078
zokrates_stdlib/stdlib/hashes/poseidon/constants.zok
Normal file
2078
zokrates_stdlib/stdlib/hashes/poseidon/constants.zok
Normal file
File diff suppressed because it is too large
Load diff
59
zokrates_stdlib/stdlib/hashes/poseidon/poseidon.zok
Normal file
59
zokrates_stdlib/stdlib/hashes/poseidon/poseidon.zok
Normal file
|
@ -0,0 +1,59 @@
|
|||
// https://eprint.iacr.org/2019/458.pdf
|
||||
|
||||
from "./constants.zok" import poseidon_c
|
||||
from "./constants.zok" import poseidon_m
|
||||
|
||||
def ark<N>(field[N] state, field[497] c, u32 it) -> field[N]:
|
||||
for u32 i in 0..N do
|
||||
state[i] = state[i] + c[it + i]
|
||||
endfor
|
||||
return state
|
||||
|
||||
def sbox<N>(field[N] state, u32 f, u32 p, u32 r) -> field[N]:
|
||||
state[0] = state[0]**5
|
||||
for u32 i in 1..N do
|
||||
state[i] = if ((r < f/2) || (r >= f/2 + p)) then state[i]**5 else state[i] fi
|
||||
endfor
|
||||
return state
|
||||
|
||||
def mix<N>(field[N] state, field[7][7] m) -> field[N]:
|
||||
field[N] out = [0; N]
|
||||
for u32 i in 0..N do
|
||||
field acc = 0
|
||||
for u32 j in 0..N do
|
||||
acc = acc + (state[j] * m[i][j])
|
||||
endfor
|
||||
out[i] = acc
|
||||
endfor
|
||||
return out
|
||||
|
||||
def main<N>(field[N] inputs) -> field:
|
||||
assert(N > 0 && N <= 6) // max 6 inputs
|
||||
|
||||
u32 t = N + 1
|
||||
u32[8] rounds_p = [56, 57, 56, 60, 60, 63, 64, 63]
|
||||
|
||||
u32 f = 8
|
||||
u32 p = rounds_p[(t - 2)]
|
||||
|
||||
// Constants are padded with zeroes to the maximum value calculated by
|
||||
// t * (f + p) = 497, where `t` (number of inputs + 1) is a max of 7.
|
||||
// This is done to keep the function generic, as resulting array size depends on `t`
|
||||
// and we do not want callers passing down constants.
|
||||
// This should be revisited once compiler limitations are gone.
|
||||
|
||||
field[497] c = poseidon_c()[t - 2]
|
||||
field[7][7] m = poseidon_m()[t - 2]
|
||||
|
||||
field[t] state = [0; t]
|
||||
for u32 i in 1..t do
|
||||
state[i] = inputs[i - 1]
|
||||
endfor
|
||||
|
||||
for u32 r in 0..f+p do
|
||||
state = ark(state, c, r * t)
|
||||
state = sbox(state, f, p, r)
|
||||
state = mix(state, m)
|
||||
endfor
|
||||
|
||||
return state[0]
|
25
zokrates_stdlib/tests/tests/hashes/poseidon/poseidon_1.json
Normal file
25
zokrates_stdlib/tests/tests/hashes/poseidon/poseidon_1.json
Normal file
|
@ -0,0 +1,25 @@
|
|||
{
|
||||
"entry_point": "./tests/tests/hashes/poseidon/poseidon_1.zok",
|
||||
"tests": [
|
||||
{
|
||||
"input": {
|
||||
"values": ["1"]
|
||||
},
|
||||
"output": {
|
||||
"Ok": {
|
||||
"values": ["18586133768512220936620570745912940619677854269274689475585506675881198879027"]
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"input": {
|
||||
"values": ["42"]
|
||||
},
|
||||
"output": {
|
||||
"Ok": {
|
||||
"values": ["12326503012965816391338144612242952408728683609716147019497703475006801258307"]
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
|
@ -0,0 +1,5 @@
|
|||
import "hashes/poseidon/poseidon" as poseidon
|
||||
|
||||
def main(field i) -> field:
|
||||
field output = poseidon([i])
|
||||
return output
|
15
zokrates_stdlib/tests/tests/hashes/poseidon/poseidon_2.json
Normal file
15
zokrates_stdlib/tests/tests/hashes/poseidon/poseidon_2.json
Normal file
|
@ -0,0 +1,15 @@
|
|||
{
|
||||
"entry_point": "./tests/tests/hashes/poseidon/poseidon_2.zok",
|
||||
"tests": [
|
||||
{
|
||||
"input": {
|
||||
"values": ["1", "2"]
|
||||
},
|
||||
"output": {
|
||||
"Ok": {
|
||||
"values": ["7853200120776062878684798364095072458815029376092732009249414926327459813530"]
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
|
@ -0,0 +1,5 @@
|
|||
import "hashes/poseidon/poseidon" as poseidon
|
||||
|
||||
def main(field[2] i) -> field:
|
||||
field output = poseidon(i)
|
||||
return output
|
15
zokrates_stdlib/tests/tests/hashes/poseidon/poseidon_3.json
Normal file
15
zokrates_stdlib/tests/tests/hashes/poseidon/poseidon_3.json
Normal file
|
@ -0,0 +1,15 @@
|
|||
{
|
||||
"entry_point": "./tests/tests/hashes/poseidon/poseidon_3.zok",
|
||||
"tests": [
|
||||
{
|
||||
"input": {
|
||||
"values": ["1", "2", "3"]
|
||||
},
|
||||
"output": {
|
||||
"Ok": {
|
||||
"values": ["6542985608222806190361240322586112750744169038454362455181422643027100751666"]
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
|
@ -0,0 +1,5 @@
|
|||
import "hashes/poseidon/poseidon" as poseidon
|
||||
|
||||
def main(field[3] i) -> field:
|
||||
field output = poseidon(i)
|
||||
return output
|
15
zokrates_stdlib/tests/tests/hashes/poseidon/poseidon_4.json
Normal file
15
zokrates_stdlib/tests/tests/hashes/poseidon/poseidon_4.json
Normal file
|
@ -0,0 +1,15 @@
|
|||
{
|
||||
"entry_point": "./tests/tests/hashes/poseidon/poseidon_4.zok",
|
||||
"tests": [
|
||||
{
|
||||
"input": {
|
||||
"values": ["1", "2", "3", "4"]
|
||||
},
|
||||
"output": {
|
||||
"Ok": {
|
||||
"values": ["18821383157269793795438455681495246036402687001665670618754263018637548127333"]
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
|
@ -0,0 +1,5 @@
|
|||
import "hashes/poseidon/poseidon" as poseidon
|
||||
|
||||
def main(field[4] i) -> field:
|
||||
field output = poseidon(i)
|
||||
return output
|
35
zokrates_stdlib/tests/tests/hashes/poseidon/poseidon_5.json
Normal file
35
zokrates_stdlib/tests/tests/hashes/poseidon/poseidon_5.json
Normal file
|
@ -0,0 +1,35 @@
|
|||
{
|
||||
"entry_point": "./tests/tests/hashes/poseidon/poseidon_5.zok",
|
||||
"tests": [
|
||||
{
|
||||
"input": {
|
||||
"values": ["1", "2", "3", "4", "5"]
|
||||
},
|
||||
"output": {
|
||||
"Ok": {
|
||||
"values": ["6183221330272524995739186171720101788151706631170188140075976616310159254464"]
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"input": {
|
||||
"values": ["1", "2", "0", "0", "0"]
|
||||
},
|
||||
"output": {
|
||||
"Ok": {
|
||||
"values": ["1018317224307729531995786483840663576608797660851238720571059489595066344487"]
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"input": {
|
||||
"values": ["3", "4", "0", "0", "0"]
|
||||
},
|
||||
"output": {
|
||||
"Ok": {
|
||||
"values": ["5811595552068139067952687508729883632420015185677766880877743348592482390548"]
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
|
@ -0,0 +1,5 @@
|
|||
import "hashes/poseidon/poseidon" as poseidon
|
||||
|
||||
def main(field[5] i) -> field:
|
||||
field output = poseidon(i)
|
||||
return output
|
35
zokrates_stdlib/tests/tests/hashes/poseidon/poseidon_6.json
Normal file
35
zokrates_stdlib/tests/tests/hashes/poseidon/poseidon_6.json
Normal file
|
@ -0,0 +1,35 @@
|
|||
{
|
||||
"entry_point": "./tests/tests/hashes/poseidon/poseidon_6.zok",
|
||||
"tests": [
|
||||
{
|
||||
"input": {
|
||||
"values": ["1", "2", "3", "4", "5", "6"]
|
||||
},
|
||||
"output": {
|
||||
"Ok": {
|
||||
"values": ["20400040500897583745843009878988256314335038853985262692600694741116813247201"]
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"input": {
|
||||
"values": ["1", "2", "0", "0", "0", "0"]
|
||||
},
|
||||
"output": {
|
||||
"Ok": {
|
||||
"values": ["15336558801450556532856248569924170992202208561737609669134139141992924267169"]
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"input": {
|
||||
"values": ["3", "4", "0", "0", "0", "0"]
|
||||
},
|
||||
"output": {
|
||||
"Ok": {
|
||||
"values": ["12263118664590987767234828103155242843640892839966517009184493198782366909018"]
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
|
@ -0,0 +1,5 @@
|
|||
import "hashes/poseidon/poseidon" as poseidon
|
||||
|
||||
def main(field[6] i) -> field:
|
||||
field output = poseidon(i)
|
||||
return output
|
Loading…
Reference in a new issue