Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
be747e0
refactor: shorten import name
Tabaie Jun 5, 2025
4b43ce3
perf: addition rather than multiplication in gates
Tabaie Jun 8, 2025
6b86526
Revert "perf: addition rather than multiplication in gates"
Tabaie Jun 8, 2025
c4b01b5
feat: generify poseidon2-gkr (not all s-Boxes available yet)
Tabaie Jun 8, 2025
5342952
fix test
Tabaie Jun 8, 2025
9d9b13b
refactor generify tests
Tabaie Jun 8, 2025
430661a
feat: gkrposeidon2 compression for all curves
Tabaie Jun 8, 2025
b75843d
feat gkr-poseidon2 hasher
Tabaie Jun 8, 2025
ca85a41
Merge branch 'feat/gkr/add-instance' into feat/gkr/hashes
Tabaie Jun 8, 2025
be8a07e
fix more renaming
Tabaie Jun 8, 2025
1894cfa
feat: gkrmimc for sbox degree 5
Tabaie Jun 9, 2025
241d645
mimc length 1 works
Tabaie Jun 10, 2025
bb36459
fix final layer
Tabaie Jun 10, 2025
311d9d9
chore generify Println changes
Tabaie Jun 10, 2025
815adc7
feat: use kvstore for caching instances
Tabaie Jun 10, 2025
85d6aaa
Merge branch 'feat/gkr/add-instance' into feat/gkr/hashes
Tabaie Jun 10, 2025
7ab8702
feat: merkledamgard hasher as statestorer
Tabaie Jun 11, 2025
2fb7daa
test: SetState
Tabaie Jun 11, 2025
de55a27
feat: mimc.New to return StateStorer
Tabaie Jun 11, 2025
bb0eca0
Merge branch 'feat/gkr/add-instance' into feat/gkr/hashes
Tabaie Jun 11, 2025
7e4b954
Merge branch 'feat/gkr/add-instance' into feat/gkr/hashes
Tabaie Jun 11, 2025
8e92d99
Merge branch 'feat/gkr/add-instance' into feat/gkr/hashes
Tabaie Jul 28, 2025
3ec0778
Merge branch 'feat/gkr/add-instance' into feat/gkr/hashes
Tabaie Sep 17, 2025
8c37435
fix: bad merge
Tabaie Sep 17, 2025
e6a64bc
bench: gkr mimc permutations
Tabaie Sep 17, 2025
d55dbf4
bench: gkr-mimc permutations
Tabaie Sep 17, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions internal/generator/backend/template/gkr/gkr.go.tmpl
Original file line number Diff line number Diff line change
Expand Up @@ -771,13 +771,13 @@ func (gateAPI) Println(a ...frontend.Variable) {

for i, v := range a {
if _, err := x.SetInterface(v); err != nil {
toPrint[i] = x.String()
} else {
if s, ok := v.(string); ok {
toPrint[i] = s
continue
}
panic(fmt.Errorf("not numeric or string: %w", err))
} else {
toPrint[i] = x.String()
}
}
fmt.Println(toPrint...)
Expand Down
4 changes: 2 additions & 2 deletions internal/gkr/bls12-377/gkr.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions internal/gkr/bls12-381/gkr.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions internal/gkr/bls24-315/gkr.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions internal/gkr/bls24-317/gkr.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions internal/gkr/bn254/gkr.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions internal/gkr/bw6-633/gkr.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions internal/gkr/bw6-761/gkr.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion internal/gkr/engine_hints.go
Original file line number Diff line number Diff line change
Expand Up @@ -187,7 +187,7 @@ func (g gateAPI) Println(a ...frontend.Variable) {
for i := range a {
if s, ok := a[i].(fmt.Stringer); ok {
strings[i] = s.String()
} else {
} else if strings[i], ok = a[i].(string); !ok {
bigInt := utils.FromInterface(a[i])
strings[i] = bigInt.String()
}
Expand Down
4 changes: 2 additions & 2 deletions internal/gkr/small_rational/gkr.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

19 changes: 18 additions & 1 deletion std/hash/hash.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
package hash

import (
"fmt"

"github.com/consensys/gnark/frontend"
"github.com/consensys/gnark/std/math/uints"
)
Expand Down Expand Up @@ -110,7 +112,7 @@ type merkleDamgardHasher struct {

// 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 Compressor, initialState frontend.Variable) FieldHasher {
func NewMerkleDamgardHasher(api frontend.API, f Compressor, initialState frontend.Variable) StateStorer {
return &merkleDamgardHasher{
state: initialState,
iv: initialState,
Expand All @@ -132,3 +134,18 @@ func (h *merkleDamgardHasher) Write(data ...frontend.Variable) {
func (h *merkleDamgardHasher) Sum() frontend.Variable {
return h.state
}

func (h *merkleDamgardHasher) State() []frontend.Variable {
return []frontend.Variable{h.state}
}

func (h *merkleDamgardHasher) SetState(state []frontend.Variable) error {
if h.state != h.iv {
return fmt.Errorf("the hasher is not in an initial state; reset before attempting to set the state")
}
if len(state) != 1 {
return fmt.Errorf("expected one state variable, got %d", len(state))
}
h.state = state[0]
return nil
}
17 changes: 17 additions & 0 deletions std/hash/mimc/gkr-mimc/gkr-mimc.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package gkr_mimc

import (
"fmt"

"github.com/consensys/gnark/frontend"
"github.com/consensys/gnark/std/hash"
gkr_mimc "github.com/consensys/gnark/std/permutation/gkr-mimc"
)

func New(api frontend.API) (hash.StateStorer, error) {
f, err := gkr_mimc.NewCompressor(api)
if err != nil {
return nil, fmt.Errorf("could not create mimc hasher: %w", err)
}
return hash.NewMerkleDamgardHasher(api, f, 0), nil
}
165 changes: 165 additions & 0 deletions std/hash/mimc/gkr-mimc/gkr-mimc_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,165 @@
package gkr_mimc

import (
"errors"
"fmt"
"os"
"slices"
"testing"

"github.com/consensys/gnark-crypto/ecc"
"github.com/consensys/gnark/backend/plonk"
"github.com/consensys/gnark/constraint"
"github.com/consensys/gnark/frontend"
"github.com/consensys/gnark/frontend/cs/scs"
"github.com/consensys/gnark/std/hash/mimc"
"github.com/consensys/gnark/test"
"github.com/stretchr/testify/require"
)

func TestGkrMiMC(t *testing.T) {
lengths := []int{1, 2, 3}
vals := make([]frontend.Variable, len(lengths)*2)
for i := range vals {
vals[i] = i + 1
}

for _, length := range lengths[1:2] {
circuit := &testGkrMiMCCircuit{
In: make([]frontend.Variable, length*2),
}
assignment := &testGkrMiMCCircuit{
In: slices.Clone(vals[:length*2]),
}

test.NewAssert(t).CheckCircuit(circuit, test.WithValidAssignment(assignment))
}
}

type testGkrMiMCCircuit struct {
In []frontend.Variable
skipCheck bool
}

func (c *testGkrMiMCCircuit) Define(api frontend.API) error {
gkrmimc, err := New(api)
if err != nil {
return err
}

plainMiMC, err := mimc.New(api)
if err != nil {
return err
}

// first check that empty input is handled correctly
api.AssertIsEqual(gkrmimc.Sum(), plainMiMC.Sum())

ins := [][]frontend.Variable{c.In[:len(c.In)/2], c.In[len(c.In)/2:]}
for _, in := range ins {
gkrmimc.Reset()
gkrmimc.Write(in...)
res := gkrmimc.Sum()

if !c.skipCheck {
plainMiMC.Reset()
plainMiMC.Write(in...)
expected := plainMiMC.Sum()
api.AssertIsEqual(expected, res)
}
}

return nil
}

func TestGkrMiMCCompiles(t *testing.T) {
const n = 52000
circuit := testGkrMiMCCircuit{
In: make([]frontend.Variable, n),
}
cs, err := frontend.Compile(ecc.BLS12_377.ScalarField(), scs.NewBuilder, &circuit, frontend.WithCapacity(27_000_000))
require.NoError(t, err)
fmt.Println(cs.GetNbConstraints(), "constraints")
}

type hashTreeCircuit struct {
Leaves []frontend.Variable
}

func (c hashTreeCircuit) Define(api frontend.API) error {
if len(c.Leaves) == 0 {
return errors.New("no hashing to do")
}

hsh, err := New(api)
if err != nil {
return err
}

layer := slices.Clone(c.Leaves)

for len(layer) > 1 {
if len(layer)%2 == 1 {
layer = append(layer, 0) // pad with zero
}

for i := range len(layer) / 2 {
hsh.Reset()
hsh.Write(layer[2*i], layer[2*i+1])
layer[i] = hsh.Sum()
}

layer = layer[:len(layer)/2]
}

api.AssertIsDifferent(layer[0], 0)
return nil
}

func loadCs(t require.TestingT, filename string, circuit frontend.Circuit) constraint.ConstraintSystem {
f, err := os.Open(filename)

if os.IsNotExist(err) {
// actually compile
cs, err := frontend.Compile(ecc.BLS12_377.ScalarField(), scs.NewBuilder, circuit)
require.NoError(t, err)
f, err = os.Create(filename)
require.NoError(t, err)
defer f.Close()
_, err = cs.WriteTo(f)
require.NoError(t, err)
return cs
}

defer f.Close()
require.NoError(t, err)

cs := plonk.NewCS(ecc.BLS12_377)

_, err = cs.ReadFrom(f)
require.NoError(t, err)

return cs
}

func BenchmarkHashTree(b *testing.B) {
const size = 1 << 15 // about 2 ^ 16 total hashes

circuit := hashTreeCircuit{
Leaves: make([]frontend.Variable, size),
}
assignment := hashTreeCircuit{
Leaves: make([]frontend.Variable, size),
}

for i := range assignment.Leaves {
assignment.Leaves[i] = i
}

cs := loadCs(b, "gkrmimc_hashtree.cs", &circuit)

w, err := frontend.NewWitness(&assignment, ecc.BLS12_377.ScalarField())
require.NoError(b, err)

require.NoError(b, cs.IsSolved(w))
}
6 changes: 4 additions & 2 deletions std/hash/mimc/mimc.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ func NewMiMC(api frontend.API) (MiMC, error) {
// NB! See the package documentation for length extension attack consideration.
//
// [gnark-crypto]: https://pkg.go.dev/github.com/consensys/gnark-crypto/hash
func New(api frontend.API) (hash.FieldHasher, error) {
func New(api frontend.API) (hash.StateStorer, error) {
h, err := NewMiMC(api)
if err != nil {
return nil, err
Expand All @@ -43,5 +43,7 @@ func New(api frontend.API) (hash.FieldHasher, error) {
}

func init() {
hash.Register(hash.MIMC, New)
hash.Register(hash.MIMC, func(api frontend.API) (hash.FieldHasher, error) {
return New(api)
})
}
Loading
Loading