Skip to content

Conversation

@yelhousni
Copy link
Contributor

@yelhousni yelhousni commented Apr 7, 2023

Fixes #630.

Suggested solution:

Select λ to be either (y1-p.y2)/(x1-x2) or 3x1²/2y1 based on x1==x1 && y1==y2. The problem is that division by x1-x2 will trigger an error as it uses big.Int ModInverse https://github.com/ConsenSys/gnark/blob/c02da5f61944d13c557d2b390ca56d5a26c597a1/std/math/emulated/hints.go#L251
So we implement a special method DivSpecial() that returns 0 when denominator is 0. We use it to compute (y1-p.y2)/(x1-x2) and proceed further, and then select 3x1²/2y1 if applicable.

Actually we can use Brier-Joye unified addition formulas, which compute a slope that works for both addition and doubling in affine coordinates — and also save half the constraints of the previous solution.

@yelhousni yelhousni added type: bug Something isn't working dep: linea Issues affecting Linea downstream labels Apr 7, 2023
@yelhousni yelhousni added this to the v0.9.0 milestone Apr 7, 2023
@yelhousni yelhousni self-assigned this Apr 7, 2023
@yelhousni
Copy link
Contributor Author

We use zero=(0,0) as the affine "representation" of the infinity point.

  • UnifiedAdd(P, zero) should output P
  • UnifiedAdd(zero, P) should output P
  • UnifiedAdd(zero, zero) should output zero
  • UnifiedAdd(P, -P) should output zero
  • ScalarMul(0, P) should output zero
  • ScalarMul(s, zero) should output zero
  • ScalarMulBase(0) should output zero

  • These methods are used in the EVM precompiles, so they should follow the (0,0) convention.
  • For double(), triple(), add() and doubleAndAdd() (now private) we don't handle the edge cases (used when these should not happen).
  • For Pair() the zkEVM arithmetization would filter the (0,0) points @OlivierBBB.

@yelhousni
Copy link
Contributor Author

fixes #634

@ivokub
Copy link
Collaborator

ivokub commented Apr 17, 2023

Suggested edit:

diff --git a/std/algebra/emulated/sw_emulated/point.go b/std/algebra/emulated/sw_emulated/point.go
index 69e32594..46bdd8d5 100644
--- a/std/algebra/emulated/sw_emulated/point.go
+++ b/std/algebra/emulated/sw_emulated/point.go
@@ -77,6 +77,9 @@ func (c *Curve[B, S]) GeneratorMultiples() []AffinePoint[B] {
 
 // AffinePoint represents a point on the elliptic curve. We do not check that
 // the point is actually on the curve.
+//
+// Point (0,0) represents point at the infinity. This representation is
+// compatible with the EVM representations of points at infinity.
 type AffinePoint[Base emulated.FieldParams] struct {
 	X, Y emulated.Element[Base]
 }

@ivokub
Copy link
Collaborator

ivokub commented Apr 17, 2023

Suggested edit:

diff --git a/std/algebra/emulated/sw_emulated/point.go b/std/algebra/emulated/sw_emulated/point.go
index 69e32594..0ef6cd01 100644
--- a/std/algebra/emulated/sw_emulated/point.go
+++ b/std/algebra/emulated/sw_emulated/point.go
@@ -126,12 +126,12 @@ func (c *Curve[B, S]) add(p, q *AffinePoint[B]) *AffinePoint[B] {
 //
 // ✅ p can be equal to q, and either or both can be (0,0).
 // (0,0) is not on the curve but we conventionally take it as the
-// neutral/infinity point as per the EVM [EYP].
+// neutral/infinity point as per the [EVM].
 //
-// It uses the unified formulas of Brier and Joye [BriJoy02] (Corollary 1).
+// It uses the unified formulas of Brier and Joye ([[BriJoy02]] (Corollary 1)).
 //
 // [BriJoy02]: https://link.springer.com/content/pdf/10.1007/3-540-45664-3_24.pdf
-// [EYP]: https://ethereum.github.io/yellowpaper/paper.pdf
+// [EVM]: https://ethereum.github.io/yellowpaper/paper.pdf
 func (c *Curve[B, S]) AddUnified(p, q *AffinePoint[B]) *AffinePoint[B] {
 
 	// selector1 = 1 when p is (0,0) and 0 otherwise
@@ -338,7 +338,7 @@ func (c *Curve[B, S]) Lookup2(b0, b1 frontend.Variable, i0, i1, i2, i3 *AffinePo
 //
 // ✅ p can can be (0,0) and s can be 0.
 // (0,0) is not on the curve but we conventionally take it as the
-// neutral/infinity point as per the EVM [EYP].
+// neutral/infinity point as per the [EVM].
 //
 // It computes the standard little-endian variable-base double-and-add algorithm
 // [HMV04] (Algorithm 3.26).
@@ -352,7 +352,7 @@ func (c *Curve[B, S]) Lookup2(b0, b1 frontend.Variable, i0, i1, i2, i3 *AffinePo
 //
 // [ELM03]: https://arxiv.org/pdf/math/0208038.pdf
 // [HMV04]: https://link.springer.com/book/10.1007/b97644
-// [EYP]: https://ethereum.github.io/yellowpaper/paper.pdf
+// [EVM]: https://ethereum.github.io/yellowpaper/paper.pdf
 func (c *Curve[B, S]) ScalarMul(p *AffinePoint[B], s *emulated.Element[S]) *AffinePoint[B] {
 
 	// if p=(0,0) we assign a dummy (0,1) to p and continue
@@ -402,7 +402,7 @@ func (c *Curve[B, S]) ScalarMul(p *AffinePoint[B], s *emulated.Element[S]) *Affi
 //
 // ✅ When s=0, it retruns (0,0).
 // (0,0) is not on the curve but we conventionally take it as the
-// neutral/infinity point as per the EVM [EYP].
+// neutral/infinity point as per the [EVM].
 //
 // It computes the standard little-endian fixed-base double-and-add algorithm
 // [HMV04] (Algorithm 3.26).
@@ -413,7 +413,7 @@ func (c *Curve[B, S]) ScalarMul(p *AffinePoint[B], s *emulated.Element[S]) *Affi
 // [3]g, [5]g and [7]g points.
 //
 // [HMV04]: https://link.springer.com/book/10.1007/b97644
-// [EYP]: https://ethereum.github.io/yellowpaper/paper.pdf
+// [EVM]: https://ethereum.github.io/yellowpaper/paper.pdf
 func (c *Curve[B, S]) ScalarMulBase(s *emulated.Element[S]) *AffinePoint[B] {
 	g := c.Generator()
 	gm := c.GeneratorMultiples()

@ivokub
Copy link
Collaborator

ivokub commented Apr 17, 2023

Suggested edit:

diff --git a/std/algebra/emulated/sw_emulated/point.go b/std/algebra/emulated/sw_emulated/point.go
index 69e32594..78b05b99 100644
--- a/std/algebra/emulated/sw_emulated/point.go
+++ b/std/algebra/emulated/sw_emulated/point.go
@@ -400,7 +400,7 @@ func (c *Curve[B, S]) ScalarMul(p *AffinePoint[B], s *emulated.Element[S]) *Affi
 // ScalarMulBase computes s * g and returns it, where g is the fixed generator.
 // It doesn't modify s.
 //
-// ✅ When s=0, it retruns (0,0).
+// ✅ When s=0, it returns (0,0).
 // (0,0) is not on the curve but we conventionally take it as the
 // neutral/infinity point as per the EVM [EYP].
 //

Copy link
Collaborator

@ivokub ivokub left a comment

Choose a reason for hiding this comment

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

  • A few stylistic change suggest: for paper use "academic"-style links and for EVM just use it.
  • An idea about renaming the methods.
  • One potential optimisation.

Other than that I think it looks good.

@ivokub
Copy link
Collaborator

ivokub commented Apr 17, 2023

Applied the changes. If looks good then go for merge.

@yelhousni yelhousni merged commit 66b8db3 into develop Apr 18, 2023
@yelhousni yelhousni deleted the feat/AddSafe branch April 18, 2023 06:44
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

dep: linea Issues affecting Linea downstream type: bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants