multicommit

package
v1.0.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Feb 8, 2024 License: Apache-2.0 Imports: 3 Imported by: 0

Documentation

Overview

Package multicommit implements commitment expansion.

If the builder implements frontend.Committer interface, then we can commit to the variables and get a commitment which can be used as a unique randomness in the circuit. For current builders implementing this interface, the function can only be called once in a circuit. This makes it difficult to compose different gadgets which require randomness.

This package extends the commitment interface by allowing to receive several functions unique commitment multiple times. It does this by collecting all variables to commit and the callbacks which want to access a commitment. Then we internally defer a function which computes the commitment over all input committed variables and then uses this commitment to derive a per-callback unique commitment. The callbacks are then called with these unique derived commitments instead.

Index

Examples

Constants

This section is empty.

Variables

This section is empty.

Functions

func Initialize

func Initialize(api frontend.API)

Initialize creates a multicommitter in the cache and defers its finalization. This can be useful in a context where `api.Defer` is already called and where calls to `WithCommitment` are deferred. Panics if the multicommit is already initialized.

func WithCommitment

func WithCommitment(api frontend.API, cb WithCommitmentFn, committedVariables ...frontend.Variable)

WithCommitment schedules the function cb to be called with a unique commitment. We append the variables committedVariables to be committed to with the native frontend.Committer interface.

Example

Full written on how to use multiple commitments in a circuit.

package main

import (
	"fmt"

	"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/multicommit"
)

// MultipleCommitmentCircuit is an example circuit showing usage of multiple
// independent commitments in-circuit.
type MultipleCommitmentsCircuit struct {
	Secrets [4]frontend.Variable
}

func (c *MultipleCommitmentsCircuit) Define(api frontend.API) error {
	// first callback receives first unique commitment derived from the root commitment
	multicommit.WithCommitment(api, func(api frontend.API, commitment frontend.Variable) error {
		// compute (X-s[0]) * (X-s[1]) for a random X
		res := api.Mul(api.Sub(commitment, c.Secrets[0]), api.Sub(commitment, c.Secrets[1]))
		api.AssertIsDifferent(res, 0)
		return nil
	}, c.Secrets[:2]...)

	// second callback receives second unique commitment derived from the root commitment
	multicommit.WithCommitment(api, func(api frontend.API, commitment frontend.Variable) error {
		// compute (X-s[2]) * (X-s[3]) for a random X
		res := api.Mul(api.Sub(commitment, c.Secrets[2]), api.Sub(commitment, c.Secrets[3]))
		api.AssertIsDifferent(res, 0)
		return nil
	}, c.Secrets[2:4]...)

	// we do not have to pass any variables in if other calls to [WithCommitment] have
	multicommit.WithCommitment(api, func(api frontend.API, commitment frontend.Variable) error {
		// compute (X-s[0]) for a random X
		api.AssertIsDifferent(api.Sub(commitment, c.Secrets[0]), 0)
		return nil
	})

	// we can share variables between the callbacks
	var shared, stored frontend.Variable
	multicommit.WithCommitment(api, func(api frontend.API, commitment frontend.Variable) error {
		shared = api.Add(c.Secrets[0], commitment)
		stored = commitment
		return nil
	})
	multicommit.WithCommitment(api, func(api frontend.API, commitment frontend.Variable) error {
		api.AssertIsEqual(api.Sub(shared, stored), c.Secrets[0])
		return nil
	})
	return nil
}

// Full written on how to use multiple commitments in a circuit.
func main() {
	circuit := MultipleCommitmentsCircuit{}
	assignment := MultipleCommitmentsCircuit{Secrets: [4]frontend.Variable{1, 2, 3, 4}}
	ccs, err := frontend.Compile(ecc.BN254.ScalarField(), r1cs.NewBuilder, &circuit)
	if err != nil {
		panic(err)
	}
	pk, vk, err := groth16.Setup(ccs)
	if err != nil {
		panic(err)
	}
	secretWitness, err := frontend.NewWitness(&assignment, ecc.BN254.ScalarField())
	if err != nil {
		panic(err)
	}
	publicWitness, err := secretWitness.Public()
	if err != nil {
		panic(err)
	}
	proof, err := groth16.Prove(ccs, pk, secretWitness)
	if err != nil {
		panic(err)
	}
	err = groth16.Verify(proof, vk, publicWitness)
	if err != nil {
		panic(err)
	}
	fmt.Println("done")
}
Output:

done

Types

type WithCommitmentFn

type WithCommitmentFn func(api frontend.API, commitment frontend.Variable) error

WithCommitmentFn is the function which is called asynchronously after all variables have been committed to. See WithCommitment for scheduling a function of this type. Every called functions received a distinct commitment built from a single root.

It is invalid to call WithCommitment in this method recursively and this leads to panic. However, the method can call defer for other callbacks.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL