Skip to content

Commit

Permalink
feat: merkle damgard and poseidon2
Browse files Browse the repository at this point in the history
  • Loading branch information
Tabaie committed Jan 31, 2025
1 parent eb18763 commit 5e00636
Show file tree
Hide file tree
Showing 3 changed files with 82 additions and 2 deletions.
42 changes: 40 additions & 2 deletions std/hash/hash.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
package hash

import (
"errors"
"fmt"
"sync"

"github.com/consensys/gnark/frontend"
Expand Down Expand Up @@ -58,7 +58,7 @@ func GetFieldHasher(name string, api frontend.API) (FieldHasher, error) {
defer lock.RUnlock()
builder, ok := builderRegistry[name]
if !ok {
return nil, errors.New("hash function not found")
return nil, fmt.Errorf("hash function \"%s\" not registered", name)
}
return builder(api)
}
Expand Down Expand Up @@ -87,3 +87,41 @@ type BinaryFixedLengthHasher interface {
// FixedLengthSum returns digest of the first length bytes.
FixedLengthSum(length frontend.Variable) []uints.U8
}

// CompressionFunction is a 2 to 1 function
type CompressionFunction interface {
Apply(frontend.API, frontend.Variable, frontend.Variable) frontend.Variable // TODO @Tabaie @ThomasPiellard better name
}

// Merkle-Damgard is a generic transformation that turns
type merkleDamgardHasher struct {
state frontend.Variable
iv frontend.Variable
f CompressionFunction
api frontend.API
}

// NewMerkleDamgardHasher transforms a 2-1 one-way function into a hash
// initialState is a value whose preimage is not known
func NewMerkleDamgardHasher(api frontend.API, f CompressionFunction, initialState frontend.Variable) FieldHasher {
return &merkleDamgardHasher{
state: initialState,
iv: initialState,
f: f,
api: api,
}
}

func (h *merkleDamgardHasher) Reset() {
h.state = h.iv
}

func (h *merkleDamgardHasher) Write(data ...frontend.Variable) {
for _, d := range data {
h.state = h.f.Apply(h.api, h.state, d)
}
}

func (h *merkleDamgardHasher) Sum() frontend.Variable {
return h.state
}
33 changes: 33 additions & 0 deletions std/hash/poseidon2/posiedon2.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package poseidon2

import (
"fmt"
"github.com/consensys/gnark-crypto/ecc"
"github.com/consensys/gnark/frontend"
"github.com/consensys/gnark/internal/utils"
"github.com/consensys/gnark/std/hash"
poseidon2 "github.com/consensys/gnark/std/permutation/poseidon2"
)

func NewPoseidon2(api frontend.API) (hash.FieldHasher, error) {
curve := utils.FieldToCurve(api.Compiler().Field())
params, ok := parameters[curve]
if !ok {
return nil, fmt.Errorf("poseidon2 hash for curve \"%s\" not yet supported", curve.String())
}
seed := fmt.Sprintf("Poseidon2 hash: curve=%s-rF=%d-rP=%d-t=2", curve.String(), params.rF, params.rP)
f := poseidon2.NewHash(2, params.d, params.rF, params.rP, seed, curve)
return hash.NewMerkleDamgardHasher(api, &f, 0), nil
}

var parameters = map[ecc.ID]struct {
d int
rF int
rP int
}{
ecc.BLS12_377: {
rF: 6,
rP: 26,
d: 17,
},
}
9 changes: 9 additions & 0 deletions std/permutation/poseidon2/poseidon2.go
Original file line number Diff line number Diff line change
Expand Up @@ -282,3 +282,12 @@ func (h *Hash) Permutation(api frontend.API, input []frontend.Variable) error {

return nil
}

// Apply aliases Permutation in the t=2 case
// implements hash.CompressionFunction
func (h *Hash) Apply(api frontend.API, l, r frontend.Variable) frontend.Variable {
if h.params.t != 2 {
panic("poseidon2: Apply can only be used when t=2")
}
return h.Permutation(api, []frontend.Variable{l, r})
}

0 comments on commit 5e00636

Please sign in to comment.