generate proof failed
#1594
-
Hi, I'm trying to run a zkp demo, but it failed. Here are the code:
The demo failed for:
|
Beta Was this translation helpful? Give feedback.
Answered by
ivokub
Sep 3, 2025
Replies: 1 comment 1 reply
-
There were some bugs in your implementation:
I rewrote your example to use mocked file system for consistency and fixed the errors. See below package main
import (
"crypto/rand"
"crypto/sha256"
"encoding/hex"
"fmt"
"io"
"io/fs"
"os"
"testing"
"testing/fstest"
"time"
"github.com/consensys/gnark/std/math/uints"
"github.com/consensys/gnark/test"
"github.com/consensys/gnark-crypto/ecc"
"github.com/consensys/gnark/backend/groth16"
"github.com/consensys/gnark/frontend"
"github.com/consensys/gnark/frontend/cs/r1cs"
"github.com/consensys/gnark/std/hash/sha2"
)
// FileHash
type FileHash struct {
FileName []uints.U8
FileData [32]uints.U8
}
// CodeVersionCircuit
type CodeVersionCircuit struct {
// private
Files []FileHash `gnark:"files,secret"`
Nonce [16]uints.U8 `gnark:"nonce,secret"`
// public
TargetHash [32]uints.U8 `gnark:"targetHash,public"`
Timestamp frontend.Variable `gnark:"timestamp,public"`
}
// Define
func (c *CodeVersionCircuit) Define(api frontend.API) error {
// 1. init hash
hash, err := sha2.New(api)
if err != nil {
return err
}
// 2.hash nonce
hash.Write(c.Nonce[:])
// 3. hash filename
for _, file := range c.Files {
hash.Write(file.FileName[:])
hash.Write(file.FileData[:])
}
// 4. current hash
currentHash := hash.Sum()
// 5. verify
b, _ := uints.NewBytes(api)
for i := 0; i < 32; i++ {
b.AssertIsEqual(currentHash[i], c.TargetHash[i])
}
return nil
}
var mockedFileSystem = fstest.MapFS{
"file1.txt": &fstest.MapFile{
Data: []byte("This is the content of file 1."),
Mode: os.ModePerm,
ModTime: time.Now(),
},
"file2.txt": &fstest.MapFile{
Data: []byte("This is the content of file 2."),
Mode: os.ModePerm,
ModTime: time.Now(),
},
}
// prepare circuit inputs
func prepareCircuitInputs() ([]FileHash, error) {
var files []FileHash
err := fs.WalkDir(mockedFileSystem, ".", func(path string, d fs.DirEntry, err error) error {
if err != nil {
return err
}
if !d.IsDir() {
f, err := mockedFileSystem.Open(path)
if err != nil {
return err
}
defer f.Close()
data, err := io.ReadAll(f)
if err != nil {
return err
}
fileDataHash := sha256.Sum256(data)
fileDataHashVar := ([32]uints.U8)(uints.NewU8Array(fileDataHash[:]))
nameBytes := []byte(d.Name())
if len(nameBytes) > 32 {
nameBytes = nameBytes[:32]
} else {
nameBytes = append(nameBytes, make([]byte, 32-len(nameBytes))...)
}
fileNameVar := uints.NewU8Array(nameBytes)
files = append(files, FileHash{
FileName: fileNameVar,
FileData: fileDataHashVar,
})
}
return nil
})
return files, err
}
// generate target hash
func generateTargetHash(nonce []byte) ([32]byte, error) {
hash := sha256.New()
hash.Write(nonce)
err := fs.WalkDir(mockedFileSystem, ".", func(path string, d fs.DirEntry, err error) error {
if err != nil {
return err
}
if !d.IsDir() {
f, err := mockedFileSystem.Open(path)
if err != nil {
return err
}
defer f.Close()
data, err := io.ReadAll(f)
if err != nil {
return err
}
nameBytes := []byte(d.Name())
if len(nameBytes) > 32 {
nameBytes = nameBytes[:32]
} else {
nameBytes = append(nameBytes, make([]byte, 32-len(nameBytes))...)
}
hash.Write(nameBytes)
fileHash := sha256.Sum256(data)
hash.Write(fileHash[:])
}
return nil
})
if err != nil {
return [32]byte{}, err
}
var result [32]byte
copy(result[:], hash.Sum(nil))
return result, nil
}
// generate nonce
func generateNonce() ([]byte, error) {
nonce := make([]byte, 16)
_, err := rand.Read(nonce)
return nonce, err
}
func TestCircuit(t *testing.T) {
// 2. generate nonce
nonce, err := generateNonce()
if err != nil {
t.Fatalf("generate nonce: %v\n", err)
}
fmt.Printf("nonce: %s\n", hex.EncodeToString(nonce))
// 3. generate target hash
targetHashBytes, err := generateTargetHash(nonce)
if err != nil {
t.Fatalf("generate target hash: %v\n", err)
}
fmt.Printf("target hash: %s\n", hex.EncodeToString(targetHashBytes[:]))
// 4. prepare inputs
currentFiles, err := prepareCircuitInputs()
if err != nil {
t.Fatalf("prepare inputs failed: %v\n", err)
}
// 5. nonce
nonceVar := ([16]uints.U8)(uints.NewU8Array(nonce))
// 6. target hash
targetHashVar := ([32]uints.U8)(uints.NewU8Array(targetHashBytes[:]))
// 7. get timestamp
timestamp := frontend.Variable(time.Now().Unix())
fmt.Printf("timestamp: %d\n", timestamp)
// 8. init circuit
fmt.Println("\ncompile circuit...")
assignment := CodeVersionCircuit{
Files: currentFiles,
Nonce: nonceVar,
TargetHash: targetHashVar,
Timestamp: timestamp,
}
var circuit CodeVersionCircuit
circuit.Files = make([]FileHash, len(currentFiles))
for i := 0; i < len(currentFiles); i++ {
circuit.Files[i].FileName = make([]uints.U8, len(currentFiles[i].FileName))
}
// solve in test engine first. It is a quick way to check if the circuit is correct
// before launching the full proof system (compile, setup, prove, verify)
fmt.Println("solve circuit...")
err = test.IsSolved(&circuit, &assignment, ecc.BN254.ScalarField())
if err != nil {
t.Fatalf("circuit not solved: %v\n", err)
}
ccs, err := frontend.Compile(ecc.BN254.ScalarField(), r1cs.NewBuilder, &circuit)
if err != nil {
t.Fatalf("compile circuit failed: %v\n", err)
}
// 9. generate key pairs
fmt.Println("generate Groth16 key pairs...")
pk, vk, err := groth16.Setup(ccs)
if err != nil {
t.Fatalf("setup failed: %v\n", err)
}
// 10. create witness
fmt.Println("create witness...")
witness, err := frontend.NewWitness(&assignment, ecc.BN254.ScalarField())
if err != nil {
t.Fatalf("create witness failed: %v\n", err)
}
publicWitness, err := witness.Public()
if err != nil {
t.Fatalf("get pub witness failed: %v\n", err)
}
// 11. generate proof
fmt.Println("generate proof...")
proof, err := groth16.Prove(ccs, pk, witness)
if err != nil {
t.Fatalf("generate proof failed: %v\n", err)
}
// 12. verify
fmt.Println("\nverify...")
err = groth16.Verify(proof, vk, publicWitness)
if err != nil {
t.Fatalf("invalid proof: %v\n", err)
}
fmt.Println("success")
} |
Beta Was this translation helpful? Give feedback.
1 reply
Answer selected by
triplewz
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
There were some bugs in your implementation:
conversion.NativeToBytes
on values which was already byte essentially (everyfrontend.Variable
contained only a value of 8 bits). But the conversion function always pads to full field element length. A better approach if we already always know inputs are bytes is to use theuints.U8
primitive which automatically performs range checks and is compatible with binary hasher interface.prepareCircuitInputs
you right padded file name with zeros, but ingenerateTargetHash
you did not.I rewrote your example to use mocked file system for consistency and fixed the errors. See below