Skip to content

Commit

Permalink
docs: update api doc following audit suggestions (#1291)
Browse files Browse the repository at this point in the history
  • Loading branch information
gbotrel authored Oct 7, 2024
1 parent 722eb3b commit f776f36
Show file tree
Hide file tree
Showing 3 changed files with 14 additions and 42 deletions.
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

0 comments on commit f776f36

Please sign in to comment.