Consensys / gnark

gnark is a fast zk-SNARK library that offers a high-level API to design circuits. The library is open source and developed under the Apache 2.0 license
https://hackmd.io/@gnark
Apache License 2.0
1.44k stars 369 forks source link

how to handle ignoring uninitialized slice errors #970

Closed readygo67 closed 11 months ago

readygo67 commented 11 months ago

ignoring uninitialized slice: Digits []frontend.Variable happen in the following circuit.

Description

When running the following TestBinaryCircuit1, it report "ignoring uninitialized slice: Digits []frontend.Variable"

import (
    "fmt"
    "github.com/consensys/gnark-crypto/ecc"
    "github.com/consensys/gnark/frontend"
    "github.com/consensys/gnark/std/math/bits"
    "github.com/consensys/gnark/test"
    "testing"
)

//decompose the Value to bits 
type BinaryCircuit1 struct {
    Value  frontend.Variable
    Digits []frontend.Variable
}

func (c *BinaryCircuit1) Define(api frontend.API) error {
    v := bits.FromBinary(api, c.Digits)
    api.AssertIsEqual(c.Value, v)
    return nil
}

func TestBinaryCircuit1(t *testing.T) {
    assert :=test.NewAssert(t)

    digits := []frontend.Variable{1, 1, 1, 1}
    value := 15

    valid := BinaryCircuit1{
        Value:  value,
        Digits: digits,
    }

    //validCircuit.Digits = digits
    fmt.Printf("circuit:%v\n", valid)
    err :=test.IsSolved(&BinaryCircuit1{}, &valid, ecc.BN254.ScalarField())
    assert.NoError(err)
}

Expected Behavior

The case should be success.

Actual Behavior

reports ignoring uninitialized slice: Digits []frontend.Variable



## Your Environment
* gnark version used (e.g. v0.9.1, `HEAD@develop`):
* gnark-crypto version used: v0.12.2-0.20231208203441-d4eab6ddd2af
* go version (e.g. 1.21.4):
* Operating System and version: macos
readygo67 commented 9 months ago

This problem is caused by the following code in frontend/schema/walk.go, where a slice is defined but its length is 0

func (w *walker) Slice(value reflect.Value) error {
    if value.Type() == w.targetSlice {
        if value.Len() == 0 {
            fmt.Printf("ignoring uninitialized slice: %s %s\n", w.name(), reflect.SliceOf(w.target).String())
            return nil
        }
        return w.handleLeaves(value)
    }

    return nil
}

To handle this problem


import (
    "fmt"
    "github.com/consensys/gnark-crypto/ecc"
    "github.com/consensys/gnark/frontend"
    "github.com/consensys/gnark/std/math/bits"
    "github.com/consensys/gnark/test"
    "testing"
)

type BinaryCircuit1 struct {
    Value  frontend.Variable
    Digits []frontend.Variable
}

func (c *BinaryCircuit1) Define(api frontend.API) error {
    v := bits.FromBinary(api, c.Digits)
    api.AssertIsEqual(c.Value, v)
    return nil
}

func TestBinaryCircuit1(t *testing.T) {
    assert := test.NewAssert(t)

    digits := []frontend.Variable{1, 1, 1, 1}
    value := 15

    circuit := BinaryCircuit1{
        Digits: make([]frontend.Variable, len(digits)),
    }

    valid := BinaryCircuit1{
        Value:  value,
        Digits: digits,
    }

    //validCircuit.Digits = digits
    fmt.Printf("circuit:%v\n", valid)
    err := test.IsSolved(&circuit, &valid, ecc.BN254.ScalarField())
    assert.NoError(err)
}