github.com/consensys/gnark@v0.11.0/test/assert_solidity.go (about)

     1  package test
     2  
     3  import (
     4  	"encoding/hex"
     5  	"os"
     6  	"os/exec"
     7  	"path/filepath"
     8  	"strconv"
     9  
    10  	fr_bn254 "github.com/consensys/gnark-crypto/ecc/bn254/fr"
    11  	"github.com/consensys/gnark/backend"
    12  	"github.com/consensys/gnark/backend/solidity"
    13  	"github.com/consensys/gnark/backend/witness"
    14  )
    15  
    16  // solidityVerification checks that the exported solidity contract can verify the proof
    17  // and that the proof is valid.
    18  // It uses gnark-solidity-checker see test.WithSolidity option.
    19  func (assert *Assert) solidityVerification(b backend.ID, vk solidity.VerifyingKey,
    20  	proof any,
    21  	validPublicWitness witness.Witness,
    22  	opts []solidity.ExportOption,
    23  ) {
    24  	if !SolcCheck || len(validPublicWitness.Vector().(fr_bn254.Vector)) == 0 {
    25  		return // nothing to check, will make solc fail.
    26  	}
    27  	assert.t.Helper()
    28  
    29  	// make temp dir
    30  	tmpDir, err := os.MkdirTemp("", "gnark-solidity-check*")
    31  	assert.NoError(err)
    32  	defer os.RemoveAll(tmpDir)
    33  
    34  	// export solidity contract
    35  	fSolidity, err := os.Create(filepath.Join(tmpDir, "gnark_verifier.sol"))
    36  	assert.NoError(err)
    37  
    38  	err = vk.ExportSolidity(fSolidity, opts...)
    39  	assert.NoError(err)
    40  
    41  	err = fSolidity.Close()
    42  	assert.NoError(err)
    43  
    44  	// generate assets
    45  	// gnark-solidity-checker generate --dir tmpdir --solidity contract_g16.sol
    46  	cmd := exec.Command("gnark-solidity-checker", "generate", "--dir", tmpDir, "--solidity", "gnark_verifier.sol")
    47  	assert.t.Log("running ", cmd.String())
    48  	out, err := cmd.CombinedOutput()
    49  	assert.NoError(err, string(out))
    50  
    51  	// len(vk.K) - 1 == len(publicWitness) + len(commitments)
    52  	numOfCommitments := vk.NbPublicWitness() - len(validPublicWitness.Vector().(fr_bn254.Vector))
    53  
    54  	checkerOpts := []string{"verify"}
    55  	if b == backend.GROTH16 {
    56  		checkerOpts = append(checkerOpts, "--groth16")
    57  	} else if b == backend.PLONK {
    58  		checkerOpts = append(checkerOpts, "--plonk")
    59  	} else {
    60  		panic("not implemented")
    61  	}
    62  
    63  	// proof to hex
    64  	_proof, ok := proof.(interface{ MarshalSolidity() []byte })
    65  	if !ok {
    66  		panic("proof does not implement MarshalSolidity()")
    67  	}
    68  
    69  	proofStr := hex.EncodeToString(_proof.MarshalSolidity())
    70  
    71  	if numOfCommitments > 0 {
    72  		checkerOpts = append(checkerOpts, "--commitment", strconv.Itoa(numOfCommitments))
    73  	}
    74  
    75  	// public witness to hex
    76  	bPublicWitness, err := validPublicWitness.MarshalBinary()
    77  	assert.NoError(err)
    78  	// that's quite dirty...
    79  	// first 4 bytes -> nbPublic
    80  	// next 4 bytes -> nbSecret
    81  	// next 4 bytes -> nb elements in the vector (== nbPublic + nbSecret)
    82  	bPublicWitness = bPublicWitness[12:]
    83  	publicWitnessStr := hex.EncodeToString(bPublicWitness)
    84  
    85  	checkerOpts = append(checkerOpts, "--dir", tmpDir)
    86  	checkerOpts = append(checkerOpts, "--nb-public-inputs", strconv.Itoa(len(validPublicWitness.Vector().(fr_bn254.Vector))))
    87  	checkerOpts = append(checkerOpts, "--proof", proofStr)
    88  	checkerOpts = append(checkerOpts, "--public-inputs", publicWitnessStr)
    89  
    90  	// verify proof
    91  	// gnark-solidity-checker verify --dir tmdir --groth16 --nb-public-inputs 1 --proof 1234 --public-inputs dead
    92  	cmd = exec.Command("gnark-solidity-checker", checkerOpts...)
    93  	assert.t.Log("running ", cmd.String())
    94  	out, err = cmd.CombinedOutput()
    95  	assert.NoError(err, string(out))
    96  }