mirror of
https://github.com/arnaucube/gnark-plonky2-verifier.git
synced 2026-01-12 09:01:32 +01:00
Merge pull request #4 from succinctlabs/scalar-mult
Add scalar multiplication
This commit is contained in:
@@ -10,8 +10,8 @@ var (
|
|||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
// https://neuromancer.sk/std/other/Ed25519
|
// https://neuromancer.sk/std/other/Ed25519
|
||||||
qEd25519, _ = new(big.Int).SetString("7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffed", 16)
|
qEd25519 = newBigInt("7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffed")
|
||||||
n, _ := new(big.Int).SetString("1000000000000000000000000000000014def9dea2f79cd65812631a5cf5d3ed", 16)
|
n := newBigInt("1000000000000000000000000000000014def9dea2f79cd65812631a5cf5d3ed")
|
||||||
// TODO: is this ok?
|
// TODO: is this ok?
|
||||||
// h := big.NewInt(8)
|
// h := big.NewInt(8)
|
||||||
// rEd25519 = new(big.Int).Mul(n, h)
|
// rEd25519 = new(big.Int).Mul(n, h)
|
||||||
@@ -24,6 +24,10 @@ func (fp Ed25519) NbLimbs() uint { return 4 }
|
|||||||
func (fp Ed25519) BitsPerLimb() uint { return 64 }
|
func (fp Ed25519) BitsPerLimb() uint { return 64 }
|
||||||
func (fp Ed25519) IsPrime() bool { return true }
|
func (fp Ed25519) IsPrime() bool { return true }
|
||||||
func (fp Ed25519) Modulus() *big.Int { return qEd25519 }
|
func (fp Ed25519) Modulus() *big.Int { return qEd25519 }
|
||||||
|
func (fp Ed25519) Generator() (*big.Int, *big.Int) {
|
||||||
|
return newBigInt("216936D3CD6E53FEC0A4E231FDD6DC5C692CC7609525A7B2C9562D608F25D51A"),
|
||||||
|
newBigInt("6666666666666666666666666666666666666666666666666666666666666658")
|
||||||
|
}
|
||||||
|
|
||||||
type Ed25519Scalars struct{}
|
type Ed25519Scalars struct{}
|
||||||
|
|
||||||
|
|||||||
@@ -44,8 +44,8 @@ func newBigInt(s string) *big.Int {
|
|||||||
// equation and generator). But for now we don't do arbitrary curves.
|
// equation and generator). But for now we don't do arbitrary curves.
|
||||||
|
|
||||||
type Curve[T, S emulated.FieldParams] struct {
|
type Curve[T, S emulated.FieldParams] struct {
|
||||||
A emulated.Element[T]
|
a emulated.Element[T]
|
||||||
D emulated.Element[T]
|
d emulated.Element[T]
|
||||||
|
|
||||||
// api is the native api, we construct it ourselves to be sure
|
// api is the native api, we construct it ourselves to be sure
|
||||||
api frontend.API
|
api frontend.API
|
||||||
@@ -61,7 +61,7 @@ func (c *Curve[T, S]) Generator() AffinePoint[T] {
|
|||||||
return c.g
|
return c.g
|
||||||
}
|
}
|
||||||
|
|
||||||
func newCurve[T, S emulated.FieldParams](api frontend.API, A, D, Gx, Gy emulated.Element[T]) (*Curve[T, S], error) {
|
func newCurve[T, S emulated.FieldParams](api frontend.API, a, d, Gx, Gy emulated.Element[T]) (*Curve[T, S], error) {
|
||||||
ba, err := emulated.NewField[T](api)
|
ba, err := emulated.NewField[T](api)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("new base api: %w", err)
|
return nil, fmt.Errorf("new base api: %w", err)
|
||||||
@@ -71,8 +71,8 @@ func newCurve[T, S emulated.FieldParams](api frontend.API, A, D, Gx, Gy emulated
|
|||||||
return nil, fmt.Errorf("new scalar api: %w", err)
|
return nil, fmt.Errorf("new scalar api: %w", err)
|
||||||
}
|
}
|
||||||
return &Curve[T, S]{
|
return &Curve[T, S]{
|
||||||
A: A,
|
a: a,
|
||||||
D: D,
|
d: d,
|
||||||
api: api,
|
api: api,
|
||||||
baseApi: ba,
|
baseApi: ba,
|
||||||
scalarApi: sa,
|
scalarApi: sa,
|
||||||
@@ -102,50 +102,69 @@ func (c *Curve[T, S]) AssertIsEqual(p, q AffinePoint[T]) {
|
|||||||
func (c *Curve[T, S]) AssertIsOnCurve(p AffinePoint[T]) {
|
func (c *Curve[T, S]) AssertIsOnCurve(p AffinePoint[T]) {
|
||||||
xx := c.baseApi.Mul(p.X, p.X)
|
xx := c.baseApi.Mul(p.X, p.X)
|
||||||
yy := c.baseApi.Mul(p.Y, p.Y)
|
yy := c.baseApi.Mul(p.Y, p.Y)
|
||||||
fmt.Println(xx)
|
axx := c.baseApi.Mul(xx, c.a)
|
||||||
fmt.Println(c.A)
|
|
||||||
axx := c.baseApi.Mul(xx, c.A)
|
|
||||||
lhs := c.baseApi.Add(axx, yy)
|
lhs := c.baseApi.Add(axx, yy)
|
||||||
|
|
||||||
dxx := c.baseApi.Mul(xx, c.D)
|
dxx := c.baseApi.Mul(xx, c.d)
|
||||||
dxxyy := c.baseApi.Mul(dxx, yy)
|
dxxyy := c.baseApi.Mul(dxx, yy)
|
||||||
rhs := c.baseApi.Add(dxxyy, 1)
|
rhs := c.baseApi.Add(dxxyy, 1)
|
||||||
|
|
||||||
c.baseApi.AssertIsEqual(lhs, rhs)
|
c.baseApi.AssertIsEqual(lhs, rhs)
|
||||||
}
|
}
|
||||||
|
|
||||||
// func (c *Curve[T, S]) Add(q, r AffinePoint[T]) AffinePoint[T] {
|
func (c *Curve[T, S]) Add(q, r AffinePoint[T]) AffinePoint[T] {
|
||||||
// // compute lambda = (p1.y-p.y)/(p1.x-p.x)
|
// u = (x1 + y1) * (x2 + y2)
|
||||||
// lambda := c.baseApi.DivUnchecked(c.baseApi.Sub(r.Y, q.Y), c.baseApi.Sub(r.X, q.X))
|
u1 := c.baseApi.Mul(q.X, c.a)
|
||||||
|
u1 = c.baseApi.Sub(q.Y, u1)
|
||||||
|
u2 := c.baseApi.Add(r.X, r.Y)
|
||||||
|
u := c.baseApi.Mul(u1, u2)
|
||||||
|
|
||||||
// // xr = lambda**2-p.x-p1.x
|
// v0 = x1 * y2
|
||||||
// xr := c.baseApi.Sub(c.baseApi.Mul(lambda, lambda), c.baseApi.Add(q.X, r.X))
|
v0 := c.baseApi.Mul(r.Y, q.X)
|
||||||
|
|
||||||
// // p.y = lambda(p.x-xr) - p.y
|
// v1 = x2 * y1
|
||||||
// py := c.baseApi.Sub(c.baseApi.Mul(lambda, c.baseApi.Sub(q.X, xr)), q.Y)
|
v1 := c.baseApi.Mul(r.X, q.Y)
|
||||||
|
|
||||||
// return AffinePoint[T]{
|
// v2 = d * v0 * v1
|
||||||
// X: xr.(emulated.Element[T]),
|
v2 := c.baseApi.Mul(c.d, v0, v1)
|
||||||
// Y: py.(emulated.Element[T]),
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
// func (c *Curve[T, S]) Double(p AffinePoint[T]) AffinePoint[T] {
|
var px, py frontend.Variable
|
||||||
|
|
||||||
// // compute lambda = (3*p1.x**2+a)/2*p1.y, here we assume a=0 (j invariant 0 curve)
|
// x = (v0 + v1) / (1 + v2)
|
||||||
// lambda := c.baseApi.DivUnchecked(c.baseApi.Mul(p.X, p.X, 3), c.baseApi.Mul(p.Y, 2))
|
px = c.baseApi.Add(v0, v1)
|
||||||
|
px = c.baseApi.DivUnchecked(px, c.baseApi.Add(1, v2))
|
||||||
|
|
||||||
// // xr = lambda**2-p1.x-p1.x
|
// y = (u + a * v0 - v1) / (1 - v2)
|
||||||
// xr := c.baseApi.Sub(c.baseApi.Mul(lambda, lambda), c.baseApi.Mul(p.X, 2))
|
py = c.baseApi.Mul(c.a, v0)
|
||||||
|
py = c.baseApi.Sub(py, v1)
|
||||||
|
py = c.baseApi.Add(py, u)
|
||||||
|
py = c.baseApi.DivUnchecked(py, c.baseApi.Sub(1, v2))
|
||||||
|
|
||||||
// // p.y = lambda(p.x-xr) - p.y
|
return AffinePoint[T]{
|
||||||
// py := c.baseApi.Sub(c.baseApi.Mul(lambda, c.baseApi.Sub(p.X, xr)), p.Y)
|
X: px.(emulated.Element[T]),
|
||||||
|
Y: py.(emulated.Element[T]),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// return AffinePoint[T]{
|
func (c *Curve[T, S]) Double(p AffinePoint[T]) AffinePoint[T] {
|
||||||
// X: xr.(emulated.Element[T]),
|
u := c.baseApi.Mul(p.X, p.Y)
|
||||||
// Y: py.(emulated.Element[T]),
|
v := c.baseApi.Mul(p.X, p.X)
|
||||||
// }
|
w := c.baseApi.Mul(p.Y, p.Y)
|
||||||
// }
|
|
||||||
|
n1 := c.baseApi.Mul(2, u)
|
||||||
|
av := c.baseApi.Mul(v, c.a)
|
||||||
|
n2 := c.baseApi.Sub(w, av)
|
||||||
|
d1 := c.baseApi.Add(w, av)
|
||||||
|
d2 := c.baseApi.Sub(2, d1)
|
||||||
|
|
||||||
|
px := c.baseApi.DivUnchecked(n1, d1)
|
||||||
|
py := c.baseApi.DivUnchecked(n2, d2)
|
||||||
|
|
||||||
|
return AffinePoint[T]{
|
||||||
|
X: px.(emulated.Element[T]),
|
||||||
|
Y: py.(emulated.Element[T]),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (c *Curve[T, S]) Select(b frontend.Variable, p, q AffinePoint[T]) AffinePoint[T] {
|
func (c *Curve[T, S]) Select(b frontend.Variable, p, q AffinePoint[T]) AffinePoint[T] {
|
||||||
x := c.baseApi.Select(b, p.X, q.X)
|
x := c.baseApi.Select(b, p.X, q.X)
|
||||||
@@ -156,18 +175,18 @@ func (c *Curve[T, S]) Select(b frontend.Variable, p, q AffinePoint[T]) AffinePoi
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// func (c *Curve[T, S]) ScalarMul(p AffinePoint[T], s emulated.Element[S]) AffinePoint[T] {
|
func (c *Curve[T, S]) ScalarMul(p AffinePoint[T], s emulated.Element[S]) AffinePoint[T] {
|
||||||
// res := p
|
res := p
|
||||||
// acc := c.Double(p)
|
acc := c.Double(p)
|
||||||
|
|
||||||
// sBits := c.scalarApi.ToBinary(s)
|
sBits := c.scalarApi.ToBinary(s)
|
||||||
// for i := 1; i < len(sBits); i++ {
|
for i := 1; i < len(sBits); i++ {
|
||||||
// tmp := c.Add(res, acc)
|
tmp := c.Add(res, acc)
|
||||||
// res = c.Select(sBits[i], tmp, res)
|
res = c.Select(sBits[i], tmp, res)
|
||||||
// acc = c.Double(acc)
|
acc = c.Double(acc)
|
||||||
// }
|
}
|
||||||
|
|
||||||
// tmp := c.Add(res, c.Neg(p))
|
tmp := c.Add(res, c.Neg(p))
|
||||||
// res = c.Select(sBits[0], res, tmp)
|
res = c.Select(sBits[0], res, tmp)
|
||||||
// return res
|
return res
|
||||||
// }
|
}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package edwards_curve
|
package edwards_curve
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"math/big"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/consensys/gnark-crypto/ecc"
|
"github.com/consensys/gnark-crypto/ecc"
|
||||||
@@ -23,7 +24,7 @@ func (c *OnCurveTest[T, S]) Define(api frontend.API) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestGenerator(t *testing.T) {
|
func TestGeneratorIsOnCurve(t *testing.T) {
|
||||||
assert := test.NewAssert(t)
|
assert := test.NewAssert(t)
|
||||||
circuit := OnCurveTest[Ed25519, Ed25519Scalars]{}
|
circuit := OnCurveTest[Ed25519, Ed25519Scalars]{}
|
||||||
witness := OnCurveTest[Ed25519, Ed25519Scalars]{
|
witness := OnCurveTest[Ed25519, Ed25519Scalars]{
|
||||||
@@ -36,6 +37,52 @@ func TestGenerator(t *testing.T) {
|
|||||||
assert.NoError(err)
|
assert.NoError(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// s1*x1 + s2*x2 = y
|
||||||
|
type MulAddTest[T, S emulated.FieldParams] struct {
|
||||||
|
X1, X2 AffinePoint[T]
|
||||||
|
S1, S2 emulated.Element[S]
|
||||||
|
Y AffinePoint[T]
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *MulAddTest[T, S]) Define(api frontend.API) error {
|
||||||
|
cr, err := New[T, S](api)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
X1S1 := cr.ScalarMul(c.X1, c.S1)
|
||||||
|
X2S2 := cr.ScalarMul(c.X2, c.S2)
|
||||||
|
sum := cr.Add(X1S1, X2S2)
|
||||||
|
cr.AssertIsEqual(sum, c.Y)
|
||||||
|
cr.scalarApi.AssertIsEqual(
|
||||||
|
cr.scalarApi.Add(c.S1, c.S2),
|
||||||
|
emulated.NewElement[S](big.NewInt(1)),
|
||||||
|
)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGeneratorGeneratesCurveOfCorrectOrder(t *testing.T) {
|
||||||
|
assert := test.NewAssert(t)
|
||||||
|
Gx, Gy := Ed25519{}.Generator()
|
||||||
|
G := AffinePoint[Ed25519]{
|
||||||
|
X: emulated.NewElement[Ed25519](Gx),
|
||||||
|
Y: emulated.NewElement[Ed25519](Gy),
|
||||||
|
}
|
||||||
|
for i := 2; i <= 3; i++ {
|
||||||
|
S1 := new(big.Int).Sub(rEd25519, big.NewInt(int64(i - 1)))
|
||||||
|
S2 := big.NewInt(int64(i))
|
||||||
|
circuit := MulAddTest[Ed25519, Ed25519Scalars]{}
|
||||||
|
witness := MulAddTest[Ed25519, Ed25519Scalars]{
|
||||||
|
X1: G,
|
||||||
|
X2: G,
|
||||||
|
S1: emulated.NewElement[Ed25519Scalars](S1),
|
||||||
|
S2: emulated.NewElement[Ed25519Scalars](S2),
|
||||||
|
Y: G,
|
||||||
|
}
|
||||||
|
err := test.IsSolved(&circuit, &witness, testCurve.ScalarField())
|
||||||
|
assert.NoError(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
var testCurve = ecc.BN254
|
var testCurve = ecc.BN254
|
||||||
|
|
||||||
// type NegTest[T, S emulated.FieldParams] struct {
|
// type NegTest[T, S emulated.FieldParams] struct {
|
||||||
|
|||||||
Reference in New Issue
Block a user