Skip to content

FixedBaseScalarMul black box function #80

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

Draft
wants to merge 6 commits into
base: generate_constraints_in_black_box_functions
Choose a base branch
from
Draft
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
123 changes: 123 additions & 0 deletions gnark_backend_ffi/backend/plonk/components.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"gnark_backend_ffi/backend"
"math/big"

"github.com/consensys/gnark-crypto/ecc/bn254"
fr_bn254 "github.com/consensys/gnark-crypto/ecc/bn254/fr"
"github.com/consensys/gnark/constraint"
cs_bn254 "github.com/consensys/gnark/constraint/bn254"
Expand Down Expand Up @@ -479,3 +480,125 @@ func assertIsInRange(felt, bits int, ctx *backend.Context) {
reconstructedFelt := fromBinaryConversion(feltBits, ctx, false)
assertIsEqual(felt, reconstructedFelt, ctx.ConstraintSystem)
}

func Square(value int, ctx *backend.Context) int {
var xa, xc int
var qL, qR, qO, qM1, qM2 constraint.Coeff

qM1 = ctx.ConstraintSystem.One()
qM2 = ctx.ConstraintSystem.One()
xa = value
xb := value

qO = ctx.ConstraintSystem.FromInterface(-1)
var square fr_bn254.Element
square.Square(&ctx.Variables[value])

variableName := fmt.Sprintf("(%s^2)", ctx.ConstraintSystem.(*cs_bn254.SparseR1CS).VariableToString(value))
xc = ctx.AddSecretVariable(variableName, square)

addConstraint := constraint.SparseR1C{
L: ctx.ConstraintSystem.MakeTerm(&qL, xa),
R: ctx.ConstraintSystem.MakeTerm(&qR, xb),
O: ctx.ConstraintSystem.MakeTerm(&qO, xc),
M: [2]constraint.Term{ctx.ConstraintSystem.MakeTerm(&qM1, xa), ctx.ConstraintSystem.MakeTerm(&qM2, xb)},
K: constraint.CoeffIdZero,
}

ctx.ConstraintSystem.AddConstraint(addConstraint)

return xc
}

// Generates constraints for asserting that a point is on a curve. The curve
// will depend on the context's constraint system used.
//
// Generates 5 Plonk constraints.
//
// pointX is the index to the x-coordinate of the point in question.
// pointY is the index to the y-coordinate of the point in question.
// ctx is the context.
func AssertPointIsOnCurve(pointX, pointY int, ctx *backend.Context) {
var left, right int
switch ctx.ConstraintSystem.(type) {
case *cs_bn254.SparseR1CS:
left = Square(pointY, ctx)
xSquared := Square(pointX, ctx)
xCubed := mul(xSquared, pointX, ctx)
// This should be handled as a constant instead of a secret variable. Maybe
// If we hardcode the constraint this could be avoided.
curveConstant := ctx.AddSecretVariable("bn254_constant", fr_bn254.NewElement(3))
right = add(xCubed, curveConstant, ctx)
}
assertIsEqual(left, right, ctx.ConstraintSystem)
}

// Generates constraints for adding two elliptic curve points.
//
// Generates 7 constraints if the point needs to be checked and 2 constraints if not.
// A point addition result could not be checked as an optimization in the case that
// the resulting point is a partial result of a multiple addition for example.
// The user should take this into account.
//
// augendPointX is the index to the x-coordinate of the augend point in question.
// augendPointY is the index to the y-coordinate of the augend point in question.
// addendPointX is the index to the x-coordinate of the addend point in question.
// addendPointY is the index to the y-coordinate of the addend point in question.
// ctx is the context.
// checkPoint is a flag that will generate additional constraints for checking
// that the resulting point is on the curve.
//
// Returns the indices to the resulting point x and y coordinates.
func AddPoints(augendPointX, augendPointY, addendPointX, addendPointY int, ctx *backend.Context, checkPoint bool) (newPointX, newPointY int) {
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Point addition algorithm is wrong.

newPointX = add(augendPointX, addendPointX, ctx)
newPointY = add(augendPointY, addendPointY, ctx)
if checkPoint {
AssertPointIsOnCurve(newPointX, newPointY, ctx)
}
return
}

// Generates constraints for doubling a point. Doubling a point means adding some
// point to itself.
//
// Generates 7 constraints if the point needs to be checked and 2 constraints if not.
// A point addition result could not be checked as an optimization in the case that
// the resulting point is a partial result of a multiple addition for example.
// The user should take this into account.
//
// x is the index to the x-coordinate of the point in question.
// y is the index to the y-coordinate of the point in question.
// ctx is the context.
// checkPoint is a flag that will generate additional constraints for checking
// that the resulting point is on the curve.
//
// Returns the indices to the resulting point x and y coordinates.
func DoublePoint(x, y int, ctx *backend.Context, checkPoint bool) (doubledX, doubledY int) {
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also point double algorithm is wrong.

return AddPoints(x, y, x, y, ctx, checkPoint)
}

// Generates constraints for computing the fixed base scalar multiplication. This
// means multiplying the curve generator with a given scalar.
//
// Generates 5n + 1 constraints where n is the integer value of the scalar.
//
// scalar is the index to the concrete value of the scalar that will multiply
// the curve generator.
// ctx is the context.
func ScalarBaseMul(scalar int, ctx *backend.Context) (resultX, resultY int) {
switch ctx.ConstraintSystem.(type) {
case *cs_bn254.SparseR1CS:
_, _, generator, _ := bn254.Generators()
x := ctx.AddSecretVariable("genX", fr_bn254.Element(generator.X))
y := ctx.AddSecretVariable("genY", fr_bn254.Element(generator.Y))
accumulatorX, accumulatorY := AddPoints(x, y, x, y, ctx, false)
for i := 0; i < int(ctx.Variables[scalar].Uint64()); i++ {
accumulatorX, accumulatorY = DoublePoint(x, y, ctx, false)
}
AssertPointIsOnCurve(accumulatorX, accumulatorY, ctx)
resultX = accumulatorX
resultY = accumulatorY
return
}
return
}
Original file line number Diff line number Diff line change
Expand Up @@ -125,3 +125,32 @@ func sub(minuend int, subtrahend int, ctx *backend.Context) int {

return xc
}

func Square(value int, ctx *backend.Context) int {
var xa, xc int
var qL, qR, qO, qM1, qM2 constraint.Coeff

qM1 = ctx.ConstraintSystem.One()
qM2 = ctx.ConstraintSystem.One()
xa = value
xb := value

qO = ctx.ConstraintSystem.FromInterface(-1)
var square fr_bn254.Element
square.Square(&ctx.Variables[value])

variableName := fmt.Sprintf("(%s^2)", ctx.ConstraintSystem.(*cs_bn254.SparseR1CS).VariableToString(value))
xc = ctx.AddSecretVariable(variableName, square)

addConstraint := constraint.SparseR1C{
L: ctx.ConstraintSystem.MakeTerm(&qL, xa),
R: ctx.ConstraintSystem.MakeTerm(&qR, xb),
O: ctx.ConstraintSystem.MakeTerm(&qO, xc),
M: [2]constraint.Term{ctx.ConstraintSystem.MakeTerm(&qM1, xa), ctx.ConstraintSystem.MakeTerm(&qM2, xb)},
K: constraint.CoeffIdZero,
}

ctx.ConstraintSystem.AddConstraint(addConstraint)

return xc
}
Original file line number Diff line number Diff line change
Expand Up @@ -62,3 +62,20 @@ func TestSubComponent(t *testing.T) {

assertThatProvingAndVerifyingSucceeds(t, ctx)
}

func TestSquareComponent(t *testing.T) {
values := fr_bn254.Vector{fr_bn254.NewElement(2), fr_bn254.NewElement(3)}
sparseR1CS := cs_bn254.NewSparseR1CS(1)

publicVariables, secretVariables, variables, variablesMap := backend.HandleValues(sparseR1CS, values, []uint32{})
ctx := backend.NewContext(acir.ACIR{}, sparseR1CS, publicVariables, secretVariables, variables, variablesMap)

// 2^2 = 4
result := Square(0, ctx)
assert.Equal(t, fr_bn254.NewElement(4), ctx.Variables[result])
// 3^3 = 9
result = Square(1, ctx)
assert.Equal(t, fr_bn254.NewElement(9), ctx.Variables[result])

assertThatProvingAndVerifyingSucceeds(t, ctx)
}
25 changes: 25 additions & 0 deletions gnark_backend_ffi/backend/plonk/components/assertions.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@ package components
import (
"gnark_backend_ffi/backend"

fr_bn254 "github.com/consensys/gnark-crypto/ecc/bn254/fr"
"github.com/consensys/gnark/constraint"
cs_bn254 "github.com/consensys/gnark/constraint/bn254"
)

// Generates constraints for asserting that a given value is boolean.
Expand Down Expand Up @@ -76,3 +78,26 @@ func assertIsInRange(felt, bits int, ctx *backend.Context) {
reconstructedFelt := fromBinaryConversion(feltBits, ctx, false)
assertIsEqual(felt, reconstructedFelt, ctx.ConstraintSystem)
}

