Skip to content
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

docs: update api doc following audit suggestions #1291

Merged
merged 2 commits into from
Oct 7, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 13 additions & 7 deletions frontend/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,18 +51,20 @@ type API interface {
// Mul returns res = i1 * i2 * ... in
Mul(i1, i2 Variable, in ...Variable) Variable

// DivUnchecked returns i1 / i2 . if i1 == i2 == 0, returns 0
// DivUnchecked returns i1 / i2
// If i1 == i2 == 0, the return value (0) is unconstrained.
DivUnchecked(i1, i2 Variable) Variable

// Div returns i1 / i2
// If i2 == 0 the constraint will not be satisfied.
Div(i1, i2 Variable) Variable

// Inverse returns res = 1 / i1
// If i1 == 0 the constraint will not be satisfied.
Inverse(i1 Variable) Variable

// ---------------------------------------------------------------------------------------------
// Bit operations
// TODO @gbotrel move bit operations in std/math/bits

// ToBinary unpacks a Variable in binary,
// n is the number of bits to select (starting from lsb)
Expand All @@ -72,29 +74,32 @@ type API interface {
ToBinary(i1 Variable, n ...int) []Variable

// FromBinary packs b, seen as a fr.Element in little endian
// This function constrain the bits b... to be boolean (0 or 1)
FromBinary(b ...Variable) Variable

// Xor returns a ^ b
// a and b must be 0 or 1
// This function constrain a and b to be boolean (0 or 1)
Xor(a, b Variable) Variable

// Or returns a | b
// a and b must be 0 or 1
// This function constrain a and b to be boolean (0 or 1)
Or(a, b Variable) Variable

// Or returns a & b
// a and b must be 0 or 1
// And returns a & b
// This function constrain a and b to be boolean (0 or 1)
And(a, b Variable) Variable

// ---------------------------------------------------------------------------------------------
// Conditionals

// Select if b is true, yields i1 else yields i2
// This function constrain b to be boolean (0 or 1)
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.
// This function constrain b0 and b1 to be boolean (0 or 1)
Lookup2(b0, b1 Variable, i0, i1, i2, i3 Variable) Variable

// IsZero returns 1 if a is zero, 0 otherwise
Expand All @@ -119,8 +124,9 @@ type API interface {
// AssertIsDifferent fails if i1 == i2
AssertIsDifferent(i1, i2 Variable)

// AssertIsBoolean fails if v != 0 and v != 1
// AssertIsBoolean fails if v ∉ {0,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)

Expand Down
33 changes: 0 additions & 33 deletions frontend/cs/scs/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,6 @@ import (
"github.com/consensys/gnark/std/math/bits"
)

// Add returns res = i1+i2+...in
func (builder *builder) Add(i1, i2 frontend.Variable, in ...frontend.Variable) frontend.Variable {
// separate the constant part from the variables
vars, k := builder.filterConstantSum(append([]frontend.Variable{i1, i2}, in...))
Expand Down Expand Up @@ -105,7 +104,6 @@ func (builder *builder) mulAccFastTrack(a, b, c frontend.Variable) frontend.Vari
return res
}

// neg returns -in
func (builder *builder) neg(in []frontend.Variable) []frontend.Variable {
res := make([]frontend.Variable, len(in))

Expand All @@ -115,13 +113,11 @@ func (builder *builder) neg(in []frontend.Variable) []frontend.Variable {
return res
}

// Sub returns res = i1 - i2 - ...in
func (builder *builder) Sub(i1, i2 frontend.Variable, in ...frontend.Variable) frontend.Variable {
r := builder.neg(append([]frontend.Variable{i2}, in...))
return builder.Add(i1, r[0], r[1:]...)
}

// Neg returns -i
func (builder *builder) Neg(i1 frontend.Variable) frontend.Variable {
if n, ok := builder.constantValue(i1); ok {
n = builder.cs.Neg(n)
Expand All @@ -132,7 +128,6 @@ func (builder *builder) Neg(i1 frontend.Variable) frontend.Variable {
return v
}

// Mul returns res = i1 * i2 * ... in
func (builder *builder) Mul(i1, i2 frontend.Variable, in ...frontend.Variable) frontend.Variable {
vars, k := builder.filterConstantProd(append([]frontend.Variable{i1, i2}, in...))
if len(vars) == 0 {
Expand All @@ -157,7 +152,6 @@ func (builder *builder) mulConstant(t expr.Term, m constraint.Element) expr.Term
return t
}

// DivUnchecked returns i1 / i2 . if i1 == i2 == 0, returns 0
func (builder *builder) DivUnchecked(i1, i2 frontend.Variable) frontend.Variable {
c1, i1Constant := builder.constantValue(i1)
c2, i2Constant := builder.constantValue(i2)
Expand Down Expand Up @@ -195,15 +189,13 @@ func (builder *builder) DivUnchecked(i1, i2 frontend.Variable) frontend.Variable
return res
}

// Div returns i1 / i2
func (builder *builder) Div(i1, i2 frontend.Variable) frontend.Variable {
// note that here we ensure that v2 can't be 0, but it costs us one extra constraint
builder.Inverse(i2)

return builder.DivUnchecked(i1, i2)
}

// Inverse returns res = 1 / i1
func (builder *builder) Inverse(i1 frontend.Variable) frontend.Variable {
if c, ok := builder.constantValue(i1); ok {
if c.IsZero() {
Expand Down Expand Up @@ -236,11 +228,6 @@ func (builder *builder) Inverse(i1 frontend.Variable) frontend.Variable {
// ---------------------------------------------------------------------------------------------
// Bit operations

// ToBinary unpacks a frontend.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 is in little endian (first bit= lsb)
func (builder *builder) ToBinary(i1 frontend.Variable, n ...int) []frontend.Variable {
// nbBits
nbBits := builder.cs.FieldBitLen()
Expand All @@ -254,13 +241,10 @@ func (builder *builder) ToBinary(i1 frontend.Variable, n ...int) []frontend.Vari
return bits.ToBinary(builder, i1, bits.WithNbDigits(nbBits))
}

// FromBinary packs b, seen as a fr.Element in little endian
func (builder *builder) FromBinary(b ...frontend.Variable) frontend.Variable {
return bits.FromBinary(builder, b)
}

// Xor returns a ^ b
// a and b must be 0 or 1
func (builder *builder) Xor(a, b frontend.Variable) frontend.Variable {
// pre condition: a, b must be booleans
builder.AssertIsBoolean(a)
Expand Down Expand Up @@ -335,8 +319,6 @@ func (builder *builder) Xor(a, b frontend.Variable) frontend.Variable {
return res
}

// Or returns a | b
// a and b must be 0 or 1
func (builder *builder) Or(a, b frontend.Variable) frontend.Variable {
builder.AssertIsBoolean(a)
builder.AssertIsBoolean(b)
Expand Down Expand Up @@ -388,8 +370,6 @@ func (builder *builder) Or(a, b frontend.Variable) frontend.Variable {
return res
}

// Or returns a & b
// a and b must be 0 or 1
func (builder *builder) And(a, b frontend.Variable) frontend.Variable {
builder.AssertIsBoolean(a)
builder.AssertIsBoolean(b)
Expand All @@ -401,7 +381,6 @@ func (builder *builder) And(a, b frontend.Variable) frontend.Variable {
// ---------------------------------------------------------------------------------------------
// Conditionals

// Select if b is true, yields i1 else yields i2
func (builder *builder) Select(b frontend.Variable, i1, i2 frontend.Variable) frontend.Variable {
_b, bConstant := builder.constantValue(b)

Expand All @@ -424,9 +403,6 @@ func (builder *builder) Select(b frontend.Variable, i1, i2 frontend.Variable) fr
return builder.Add(l, i2)
}

// 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.
func (builder *builder) Lookup2(b0, b1 frontend.Variable, i0, i1, i2, i3 frontend.Variable) frontend.Variable {
// ensure that bits are actually bits. Adds no constraints if the variables
// are already constrained.
Expand Down Expand Up @@ -473,7 +449,6 @@ func (builder *builder) Lookup2(b0, b1 frontend.Variable, i0, i1, i2, i3 fronten

}

// IsZero returns 1 if a is zero, 0 otherwise
func (builder *builder) IsZero(i1 frontend.Variable) frontend.Variable {
if a, ok := builder.constantValue(i1); ok {
if a.IsZero() {
Expand Down Expand Up @@ -519,7 +494,6 @@ func (builder *builder) IsZero(i1 frontend.Variable) frontend.Variable {
return m
}

// Cmp returns 1 if i1>i2, 0 if i1=i2, -1 if i1<i2
func (builder *builder) Cmp(i1, i2 frontend.Variable) frontend.Variable {

nbBits := builder.cs.FieldBitLen()
Expand Down Expand Up @@ -547,13 +521,6 @@ func (builder *builder) Cmp(i1, i2 frontend.Variable) frontend.Variable {
return res
}

// Println behaves like fmt.Println but accepts Variable as parameter
// whose value will be resolved at runtime when computed by the solver
// Println enables circuit debugging and behaves almost like fmt.Println()
//
// the print will be done once the R1CS.Solve() method is executed
//
// if one of the input is a variable, its value will be resolved when R1CS.Solve() method is called
func (builder *builder) Println(a ...frontend.Variable) {
var log constraint.LogEntry

Expand Down
3 changes: 1 addition & 2 deletions frontend/cs/scs/builder.go
Original file line number Diff line number Diff line change
Expand Up @@ -309,8 +309,7 @@ func (builder *builder) Compile() (constraint.ConstraintSystem, error) {
return builder.cs, nil
}

// ConstantValue returns the big.Int value of v.
// Will panic if v.IsConstant() == false
// ConstantValue returns the big.Int value of v and true if v is a constant, false otherwise
func (builder *builder) ConstantValue(v frontend.Variable) (*big.Int, bool) {
coeff, ok := builder.constantValue(v)
if !ok {
Expand Down