-
Notifications
You must be signed in to change notification settings - Fork 379
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Feat/poseidon2 #1300
Open
ThomasPiellard
wants to merge
17
commits into
master
Choose a base branch
from
feat/poseidon2
base: master
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Feat/poseidon2 #1300
Changes from 15 commits
Commits
Show all changes
17 commits
Select commit
Hold shift + click to select a range
c6a27fc
feat: matMulM4InPlace
ivokub fa51a21
feat: matMulExternalInPlace
ThomasPiellard 4368103
feat: permutation
ThomasPiellard 22a972b
feat: bumped gnark-crypto
ThomasPiellard 93ce72f
feat: bumped gnark-crypto
ThomasPiellard f12cfae
feat: remove internal state
ThomasPiellard d27dc2b
-feat: init poseidon2
ThomasPiellard 4a5ea8d
feat: inverse sbox
ThomasPiellard 8ec1272
feat: sbox17
ThomasPiellard 1edf3c3
feat: fixed addroundkey
ThomasPiellard 2ff62cb
feat: tests bls12377, bn254 ok
ThomasPiellard 6994606
feat: test file ok
ThomasPiellard 9b22eb3
feat: tests ok
ThomasPiellard bd1d9a7
feat: bump gnark-crypto
ThomasPiellard 49e6c68
feat: bumped gnark-crypto
ThomasPiellard 67fd4ae
feat: bumped gnark-crypto
ThomasPiellard e5cd895
fix: fixed too many args
ThomasPiellard File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -85,7 +85,7 @@ You can also get in touch directly: [email protected] | |
* [OpenZeppelin - November 2023 - gnark PLONK Solidity verifier template](https://blog.openzeppelin.com/linea-verifier-audit-1) | ||
* [ZKSecurity.xyz - May 2024 - gnark standard library](audits/2024-05%20-%20zksecurity%20-%20gnark%20std.pdf) | ||
* [OpenZeppelin - June 2024 - gnark PLONK prover and verifier](https://blog.openzeppelin.com/linea-prover-audit) | ||
* [LeastAuthority - July 2024 - gnark general and GKR (initial report)](audits/2024-07%20-%20Least%20Authority%20-%20arithm%20and%20GKR.pdf) | ||
* [LeastAuthority - September 2024 - gnark general and GKR](audits/2024-09%20-%20Least%20Authority%20-%20arithm%20and%20GKR.pdf) | ||
|
||
## Proving schemes and curves | ||
|
||
|
Binary file not shown.
Binary file not shown.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,284 @@ | ||
package poseidon | ||
|
||
import ( | ||
"errors" | ||
"math/big" | ||
|
||
"github.com/consensys/gnark-crypto/ecc" | ||
poseidonbls12377 "github.com/consensys/gnark-crypto/ecc/bls12-377/fr/poseidon2" | ||
poseidonbls12381 "github.com/consensys/gnark-crypto/ecc/bls12-381/fr/poseidon2" | ||
poseidonbls24315 "github.com/consensys/gnark-crypto/ecc/bls24-315/fr/poseidon2" | ||
poseidonbls24317 "github.com/consensys/gnark-crypto/ecc/bls24-317/fr/poseidon2" | ||
poseidonbn254 "github.com/consensys/gnark-crypto/ecc/bn254/fr/poseidon2" | ||
poseidonbw6633 "github.com/consensys/gnark-crypto/ecc/bw6-633/fr/poseidon2" | ||
poseidonbw6761 "github.com/consensys/gnark-crypto/ecc/bw6-761/fr/poseidon2" | ||
"github.com/consensys/gnark/frontend" | ||
) | ||
|
||
var ( | ||
ErrInvalidSizebuffer = errors.New("the size of the input should match the size of the hash buffer") | ||
) | ||
|
||
type Hash struct { | ||
params parameters | ||
} | ||
|
||
// parameters describing the poseidon2 implementation | ||
type parameters struct { | ||
|
||
// len(preimage)+len(digest)=len(preimage)+ceil(log(2*<security_level>/r)) | ||
t int | ||
|
||
// sbox degree | ||
d int | ||
|
||
// number of full rounds (even number) | ||
rF int | ||
|
||
// number of partial rounds | ||
rP int | ||
|
||
// diagonal elements of the internal matrices, minus one | ||
diagInternalMatrices []big.Int | ||
|
||
// round keys | ||
roundKeys [][]big.Int | ||
} | ||
|
||
func NewHash(t, d, rf, rp int, seed string, curve ecc.ID) Hash { | ||
params := parameters{t: t, d: d, rF: rf, rP: rp} | ||
if curve == ecc.BN254 { | ||
rc := poseidonbn254.InitRC(seed, rf, rp, t) | ||
params.roundKeys = make([][]big.Int, len(rc)) | ||
for i := 0; i < len(rc); i++ { | ||
params.roundKeys[i] = make([]big.Int, len(rc[i])) | ||
for j := 0; j < len(rc[i]); j++ { | ||
rc[i][j].BigInt(¶ms.roundKeys[i][j]) | ||
} | ||
} | ||
} else if curve == ecc.BLS12_381 { | ||
rc := poseidonbls12381.InitRC(seed, rf, rp, t) | ||
params.roundKeys = make([][]big.Int, len(rc)) | ||
for i := 0; i < len(rc); i++ { | ||
params.roundKeys[i] = make([]big.Int, len(rc[i])) | ||
for j := 0; j < len(rc[i]); j++ { | ||
rc[i][j].BigInt(¶ms.roundKeys[i][j]) | ||
} | ||
} | ||
} else if curve == ecc.BLS12_377 { | ||
rc := poseidonbls12377.InitRC(seed, rf, rp, t) | ||
params.roundKeys = make([][]big.Int, len(rc)) | ||
for i := 0; i < len(rc); i++ { | ||
params.roundKeys[i] = make([]big.Int, len(rc[i])) | ||
for j := 0; j < len(rc[i]); j++ { | ||
rc[i][j].BigInt(¶ms.roundKeys[i][j]) | ||
} | ||
} | ||
} else if curve == ecc.BW6_761 { | ||
rc := poseidonbw6761.InitRC(seed, rf, rp, t) | ||
params.roundKeys = make([][]big.Int, len(rc)) | ||
for i := 0; i < len(rc); i++ { | ||
params.roundKeys[i] = make([]big.Int, len(rc[i])) | ||
for j := 0; j < len(rc[i]); j++ { | ||
rc[i][j].BigInt(¶ms.roundKeys[i][j]) | ||
} | ||
} | ||
} else if curve == ecc.BW6_633 { | ||
rc := poseidonbw6633.InitRC(seed, rf, rp, t) | ||
params.roundKeys = make([][]big.Int, len(rc)) | ||
for i := 0; i < len(rc); i++ { | ||
params.roundKeys[i] = make([]big.Int, len(rc[i])) | ||
for j := 0; j < len(rc[i]); j++ { | ||
rc[i][j].BigInt(¶ms.roundKeys[i][j]) | ||
} | ||
} | ||
} else if curve == ecc.BLS24_315 { | ||
rc := poseidonbls24315.InitRC(seed, rf, rp, t) | ||
params.roundKeys = make([][]big.Int, len(rc)) | ||
for i := 0; i < len(rc); i++ { | ||
params.roundKeys[i] = make([]big.Int, len(rc[i])) | ||
for j := 0; j < len(rc[i]); j++ { | ||
rc[i][j].BigInt(¶ms.roundKeys[i][j]) | ||
} | ||
} | ||
} else if curve == ecc.BLS24_317 { | ||
rc := poseidonbls24317.InitRC(seed, rf, rp, t) | ||
params.roundKeys = make([][]big.Int, len(rc)) | ||
for i := 0; i < len(rc); i++ { | ||
params.roundKeys[i] = make([]big.Int, len(rc[i])) | ||
for j := 0; j < len(rc[i]); j++ { | ||
rc[i][j].BigInt(¶ms.roundKeys[i][j]) | ||
} | ||
} | ||
} | ||
return Hash{params: params} | ||
} | ||
|
||
// sBox applies the sBox on buffer[index] | ||
func (h *Hash) sBox(api frontend.API, index int, input []frontend.Variable) { | ||
tmp := input[index] | ||
if h.params.d == 3 { | ||
input[index] = api.Mul(input[index], input[index]) | ||
input[index] = api.Mul(tmp, input[index]) | ||
} else if h.params.d == 5 { | ||
input[index] = api.Mul(input[index], input[index]) | ||
input[index] = api.Mul(input[index], input[index]) | ||
input[index] = api.Mul(input[index], tmp) | ||
} else if h.params.d == 7 { | ||
input[index] = api.Mul(input[index], input[index]) | ||
input[index] = api.Mul(input[index], tmp) | ||
input[index] = api.Mul(input[index], input[index]) | ||
input[index] = api.Mul(input[index], tmp) | ||
} else if h.params.d == 17 { | ||
input[index] = api.Mul(input[index], input[index]) | ||
input[index] = api.Mul(input[index], input[index]) | ||
input[index] = api.Mul(input[index], input[index]) | ||
input[index] = api.Mul(input[index], input[index]) | ||
input[index] = api.Mul(input[index], tmp) | ||
} else if h.params.d == -1 { | ||
input[index] = api.Inverse(input[index]) | ||
} | ||
} | ||
|
||
// matMulM4 computes | ||
// s <- M4*s | ||
// where M4= | ||
// (5 7 1 3) | ||
// (4 6 1 1) | ||
// (1 3 5 7) | ||
// (1 1 4 6) | ||
// on chunks of 4 elemts on each part of the buffer | ||
// see https://eprint.iacr.org/2023/323.pdf appendix B for the addition chain | ||
func (h *Hash) matMulM4InPlace(api frontend.API, s []frontend.Variable) { | ||
c := len(s) / 4 | ||
for i := 0; i < c; i++ { | ||
t0 := api.Add(s[4*i], s[4*i+1]) // s0+s1 | ||
t1 := api.Add(s[4*i+2], s[4*i+3]) // s2+s3 | ||
t2 := api.Mul(s[4*i+1], 2) | ||
t2 = api.Add(t2, t1) // 2s1+t1 | ||
t3 := api.Mul(s[4*i+3], 2) | ||
t3 = api.Add(t3, t0) // 2s3+t0 | ||
t4 := api.Mul(t1, 4) | ||
t4 = api.Add(t4, t3) // 4t1+t3 | ||
t5 := api.Mul(t0, 4) | ||
t5 = api.Add(t5, t2) // 4t0+t2 | ||
t6 := api.Add(t3, t5) // t3+t5 | ||
t7 := api.Add(t2, t4) // t2+t4 | ||
s[4*i] = t6 | ||
s[4*i+1] = t5 | ||
s[4*i+2] = t7 | ||
s[4*i+3] = t4 | ||
} | ||
} | ||
|
||
// when t=2,3 the buffer is multiplied by circ(2,1) and circ(2,1,1) | ||
// see https://eprint.iacr.org/2023/323.pdf page 15, case t=2,3 | ||
// | ||
// when t=0[4], the buffer is multiplied by circ(2M4,M4,..,M4) | ||
// see https://eprint.iacr.org/2023/323.pdf | ||
func (h *Hash) matMulExternalInPlace(api frontend.API, input []frontend.Variable) { | ||
|
||
if h.params.t == 2 { | ||
tmp := api.Add(input[0], input[1]) | ||
input[0] = api.Add(tmp, input[0]) | ||
input[1] = api.Add(tmp, input[1]) | ||
} else if h.params.t == 3 { | ||
var tmp frontend.Variable | ||
tmp = api.Add(input[0], input[1]) | ||
tmp = api.Add(tmp, input[2]) | ||
input[0] = api.Add(input[0], tmp) | ||
input[1] = api.Add(input[1], tmp) | ||
input[2] = api.Add(input[2], tmp) | ||
} else if h.params.t == 4 { | ||
h.matMulM4InPlace(api, input) | ||
} else { | ||
// at this stage t is supposed to be a multiple of 4 | ||
// the MDS matrix is circ(2M4,M4,..,M4) | ||
h.matMulM4InPlace(api, input) | ||
tmp := make([]frontend.Variable, 4) | ||
for i := 0; i < h.params.t/4; i++ { | ||
tmp[0] = api.Add(tmp[0], input[4*i]) | ||
tmp[1] = api.Add(tmp[1], input[4*i+1]) | ||
tmp[2] = api.Add(tmp[2], input[4*i+2]) | ||
tmp[3] = api.Add(tmp[3], input[4*i+3]) | ||
} | ||
for i := 0; i < h.params.t/4; i++ { | ||
input[4*i] = api.Add(input[4*i], tmp[0]) | ||
input[4*i+1] = api.Add(input[4*i], tmp[1]) | ||
input[4*i+2] = api.Add(input[4*i], tmp[2]) | ||
input[4*i+3] = api.Add(input[4*i], tmp[3]) | ||
} | ||
} | ||
} | ||
|
||
// when t=2,3 the matrix are respectibely [[2,1][1,3]] and [[2,1,1][1,2,1][1,1,3]] | ||
// otherwise the matrix is filled with ones except on the diagonal, | ||
func (h *Hash) matMulInternalInPlace(api frontend.API, input []frontend.Variable) { | ||
if h.params.t == 2 { | ||
sum := api.Add(input[0], input[1]) | ||
input[0] = api.Add(input[0], sum) | ||
input[1] = api.Mul(2, input[1]) | ||
input[1] = api.Add(input[1], sum) | ||
} else if h.params.t == 3 { | ||
var sum frontend.Variable | ||
sum = api.Add(input[0], input[1]) | ||
sum = api.Add(sum, input[2]) | ||
input[0] = api.Add(input[0], sum) | ||
input[1] = api.Add(input[1], sum) | ||
input[2] = api.Mul(input[2], 2) | ||
input[2] = api.Add(input[2], sum) | ||
} else { | ||
var sum frontend.Variable | ||
sum = input[0] | ||
for i := 1; i < h.params.t; i++ { | ||
sum = api.Add(sum, input[i]) | ||
} | ||
for i := 0; i < h.params.t; i++ { | ||
input[i] = api.Mul(input[i], h.params.diagInternalMatrices[i]) | ||
input[i] = api.Add(input[i], sum) | ||
} | ||
} | ||
} | ||
|
||
// addRoundKeyInPlace adds the round-th key to the buffer | ||
func (h *Hash) addRoundKeyInPlace(api frontend.API, round int, input []frontend.Variable) { | ||
for i := 0; i < len(h.params.roundKeys[round]); i++ { | ||
input[i] = api.Add(input[i], h.params.roundKeys[round][i]) | ||
} | ||
} | ||
|
||
func (h *Hash) Permutation(api frontend.API, input []frontend.Variable) error { | ||
if len(input) != h.params.t { | ||
return ErrInvalidSizebuffer | ||
} | ||
|
||
// external matrix multiplication, cf https://eprint.iacr.org/2023/323.pdf page 14 (part 6) | ||
h.matMulExternalInPlace(api, input) | ||
|
||
rf := h.params.rF / 2 | ||
for i := 0; i < rf; i++ { | ||
// one round = matMulExternal(sBox_Full(addRoundKey)) | ||
h.addRoundKeyInPlace(api, i, input) | ||
for j := 0; j < h.params.t; j++ { | ||
h.sBox(api, j, input) | ||
} | ||
h.matMulExternalInPlace(api, input) | ||
} | ||
|
||
for i := rf; i < rf+h.params.rP; i++ { | ||
// one round = matMulInternal(sBox_sparse(addRoundKey)) | ||
h.addRoundKeyInPlace(api, i, input) | ||
h.sBox(api, 0, input) | ||
h.matMulInternalInPlace(api, input) | ||
} | ||
for i := rf + h.params.rP; i < h.params.rF+h.params.rP; i++ { | ||
// one round = matMulExternal(sBox_Full(addRoundKey)) | ||
h.addRoundKeyInPlace(api, i, input) | ||
for j := 0; j < h.params.t; j++ { | ||
h.sBox(api, j, input) | ||
} | ||
h.matMulExternalInPlace(api, input) | ||
} | ||
|
||
return nil | ||
} |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
should the branch be rebased on master?