// Generates constraints for asserting that a point is on a curve. The curve
// will depend on the context's constraint system used.
//
// Generates 5 Plonk constraints.
//
// pointX is the index to the x-coordinate of the point in question.
// pointY is the index to the y-coordinate of the point in question.
// ctx is the context.
func AssertPointIsOnCurve(pointX, pointY int, ctx *backend.Context) {
var left, right int
switch ctx.ConstraintSystem.(type) {
case *cs_bn254.SparseR1CS:
left = Square(pointY, ctx)
xSquared := Square(pointX, ctx)
xCubed := mul(xSquared, pointX, ctx)
// This should be handled as a constant instead of a secret variable. Maybe
// If we hardcode the constraint this could be avoided.
curveConstant := ctx.AddSecretVariable("bn254_constant", fr_bn254.NewElement(3))
right = add(xCubed, curveConstant, ctx)
}
assertIsEqual(left, right, ctx.ConstraintSystem)
}
8 changes: 8 additions & 0 deletions gnark_backend_ffi/backend/plonk/components/assertions_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -92,3 +92,11 @@ func TestAssertIsInRangeComponentFails(t *testing.T) {

assertThatProvingFails(t, ctx)
}

func TestAssertPointIsOnCurveSucceeds(t *testing.T) {

}

func TestAssertPointIsOnCurveFails(t *testing.T) {

}
79 changes: 79 additions & 0 deletions gnark_backend_ffi/backend/plonk/components/curve.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
package components

import (
"gnark_backend_ffi/backend"

"github.com/consensys/gnark-crypto/ecc/bn254"
fr_bn254 "github.com/consensys/gnark-crypto/ecc/bn254/fr"
cs_bn254 "github.com/consensys/gnark/constraint/bn254"
)

// Generates constraints for adding two elliptic curve points.
//
// Generates 7 constraints if the point needs to be checked and 2 constraints if not.
// A point addition result could not be checked as an optimization in the case that
// the resulting point is a partial result of a multiple addition for example.
// The user should take this into account.
//
// augendPointX is the index to the x-coordinate of the augend point in question.
// augendPointY is the index to the y-coordinate of the augend point in question.
// addendPointX is the index to the x-coordinate of the addend point in question.
// addendPointY is the index to the y-coordinate of the addend point in question.
// ctx is the context.
// checkPoint is a flag that will generate additional constraints for checking
// that the resulting point is on the curve.
//
// Returns the indices to the resulting point x and y coordinates.
func AddPoints(augendPointX, augendPointY, addendPointX, addendPointY int, ctx *backend.Context, checkPoint bool) (newPointX, newPointY int) {
newPointX = add(augendPointX, addendPointX, ctx)
newPointY = add(augendPointY, addendPointY, ctx)
if checkPoint {
AssertPointIsOnCurve(newPointX, newPointY, ctx)
}
return
}

// Generates constraints for doubling a point. Doubling a point means adding some
// point to itself.
//
// Generates 7 constraints if the point needs to be checked and 2 constraints if not.
// A point addition result could not be checked as an optimization in the case that
// the resulting point is a partial result of a multiple addition for example.
// The user should take this into account.
//
// x is the index to the x-coordinate of the point in question.
// y is the index to the y-coordinate of the point in question.
// ctx is the context.
// checkPoint is a flag that will generate additional constraints for checking
// that the resulting point is on the curve.
//
// Returns the indices to the resulting point x and y coordinates.
func DoublePoint(x, y int, ctx *backend.Context, checkPoint bool) (doubledX, doubledY int) {
return AddPoints(x, y, x, y, ctx, checkPoint)
}

// Generates constraints for computing the fixed base scalar multiplication. This
// means multiplying the curve generator with a given scalar.
//
// Generates 5n + 1 constraints where n is the integer value of the scalar.
//
// scalar is the index to the concrete value of the scalar that will multiply
// the curve generator.
// ctx is the context.
func ScalarBaseMul(scalar int, ctx *backend.Context) (resultX, resultY int) {
switch ctx.ConstraintSystem.(type) {
case *cs_bn254.SparseR1CS:
_, _, generator, _ := bn254.Generators()
x := ctx.AddSecretVariable("genX", fr_bn254.Element(generator.X))
y := ctx.AddSecretVariable("genY", fr_bn254.Element(generator.Y))
accumulatorX, accumulatorY := AddPoints(x, y, x, y, ctx, false)
for i := 0; i < int(ctx.Variables[scalar].Uint64()); i++ {
accumulatorX, accumulatorY = DoublePoint(x, y, ctx, false)
}
AssertPointIsOnCurve(accumulatorX, accumulatorY, ctx)
resultX = accumulatorX
resultY = accumulatorY
return
}
return
}
15 changes: 15 additions & 0 deletions gnark_backend_ffi/backend/plonk/components/curve_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package components

import "testing"

func TestPointAddition(t *testing.T) {

}

func TestPointDoubling(t *testing.T) {

}

func TestPointBaseScalarMultiplication(t *testing.T) {

}