-
Notifications
You must be signed in to change notification settings - Fork 393
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
I wanna use proof without commitment [gnark with BLS12-381] #1316
Comments
There should be a way in some of the cases. In some places we check if the builder interface implicitly implements the What is your use case for trying to avoid the commitment? I guess one issue would be if you want to implement folding on the compiled R1CS which imo currently wouldn't work well with the pairing check necessary. But maybe there could be some other way to do it. I'll post an example on how to override the |
Thank you for your reply. Actually, it's because I don't know what kind of circuit's vk would generate vk.PublicAndCommitmentCommitted. My expectation is that, since the circuit doesn't use commitments, this vk.PublicAndCommitmentCommitted should always be empty. |
Have a look at this example: package examples
import (
"fmt"
"math/big"
"testing"
"github.com/consensys/gnark-crypto/ecc"
"github.com/consensys/gnark/backend/groth16"
groth16_bn254 "github.com/consensys/gnark/backend/groth16/bn254"
"github.com/consensys/gnark/frontend"
"github.com/consensys/gnark/frontend/cs/r1cs"
"github.com/consensys/gnark/internal/kvstore"
"github.com/consensys/gnark/std/rangecheck"
"github.com/consensys/gnark/test"
)
type PublicCommitmentOnly struct {
A frontend.Variable `gnark:",public"`
B frontend.Variable `gnark:",secret"`
}
type PrivateCommitmentOnly struct {
A frontend.Variable `gnark:",public"`
B frontend.Variable `gnark:",secret"`
}
type PublicAndPrivateCommitment struct {
A frontend.Variable `gnark:",public"`
B frontend.Variable `gnark:",secret"`
}
func (c *PublicCommitmentOnly) Define(api frontend.API) error {
cmter, ok := api.(frontend.Committer)
if !ok {
return fmt.Errorf("does not implement commitment")
}
r, err := cmter.Commit(c.A)
if err != nil {
return fmt.Errorf("commit A: %w", err)
}
api.AssertIsDifferent(c.B, r)
return nil
}
func (c *PrivateCommitmentOnly) Define(api frontend.API) error {
cmter, ok := api.(frontend.Committer)
if !ok {
return fmt.Errorf("does not implement commitment")
}
r, err := cmter.Commit(c.B)
if err != nil {
return fmt.Errorf("commit B: %w", err)
}
api.AssertIsDifferent(c.A, r)
return nil
}
func (c *PublicAndPrivateCommitment) Define(api frontend.API) error {
cmter, ok := api.(frontend.Committer)
if !ok {
return fmt.Errorf("does not implement commitment")
}
r, err := cmter.Commit(c.A, c.B)
if err != nil {
return fmt.Errorf("commit A: %w", err)
}
api.AssertIsDifferent(c.B, r)
return nil
}
type NoCommitment struct {
A frontend.Variable `gnark:",public"`
B frontend.Variable `gnark:",secret"`
}
func (c *NoCommitment) Define(api frontend.API) error {
api.AssertIsDifferent(c.A, c.B)
return nil
}
func TestCommitments(t *testing.T) {
assert := test.NewAssert(t)
vk1, p1 := getProof(assert, &PublicCommitmentOnly{}, &PublicCommitmentOnly{A: 1, B: 1})
vk2, p2 := getProof(assert, &PrivateCommitmentOnly{}, &PrivateCommitmentOnly{A: 1, B: 1})
vk3, p3 := getProof(assert, &PublicAndPrivateCommitment{}, &PublicAndPrivateCommitment{A: 1, B: 1})
vk4, p4 := getProof(assert, &NoCommitment{}, &NoCommitment{A: 1, B: 2})
assert.Log("vk1", len(vk1.PublicAndCommitmentCommitted))
assert.Log("vk2", len(vk2.PublicAndCommitmentCommitted))
assert.Log("vk3", len(vk3.PublicAndCommitmentCommitted))
assert.Log("vk4", len(vk4.PublicAndCommitmentCommitted))
_, _, _, _ = p1, p2, p3, p4
}
func getProof(assert *test.Assert, circuit frontend.Circuit, assignment frontend.Circuit) (*groth16_bn254.VerifyingKey, *groth16_bn254.Proof) {
ccs, err := frontend.Compile(ecc.BN254.ScalarField(), r1cs.NewBuilder, circuit)
assert.NoError(err)
pk, vk, err := groth16.Setup(ccs)
assert.NoError(err)
w, err := frontend.NewWitness(assignment, ecc.BN254.ScalarField())
assert.NoError(err)
pw, err := frontend.NewWitness(assignment, ecc.BN254.ScalarField(), frontend.PublicOnly())
assert.NoError(err)
proof, err := groth16.Prove(ccs, pk, w)
assert.NoError(err)
err = groth16.Verify(proof, vk, pw)
assert.NoError(err)
tVk, ok := vk.(*groth16_bn254.VerifyingKey)
assert.True(ok)
tProof, ok := proof.(*groth16_bn254.Proof)
assert.True(ok)
return tVk, tProof
}
type wrappedBuilder interface {
frontend.Builder
kvstore.Store
}
type NoCommitter struct {
wrappedBuilder
}
func (c *NoCommitter) SetKeyValue(key any, value any) {
c.wrappedBuilder.SetKeyValue(key, value)
}
func (c *NoCommitter) GetKeyValue(key any) (value any) {
return c.wrappedBuilder.GetKeyValue(key)
}
func NewBuilder(nb frontend.NewBuilder) frontend.NewBuilder {
return func(sc *big.Int, cc frontend.CompileConfig) (frontend.Builder, error) {
bb, err := nb(sc, cc)
if err != nil {
return nil, fmt.Errorf("unwrapped: %w", err)
}
bbb, ok := bb.(wrappedBuilder)
if !ok {
return nil, fmt.Errorf("does not implement kvstore")
}
return &NoCommitter{wrappedBuilder: bbb}, nil
}
}
type RangecheckCircuit struct {
A frontend.Variable `gnark:",public"`
B frontend.Variable `gnark:",secret"`
}
func (C *RangecheckCircuit) Define(api frontend.API) error {
rc := rangecheck.New(api)
rc.Check(C.B, 8)
api.AssertIsDifferent(C.A, C.B)
return nil
}
func TestOverride(t *testing.T) {
assert := test.NewAssert(t)
// we first compile a circuit directly which implements committer
ccs, err := frontend.Compile(ecc.BN254.ScalarField(), r1cs.NewBuilder, &RangecheckCircuit{})
assert.NoError(err)
// then we compile a circuit which does not implement committer
ccs2, err := frontend.Compile(ecc.BN254.ScalarField(), NewBuilder(r1cs.NewBuilder), &RangecheckCircuit{})
assert.NoError(err)
assert.Log("with committemnt", ccs.GetNbConstraints())
assert.Log("without committemnt", ccs2.GetNbConstraints())
} First, there are different circuits which show when the Finally, there is the construction See if this works for your approach. Otherwise I think it would be more useful to know what kind of circuit you are using and what is the goal of not having |
Hello, when using gnark with BLS12-381, I don't want to generate commitments and commitmentPok. What should I do?
Currently, compiling some circuits include commitments and commitmentPok, while others do not.
I would like to avoid using commitments and commitmentPok and work only with inputs and proofs. Thank you!
The text was updated successfully, but these errors were encountered: