frontend

package
v0.0.4 Latest Latest
Warning

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

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

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func Compile

func Compile(field *big.Int, newBuilder NewBuilder, circuit Circuit, opts ...CompileOption) (constraint.ConstraintSystem, error)

Compile will generate a ConstraintSystem from the given circuit

1. it will first allocate the user inputs (see schema.TagOpt and Circuit for more info) example:

type MyCircuit struct {
	Y frontend.Variable `gnark:"exponent,public"`
}

in that case, Compile() will allocate one public variable with id "exponent"

2. it then calls circuit.Define(curveID, R1CS) to build the internal constraint system from the declarative code

  1. finally, it converts that to a ConstraintSystem. if zkpID == backend.GROTH16 → R1CS if zkpID == backend.PLONK → SparseR1CS

initialCapacity is an optional parameter that reserves memory in slices it should be set to the estimated number of constraints in the circuit, if known.

func IsCanonical

func IsCanonical(v Variable) bool

IsCanonical returns true if the Variable has been normalized in a (internal) LinearExpression by one of the constraint system builder. In other words, if the Variable is a circuit input OR returned by the API.

func NewSchema

func NewSchema(circuit Circuit) (*schema.Schema, error)

NewSchema returns the schema corresponding to the circuit structure.

This is used to JSON (un)marshall witnesses.

func NewWitness

func NewWitness(assignment Circuit, field *big.Int, opts ...WitnessOption) (witness.Witness, error)

NewWitness build an ordered vector of field elements from the given assignment (Circuit) if PublicOnly is specified, returns the public part of the witness only else returns [public | secret]. The result can then be serialized to / from json & binary.

See ExampleWitness in witness package for usage.

Types

type API

type API interface {

	// Add returns res = i1+i2+...in
	Add(i1, i2 Variable, in ...Variable) Variable

	// MulAcc sets and return a = a + (b*c).
	//
	// ! The method may mutate a without allocating a new result. If the input
	// is used elsewhere, then first initialize new variable, for example by
	// doing:
	//
	//     acopy := api.Mul(a, 1)
	//     acopy = MulAcc(acopy, b, c)
	//
	// ! But it may not modify a, always use MulAcc(...) result for correctness.
	MulAcc(a, b, c Variable) Variable

	// Neg returns -i
	Neg(i1 Variable) Variable

	// Sub returns res = i1 - i2 - ...in
	Sub(i1, i2 Variable, in ...Variable) Variable

	// Mul returns res = i1 * i2 * ... in
	Mul(i1, i2 Variable, in ...Variable) Variable

	// DivUnchecked returns i1 / i2 . if i1 == i2 == 0, returns 0
	DivUnchecked(i1, i2 Variable) Variable

	// Div returns i1 / i2
	Div(i1, i2 Variable) Variable

	// Inverse returns res = 1 / i1
	Inverse(i1 Variable) Variable

	// ToBinary unpacks a Variable in binary,
	// n is the number of bits to select (starting from lsb)
	// n default value is fr.Bits the number of bits needed to represent a field element
	//
	// The result in little endian (first bit= lsb)
	ToBinary(i1 Variable, n ...int) []Variable

	// FromBinary packs b, seen as a fr.Element in little endian
	FromBinary(b ...Variable) Variable

	// Xor returns a ^ b
	// a and b must be 0 or 1
	Xor(a, b Variable) Variable

	// Or returns a | b
	// a and b must be 0 or 1
	Or(a, b Variable) Variable

	// Or returns a & b
	// a and b must be 0 or 1
	And(a, b Variable) Variable

	// Select if b is true, yields i1 else yields i2
	Select(b Variable, i1, i2 Variable) Variable

	// Lookup2 performs a 2-bit lookup between i1, i2, i3, i4 based on bits b0
	// and b1. Returns i0 if b0=b1=0, i1 if b0=1 and b1=0, i2 if b0=0 and b1=1
	// and i3 if b0=b1=1.
	Lookup2(b0, b1 Variable, i0, i1, i2, i3 Variable) Variable

	// IsZero returns 1 if a is zero, 0 otherwise
	IsZero(i1 Variable) Variable

	// Cmp returns:
	//  * 1 if i1>i2,
	//  * 0 if i1=i2,
	//  * -1 if i1<i2.
	//
	// If the absolute difference between the variables i1 and i2 is known, then
	// it is more efficient to use the bounded methdods in package
	// [github.com/consensys/gnark/std/math/bits].
	Cmp(i1, i2 Variable) Variable

	// AssertIsEqual fails if i1 != i2
	AssertIsEqual(i1, i2 Variable)

	// AssertIsDifferent fails if i1 == i2
	AssertIsDifferent(i1, i2 Variable)

	// AssertIsBoolean fails if v != 0 and v != 1
	AssertIsBoolean(i1 Variable)
	// AssertIsCrumb fails if v ∉ {0,1,2,3} (crumb is a 2-bit variable; see https://en.wikipedia.org/wiki/Units_of_information)
	AssertIsCrumb(i1 Variable)

	// AssertIsLessOrEqual fails if v > bound.
	//
	// If the absolute difference between the variables b and bound is known, then
	// it is more efficient to use the bounded methdods in package
	// [github.com/consensys/gnark/std/math/bits].
	AssertIsLessOrEqual(v Variable, bound Variable)

	// Println behaves like fmt.Println but accepts cd.Variable as parameter
	// whose value will be resolved at runtime when computed by the solver
	Println(a ...Variable)

	// Compiler returns the compiler object for advanced circuit development
	Compiler() Compiler

	// NewHint is a shortcut to api.Compiler().NewHint()
	// Deprecated: use api.Compiler().NewHint() instead
	NewHint(f solver.Hint, nbOutputs int, inputs ...Variable) ([]Variable, error)

	// ConstantValue is a shortcut to api.Compiler().ConstantValue()
	// Deprecated: use api.Compiler().ConstantValue() instead
	ConstantValue(v Variable) (*big.Int, bool)
}

API represents the available functions to circuit developers

type BatchInverter

type BatchInverter interface {
	// BatchInvert returns a slice of variables containing the inverse of each element in i1
	// This is a temporary API, do not use it in your circuit
	BatchInvert(i1 []Variable) []Variable
}

BatchInvert returns a slice of variables containing the inverse of each element in i1 This is a temporary API, do not use it in your circuit

type Builder

type Builder interface {
	API
	Compiler

	// Compile is called after circuit.Define() to produce a final IR (ConstraintSystem)
	Compile() (constraint.ConstraintSystem, error)

	// PublicVariable is called by the compiler when parsing the circuit schema. It panics if
	// called inside circuit.Define()
	PublicVariable(schema.LeafInfo) Variable

	// SecretVariable is called by the compiler when parsing the circuit schema. It panics if
	// called inside circuit.Define()
	SecretVariable(schema.LeafInfo) Variable
}

Builder represents a constraint system builder

type CanonicalVariable

type CanonicalVariable interface {
	constraint.Compressible
}

CanonicalVariable represents a variable that's encoded in a constraint system specific way. For example a R1CS builder may represent this as a constraint.LinearExpression, a PLONK builder --> constraint.Term and the test/Engine --> ~*big.Int.

type Circuit

type Circuit interface {
	// Define declares the circuit's Constraints
	Define(api API) error
}

Circuit must be implemented by user-defined circuit. The best way to define a circuit is to define a type which contains all the witness elements as fields and declare `Define` method on the type.

For example, the following is a minimal valid circuit:

type MyCircuit struct {
    X frontend.Variable `gnark:"-,public"`
    Y frontend.Variable `gnark:"-,secret"`
}

func (c *MyCircuit) Define(api frontend.API) error {
    api.AssertIsEqual(c.X, c.Y)
	return nil
}

See the documentation for schema.TagOpt for how to use tags to define the behaviour of the compiler and schema parser.

type Committer

type Committer interface {
	// Commit commits to the variables and returns the commitment.
	Commit(toCommit ...Variable) (commitment Variable, err error)
}

Committer allows to commit to the variables and returns the commitment. The commitment can be used as a challenge using Fiat-Shamir heuristic.

type CompileConfig

type CompileConfig struct {
	Capacity                  int
	IgnoreUnconstrainedInputs bool
	CompressThreshold         int
}

type CompileOption

type CompileOption func(opt *CompileConfig) error

CompileOption defines option for altering the behaviour of the Compile method. See the descriptions of the functions returning instances of this type for available options.

func IgnoreUnconstrainedInputs

func IgnoreUnconstrainedInputs() CompileOption

IgnoreUnconstrainedInputs is a compile option which allow compiling input circuits where not all inputs are not constrained. If not set, then the compiler returns an error if there exists an unconstrained input.

This option is useful for debugging circuits, but should not be used in production settings as it means that there is a potential error in the circuit definition or that it is possible to optimize witness size.

func WithCapacity

func WithCapacity(capacity int) CompileOption

WithCapacity is a compile option that specifies the estimated capacity needed for internal variables and constraints. If not set, then the initial capacity is 0 and is dynamically allocated as needed.

func WithCompressThreshold

func WithCompressThreshold(threshold int) CompileOption

WithCompressThreshold is a compile option which enforces automatic variable compression if the length of the linear expression in the variable exceeds given threshold.

This option is usable in arithmetisations where the variable is a linear combination, as for example in R1CS. If variable is not a linear combination, then this option does not change the compile behaviour.

This compile option should be used in cases when it is known that there are long addition chains and the compile time and memory usage start are growing fast. The compression adds some overhead in the number of constraints. The overhead and compile performance depends on threshold value, and it should be chosen carefully.

If this option is not given then by default we use the compress threshold of 300.

type Compiler

type Compiler interface {
	constraint.CustomizableSystem

	// MarkBoolean sets (but do not constraint!) v to be boolean
	// This is useful in scenarios where a variable is known to be boolean through a constraint
	// that is not api.AssertIsBoolean. If v is a constant, this is a no-op.
	MarkBoolean(v Variable)

	// IsBoolean returns true if given variable was marked as boolean in the compiler (see MarkBoolean)
	// Use with care; variable may not have been **constrained** to be boolean
	// This returns true if the v is a constant and v == 0 || v == 1.
	IsBoolean(v Variable) bool

	// NewHint initializes internal variables whose value will be evaluated
	// using the provided hint function at run time from the inputs. Inputs must
	// be either variables or convertible to *big.Int. The function returns an
	// error if the number of inputs is not compatible with f.
	//
	// The hint function is provided at the proof creation time and is not
	// embedded into the circuit. From the backend point of view, the variable
	// returned by the hint function is equivalent to the user-supplied witness,
	// but its actual value is assigned by the solver, not the caller.
	//
	// No new constraints are added to the newly created wire and must be added
	// manually in the circuit. Failing to do so leads to solver failure.
	//
	// If nbOutputs is specified, it must be >= 1 and <= f.NbOutputs
	NewHint(f solver.Hint, nbOutputs int, inputs ...Variable) ([]Variable, error)

	// ConstantValue returns the big.Int value of v and true if op is a success.
	// nil and false if failure. This API returns a boolean to allow for future refactoring
	// replacing *big.Int with fr.Element
	ConstantValue(v Variable) (*big.Int, bool)

	// Field returns the finite field modulus injected by the compiler
	Field() *big.Int

	// FieldBitLen returns the number of bits needed to represent an element in the scalar field
	FieldBitLen() int

	// Defer is called after circuit.Define() and before Compile(). This method
	// allows for the circuits to register callbacks which finalize batching
	// operations etc. Unlike Go defer, it is not locally scoped.
	Defer(cb func(api API) error)

	// InternalVariable returns the internal variable associated with the given wireID
	// ! Experimental: use in conjunction with constraint.CustomizableSystem
	InternalVariable(wireID uint32) Variable

	// ToCanonicalVariable converts a frontend.Variable to a constraint system specific Variable
	// ! Experimental: use in conjunction with constraint.CustomizableSystem
	ToCanonicalVariable(Variable) CanonicalVariable

	SetGkrInfo(constraint.GkrInfo) error
}

Compiler represents a constraint system compiler

type NewBuilder

type NewBuilder func(*big.Int, CompileConfig) (Builder, error)

type PlonkAPI

type PlonkAPI interface {
	// EvaluatePlonkExpression returns res = qL.a + qR.b + qM.ab + qC
	EvaluatePlonkExpression(a, b Variable, qL, qR, qM, qC int) Variable

	// AddPlonkConstraint asserts qL.a + qR.b + qM.ab + qO.o + qC
	AddPlonkConstraint(a, b, o Variable, qL, qR, qO, qM, qC int)
}

type Rangechecker

type Rangechecker interface {
	// Check checks that the given variable v has bit-length bits.
	Check(v Variable, bits int)
}

Rangechecker allows to externally range-check the variables to be of specified width. Not all compilers implement this interface. Users should instead use github.com/consensys/gnark/std/rangecheck package which automatically chooses most optimal method for range checking the variables.

type Variable

type Variable interface{}

Variable represents a variable in the circuit. Any integer type (e.g. int, *big.Int, fr.Element) can be assigned to it. It is also allowed to set a base-10 encoded string representing an integer value. The only purpose of putting this definition here is to avoid the import cycles (cs/plonk <-> frontend) and (cs/r1cs <-> frontend)

type WitnessOption

type WitnessOption func(*witnessConfig) error

WitnessOption sets optional parameter to witness instantiation from an assignment

func PublicOnly

func PublicOnly() WitnessOption

PublicOnly enables to instantiate a witness with the public part only of the assignment

Directories

Path Synopsis
cs
scs
internal
internal/reflectwalk
reflectwalk is a package that allows you to "walk" complex structures similar to how you may "walk" a filesystem: visiting every element one by one and calling callback functions allowing you to handle and manipulate those elements.
reflectwalk is a package that allows you to "walk" complex structures similar to how you may "walk" a filesystem: visiting every element one by one and calling callback functions allowing you to handle and manipulate those elements.

Jump to

Keyboard shortcuts

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