From 8ac3063d9cf173ada3096b5b4d1a3add70c70755 Mon Sep 17 00:00:00 2001 From: Youssef El Housni Date: Thu, 20 Jun 2024 15:17:25 +0100 Subject: [PATCH 1/6] refactor: correct IsZero comments --- ecc/bls12-377/internal/fptower/e12.go | 3 ++- ecc/bls12-377/internal/fptower/e2.go | 3 ++- ecc/bls12-377/internal/fptower/e6.go | 3 ++- ecc/bls12-378/internal/fptower/e12.go | 3 ++- ecc/bls12-378/internal/fptower/e2.go | 3 ++- ecc/bls12-378/internal/fptower/e6.go | 3 ++- ecc/bls12-381/internal/fptower/e12.go | 3 ++- ecc/bls12-381/internal/fptower/e2.go | 3 ++- ecc/bls12-381/internal/fptower/e6.go | 3 ++- ecc/bls24-315/internal/fptower/e12.go | 3 ++- ecc/bls24-315/internal/fptower/e2.go | 3 ++- ecc/bls24-315/internal/fptower/e24.go | 3 ++- ecc/bls24-315/internal/fptower/e4.go | 3 ++- ecc/bls24-317/internal/fptower/e12.go | 3 ++- ecc/bls24-317/internal/fptower/e2.go | 3 ++- ecc/bls24-317/internal/fptower/e24.go | 3 ++- ecc/bls24-317/internal/fptower/e4.go | 3 ++- ecc/bn254/internal/fptower/e12.go | 3 ++- ecc/bn254/internal/fptower/e2.go | 3 ++- ecc/bn254/internal/fptower/e6.go | 3 ++- ecc/bw6-633/internal/fptower/e3.go | 3 ++- ecc/bw6-633/internal/fptower/e6.go | 3 ++- ecc/bw6-756/internal/fptower/e3.go | 3 ++- ecc/bw6-756/internal/fptower/e6.go | 3 ++- ecc/bw6-761/internal/fptower/e3.go | 3 ++- ecc/bw6-761/internal/fptower/e6.go | 3 ++- internal/generator/tower/template/fq12over6over2/fq12.go.tmpl | 3 ++- internal/generator/tower/template/fq12over6over2/fq2.go.tmpl | 3 ++- internal/generator/tower/template/fq12over6over2/fq6.go.tmpl | 3 ++- 29 files changed, 58 insertions(+), 29 deletions(-) diff --git a/ecc/bls12-377/internal/fptower/e12.go b/ecc/bls12-377/internal/fptower/e12.go index 450562473..c80b4a785 100644 --- a/ecc/bls12-377/internal/fptower/e12.go +++ b/ecc/bls12-377/internal/fptower/e12.go @@ -99,11 +99,12 @@ func (z *E12) SetRandom() (*E12, error) { return z, nil } -// IsZero returns true if the two elements are equal, false otherwise +// IsZero returns true if z is zero, false otherwise func (z *E12) IsZero() bool { return z.C0.IsZero() && z.C1.IsZero() } +// IsOne returns true if z is one, false otherwise func (z *E12) IsOne() bool { return z.C0.IsOne() && z.C1.IsZero() } diff --git a/ecc/bls12-377/internal/fptower/e2.go b/ecc/bls12-377/internal/fptower/e2.go index 874802d74..8efb57667 100644 --- a/ecc/bls12-377/internal/fptower/e2.go +++ b/ecc/bls12-377/internal/fptower/e2.go @@ -101,11 +101,12 @@ func (z *E2) SetRandom() (*E2, error) { return z, nil } -// IsZero returns true if the two elements are equal, false otherwise +// IsZero returns true if z is zero, false otherwise func (z *E2) IsZero() bool { return z.A0.IsZero() && z.A1.IsZero() } +// IsOne returns true if z is one, false otherwise func (z *E2) IsOne() bool { return z.A0.IsOne() && z.A1.IsZero() } diff --git a/ecc/bls12-377/internal/fptower/e6.go b/ecc/bls12-377/internal/fptower/e6.go index 128007df2..64ad60ef1 100644 --- a/ecc/bls12-377/internal/fptower/e6.go +++ b/ecc/bls12-377/internal/fptower/e6.go @@ -63,11 +63,12 @@ func (z *E6) SetRandom() (*E6, error) { return z, nil } -// IsZero returns true if the two elements are equal, false otherwise +// IsZero returns true if z is zero, false otherwise func (z *E6) IsZero() bool { return z.B0.IsZero() && z.B1.IsZero() && z.B2.IsZero() } +// IsOne returns true if z is one, false otherwise func (z *E6) IsOne() bool { return z.B0.IsOne() && z.B1.IsZero() && z.B2.IsZero() } diff --git a/ecc/bls12-378/internal/fptower/e12.go b/ecc/bls12-378/internal/fptower/e12.go index a90486611..1c4cbac2c 100644 --- a/ecc/bls12-378/internal/fptower/e12.go +++ b/ecc/bls12-378/internal/fptower/e12.go @@ -99,11 +99,12 @@ func (z *E12) SetRandom() (*E12, error) { return z, nil } -// IsZero returns true if the two elements are equal, false otherwise +// IsZero returns true if z is zero, false otherwise func (z *E12) IsZero() bool { return z.C0.IsZero() && z.C1.IsZero() } +// IsOne returns true if z is one, false otherwise func (z *E12) IsOne() bool { return z.C0.IsOne() && z.C1.IsZero() } diff --git a/ecc/bls12-378/internal/fptower/e2.go b/ecc/bls12-378/internal/fptower/e2.go index ff031c8d8..e98e16a66 100644 --- a/ecc/bls12-378/internal/fptower/e2.go +++ b/ecc/bls12-378/internal/fptower/e2.go @@ -101,11 +101,12 @@ func (z *E2) SetRandom() (*E2, error) { return z, nil } -// IsZero returns true if the two elements are equal, false otherwise +// IsZero returns true if z is zero, false otherwise func (z *E2) IsZero() bool { return z.A0.IsZero() && z.A1.IsZero() } +// IsOne returns true if z is one, false otherwise func (z *E2) IsOne() bool { return z.A0.IsOne() && z.A1.IsZero() } diff --git a/ecc/bls12-378/internal/fptower/e6.go b/ecc/bls12-378/internal/fptower/e6.go index 128007df2..64ad60ef1 100644 --- a/ecc/bls12-378/internal/fptower/e6.go +++ b/ecc/bls12-378/internal/fptower/e6.go @@ -63,11 +63,12 @@ func (z *E6) SetRandom() (*E6, error) { return z, nil } -// IsZero returns true if the two elements are equal, false otherwise +// IsZero returns true if z is zero, false otherwise func (z *E6) IsZero() bool { return z.B0.IsZero() && z.B1.IsZero() && z.B2.IsZero() } +// IsOne returns true if z is one, false otherwise func (z *E6) IsOne() bool { return z.B0.IsOne() && z.B1.IsZero() && z.B2.IsZero() } diff --git a/ecc/bls12-381/internal/fptower/e12.go b/ecc/bls12-381/internal/fptower/e12.go index 095a79a4c..859a7e384 100644 --- a/ecc/bls12-381/internal/fptower/e12.go +++ b/ecc/bls12-381/internal/fptower/e12.go @@ -99,11 +99,12 @@ func (z *E12) SetRandom() (*E12, error) { return z, nil } -// IsZero returns true if the two elements are equal, false otherwise +// IsZero returns true if z is zero, false otherwise func (z *E12) IsZero() bool { return z.C0.IsZero() && z.C1.IsZero() } +// IsOne returns true if z is one, false otherwise func (z *E12) IsOne() bool { return z.C0.IsOne() && z.C1.IsZero() } diff --git a/ecc/bls12-381/internal/fptower/e2.go b/ecc/bls12-381/internal/fptower/e2.go index 0390e7e4b..5a9d362f9 100644 --- a/ecc/bls12-381/internal/fptower/e2.go +++ b/ecc/bls12-381/internal/fptower/e2.go @@ -101,11 +101,12 @@ func (z *E2) SetRandom() (*E2, error) { return z, nil } -// IsZero returns true if the two elements are equal, false otherwise +// IsZero returns true if z is zero, false otherwise func (z *E2) IsZero() bool { return z.A0.IsZero() && z.A1.IsZero() } +// IsOne returns true if z is one, false otherwise func (z *E2) IsOne() bool { return z.A0.IsOne() && z.A1.IsZero() } diff --git a/ecc/bls12-381/internal/fptower/e6.go b/ecc/bls12-381/internal/fptower/e6.go index 128007df2..64ad60ef1 100644 --- a/ecc/bls12-381/internal/fptower/e6.go +++ b/ecc/bls12-381/internal/fptower/e6.go @@ -63,11 +63,12 @@ func (z *E6) SetRandom() (*E6, error) { return z, nil } -// IsZero returns true if the two elements are equal, false otherwise +// IsZero returns true if z is zero, false otherwise func (z *E6) IsZero() bool { return z.B0.IsZero() && z.B1.IsZero() && z.B2.IsZero() } +// IsOne returns true if z is one, false otherwise func (z *E6) IsOne() bool { return z.B0.IsOne() && z.B1.IsZero() && z.B2.IsZero() } diff --git a/ecc/bls24-315/internal/fptower/e12.go b/ecc/bls24-315/internal/fptower/e12.go index f2c392201..ca0f09216 100644 --- a/ecc/bls24-315/internal/fptower/e12.go +++ b/ecc/bls24-315/internal/fptower/e12.go @@ -70,11 +70,12 @@ func (z *E12) SetRandom() (*E12, error) { return z, nil } -// IsZero returns true if the two elements are equal, false otherwise +// IsZero returns true if z is zero, false otherwise func (z *E12) IsZero() bool { return z.C0.IsZero() && z.C1.IsZero() && z.C2.IsZero() } +// IsOne returns true if z is one, false otherwise func (z *E12) IsOne() bool { return z.C0.IsOne() && z.C1.IsZero() && z.C2.IsZero() } diff --git a/ecc/bls24-315/internal/fptower/e2.go b/ecc/bls24-315/internal/fptower/e2.go index a23c0ebb9..2c1d53fbb 100644 --- a/ecc/bls24-315/internal/fptower/e2.go +++ b/ecc/bls24-315/internal/fptower/e2.go @@ -91,11 +91,12 @@ func (z *E2) SetRandom() (*E2, error) { return z, nil } -// IsZero returns true if the two elements are equal, false otherwise +// IsZero returns true if z is zero, false otherwise func (z *E2) IsZero() bool { return z.A0.IsZero() && z.A1.IsZero() } +// IsOne returns true if z is one, false otherwise func (z *E2) IsOne() bool { return z.A0.IsOne() && z.A1.IsZero() } diff --git a/ecc/bls24-315/internal/fptower/e24.go b/ecc/bls24-315/internal/fptower/e24.go index 3cefb7194..22b7183b1 100644 --- a/ecc/bls24-315/internal/fptower/e24.go +++ b/ecc/bls24-315/internal/fptower/e24.go @@ -97,11 +97,12 @@ func (z *E24) SetRandom() (*E24, error) { return z, nil } -// IsZero returns true if the two elements are equal, false otherwise +// IsZero returns true if z is zero, false otherwise func (z *E24) IsZero() bool { return z.D0.IsZero() && z.D1.IsZero() } +// IsOne returns true if z is one, false otherwise func (z *E24) IsOne() bool { return z.D0.IsOne() && z.D1.IsZero() } diff --git a/ecc/bls24-315/internal/fptower/e4.go b/ecc/bls24-315/internal/fptower/e4.go index 204cf5bd3..3eb683b78 100644 --- a/ecc/bls24-315/internal/fptower/e4.go +++ b/ecc/bls24-315/internal/fptower/e4.go @@ -133,11 +133,12 @@ func (z *E4) SetRandom() (*E4, error) { return z, nil } -// IsZero returns true if the element is zero, false otherwise +// IsZero returns true if z is zero, false otherwise func (z *E4) IsZero() bool { return z.B0.IsZero() && z.B1.IsZero() } +// IsOne returns true if z is one, false otherwise func (z *E4) IsOne() bool { return z.B0.IsOne() && z.B1.IsZero() } diff --git a/ecc/bls24-317/internal/fptower/e12.go b/ecc/bls24-317/internal/fptower/e12.go index 5d33f44aa..3caa81196 100644 --- a/ecc/bls24-317/internal/fptower/e12.go +++ b/ecc/bls24-317/internal/fptower/e12.go @@ -70,11 +70,12 @@ func (z *E12) SetRandom() (*E12, error) { return z, nil } -// IsZero returns true if the two elements are equal, false otherwise +// IsZero returns true if z is zero, false otherwise func (z *E12) IsZero() bool { return z.C0.IsZero() && z.C1.IsZero() && z.C2.IsZero() } +// IsOne returns true if z is one, false otherwise func (z *E12) IsOne() bool { return z.C0.IsOne() && z.C1.IsZero() && z.C2.IsZero() } diff --git a/ecc/bls24-317/internal/fptower/e2.go b/ecc/bls24-317/internal/fptower/e2.go index e88426e59..ad6483b5e 100644 --- a/ecc/bls24-317/internal/fptower/e2.go +++ b/ecc/bls24-317/internal/fptower/e2.go @@ -91,11 +91,12 @@ func (z *E2) SetRandom() (*E2, error) { return z, nil } -// IsZero returns true if the two elements are equal, false otherwise +// IsZero returns true if z is zero, false otherwise func (z *E2) IsZero() bool { return z.A0.IsZero() && z.A1.IsZero() } +// IsOne returns true if z is one, false otherwise func (z *E2) IsOne() bool { return z.A0.IsOne() && z.A1.IsZero() } diff --git a/ecc/bls24-317/internal/fptower/e24.go b/ecc/bls24-317/internal/fptower/e24.go index e2a9a0946..2e7668dc7 100644 --- a/ecc/bls24-317/internal/fptower/e24.go +++ b/ecc/bls24-317/internal/fptower/e24.go @@ -97,11 +97,12 @@ func (z *E24) SetRandom() (*E24, error) { return z, nil } -// IsZero returns true if the two elements are equal, false otherwise +// IsZero returns true if z is zero, false otherwise func (z *E24) IsZero() bool { return z.D0.IsZero() && z.D1.IsZero() } +// IsOne returns true if z is one, false otherwise func (z *E24) IsOne() bool { return z.D0.IsOne() && z.D1.IsZero() } diff --git a/ecc/bls24-317/internal/fptower/e4.go b/ecc/bls24-317/internal/fptower/e4.go index 3569253c7..dee409ddc 100644 --- a/ecc/bls24-317/internal/fptower/e4.go +++ b/ecc/bls24-317/internal/fptower/e4.go @@ -133,11 +133,12 @@ func (z *E4) SetRandom() (*E4, error) { return z, nil } -// IsZero returns true if the element is zero, false otherwise +// IsZero returns true if z is zero, false otherwise func (z *E4) IsZero() bool { return z.B0.IsZero() && z.B1.IsZero() } +// IsOne returns true if z is one, false otherwise func (z *E4) IsOne() bool { return z.B0.IsOne() && z.B1.IsZero() } diff --git a/ecc/bn254/internal/fptower/e12.go b/ecc/bn254/internal/fptower/e12.go index a9f6d28e9..318a06b9f 100644 --- a/ecc/bn254/internal/fptower/e12.go +++ b/ecc/bn254/internal/fptower/e12.go @@ -99,11 +99,12 @@ func (z *E12) SetRandom() (*E12, error) { return z, nil } -// IsZero returns true if the two elements are equal, false otherwise +// IsZero returns true if z is zero, false otherwise func (z *E12) IsZero() bool { return z.C0.IsZero() && z.C1.IsZero() } +// IsOne returns true if z is one, false otherwise func (z *E12) IsOne() bool { return z.C0.IsOne() && z.C1.IsZero() } diff --git a/ecc/bn254/internal/fptower/e2.go b/ecc/bn254/internal/fptower/e2.go index 8c16efc93..985a7c1a2 100644 --- a/ecc/bn254/internal/fptower/e2.go +++ b/ecc/bn254/internal/fptower/e2.go @@ -101,11 +101,12 @@ func (z *E2) SetRandom() (*E2, error) { return z, nil } -// IsZero returns true if the two elements are equal, false otherwise +// IsZero returns true if z is zero, false otherwise func (z *E2) IsZero() bool { return z.A0.IsZero() && z.A1.IsZero() } +// IsOne returns true if z is one, false otherwise func (z *E2) IsOne() bool { return z.A0.IsOne() && z.A1.IsZero() } diff --git a/ecc/bn254/internal/fptower/e6.go b/ecc/bn254/internal/fptower/e6.go index 128007df2..64ad60ef1 100644 --- a/ecc/bn254/internal/fptower/e6.go +++ b/ecc/bn254/internal/fptower/e6.go @@ -63,11 +63,12 @@ func (z *E6) SetRandom() (*E6, error) { return z, nil } -// IsZero returns true if the two elements are equal, false otherwise +// IsZero returns true if z is zero, false otherwise func (z *E6) IsZero() bool { return z.B0.IsZero() && z.B1.IsZero() && z.B2.IsZero() } +// IsOne returns true if z is one, false otherwise func (z *E6) IsOne() bool { return z.B0.IsOne() && z.B1.IsZero() && z.B2.IsZero() } diff --git a/ecc/bw6-633/internal/fptower/e3.go b/ecc/bw6-633/internal/fptower/e3.go index 03f65c004..356cdeff5 100644 --- a/ecc/bw6-633/internal/fptower/e3.go +++ b/ecc/bw6-633/internal/fptower/e3.go @@ -82,11 +82,12 @@ func (z *E3) SetRandom() (*E3, error) { return z, nil } -// IsZero returns true if the two elements are equal, false otherwise +// IsZero returns true if z is zero, false otherwise func (z *E3) IsZero() bool { return z.A0.IsZero() && z.A1.IsZero() && z.A2.IsZero() } +// IsOne returns true if z is one, false otherwise func (z *E3) IsOne() bool { return z.A0.IsOne() && z.A1.IsZero() && z.A2.IsZero() } diff --git a/ecc/bw6-633/internal/fptower/e6.go b/ecc/bw6-633/internal/fptower/e6.go index fe757a19c..1ed3553d3 100644 --- a/ecc/bw6-633/internal/fptower/e6.go +++ b/ecc/bw6-633/internal/fptower/e6.go @@ -98,11 +98,12 @@ func (z *E6) SetRandom() (*E6, error) { return z, nil } -// IsZero returns true if the two elements are equal, false otherwise +// IsZero returns true if z is zero, false otherwise func (z *E6) IsZero() bool { return z.B0.IsZero() && z.B1.IsZero() } +// IsOne returns true if z is one, false otherwise func (z *E6) IsOne() bool { return z.B0.IsOne() && z.B1.IsZero() } diff --git a/ecc/bw6-756/internal/fptower/e3.go b/ecc/bw6-756/internal/fptower/e3.go index 15fc2d4bb..35e5bc5f5 100644 --- a/ecc/bw6-756/internal/fptower/e3.go +++ b/ecc/bw6-756/internal/fptower/e3.go @@ -78,11 +78,12 @@ func (z *E3) SetRandom() (*E3, error) { return z, nil } -// IsZero returns true if the two elements are equal, false otherwise +// IsZero returns true if z is zero, false otherwise func (z *E3) IsZero() bool { return z.A0.IsZero() && z.A1.IsZero() && z.A2.IsZero() } +// IsOne returns true if z is one, false otherwise func (z *E3) IsOne() bool { return z.A0.IsOne() && z.A1.IsZero() && z.A2.IsZero() } diff --git a/ecc/bw6-756/internal/fptower/e6.go b/ecc/bw6-756/internal/fptower/e6.go index 06f572ea8..7c5a5688f 100644 --- a/ecc/bw6-756/internal/fptower/e6.go +++ b/ecc/bw6-756/internal/fptower/e6.go @@ -97,11 +97,12 @@ func (z *E6) SetRandom() (*E6, error) { return z, nil } -// IsZero returns true if the two elements are equal, false otherwise +// IsZero returns true if z is zero, false otherwise func (z *E6) IsZero() bool { return z.B0.IsZero() && z.B1.IsZero() } +// IsOne returns true if z is one, false otherwise func (z *E6) IsOne() bool { return z.B0.IsOne() && z.B1.IsZero() } diff --git a/ecc/bw6-761/internal/fptower/e3.go b/ecc/bw6-761/internal/fptower/e3.go index 29e7fd7ff..4db7495f6 100644 --- a/ecc/bw6-761/internal/fptower/e3.go +++ b/ecc/bw6-761/internal/fptower/e3.go @@ -78,11 +78,12 @@ func (z *E3) SetRandom() (*E3, error) { return z, nil } -// IsZero returns true if the two elements are equal, false otherwise +// IsZero returns true if z is zero, false otherwise func (z *E3) IsZero() bool { return z.A0.IsZero() && z.A1.IsZero() && z.A2.IsZero() } +// IsOne returns true if z is one, false otherwise func (z *E3) IsOne() bool { return z.A0.IsOne() && z.A1.IsZero() && z.A2.IsZero() } diff --git a/ecc/bw6-761/internal/fptower/e6.go b/ecc/bw6-761/internal/fptower/e6.go index 76e63b34e..b736d656e 100644 --- a/ecc/bw6-761/internal/fptower/e6.go +++ b/ecc/bw6-761/internal/fptower/e6.go @@ -97,11 +97,12 @@ func (z *E6) SetRandom() (*E6, error) { return z, nil } -// IsZero returns true if the two elements are equal, false otherwise +// IsZero returns true if z is zero, false otherwise func (z *E6) IsZero() bool { return z.B0.IsZero() && z.B1.IsZero() } +// IsOne returns true if z is one, false otherwise func (z *E6) IsOne() bool { return z.B0.IsOne() && z.B1.IsZero() } diff --git a/internal/generator/tower/template/fq12over6over2/fq12.go.tmpl b/internal/generator/tower/template/fq12over6over2/fq12.go.tmpl index 721ba961b..fdc9dd1d4 100644 --- a/internal/generator/tower/template/fq12over6over2/fq12.go.tmpl +++ b/internal/generator/tower/template/fq12over6over2/fq12.go.tmpl @@ -81,11 +81,12 @@ func (z *E12) SetRandom() (*E12, error) { return z, nil } -// IsZero returns true if the two elements are equal, false otherwise +// IsZero returns true if z is zero, false otherwise func (z *E12) IsZero() bool { return z.C0.IsZero() && z.C1.IsZero() } +// IsOne returns true if z is one, false otherwise func (z *E12) IsOne() bool { return z.C0.IsOne() && z.C1.IsZero() } diff --git a/internal/generator/tower/template/fq12over6over2/fq2.go.tmpl b/internal/generator/tower/template/fq12over6over2/fq2.go.tmpl index 68b33f07d..0e3d8ff4a 100644 --- a/internal/generator/tower/template/fq12over6over2/fq2.go.tmpl +++ b/internal/generator/tower/template/fq12over6over2/fq2.go.tmpl @@ -86,11 +86,12 @@ func (z *E2) SetRandom() (*E2, error) { return z, nil } -// IsZero returns true if the two elements are equal, false otherwise +// IsZero returns true if z is zero, false otherwise func (z *E2) IsZero() bool { return z.A0.IsZero() && z.A1.IsZero() } +// IsOne returns true if z is one, false otherwise func (z *E2) IsOne() bool { return z.A0.IsOne() && z.A1.IsZero() } diff --git a/internal/generator/tower/template/fq12over6over2/fq6.go.tmpl b/internal/generator/tower/template/fq12over6over2/fq6.go.tmpl index 621a57701..1169c0930 100644 --- a/internal/generator/tower/template/fq12over6over2/fq6.go.tmpl +++ b/internal/generator/tower/template/fq12over6over2/fq6.go.tmpl @@ -45,11 +45,12 @@ func (z *E6) SetRandom() (*E6, error) { return z, nil } -// IsZero returns true if the two elements are equal, false otherwise +// IsZero returns true if z is zero, false otherwise func (z *E6) IsZero() bool { return z.B0.IsZero() && z.B1.IsZero() && z.B2.IsZero() } +// IsOne returns true if z is one, false otherwise func (z *E6) IsOne() bool { return z.B0.IsOne() && z.B1.IsZero() && z.B2.IsZero() } From 2dee1a5f20f372e5f0c91d72c5fa83e1b998fb78 Mon Sep 17 00:00:00 2001 From: Youssef El Housni Date: Thu, 20 Jun 2024 15:56:02 +0100 Subject: [PATCH 2/6] refactor: typos in comments --- ecc/bls12-377/internal/fptower/e12.go | 21 +++++++++++-------- ecc/bls12-377/internal/fptower/e2.go | 11 ++++++---- ecc/bls12-377/internal/fptower/e6.go | 9 +++++--- ecc/bls12-378/internal/fptower/e12.go | 21 +++++++++++-------- ecc/bls12-378/internal/fptower/e2.go | 11 ++++++---- ecc/bls12-378/internal/fptower/e6.go | 9 +++++--- ecc/bls12-381/internal/fptower/e12.go | 21 +++++++++++-------- ecc/bls12-381/internal/fptower/e2.go | 13 +++++++----- ecc/bls12-381/internal/fptower/e6.go | 9 +++++--- ecc/bls24-317/internal/fptower/e12.go | 10 ++++----- ecc/bls24-317/internal/fptower/e2.go | 5 ++++- ecc/bls24-317/internal/fptower/e24.go | 18 ++++++++-------- ecc/bls24-317/internal/fptower/e4.go | 17 ++++++++------- ecc/bn254/internal/fptower/e12.go | 21 +++++++++++-------- ecc/bn254/internal/fptower/e2.go | 13 +++++++----- ecc/bn254/internal/fptower/e6.go | 9 +++++--- ecc/bw6-633/internal/fptower/e3.go | 8 +++---- ecc/bw6-633/internal/fptower/e6.go | 18 ++++++++-------- ecc/bw6-756/internal/fptower/e3.go | 8 +++---- ecc/bw6-756/internal/fptower/e6.go | 18 ++++++++-------- ecc/bw6-761/internal/fptower/e3.go | 8 +++---- ecc/bw6-761/internal/fptower/e6.go | 18 ++++++++-------- .../template/fq12over6over2/base.go.tmpl | 5 ++++- .../template/fq12over6over2/fq12.go.tmpl | 18 ++++++++-------- .../tower/template/fq12over6over2/fq2.go.tmpl | 10 ++++----- .../tower/template/fq12over6over2/fq6.go.tmpl | 6 +++--- 26 files changed, 189 insertions(+), 146 deletions(-) diff --git a/ecc/bls12-377/internal/fptower/e12.go b/ecc/bls12-377/internal/fptower/e12.go index c80b4a785..ca7aef9ed 100644 --- a/ecc/bls12-377/internal/fptower/e12.go +++ b/ecc/bls12-377/internal/fptower/e12.go @@ -67,14 +67,14 @@ func (z *E12) SetOne() *E12 { return z } -// Add set z=x+y in E12 and return z +// Add sets z=x+y in E12 and returns z func (z *E12) Add(x, y *E12) *E12 { z.C0.Add(&x.C0, &y.C0) z.C1.Add(&x.C1, &y.C1) return z } -// Sub sets z to x sub y and return z +// Sub sets z to x-y and returns z func (z *E12) Sub(x, y *E12) *E12 { z.C0.Sub(&x.C0, &y.C0) z.C1.Sub(&x.C1, &y.C1) @@ -109,7 +109,7 @@ func (z *E12) IsOne() bool { return z.C0.IsOne() && z.C1.IsZero() } -// Mul set z=x*y in E12 and return z +// Mul sets z=x*y in E12 and returns z func (z *E12) Mul(x, y *E12) *E12 { var a, b, c E6 a.Add(&x.C0, &x.C1) @@ -122,7 +122,7 @@ func (z *E12) Mul(x, y *E12) *E12 { return z } -// Square set z=x*x in E12 and return z +// Square sets z=x*x in E12 and returns z func (z *E12) Square(x *E12) *E12 { //Algorithm 22 from https://eprint.iacr.org/2010/354.pdf @@ -407,7 +407,7 @@ func (z *E12) CyclotomicSquare(x *E12) *E12 { return z } -// Inverse set z to the inverse of x in E12 and return z +// Inverse sets z to the inverse of x in E12 and returns z // // if x == 0, sets and returns z = x func (z *E12) Inverse(x *E12) *E12 { @@ -425,8 +425,8 @@ func (z *E12) Inverse(x *E12) *E12 { return z } -// BatchInvertE12 returns a new slice with every element inverted. -// Uses Montgomery batch inversion trick +// BatchInvertE12 returns a new slice with every element in a inverted. +// It uses Montgomery batch inversion trick. // // if a[i] == 0, returns result[i] = a[i] func BatchInvertE12(a []E12) []E12 { @@ -636,12 +636,12 @@ func (z *E12) ExpGLV(x E12, k *big.Int) *E12 { return z } -// InverseUnitary inverse a unitary element +// InverseUnitary inverses a unitary element func (z *E12) InverseUnitary(x *E12) *E12 { return z.Conjugate(x) } -// Conjugate set z to x conjugated and return z +// Conjugate sets z to x conjugated and returns z func (z *E12) Conjugate(x *E12) *E12 { *z = *x z.C1.Neg(&z.C1) @@ -847,6 +847,8 @@ func BatchDecompressTorus(x []E6) ([]E12, error) { return res, nil } +// Select is conditional move. +// If cond = 0, it sets z to caseZ and returns it. otherwise caseNz. func (z *E12) Select(cond int, caseZ *E12, caseNz *E12) *E12 { //Might be able to save a nanosecond or two by an aggregate implementation @@ -856,6 +858,7 @@ func (z *E12) Select(cond int, caseZ *E12, caseNz *E12) *E12 { return z } +// Div divides an element in E12 by an element in E12 func (z *E12) Div(x *E12, y *E12) *E12 { var r E12 r.Inverse(y).Mul(x, &r) diff --git a/ecc/bls12-377/internal/fptower/e2.go b/ecc/bls12-377/internal/fptower/e2.go index 8efb57667..c5f7aaaa2 100644 --- a/ecc/bls12-377/internal/fptower/e2.go +++ b/ecc/bls12-377/internal/fptower/e2.go @@ -117,7 +117,7 @@ func (z *E2) Add(x, y *E2) *E2 { return z } -// Sub two elements of E2 +// Sub subtracts two elements of E2 func (z *E2) Sub(x, y *E2) *E2 { subE2(z, x, y) return z @@ -156,7 +156,7 @@ func (z *E2) Conjugate(x *E2) *E2 { return z } -// Halve sets z = z / 2 +// Halve sets z to z / 2 func (z *E2) Halve() { z.A0.Halve() z.A1.Halve() @@ -243,8 +243,8 @@ func (z *E2) Sqrt(x *E2) *E2 { return z } -// BatchInvertE2 returns a new slice with every element inverted. -// Uses Montgomery batch inversion trick +// BatchInvertE2 returns a new slice with every element in a inverted. +// It uses Montgomery batch inversion trick. // // if a[i] == 0, returns result[i] = a[i] func BatchInvertE2(a []E2) []E2 { @@ -279,6 +279,8 @@ func BatchInvertE2(a []E2) []E2 { return res } +// Select is conditional move. +// If cond = 0, it sets z to caseZ and returns it. otherwise caseNz. func (z *E2) Select(cond int, caseZ *E2, caseNz *E2) *E2 { //Might be able to save a nanosecond or two by an aggregate implementation @@ -288,6 +290,7 @@ func (z *E2) Select(cond int, caseZ *E2, caseNz *E2) *E2 { return z } +// Div divides an element in E2 by an element in E2 func (z *E2) Div(x *E2, y *E2) *E2 { var r E2 r.Inverse(y).Mul(x, &r) diff --git a/ecc/bls12-377/internal/fptower/e6.go b/ecc/bls12-377/internal/fptower/e6.go index 64ad60ef1..1867470a8 100644 --- a/ecc/bls12-377/internal/fptower/e6.go +++ b/ecc/bls12-377/internal/fptower/e6.go @@ -89,7 +89,7 @@ func (z *E6) Neg(x *E6) *E6 { return z } -// Sub two elements of E6 +// Sub subtracts two elements of E6 func (z *E6) Sub(x, y *E6) *E6 { z.B0.Sub(&x.B0, &y.B0) z.B1.Sub(&x.B1, &y.B1) @@ -287,8 +287,8 @@ func (z *E6) Inverse(x *E6) *E6 { return z } -// BatchInvertE6 returns a new slice with every element inverted. -// Uses Montgomery batch inversion trick +// BatchInvertE6 returns a new slice with every element in a inverted. +// It uses Montgomery batch inversion trick. // // if a[i] == 0, returns result[i] = a[i] func BatchInvertE6(a []E6) []E6 { @@ -323,6 +323,8 @@ func BatchInvertE6(a []E6) []E6 { return res } +// Select is conditional move. +// If cond = 0, it sets z to caseZ and returns it. otherwise caseNz. func (z *E6) Select(cond int, caseZ *E6, caseNz *E6) *E6 { //Might be able to save a nanosecond or two by an aggregate implementation @@ -333,6 +335,7 @@ func (z *E6) Select(cond int, caseZ *E6, caseNz *E6) *E6 { return z } +// Div divides an element in E6 by an element in E6 func (z *E6) Div(x *E6, y *E6) *E6 { var r E6 r.Inverse(y).Mul(x, &r) diff --git a/ecc/bls12-378/internal/fptower/e12.go b/ecc/bls12-378/internal/fptower/e12.go index 1c4cbac2c..72b666456 100644 --- a/ecc/bls12-378/internal/fptower/e12.go +++ b/ecc/bls12-378/internal/fptower/e12.go @@ -67,14 +67,14 @@ func (z *E12) SetOne() *E12 { return z } -// Add set z=x+y in E12 and return z +// Add sets z=x+y in E12 and returns z func (z *E12) Add(x, y *E12) *E12 { z.C0.Add(&x.C0, &y.C0) z.C1.Add(&x.C1, &y.C1) return z } -// Sub sets z to x sub y and return z +// Sub sets z to x-y and returns z func (z *E12) Sub(x, y *E12) *E12 { z.C0.Sub(&x.C0, &y.C0) z.C1.Sub(&x.C1, &y.C1) @@ -109,7 +109,7 @@ func (z *E12) IsOne() bool { return z.C0.IsOne() && z.C1.IsZero() } -// Mul set z=x*y in E12 and return z +// Mul sets z=x*y in E12 and returns z func (z *E12) Mul(x, y *E12) *E12 { var a, b, c E6 a.Add(&x.C0, &x.C1) @@ -122,7 +122,7 @@ func (z *E12) Mul(x, y *E12) *E12 { return z } -// Square set z=x*x in E12 and return z +// Square sets z=x*x in E12 and returns z func (z *E12) Square(x *E12) *E12 { //Algorithm 22 from https://eprint.iacr.org/2010/354.pdf @@ -407,7 +407,7 @@ func (z *E12) CyclotomicSquare(x *E12) *E12 { return z } -// Inverse set z to the inverse of x in E12 and return z +// Inverse sets z to the inverse of x in E12 and returns z // // if x == 0, sets and returns z = x func (z *E12) Inverse(x *E12) *E12 { @@ -425,8 +425,8 @@ func (z *E12) Inverse(x *E12) *E12 { return z } -// BatchInvertE12 returns a new slice with every element inverted. -// Uses Montgomery batch inversion trick +// BatchInvertE12 returns a new slice with every element in a inverted. +// It uses Montgomery batch inversion trick. // // if a[i] == 0, returns result[i] = a[i] func BatchInvertE12(a []E12) []E12 { @@ -636,12 +636,12 @@ func (z *E12) ExpGLV(x E12, k *big.Int) *E12 { return z } -// InverseUnitary inverse a unitary element +// InverseUnitary inverses a unitary element func (z *E12) InverseUnitary(x *E12) *E12 { return z.Conjugate(x) } -// Conjugate set z to x conjugated and return z +// Conjugate sets z to x conjugated and returns z func (z *E12) Conjugate(x *E12) *E12 { *z = *x z.C1.Neg(&z.C1) @@ -847,6 +847,8 @@ func BatchDecompressTorus(x []E6) ([]E12, error) { return res, nil } +// Select is conditional move. +// If cond = 0, it sets z to caseZ and returns it. otherwise caseNz. func (z *E12) Select(cond int, caseZ *E12, caseNz *E12) *E12 { //Might be able to save a nanosecond or two by an aggregate implementation @@ -856,6 +858,7 @@ func (z *E12) Select(cond int, caseZ *E12, caseNz *E12) *E12 { return z } +// Div divides an element in E12 by an element in E12 func (z *E12) Div(x *E12, y *E12) *E12 { var r E12 r.Inverse(y).Mul(x, &r) diff --git a/ecc/bls12-378/internal/fptower/e2.go b/ecc/bls12-378/internal/fptower/e2.go index e98e16a66..e6a6c350c 100644 --- a/ecc/bls12-378/internal/fptower/e2.go +++ b/ecc/bls12-378/internal/fptower/e2.go @@ -117,7 +117,7 @@ func (z *E2) Add(x, y *E2) *E2 { return z } -// Sub two elements of E2 +// Sub subtracts two elements of E2 func (z *E2) Sub(x, y *E2) *E2 { subE2(z, x, y) return z @@ -156,7 +156,7 @@ func (z *E2) Conjugate(x *E2) *E2 { return z } -// Halve sets z = z / 2 +// Halve sets z to z / 2 func (z *E2) Halve() { z.A0.Halve() z.A1.Halve() @@ -243,8 +243,8 @@ func (z *E2) Sqrt(x *E2) *E2 { return z } -// BatchInvertE2 returns a new slice with every element inverted. -// Uses Montgomery batch inversion trick +// BatchInvertE2 returns a new slice with every element in a inverted. +// It uses Montgomery batch inversion trick. // // if a[i] == 0, returns result[i] = a[i] func BatchInvertE2(a []E2) []E2 { @@ -279,6 +279,8 @@ func BatchInvertE2(a []E2) []E2 { return res } +// Select is conditional move. +// If cond = 0, it sets z to caseZ and returns it. otherwise caseNz. func (z *E2) Select(cond int, caseZ *E2, caseNz *E2) *E2 { //Might be able to save a nanosecond or two by an aggregate implementation @@ -288,6 +290,7 @@ func (z *E2) Select(cond int, caseZ *E2, caseNz *E2) *E2 { return z } +// Div divides an element in E2 by an element in E2 func (z *E2) Div(x *E2, y *E2) *E2 { var r E2 r.Inverse(y).Mul(x, &r) diff --git a/ecc/bls12-378/internal/fptower/e6.go b/ecc/bls12-378/internal/fptower/e6.go index 64ad60ef1..1867470a8 100644 --- a/ecc/bls12-378/internal/fptower/e6.go +++ b/ecc/bls12-378/internal/fptower/e6.go @@ -89,7 +89,7 @@ func (z *E6) Neg(x *E6) *E6 { return z } -// Sub two elements of E6 +// Sub subtracts two elements of E6 func (z *E6) Sub(x, y *E6) *E6 { z.B0.Sub(&x.B0, &y.B0) z.B1.Sub(&x.B1, &y.B1) @@ -287,8 +287,8 @@ func (z *E6) Inverse(x *E6) *E6 { return z } -// BatchInvertE6 returns a new slice with every element inverted. -// Uses Montgomery batch inversion trick +// BatchInvertE6 returns a new slice with every element in a inverted. +// It uses Montgomery batch inversion trick. // // if a[i] == 0, returns result[i] = a[i] func BatchInvertE6(a []E6) []E6 { @@ -323,6 +323,8 @@ func BatchInvertE6(a []E6) []E6 { return res } +// Select is conditional move. +// If cond = 0, it sets z to caseZ and returns it. otherwise caseNz. func (z *E6) Select(cond int, caseZ *E6, caseNz *E6) *E6 { //Might be able to save a nanosecond or two by an aggregate implementation @@ -333,6 +335,7 @@ func (z *E6) Select(cond int, caseZ *E6, caseNz *E6) *E6 { return z } +// Div divides an element in E6 by an element in E6 func (z *E6) Div(x *E6, y *E6) *E6 { var r E6 r.Inverse(y).Mul(x, &r) diff --git a/ecc/bls12-381/internal/fptower/e12.go b/ecc/bls12-381/internal/fptower/e12.go index 859a7e384..65945c3d9 100644 --- a/ecc/bls12-381/internal/fptower/e12.go +++ b/ecc/bls12-381/internal/fptower/e12.go @@ -67,14 +67,14 @@ func (z *E12) SetOne() *E12 { return z } -// Add set z=x+y in E12 and return z +// Add sets z=x+y in E12 and returns z func (z *E12) Add(x, y *E12) *E12 { z.C0.Add(&x.C0, &y.C0) z.C1.Add(&x.C1, &y.C1) return z } -// Sub sets z to x sub y and return z +// Sub sets z to x-y and returns z func (z *E12) Sub(x, y *E12) *E12 { z.C0.Sub(&x.C0, &y.C0) z.C1.Sub(&x.C1, &y.C1) @@ -109,7 +109,7 @@ func (z *E12) IsOne() bool { return z.C0.IsOne() && z.C1.IsZero() } -// Mul set z=x*y in E12 and return z +// Mul sets z=x*y in E12 and returns z func (z *E12) Mul(x, y *E12) *E12 { var a, b, c E6 a.Add(&x.C0, &x.C1) @@ -122,7 +122,7 @@ func (z *E12) Mul(x, y *E12) *E12 { return z } -// Square set z=x*x in E12 and return z +// Square sets z=x*x in E12 and returns z func (z *E12) Square(x *E12) *E12 { //Algorithm 22 from https://eprint.iacr.org/2010/354.pdf @@ -407,7 +407,7 @@ func (z *E12) CyclotomicSquare(x *E12) *E12 { return z } -// Inverse set z to the inverse of x in E12 and return z +// Inverse sets z to the inverse of x in E12 and returns z // // if x == 0, sets and returns z = x func (z *E12) Inverse(x *E12) *E12 { @@ -425,8 +425,8 @@ func (z *E12) Inverse(x *E12) *E12 { return z } -// BatchInvertE12 returns a new slice with every element inverted. -// Uses Montgomery batch inversion trick +// BatchInvertE12 returns a new slice with every element in a inverted. +// It uses Montgomery batch inversion trick. // // if a[i] == 0, returns result[i] = a[i] func BatchInvertE12(a []E12) []E12 { @@ -636,12 +636,12 @@ func (z *E12) ExpGLV(x E12, k *big.Int) *E12 { return z } -// InverseUnitary inverse a unitary element +// InverseUnitary inverses a unitary element func (z *E12) InverseUnitary(x *E12) *E12 { return z.Conjugate(x) } -// Conjugate set z to x conjugated and return z +// Conjugate sets z to x conjugated and returns z func (z *E12) Conjugate(x *E12) *E12 { *z = *x z.C1.Neg(&z.C1) @@ -847,6 +847,8 @@ func BatchDecompressTorus(x []E6) ([]E12, error) { return res, nil } +// Select is conditional move. +// If cond = 0, it sets z to caseZ and returns it. otherwise caseNz. func (z *E12) Select(cond int, caseZ *E12, caseNz *E12) *E12 { //Might be able to save a nanosecond or two by an aggregate implementation @@ -856,6 +858,7 @@ func (z *E12) Select(cond int, caseZ *E12, caseNz *E12) *E12 { return z } +// Div divides an element in E12 by an element in E12 func (z *E12) Div(x *E12, y *E12) *E12 { var r E12 r.Inverse(y).Mul(x, &r) diff --git a/ecc/bls12-381/internal/fptower/e2.go b/ecc/bls12-381/internal/fptower/e2.go index 5a9d362f9..75fd711c7 100644 --- a/ecc/bls12-381/internal/fptower/e2.go +++ b/ecc/bls12-381/internal/fptower/e2.go @@ -117,7 +117,7 @@ func (z *E2) Add(x, y *E2) *E2 { return z } -// Sub two elements of E2 +// Sub subtracts two elements of E2 func (z *E2) Sub(x, y *E2) *E2 { subE2(z, x, y) return z @@ -156,7 +156,7 @@ func (z *E2) Conjugate(x *E2) *E2 { return z } -// Halve sets z = z / 2 +// Halve sets z to z / 2 func (z *E2) Halve() { z.A0.Halve() z.A1.Halve() @@ -214,7 +214,7 @@ func init() { var sqrtExp1, sqrtExp2 big.Int -// Sqrt sets z to the square root of and returns z +// Sqrt sets z to the square root of x and returns z // The function does not test whether the square root // exists or not, it's up to the caller to call // Legendre beforehand. @@ -244,8 +244,8 @@ func (z *E2) Sqrt(x *E2) *E2 { return z } -// BatchInvertE2 returns a new slice with every element inverted. -// Uses Montgomery batch inversion trick +// BatchInvertE2 returns a new slice with every element in a inverted. +// It uses Montgomery batch inversion trick. // // if a[i] == 0, returns result[i] = a[i] func BatchInvertE2(a []E2) []E2 { @@ -280,6 +280,8 @@ func BatchInvertE2(a []E2) []E2 { return res } +// Select is conditional move. +// If cond = 0, it sets z to caseZ and returns it. otherwise caseNz. func (z *E2) Select(cond int, caseZ *E2, caseNz *E2) *E2 { //Might be able to save a nanosecond or two by an aggregate implementation @@ -289,6 +291,7 @@ func (z *E2) Select(cond int, caseZ *E2, caseNz *E2) *E2 { return z } +// Div divides an element in E2 by an element in E2 func (z *E2) Div(x *E2, y *E2) *E2 { var r E2 r.Inverse(y).Mul(x, &r) diff --git a/ecc/bls12-381/internal/fptower/e6.go b/ecc/bls12-381/internal/fptower/e6.go index 64ad60ef1..1867470a8 100644 --- a/ecc/bls12-381/internal/fptower/e6.go +++ b/ecc/bls12-381/internal/fptower/e6.go @@ -89,7 +89,7 @@ func (z *E6) Neg(x *E6) *E6 { return z } -// Sub two elements of E6 +// Sub subtracts two elements of E6 func (z *E6) Sub(x, y *E6) *E6 { z.B0.Sub(&x.B0, &y.B0) z.B1.Sub(&x.B1, &y.B1) @@ -287,8 +287,8 @@ func (z *E6) Inverse(x *E6) *E6 { return z } -// BatchInvertE6 returns a new slice with every element inverted. -// Uses Montgomery batch inversion trick +// BatchInvertE6 returns a new slice with every element in a inverted. +// It uses Montgomery batch inversion trick. // // if a[i] == 0, returns result[i] = a[i] func BatchInvertE6(a []E6) []E6 { @@ -323,6 +323,8 @@ func BatchInvertE6(a []E6) []E6 { return res } +// Select is conditional move. +// If cond = 0, it sets z to caseZ and returns it. otherwise caseNz. func (z *E6) Select(cond int, caseZ *E6, caseNz *E6) *E6 { //Might be able to save a nanosecond or two by an aggregate implementation @@ -333,6 +335,7 @@ func (z *E6) Select(cond int, caseZ *E6, caseNz *E6) *E6 { return z } +// Div divides an element in E6 by an element in E6 func (z *E6) Div(x *E6, y *E6) *E6 { var r E6 r.Inverse(y).Mul(x, &r) diff --git a/ecc/bls24-317/internal/fptower/e12.go b/ecc/bls24-317/internal/fptower/e12.go index 3caa81196..9d48e0d72 100644 --- a/ecc/bls24-317/internal/fptower/e12.go +++ b/ecc/bls24-317/internal/fptower/e12.go @@ -56,7 +56,7 @@ func (z *E12) SetOne() *E12 { return z } -// SetRandom set z to a random elmt +// SetRandom sets z to a random elmt func (z *E12) SetRandom() (*E12, error) { if _, err := z.C0.SetRandom(); err != nil { return nil, err @@ -96,7 +96,7 @@ func (z *E12) Neg(x *E12) *E12 { return z } -// Sub two elements of E12 +// Sub subtracts two elements of E12 func (z *E12) Sub(x, y *E12) *E12 { z.C0.Sub(&x.C0, &y.C0) z.C1.Sub(&x.C1, &y.C1) @@ -197,8 +197,8 @@ func (z *E12) Inverse(x *E12) *E12 { return z } -// BatchInvertE12 returns a new slice with every element inverted. -// Uses Montgomery batch inversion trick +// BatchInvertE12 returns a new slice with every element in a inverted. +// It uses Montgomery batch inversion trick. // // if a[i] == 0, returns result[i] = a[i] func BatchInvertE12(a []E12) []E12 { @@ -284,7 +284,7 @@ func (z *E12) InverseUnitary(x *E12) *E12 { return z.Conjugate(x) } -// Conjugate set z to x conjugated and return z +// Conjugate sets z to x conjugated and returns z func (z *E12) Conjugate(x *E12) *E12 { z.C0.Conjugate(&x.C0) z.C1.Conjugate(&x.C1).Neg(&z.C1) diff --git a/ecc/bls24-317/internal/fptower/e2.go b/ecc/bls24-317/internal/fptower/e2.go index ad6483b5e..b2195608f 100644 --- a/ecc/bls24-317/internal/fptower/e2.go +++ b/ecc/bls24-317/internal/fptower/e2.go @@ -107,7 +107,7 @@ func (z *E2) Add(x, y *E2) *E2 { return z } -// Sub two elements of E2 +// Sub subtracts two elements of E2 func (z *E2) Sub(x, y *E2) *E2 { subE2(z, x, y) return z @@ -228,6 +228,8 @@ func (z *E2) Sqrt(x *E2) *E2 { return z } +// Select is conditional move. +// If cond = 0, it sets z to caseZ and returns it. otherwise caseNz. func (z *E2) Select(cond int, caseZ *E2, caseNz *E2) *E2 { //Might be able to save a nanosecond or two by an aggregate implementation @@ -237,6 +239,7 @@ func (z *E2) Select(cond int, caseZ *E2, caseNz *E2) *E2 { return z } +// Div divides an element in E2 by an element in E2 func (z *E2) Div(x *E2, y *E2) *E2 { var r E2 r.Inverse(y).Mul(x, &r) diff --git a/ecc/bls24-317/internal/fptower/e24.go b/ecc/bls24-317/internal/fptower/e24.go index 2e7668dc7..b0a4e99b9 100644 --- a/ecc/bls24-317/internal/fptower/e24.go +++ b/ecc/bls24-317/internal/fptower/e24.go @@ -65,14 +65,14 @@ func (z *E24) SetOne() *E24 { return z } -// Add set z=x+y in E24 and return z +// Add sets z=x+y in E24 and return z func (z *E24) Add(x, y *E24) *E24 { z.D0.Add(&x.D0, &y.D0) z.D1.Add(&x.D1, &y.D1) return z } -// Sub sets z to x sub y and return z +// Sub sets z to x-y and return z func (z *E24) Sub(x, y *E24) *E24 { z.D0.Sub(&x.D0, &y.D0) z.D1.Sub(&x.D1, &y.D1) @@ -107,7 +107,7 @@ func (z *E24) IsOne() bool { return z.D0.IsOne() && z.D1.IsZero() } -// Mul set z=x*y in E24 and return z +// Mul sets z=x*y in E24 and return z func (z *E24) Mul(x, y *E24) *E24 { var a, b, c E12 a.Add(&x.D0, &x.D1) @@ -120,7 +120,7 @@ func (z *E24) Mul(x, y *E24) *E24 { return z } -// Square set z=x*x in E24 and return z +// Square sets z=x*x in E24 and return z func (z *E24) Square(x *E24) *E24 { //Algorithm 22 from https://eprint.iacr.org/2010/354.pdf @@ -318,7 +318,7 @@ func (z *E24) CyclotomicSquare(x *E24) *E24 { return z } -// Inverse set z to the inverse of x in E24 and return z +// Inverse sets z to the inverse of x in E24 and return z // // if x == 0, sets and returns z = x func (z *E24) Inverse(x *E24) *E24 { @@ -336,8 +336,8 @@ func (z *E24) Inverse(x *E24) *E24 { return z } -// BatchInvertE24 returns a new slice with every element inverted. -// Uses Montgomery batch inversion trick +// BatchInvertE24 returns a new slice with every element in a inverted. +// It uses Montgomery batch inversion trick. // // if a[i] == 0, returns result[i] = a[i] func BatchInvertE24(a []E24) []E24 { @@ -547,12 +547,12 @@ func (z *E24) ExpGLV(x E24, k *big.Int) *E24 { return z } -// InverseUnitary inverse a unitary element +// InverseUnitary inverses a unitary element func (z *E24) InverseUnitary(x *E24) *E24 { return z.Conjugate(x) } -// Conjugate set z to x conjugated and return z +// Conjugate sets z to x conjugated and return z func (z *E24) Conjugate(x *E24) *E24 { *z = *x z.D1.Neg(&z.D1) diff --git a/ecc/bls24-317/internal/fptower/e4.go b/ecc/bls24-317/internal/fptower/e4.go index dee409ddc..364162512 100644 --- a/ecc/bls24-317/internal/fptower/e4.go +++ b/ecc/bls24-317/internal/fptower/e4.go @@ -94,14 +94,14 @@ func (z *E4) MulByElement(x *E4, y *fp.Element) *E4 { return z } -// Add set z=x+y in E4 and return z +// Add sets z=x+y in E4 and returns z func (z *E4) Add(x, y *E4) *E4 { z.B0.Add(&x.B0, &y.B0) z.B1.Add(&x.B1, &y.B1) return z } -// Sub sets z to x sub y and return z +// Sub sets z to x-y and returns z func (z *E4) Sub(x, y *E4) *E4 { z.B0.Sub(&x.B0, &y.B0) z.B1.Sub(&x.B1, &y.B1) @@ -161,7 +161,7 @@ func (z *E4) MulByNonResidueInv(x *E4) *E4 { return z } -// Mul set z=x*y in E4 and return z +// Mul sets z=x*y in E4 and returns z func (z *E4) Mul(x, y *E4) *E4 { var a, b, c E2 a.Add(&x.B0, &x.B1) @@ -174,7 +174,7 @@ func (z *E4) Mul(x, y *E4) *E4 { return z } -// Square set z=x*x in E4 and return z +// Square sets z=x*x in E4 and returns z func (z *E4) Square(x *E4) *E4 { //Algorithm 22 from https://eprint.iacr.org/2010/354.pdf @@ -190,7 +190,7 @@ func (z *E4) Square(x *E4) *E4 { return z } -// Inverse set z to the inverse of x in E4 and return z +// Inverse sets z to the inverse of x in E4 and returns z // // if x == 0, sets and returns z = x func (z *E4) Inverse(x *E4) *E4 { @@ -242,7 +242,7 @@ func (z *E4) Exp(x E4, k *big.Int) *E4 { return z } -// Conjugate set z to x conjugated and return z +// Conjugate sets z to x conjugated and returns z func (z *E4) Conjugate(x *E4) *E4 { z.B0 = x.B0 z.B1.Neg(&x.B1) @@ -313,8 +313,8 @@ func (z *E4) Sqrt(x *E4) *E4 { return z } -// BatchInvertE4 returns a new slice with every element inverted. -// Uses Montgomery batch inversion trick +// BatchInvertE4 returns a new slice with every element in a inverted. +// It uses Montgomery batch inversion trick. // // if a[i] == 0, returns result[i] = a[i] func BatchInvertE4(a []E4) []E4 { @@ -349,6 +349,7 @@ func BatchInvertE4(a []E4) []E4 { return res } +// Div divides an element in E4 by an element in E4 func (z *E4) Div(x *E4, y *E4) *E4 { var r E4 r.Inverse(y).Mul(x, &r) diff --git a/ecc/bn254/internal/fptower/e12.go b/ecc/bn254/internal/fptower/e12.go index 318a06b9f..d2d789310 100644 --- a/ecc/bn254/internal/fptower/e12.go +++ b/ecc/bn254/internal/fptower/e12.go @@ -67,14 +67,14 @@ func (z *E12) SetOne() *E12 { return z } -// Add set z=x+y in E12 and return z +// Add sets z=x+y in E12 and returns z func (z *E12) Add(x, y *E12) *E12 { z.C0.Add(&x.C0, &y.C0) z.C1.Add(&x.C1, &y.C1) return z } -// Sub sets z to x sub y and return z +// Sub sets z to x-y and returns z func (z *E12) Sub(x, y *E12) *E12 { z.C0.Sub(&x.C0, &y.C0) z.C1.Sub(&x.C1, &y.C1) @@ -109,7 +109,7 @@ func (z *E12) IsOne() bool { return z.C0.IsOne() && z.C1.IsZero() } -// Mul set z=x*y in E12 and return z +// Mul sets z=x*y in E12 and returns z func (z *E12) Mul(x, y *E12) *E12 { var a, b, c E6 a.Add(&x.C0, &x.C1) @@ -122,7 +122,7 @@ func (z *E12) Mul(x, y *E12) *E12 { return z } -// Square set z=x*x in E12 and return z +// Square sets z=x*x in E12 and returns z func (z *E12) Square(x *E12) *E12 { //Algorithm 22 from https://eprint.iacr.org/2010/354.pdf @@ -407,7 +407,7 @@ func (z *E12) CyclotomicSquare(x *E12) *E12 { return z } -// Inverse set z to the inverse of x in E12 and return z +// Inverse sets z to the inverse of x in E12 and returns z // // if x == 0, sets and returns z = x func (z *E12) Inverse(x *E12) *E12 { @@ -425,8 +425,8 @@ func (z *E12) Inverse(x *E12) *E12 { return z } -// BatchInvertE12 returns a new slice with every element inverted. -// Uses Montgomery batch inversion trick +// BatchInvertE12 returns a new slice with every element in a inverted. +// It uses Montgomery batch inversion trick. // // if a[i] == 0, returns result[i] = a[i] func BatchInvertE12(a []E12) []E12 { @@ -636,12 +636,12 @@ func (z *E12) ExpGLV(x E12, k *big.Int) *E12 { return z } -// InverseUnitary inverse a unitary element +// InverseUnitary inverses a unitary element func (z *E12) InverseUnitary(x *E12) *E12 { return z.Conjugate(x) } -// Conjugate set z to x conjugated and return z +// Conjugate sets z to x conjugated and returns z func (z *E12) Conjugate(x *E12) *E12 { *z = *x z.C1.Neg(&z.C1) @@ -842,6 +842,8 @@ func BatchDecompressTorus(x []E6) ([]E12, error) { return res, nil } +// Select is conditional move. +// If cond = 0, it sets z to caseZ and returns it. otherwise caseNz. func (z *E12) Select(cond int, caseZ *E12, caseNz *E12) *E12 { //Might be able to save a nanosecond or two by an aggregate implementation @@ -851,6 +853,7 @@ func (z *E12) Select(cond int, caseZ *E12, caseNz *E12) *E12 { return z } +// Div divides an element in E12 by an element in E12 func (z *E12) Div(x *E12, y *E12) *E12 { var r E12 r.Inverse(y).Mul(x, &r) diff --git a/ecc/bn254/internal/fptower/e2.go b/ecc/bn254/internal/fptower/e2.go index 985a7c1a2..d22708756 100644 --- a/ecc/bn254/internal/fptower/e2.go +++ b/ecc/bn254/internal/fptower/e2.go @@ -117,7 +117,7 @@ func (z *E2) Add(x, y *E2) *E2 { return z } -// Sub two elements of E2 +// Sub subtracts two elements of E2 func (z *E2) Sub(x, y *E2) *E2 { subE2(z, x, y) return z @@ -156,7 +156,7 @@ func (z *E2) Conjugate(x *E2) *E2 { return z } -// Halve sets z = z / 2 +// Halve sets z to z / 2 func (z *E2) Halve() { z.A0.Halve() z.A1.Halve() @@ -214,7 +214,7 @@ func init() { var sqrtExp1, sqrtExp2 big.Int -// Sqrt sets z to the square root of and returns z +// Sqrt sets z to the square root of x and returns z // The function does not test whether the square root // exists or not, it's up to the caller to call // Legendre beforehand. @@ -244,8 +244,8 @@ func (z *E2) Sqrt(x *E2) *E2 { return z } -// BatchInvertE2 returns a new slice with every element inverted. -// Uses Montgomery batch inversion trick +// BatchInvertE2 returns a new slice with every element in a inverted. +// It uses Montgomery batch inversion trick. // // if a[i] == 0, returns result[i] = a[i] func BatchInvertE2(a []E2) []E2 { @@ -280,6 +280,8 @@ func BatchInvertE2(a []E2) []E2 { return res } +// Select is conditional move. +// If cond = 0, it sets z to caseZ and returns it. otherwise caseNz. func (z *E2) Select(cond int, caseZ *E2, caseNz *E2) *E2 { //Might be able to save a nanosecond or two by an aggregate implementation @@ -289,6 +291,7 @@ func (z *E2) Select(cond int, caseZ *E2, caseNz *E2) *E2 { return z } +// Div divides an element in E2 by an element in E2 func (z *E2) Div(x *E2, y *E2) *E2 { var r E2 r.Inverse(y).Mul(x, &r) diff --git a/ecc/bn254/internal/fptower/e6.go b/ecc/bn254/internal/fptower/e6.go index 64ad60ef1..1867470a8 100644 --- a/ecc/bn254/internal/fptower/e6.go +++ b/ecc/bn254/internal/fptower/e6.go @@ -89,7 +89,7 @@ func (z *E6) Neg(x *E6) *E6 { return z } -// Sub two elements of E6 +// Sub subtracts two elements of E6 func (z *E6) Sub(x, y *E6) *E6 { z.B0.Sub(&x.B0, &y.B0) z.B1.Sub(&x.B1, &y.B1) @@ -287,8 +287,8 @@ func (z *E6) Inverse(x *E6) *E6 { return z } -// BatchInvertE6 returns a new slice with every element inverted. -// Uses Montgomery batch inversion trick +// BatchInvertE6 returns a new slice with every element in a inverted. +// It uses Montgomery batch inversion trick. // // if a[i] == 0, returns result[i] = a[i] func BatchInvertE6(a []E6) []E6 { @@ -323,6 +323,8 @@ func BatchInvertE6(a []E6) []E6 { return res } +// Select is conditional move. +// If cond = 0, it sets z to caseZ and returns it. otherwise caseNz. func (z *E6) Select(cond int, caseZ *E6, caseNz *E6) *E6 { //Might be able to save a nanosecond or two by an aggregate implementation @@ -333,6 +335,7 @@ func (z *E6) Select(cond int, caseZ *E6, caseNz *E6) *E6 { return z } +// Div divides an element in E6 by an element in E6 func (z *E6) Div(x *E6, y *E6) *E6 { var r E6 r.Inverse(y).Mul(x, &r) diff --git a/ecc/bw6-633/internal/fptower/e3.go b/ecc/bw6-633/internal/fptower/e3.go index 356cdeff5..857138837 100644 --- a/ecc/bw6-633/internal/fptower/e3.go +++ b/ecc/bw6-633/internal/fptower/e3.go @@ -68,7 +68,7 @@ func (z *E3) SetOne() *E3 { return z } -// SetRandom set z to a random elmt +// SetRandom sets z to a random elmt func (z *E3) SetRandom() (*E3, error) { if _, err := z.A0.SetRandom(); err != nil { return nil, err @@ -108,7 +108,7 @@ func (z *E3) Add(x, y *E3) *E3 { return z } -// Sub two elements of E3 +// Sub subtracts two elements of E3 func (z *E3) Sub(x, y *E3) *E3 { z.A0.Sub(&x.A0, &y.A0) z.A1.Sub(&x.A1, &y.A1) @@ -320,8 +320,8 @@ func (z *E3) Inverse(x *E3) *E3 { return z } -// BatchInvertE3 returns a new slice with every element inverted. -// Uses Montgomery batch inversion trick +// BatchInvertE3 returns a new slice with every element in a inverted. +// It uses Montgomery batch inversion trick. // // if a[i] == 0, returns result[i] = a[i] func BatchInvertE3(a []E3) []E3 { diff --git a/ecc/bw6-633/internal/fptower/e6.go b/ecc/bw6-633/internal/fptower/e6.go index 1ed3553d3..a618ea2ef 100644 --- a/ecc/bw6-633/internal/fptower/e6.go +++ b/ecc/bw6-633/internal/fptower/e6.go @@ -66,14 +66,14 @@ func (z *E6) SetOne() *E6 { return z } -// Add set z=x+y in E6 and return z +// Add sets z=x+y in E6 and returns z func (z *E6) Add(x, y *E6) *E6 { z.B0.Add(&x.B0, &y.B0) z.B1.Add(&x.B1, &y.B1) return z } -// Sub sets z to x sub y and return z +// Sub sets z to x-y and returns z func (z *E6) Sub(x, y *E6) *E6 { z.B0.Sub(&x.B0, &y.B0) z.B1.Sub(&x.B1, &y.B1) @@ -108,7 +108,7 @@ func (z *E6) IsOne() bool { return z.B0.IsOne() && z.B1.IsZero() } -// Mul set z=x*y in E6 and return z +// Mul sets z=x*y in E6 and returns z func (z *E6) Mul(x, y *E6) *E6 { var a, b, c E3 a.Add(&x.B0, &x.B1) @@ -121,7 +121,7 @@ func (z *E6) Mul(x, y *E6) *E6 { return z } -// Square set z=x*x in E6 and return z +// Square sets z=x*x in E6 and returns z func (z *E6) Square(x *E6) *E6 { //Algorithm 22 from https://eprint.iacr.org/2010/354.pdf @@ -396,7 +396,7 @@ func (z *E6) CyclotomicSquare(x *E6) *E6 { return z } -// Inverse set z to the inverse of x in E6 and return z +// Inverse sets z to the inverse of x in E6 and returns z // // if x == 0, sets and returns z = x func (z *E6) Inverse(x *E6) *E6 { @@ -414,8 +414,8 @@ func (z *E6) Inverse(x *E6) *E6 { return z } -// BatchInvertE6 returns a new slice with every element inverted. -// Uses Montgomery batch inversion trick +// BatchInvertE6 returns a new slice with every element in a inverted. +// It uses Montgomery batch inversion trick. // // if a[i] == 0, returns result[i] = a[i] func BatchInvertE6(a []E6) []E6 { @@ -625,12 +625,12 @@ func (z *E6) ExpGLV(x E6, k *big.Int) *E6 { return z } -// InverseUnitary inverse a unitary element +// InverseUnitary inverses a unitary element func (z *E6) InverseUnitary(x *E6) *E6 { return z.Conjugate(x) } -// Conjugate set z to x conjugated and return z +// Conjugate sets z to x conjugated and returns z func (z *E6) Conjugate(x *E6) *E6 { *z = *x z.B1.Neg(&z.B1) diff --git a/ecc/bw6-756/internal/fptower/e3.go b/ecc/bw6-756/internal/fptower/e3.go index 35e5bc5f5..3382b642c 100644 --- a/ecc/bw6-756/internal/fptower/e3.go +++ b/ecc/bw6-756/internal/fptower/e3.go @@ -64,7 +64,7 @@ func (z *E3) SetOne() *E3 { return z } -// SetRandom set z to a random elmt +// SetRandom sets z to a random elmt func (z *E3) SetRandom() (*E3, error) { if _, err := z.A0.SetRandom(); err != nil { return nil, err @@ -104,7 +104,7 @@ func (z *E3) Add(x, y *E3) *E3 { return z } -// Sub two elements of E3 +// Sub subtracts two elements of E3 func (z *E3) Sub(x, y *E3) *E3 { z.A0.Sub(&x.A0, &y.A0) z.A1.Sub(&x.A1, &y.A1) @@ -317,8 +317,8 @@ func (z *E3) Inverse(x *E3) *E3 { return z } -// BatchInvertE3 returns a new slice with every element inverted. -// Uses Montgomery batch inversion trick +// BatchInvertE3 returns a new slice with every element in a inverted. +// It uses Montgomery batch inversion trick. // // if a[i] == 0, returns result[i] = a[i] func BatchInvertE3(a []E3) []E3 { diff --git a/ecc/bw6-756/internal/fptower/e6.go b/ecc/bw6-756/internal/fptower/e6.go index 7c5a5688f..afb5ecc59 100644 --- a/ecc/bw6-756/internal/fptower/e6.go +++ b/ecc/bw6-756/internal/fptower/e6.go @@ -65,14 +65,14 @@ func (z *E6) SetOne() *E6 { return z } -// Add set z=x+y in E6 and return z +// Add sets z=x+y in E6 and returns z func (z *E6) Add(x, y *E6) *E6 { z.B0.Add(&x.B0, &y.B0) z.B1.Add(&x.B1, &y.B1) return z } -// Sub sets z to x sub y and return z +// Sub sets z to x-y and returns z func (z *E6) Sub(x, y *E6) *E6 { z.B0.Sub(&x.B0, &y.B0) z.B1.Sub(&x.B1, &y.B1) @@ -107,7 +107,7 @@ func (z *E6) IsOne() bool { return z.B0.IsOne() && z.B1.IsZero() } -// Mul set z=x*y in E6 and return z +// Mul sets z=x*y in E6 and returns z func (z *E6) Mul(x, y *E6) *E6 { var a, b, c E3 a.Add(&x.B0, &x.B1) @@ -120,7 +120,7 @@ func (z *E6) Mul(x, y *E6) *E6 { return z } -// Square set z=x*x in E6 and return z +// Square sets z=x*x in E6 and returns z func (z *E6) Square(x *E6) *E6 { //Algorithm 22 from https://eprint.iacr.org/2010/354.pdf @@ -319,7 +319,7 @@ func (z *E6) CyclotomicSquare(x *E6) *E6 { return z } -// Inverse set z to the inverse of x in E6 and return z +// Inverse sets z to the inverse of x in E6 and returns z // // if x == 0, sets and returns z = x func (z *E6) Inverse(x *E6) *E6 { @@ -337,8 +337,8 @@ func (z *E6) Inverse(x *E6) *E6 { return z } -// BatchInvertE6 returns a new slice with every element inverted. -// Uses Montgomery batch inversion trick +// BatchInvertE6 returns a new slice with every element in a inverted. +// It uses Montgomery batch inversion trick. // // if a[i] == 0, returns result[i] = a[i] func BatchInvertE6(a []E6) []E6 { @@ -548,12 +548,12 @@ func (z *E6) ExpGLV(x E6, k *big.Int) *E6 { return z } -// InverseUnitary inverse a unitary element +// InverseUnitary inverses a unitary element func (z *E6) InverseUnitary(x *E6) *E6 { return z.Conjugate(x) } -// Conjugate set z to x conjugated and return z +// Conjugate sets z to x conjugated and returns z func (z *E6) Conjugate(x *E6) *E6 { *z = *x z.B1.Neg(&z.B1) diff --git a/ecc/bw6-761/internal/fptower/e3.go b/ecc/bw6-761/internal/fptower/e3.go index 4db7495f6..6a2a4e97a 100644 --- a/ecc/bw6-761/internal/fptower/e3.go +++ b/ecc/bw6-761/internal/fptower/e3.go @@ -64,7 +64,7 @@ func (z *E3) SetOne() *E3 { return z } -// SetRandom set z to a random elmt +// SetRandom sets z to a random elmt func (z *E3) SetRandom() (*E3, error) { if _, err := z.A0.SetRandom(); err != nil { return nil, err @@ -104,7 +104,7 @@ func (z *E3) Add(x, y *E3) *E3 { return z } -// Sub two elements of E3 +// Sub subtracts two elements of E3 func (z *E3) Sub(x, y *E3) *E3 { z.A0.Sub(&x.A0, &y.A0) z.A1.Sub(&x.A1, &y.A1) @@ -317,8 +317,8 @@ func (z *E3) Inverse(x *E3) *E3 { return z } -// BatchInvertE3 returns a new slice with every element inverted. -// Uses Montgomery batch inversion trick +// BatchInvertE3 returns a new slice with every element in a inverted. +// It uses Montgomery batch inversion trick. // // if a[i] == 0, returns result[i] = a[i] func BatchInvertE3(a []E3) []E3 { diff --git a/ecc/bw6-761/internal/fptower/e6.go b/ecc/bw6-761/internal/fptower/e6.go index b736d656e..508fc3069 100644 --- a/ecc/bw6-761/internal/fptower/e6.go +++ b/ecc/bw6-761/internal/fptower/e6.go @@ -65,14 +65,14 @@ func (z *E6) SetOne() *E6 { return z } -// Add set z=x+y in E6 and return z +// Add sets z=x+y in E6 and returns z func (z *E6) Add(x, y *E6) *E6 { z.B0.Add(&x.B0, &y.B0) z.B1.Add(&x.B1, &y.B1) return z } -// Sub sets z to x sub y and return z +// Sub sets z to x-y and returns z func (z *E6) Sub(x, y *E6) *E6 { z.B0.Sub(&x.B0, &y.B0) z.B1.Sub(&x.B1, &y.B1) @@ -107,7 +107,7 @@ func (z *E6) IsOne() bool { return z.B0.IsOne() && z.B1.IsZero() } -// Mul set z=x*y in E6 and return z +// Mul sets z=x*y in E6 and returns z func (z *E6) Mul(x, y *E6) *E6 { var a, b, c E3 a.Add(&x.B0, &x.B1) @@ -120,7 +120,7 @@ func (z *E6) Mul(x, y *E6) *E6 { return z } -// Square set z=x*x in E6 and return z +// Square sets z=x*x in E6 and returns z func (z *E6) Square(x *E6) *E6 { //Algorithm 22 from https://eprint.iacr.org/2010/354.pdf @@ -319,7 +319,7 @@ func (z *E6) CyclotomicSquare(x *E6) *E6 { return z } -// Inverse set z to the inverse of x in E6 and return z +// Inverse sets z to the inverse of x in E6 and returns z // // if x == 0, sets and returns z = x func (z *E6) Inverse(x *E6) *E6 { @@ -337,8 +337,8 @@ func (z *E6) Inverse(x *E6) *E6 { return z } -// BatchInvertE6 returns a new slice with every element inverted. -// Uses Montgomery batch inversion trick +// BatchInvertE6 returns a new slice with every element in a inverted. +// It uses Montgomery batch inversion trick. // // if a[i] == 0, returns result[i] = a[i] func BatchInvertE6(a []E6) []E6 { @@ -548,12 +548,12 @@ func (z *E6) ExpGLV(x E6, k *big.Int) *E6 { return z } -// InverseUnitary inverse a unitary element +// InverseUnitary inverses a unitary element func (z *E6) InverseUnitary(x *E6) *E6 { return z.Conjugate(x) } -// Conjugate set z to x conjugated and return z +// Conjugate sets z to x conjugated and returns z func (z *E6) Conjugate(x *E6) *E6 { *z = *x z.B1.Neg(&z.B1) diff --git a/internal/generator/tower/template/fq12over6over2/base.go.tmpl b/internal/generator/tower/template/fq12over6over2/base.go.tmpl index 699eaa0b1..cfb2b73a4 100644 --- a/internal/generator/tower/template/fq12over6over2/base.go.tmpl +++ b/internal/generator/tower/template/fq12over6over2/base.go.tmpl @@ -1,6 +1,8 @@ {{ define "base" }} {{ $TypeTitle := print "E" .TotalDegree}} +// Select is conditional move. +// If cond = 0, it sets z to caseZ and returns it. otherwise caseNz. func (z *{{$TypeTitle}}) Select(cond int, caseZ *{{$TypeTitle}}, caseNz *{{$TypeTitle}}) *{{$TypeTitle}}{ //Might be able to save a nanosecond or two by an aggregate implementation {{range $i := interval 0 .RecursionDegree}}{{$ii := print $.BaseElementName $i}} @@ -9,10 +11,11 @@ func (z *{{$TypeTitle}}) Select(cond int, caseZ *{{$TypeTitle}}, caseNz *{{$Type return z } +// Div divides an element in {{$TypeTitle}} by an element in {{$TypeTitle}} func (z *{{$TypeTitle}}) Div(x *{{$TypeTitle}}, y *{{$TypeTitle}}) *{{$TypeTitle}} { var r {{$TypeTitle}} r.Inverse(y).Mul(x, &r) return z.Set(&r) } -{{ end }} \ No newline at end of file +{{ end }} diff --git a/internal/generator/tower/template/fq12over6over2/fq12.go.tmpl b/internal/generator/tower/template/fq12over6over2/fq12.go.tmpl index fdc9dd1d4..498139c20 100644 --- a/internal/generator/tower/template/fq12over6over2/fq12.go.tmpl +++ b/internal/generator/tower/template/fq12over6over2/fq12.go.tmpl @@ -49,14 +49,14 @@ func (z *E12) SetOne() *E12 { return z } -// Add set z=x+y in E12 and return z +// Add sets z=x+y in E12 and returns z func (z *E12) Add(x, y *E12) *E12 { z.C0.Add(&x.C0, &y.C0) z.C1.Add(&x.C1, &y.C1) return z } -// Sub sets z to x sub y and return z +// Sub sets z to x-y and returns z func (z *E12) Sub(x, y *E12) *E12 { z.C0.Sub(&x.C0, &y.C0) z.C1.Sub(&x.C1, &y.C1) @@ -91,7 +91,7 @@ func (z *E12) IsOne() bool { return z.C0.IsOne() && z.C1.IsZero() } -// Mul set z=x*y in E12 and return z +// Mul sets z=x*y in E12 and returns z func (z *E12) Mul(x, y *E12) *E12 { var a, b, c E6 a.Add(&x.C0, &x.C1) @@ -104,7 +104,7 @@ func (z *E12) Mul(x, y *E12) *E12 { return z } -// Square set z=x*x in E12 and return z +// Square sets z=x*x in E12 and returns z func (z *E12) Square(x *E12) *E12 { //Algorithm 22 from https://eprint.iacr.org/2010/354.pdf @@ -384,7 +384,7 @@ func (z *E12) CyclotomicSquare(x *E12) *E12 { } -// Inverse set z to the inverse of x in E12 and return z +// Inverse sets z to the inverse of x in E12 and returns z // // if x == 0, sets and returns z = x func (z *E12) Inverse(x *E12) *E12 { @@ -402,8 +402,8 @@ func (z *E12) Inverse(x *E12) *E12 { return z } -// BatchInvertE12 returns a new slice with every element inverted. -// Uses Montgomery batch inversion trick +// BatchInvertE12 returns a new slice with every element in a inverted. +// It uses Montgomery batch inversion trick. // // if a[i] == 0, returns result[i] = a[i] func BatchInvertE12(a []E12) []E12 { @@ -613,12 +613,12 @@ func (z *E12) ExpGLV(x E12, k *big.Int) *E12 { return z } -// InverseUnitary inverse a unitary element +// InverseUnitary inverses a unitary element func (z *E12) InverseUnitary(x *E12) *E12 { return z.Conjugate(x) } -// Conjugate set z to x conjugated and return z +// Conjugate sets z to x conjugated and returns z func (z *E12) Conjugate(x *E12) *E12 { *z = *x z.C1.Neg(&z.C1) diff --git a/internal/generator/tower/template/fq12over6over2/fq2.go.tmpl b/internal/generator/tower/template/fq12over6over2/fq2.go.tmpl index 0e3d8ff4a..8ba663571 100644 --- a/internal/generator/tower/template/fq12over6over2/fq2.go.tmpl +++ b/internal/generator/tower/template/fq12over6over2/fq2.go.tmpl @@ -102,7 +102,7 @@ func (z *E2) Add(x, y *E2) *E2 { return z } -// Sub two elements of E2 +// Sub subtracts two elements of E2 func (z *E2) Sub(x, y *E2) *E2 { subE2(z, x, y) return z @@ -143,7 +143,7 @@ func (z *E2) Conjugate(x *E2) *E2 { return z } -// Halve sets z = z / 2 +// Halve sets z to z / 2 func (z *E2) Halve() { z.A0.Halve() z.A1.Halve() @@ -202,7 +202,7 @@ func (z *E2) Exp(x E2, k *big.Int) *E2 { var sqrtExp1, sqrtExp2 big.Int - // Sqrt sets z to the square root of and returns z + // Sqrt sets z to the square root of x and returns z // The function does not test whether the square root // exists or not, it's up to the caller to call // Legendre beforehand. @@ -273,8 +273,8 @@ func (z *E2) Exp(x E2, k *big.Int) *E2 { } {{end}} -// BatchInvertE2 returns a new slice with every element inverted. -// Uses Montgomery batch inversion trick +// BatchInvertE2 returns a new slice with every element in a inverted. +// It uses Montgomery batch inversion trick. // // if a[i] == 0, returns result[i] = a[i] func BatchInvertE2(a []E2) []E2 { diff --git a/internal/generator/tower/template/fq12over6over2/fq6.go.tmpl b/internal/generator/tower/template/fq12over6over2/fq6.go.tmpl index 1169c0930..d7f44b3fa 100644 --- a/internal/generator/tower/template/fq12over6over2/fq6.go.tmpl +++ b/internal/generator/tower/template/fq12over6over2/fq6.go.tmpl @@ -71,7 +71,7 @@ func (z *E6) Neg(x *E6) *E6 { return z } -// Sub two elements of E6 +// Sub subtracts two elements of E6 func (z *E6) Sub(x, y *E6) *E6 { z.B0.Sub(&x.B0, &y.B0) z.B1.Sub(&x.B1, &y.B1) @@ -269,8 +269,8 @@ func (z *E6) Inverse(x *E6) *E6 { return z } -// BatchInvertE6 returns a new slice with every element inverted. -// Uses Montgomery batch inversion trick +// BatchInvertE6 returns a new slice with every element in a inverted. +// It uses Montgomery batch inversion trick. // // if a[i] == 0, returns result[i] = a[i] func BatchInvertE6(a []E6) []E6 { From 903b401e90bf9f19d0f4c204e277828ec1d91e5c Mon Sep 17 00:00:00 2001 From: Youssef El Housni Date: Tue, 25 Jun 2024 12:17:48 +0100 Subject: [PATCH 3/6] docs: up E3 mul comment --- ecc/bw6-633/internal/fptower/e3.go | 3 ++- ecc/bw6-756/internal/fptower/e3.go | 3 ++- ecc/bw6-761/internal/fptower/e3.go | 3 ++- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/ecc/bw6-633/internal/fptower/e3.go b/ecc/bw6-633/internal/fptower/e3.go index 857138837..222529958 100644 --- a/ecc/bw6-633/internal/fptower/e3.go +++ b/ecc/bw6-633/internal/fptower/e3.go @@ -231,7 +231,8 @@ func (z *E3) MulBy1(c1 *fp.Element) *E3 { // Mul sets z to the E3-product of x,y, returns z func (z *E3) Mul(x, y *E3) *E3 { - // Algorithm 13 from https://eprint.iacr.org/2010/354.pdf + // Karatsuba method for cubic extensions + // https://eprint.iacr.org/2006/471.pdf (section 4) var t0, t1, t2, c0, c1, c2, tmp fp.Element t0.Mul(&x.A0, &y.A0) t1.Mul(&x.A1, &y.A1) diff --git a/ecc/bw6-756/internal/fptower/e3.go b/ecc/bw6-756/internal/fptower/e3.go index 3382b642c..d35cdcf51 100644 --- a/ecc/bw6-756/internal/fptower/e3.go +++ b/ecc/bw6-756/internal/fptower/e3.go @@ -225,7 +225,8 @@ func (z *E3) MulBy1(c1 *fp.Element) *E3 { // Mul sets z to the E3-product of x,y, returns z func (z *E3) Mul(x, y *E3) *E3 { - // Algorithm 13 from https://eprint.iacr.org/2010/354.pdf + // Karatsuba method for cubic extensions + // https://eprint.iacr.org/2006/471.pdf (section 4) var t0, t1, t2, c0, c1, c2, tmp fp.Element t0.Mul(&x.A0, &y.A0) t1.Mul(&x.A1, &y.A1) diff --git a/ecc/bw6-761/internal/fptower/e3.go b/ecc/bw6-761/internal/fptower/e3.go index 6a2a4e97a..d5614ab42 100644 --- a/ecc/bw6-761/internal/fptower/e3.go +++ b/ecc/bw6-761/internal/fptower/e3.go @@ -225,7 +225,8 @@ func (z *E3) MulBy1(c1 *fp.Element) *E3 { // Mul sets z to the E3-product of x,y, returns z func (z *E3) Mul(x, y *E3) *E3 { - // Algorithm 13 from https://eprint.iacr.org/2010/354.pdf + // Karatsuba method for cubic extensions + // https://eprint.iacr.org/2006/471.pdf (section 4) var t0, t1, t2, c0, c1, c2, tmp fp.Element t0.Mul(&x.A0, &y.A0) t1.Mul(&x.A1, &y.A1) From bcce894bde55fccfa678446308fafc71f0c631e0 Mon Sep 17 00:00:00 2001 From: Youssef El Housni Date: Tue, 25 Jun 2024 12:19:03 +0100 Subject: [PATCH 4/6] docs: correct BW6 tower comment --- ecc/bw6-633/bw6-633.go | 2 +- ecc/bw6-756/bw6-756.go | 2 +- ecc/bw6-761/bw6-761.go | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/ecc/bw6-633/bw6-633.go b/ecc/bw6-633/bw6-633.go index 4bf35e945..07f25ecba 100644 --- a/ecc/bw6-633/bw6-633.go +++ b/ecc/bw6-633/bw6-633.go @@ -13,7 +13,7 @@ // Extension fields tower: // // 𝔽p³[u] = 𝔽p/u³-2 -// 𝔽p⁶[v] = 𝔽p²/v²-u +// 𝔽p⁶[v] = 𝔽p³/v²-u // // case t % r % u = 0 // diff --git a/ecc/bw6-756/bw6-756.go b/ecc/bw6-756/bw6-756.go index d1e01e394..8161ced27 100644 --- a/ecc/bw6-756/bw6-756.go +++ b/ecc/bw6-756/bw6-756.go @@ -15,7 +15,7 @@ // Extension fields tower: // // 𝔽p³[u] = 𝔽p/u³-33 -// 𝔽p⁶[v] = 𝔽p²/v²-u +// 𝔽p⁶[v] = 𝔽p³/v²-u // // optimal Ate loops: // diff --git a/ecc/bw6-761/bw6-761.go b/ecc/bw6-761/bw6-761.go index 62bdb2390..493df2f02 100644 --- a/ecc/bw6-761/bw6-761.go +++ b/ecc/bw6-761/bw6-761.go @@ -15,7 +15,7 @@ // Extension fields tower: // // 𝔽p³[u] = 𝔽p/u³+4 -// 𝔽p⁶[v] = 𝔽p²/v²-u +// 𝔽p⁶[v] = 𝔽p³/v²-u // // optimal Ate loops: // From d8b68d8e9ee8befb55a5a014c07eceb8beac6fd1 Mon Sep 17 00:00:00 2001 From: Youssef El Housni Date: Tue, 2 Jul 2024 15:02:12 +0100 Subject: [PATCH 5/6] docs(ecc): refactor comments in g*.go --- ecc/bls12-377/g1.go | 320 ++++++------ ecc/bls12-377/g2.go | 345 ++++++------- ecc/bls12-377/multiexp_affine.go | 4 +- ecc/bls12-377/multiexp_jacobian.go | 4 +- ecc/bls12-378/g1.go | 320 ++++++------ ecc/bls12-378/g2.go | 345 ++++++------- ecc/bls12-378/multiexp_affine.go | 4 +- ecc/bls12-378/multiexp_jacobian.go | 4 +- ecc/bls12-381/g1.go | 320 ++++++------ ecc/bls12-381/g2.go | 345 ++++++------- ecc/bls12-381/multiexp_affine.go | 4 +- ecc/bls12-381/multiexp_jacobian.go | 4 +- ecc/bls24-315/g1.go | 320 ++++++------ ecc/bls24-315/g2.go | 343 +++++++------ ecc/bls24-315/multiexp_affine.go | 4 +- ecc/bls24-315/multiexp_jacobian.go | 4 +- ecc/bls24-317/g1.go | 320 ++++++------ ecc/bls24-317/g2.go | 343 +++++++------ ecc/bls24-317/multiexp_affine.go | 4 +- ecc/bls24-317/multiexp_jacobian.go | 4 +- ecc/bn254/g1.go | 316 ++++++------ ecc/bn254/g2.go | 341 +++++++------ ecc/bn254/multiexp_affine.go | 4 +- ecc/bn254/multiexp_jacobian.go | 4 +- ecc/bw6-633/g1.go | 328 +++++++------ ecc/bw6-633/g2.go | 343 +++++++------ ecc/bw6-633/multiexp_affine.go | 4 +- ecc/bw6-633/multiexp_jacobian.go | 4 +- ecc/bw6-756/g1.go | 332 +++++++------ ecc/bw6-756/g2.go | 337 +++++++------ ecc/bw6-756/multiexp_affine.go | 4 +- ecc/bw6-756/multiexp_jacobian.go | 4 +- ecc/bw6-761/g1.go | 322 +++++++------ ecc/bw6-761/g2.go | 335 +++++++------ ecc/bw6-761/multiexp_affine.go | 4 +- ecc/bw6-761/multiexp_jacobian.go | 4 +- ecc/secp256k1/g1.go | 316 ++++++------ ecc/secp256k1/multiexp_affine.go | 2 +- ecc/secp256k1/multiexp_jacobian.go | 2 +- ecc/stark-curve/g1.go | 135 +++--- .../ecc/template/multiexp_affine.go.tmpl | 2 +- .../ecc/template/multiexp_jacobian.go.tmpl | 2 +- internal/generator/ecc/template/point.go.tmpl | 454 +++++++++--------- 43 files changed, 3717 insertions(+), 3243 deletions(-) diff --git a/ecc/bls12-377/g1.go b/ecc/bls12-377/g1.go index 9d2739f1d..4df42849b 100644 --- a/ecc/bls12-377/g1.go +++ b/ecc/bls12-377/g1.go @@ -25,38 +25,40 @@ import ( "runtime" ) -// G1Affine point in affine coordinates +// G1Affine is a point in affine coordinates (x,y) type G1Affine struct { X, Y fp.Element } -// G1Jac is a point with fp.Element coordinates +// G1Jac is a point in Jacobian coordinates (x=X/Z², y=Y/Z³) type G1Jac struct { X, Y, Z fp.Element } -// g1JacExtended parameterized Jacobian coordinates (x=X/ZZ, y=Y/ZZZ, ZZ³=ZZZ²) +// g1JacExtended is a point in extended Jacobian coordinates (x=X/ZZ, y=Y/ZZZ, ZZ³=ZZZ²) type g1JacExtended struct { X, Y, ZZ, ZZZ fp.Element } // ------------------------------------------------------------------------------------------------- -// Affine +// Affine coordinates -// Set sets p to the provided point +// Set sets p to a in affine coordinates. func (p *G1Affine) Set(a *G1Affine) *G1Affine { p.X, p.Y = a.X, a.Y return p } -// setInfinity sets p to O +// setInfinity sets p to the infinity point, which is encoded as (0,0). +// N.B.: (0,0) is never on the curve for j=0 curves (Y²=X³+B). func (p *G1Affine) setInfinity() *G1Affine { p.X.SetZero() p.Y.SetZero() return p } -// ScalarMultiplication computes and returns p = a ⋅ s +// ScalarMultiplication computes and returns p = [s]a +// where p and a are affine points. func (p *G1Affine) ScalarMultiplication(a *G1Affine, s *big.Int) *G1Affine { var _p G1Jac _p.FromAffine(a) @@ -65,20 +67,22 @@ func (p *G1Affine) ScalarMultiplication(a *G1Affine, s *big.Int) *G1Affine { return p } -// ScalarMultiplicationAffine computes and returns p = a ⋅ s -// Takes an affine point and returns a Jacobian point (useful for KZG) +// ScalarMultiplicationAffine computes and returns p = [s]a +// where a is an affine point and p a Jacobian point (useful for KZG). func (p *G1Jac) ScalarMultiplicationAffine(a *G1Affine, s *big.Int) *G1Jac { p.FromAffine(a) p.mulGLV(p, s) return p } -// ScalarMultiplicationBase computes and returns p = g ⋅ s where g is the prime subgroup generator +// ScalarMultiplicationBase computes and returns p = [s]g +// where g is the Jacobian point generating the prime subgroup. func (p *G1Jac) ScalarMultiplicationBase(s *big.Int) *G1Jac { return p.mulGLV(&g1Gen, s) } -// ScalarMultiplicationBase computes and returns p = g ⋅ s where g is the prime subgroup generator +// ScalarMultiplicationBase computes and returns p = [s]g +// where g is the affine point generating the prime subgroup. func (p *G1Affine) ScalarMultiplicationBase(s *big.Int) *G1Affine { var _p G1Jac _p.mulGLV(&g1Gen, s) @@ -86,8 +90,9 @@ func (p *G1Affine) ScalarMultiplicationBase(s *big.Int) *G1Affine { return p } -// Add adds two point in affine coordinates. -// Jacobian addition with Z1=Z2=1 +// Add adds two points in affine coordinates. +// It uses the Jacobian addition with a.Z=b.Z=1 and converts the result to affine coordinates. +// // https://www.hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html#addition-mmadd-2007-bl func (p *G1Affine) Add(a, b *G1Affine) *G1Affine { var q G1Jac @@ -133,6 +138,10 @@ func (p *G1Affine) Add(a, b *G1Affine) *G1Affine { } // Double doubles a point in affine coordinates. +// It converts the point to Jacobian coordinates, doubles it using Jacobian +// addition with a.Z=1, and converts it back to affine coordinates. +// +// http://www.hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html#doubling-mdbl-2007-bl func (p *G1Affine) Double(a *G1Affine) *G1Affine { var q G1Jac q.FromAffine(a) @@ -141,7 +150,8 @@ func (p *G1Affine) Double(a *G1Affine) *G1Affine { return p } -// Sub subs two point in affine coordinates. +// Sub subtracts two points in affine coordinates. +// It uses a similar approach to Add, but negates the second point before adding. func (p *G1Affine) Sub(a, b *G1Affine) *G1Affine { var bneg G1Affine bneg.Neg(b) @@ -149,19 +159,19 @@ func (p *G1Affine) Sub(a, b *G1Affine) *G1Affine { return p } -// Equal tests if two points (in Affine coordinates) are equal +// Equal tests if two points in affine coordinates are equal. func (p *G1Affine) Equal(a *G1Affine) bool { return p.X.Equal(&a.X) && p.Y.Equal(&a.Y) } -// Neg computes -G +// Neg sets p to the affine negative point -a = (a.X, -a.Y). func (p *G1Affine) Neg(a *G1Affine) *G1Affine { p.X = a.X p.Y.Neg(&a.Y) return p } -// FromJacobian rescales a point in Jacobian coord in z=1 plane +// FromJacobian converts a point p1 from Jacobian to affine coordinates. func (p *G1Affine) FromJacobian(p1 *G1Jac) *G1Affine { var a, b fp.Element @@ -180,7 +190,7 @@ func (p *G1Affine) FromJacobian(p1 *G1Jac) *G1Affine { return p } -// String returns the string representation of the point or "O" if it is infinity +// String returns the string representation E(x,y) of the affine point p or "O" if it is infinity. func (p *G1Affine) String() string { if p.IsInfinity() { return "O" @@ -188,21 +198,20 @@ func (p *G1Affine) String() string { return "E([" + p.X.String() + "," + p.Y.String() + "])" } -// IsInfinity checks if the point is infinity -// in affine, it's encoded as (0,0) -// (0,0) is never on the curve for j=0 curves +// IsInfinity checks if the affine point p is infinity, which is encoded as (0,0). +// N.B.: (0,0) is never on the curve for j=0 curves (Y²=X³+B). func (p *G1Affine) IsInfinity() bool { return p.X.IsZero() && p.Y.IsZero() } -// IsOnCurve returns true if p in on the curve +// IsOnCurve returns true if the affine point p in on the curve. func (p *G1Affine) IsOnCurve() bool { var point G1Jac point.FromAffine(p) return point.IsOnCurve() // call this function to handle infinity point } -// IsInSubGroup returns true if p is in the correct subgroup, false otherwise +// IsInSubGroup returns true if the affine point p is in the correct subgroup, false otherwise. func (p *G1Affine) IsInSubGroup() bool { var _p G1Jac _p.FromAffine(p) @@ -210,84 +219,76 @@ func (p *G1Affine) IsInSubGroup() bool { } // ------------------------------------------------------------------------------------------------- -// Jacobian +// Jacobian coordinates -// Set sets p to the provided point -func (p *G1Jac) Set(a *G1Jac) *G1Jac { - p.X, p.Y, p.Z = a.X, a.Y, a.Z +// Set sets p to a in Jacobian coordinates. +func (p *G1Jac) Set(q *G1Jac) *G1Jac { + p.X, p.Y, p.Z = q.X, q.Y, q.Z return p } -// Equal tests if two points (in Jacobian coordinates) are equal -func (p *G1Jac) Equal(a *G1Jac) bool { +// Equal tests if two points in Jacobian coordinates are equal. +func (p *G1Jac) Equal(q *G1Jac) bool { // If one point is infinity, the other must also be infinity. if p.Z.IsZero() { - return a.Z.IsZero() + return q.Z.IsZero() } // If the other point is infinity, return false since we can't // the following checks would be incorrect. - if a.Z.IsZero() { + if q.Z.IsZero() { return false } var pZSquare, aZSquare fp.Element pZSquare.Square(&p.Z) - aZSquare.Square(&a.Z) + aZSquare.Square(&q.Z) var lhs, rhs fp.Element lhs.Mul(&p.X, &aZSquare) - rhs.Mul(&a.X, &pZSquare) + rhs.Mul(&q.X, &pZSquare) if !lhs.Equal(&rhs) { return false } - lhs.Mul(&p.Y, &aZSquare).Mul(&lhs, &a.Z) - rhs.Mul(&a.Y, &pZSquare).Mul(&rhs, &p.Z) + lhs.Mul(&p.Y, &aZSquare).Mul(&lhs, &q.Z) + rhs.Mul(&q.Y, &pZSquare).Mul(&rhs, &p.Z) return lhs.Equal(&rhs) } -// Neg computes -G -func (p *G1Jac) Neg(a *G1Jac) *G1Jac { - *p = *a - p.Y.Neg(&a.Y) +// Neg sets p to the Jacobian negative point -q = (q.X, -q.Y, q.Z). +func (p *G1Jac) Neg(q *G1Jac) *G1Jac { + *p = *q + p.Y.Neg(&q.Y) return p } -// SubAssign subtracts two points on the curve -func (p *G1Jac) SubAssign(a *G1Jac) *G1Jac { - var tmp G1Jac - tmp.Set(a) - tmp.Y.Neg(&tmp.Y) - p.AddAssign(&tmp) - return p -} - -// AddAssign point addition in montgomery form +// AddAssign sets p to p+a in Jacobian coordinates. +// // https://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-3.html#addition-add-2007-bl -func (p *G1Jac) AddAssign(a *G1Jac) *G1Jac { +func (p *G1Jac) AddAssign(q *G1Jac) *G1Jac { - // p is infinity, return a + // p is infinity, return q if p.Z.IsZero() { - p.Set(a) + p.Set(q) return p } - // a is infinity, return p - if a.Z.IsZero() { + // q is infinity, return p + if q.Z.IsZero() { return p } var Z1Z1, Z2Z2, U1, U2, S1, S2, H, I, J, r, V fp.Element - Z1Z1.Square(&a.Z) + Z1Z1.Square(&q.Z) Z2Z2.Square(&p.Z) - U1.Mul(&a.X, &Z2Z2) + U1.Mul(&q.X, &Z2Z2) U2.Mul(&p.X, &Z1Z1) - S1.Mul(&a.Y, &p.Z). + S1.Mul(&q.Y, &p.Z). Mul(&S1, &Z2Z2) - S2.Mul(&p.Y, &a.Z). + S2.Mul(&p.Y, &q.Z). Mul(&S2, &Z1Z1) - // if p == a, we double instead + // if p == q, we double instead if U1.Equal(&U2) && S1.Equal(&S2) { return p.DoubleAssign() } @@ -306,7 +307,7 @@ func (p *G1Jac) AddAssign(a *G1Jac) *G1Jac { Mul(&p.Y, &r) S1.Mul(&S1, &J).Double(&S1) p.Y.Sub(&p.Y, &S1) - p.Z.Add(&p.Z, &a.Z) + p.Z.Add(&p.Z, &q.Z) p.Z.Square(&p.Z). Sub(&p.Z, &Z1Z1). Sub(&p.Z, &Z2Z2). @@ -315,8 +316,19 @@ func (p *G1Jac) AddAssign(a *G1Jac) *G1Jac { return p } -// DoubleMixed point addition -// http://www.hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html#doubling-mdbl-2007-bl +// SubAssign sets p to p-a in Jacobian coordinates. +// It uses a similar approach to AddAssign, but negates the point a before adding. +func (p *G1Jac) SubAssign(q *G1Jac) *G1Jac { + var tmp G1Jac + tmp.Set(q) + tmp.Y.Neg(&tmp.Y) + p.AddAssign(&tmp) + return p +} + +// Double sets p to [2]q in Jacobian coordinates. +// +// https://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-3.html#doubling-dbl-2007-bl func (p *G1Jac) DoubleMixed(a *G1Affine) *G1Jac { var XX, YY, YYYY, S, M, T fp.Element XX.Square(&a.X) @@ -328,7 +340,7 @@ func (p *G1Jac) DoubleMixed(a *G1Affine) *G1Jac { Sub(&S, &YYYY). Double(&S) M.Double(&XX). - Add(&M, &XX) // -> + a, but a=0 here + Add(&M, &XX) // -> + A, but A=0 here T.Square(&M). Sub(&T, &S). Sub(&T, &S) @@ -344,7 +356,8 @@ func (p *G1Jac) DoubleMixed(a *G1Affine) *G1Jac { return p } -// AddMixed point addition +// AddMixed sets p to p+a in Jacobian coordinates, where a.Z = 1. +// // http://www.hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html#addition-madd-2007-bl func (p *G1Jac) AddMixed(a *G1Affine) *G1Jac { @@ -393,7 +406,8 @@ func (p *G1Jac) AddMixed(a *G1Affine) *G1Jac { return p } -// Double doubles a point in Jacobian coordinates +// Double sets p to [2]q in Jacobian coordinates. +// // https://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-3.html#doubling-dbl-2007-bl func (p *G1Jac) Double(q *G1Jac) *G1Jac { p.Set(q) @@ -401,7 +415,8 @@ func (p *G1Jac) Double(q *G1Jac) *G1Jac { return p } -// DoubleAssign doubles a point in Jacobian coordinates +// DoubleAssign doubles p in Jacobian coordinates. +// // https://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-3.html#doubling-dbl-2007-bl func (p *G1Jac) DoubleAssign() *G1Jac { @@ -433,34 +448,36 @@ func (p *G1Jac) DoubleAssign() *G1Jac { return p } -// ScalarMultiplication computes and returns p = a ⋅ s +// ScalarMultiplication computes and returns p = [s]a +// where p and a are Jacobian points. +// using the GLV technique. // see https://www.iacr.org/archive/crypto2001/21390189.pdf -func (p *G1Jac) ScalarMultiplication(a *G1Jac, s *big.Int) *G1Jac { - return p.mulGLV(a, s) +func (p *G1Jac) ScalarMultiplication(q *G1Jac, s *big.Int) *G1Jac { + return p.mulGLV(q, s) } -// String returns canonical representation of the point in affine coordinates +// String converts p to affine coordinates and returns its string representation E(x,y) or "O" if it is infinity. func (p *G1Jac) String() string { _p := G1Affine{} _p.FromJacobian(p) return _p.String() } -// FromAffine sets p = Q, p in Jacobian, Q in affine -func (p *G1Jac) FromAffine(Q *G1Affine) *G1Jac { - if Q.IsInfinity() { +// FromAffine converts a point a from affine to Jacobian coordinates. +func (p *G1Jac) FromAffine(a *G1Affine) *G1Jac { + if a.IsInfinity() { p.Z.SetZero() p.X.SetOne() p.Y.SetOne() return p } p.Z.SetOne() - p.X.Set(&Q.X) - p.Y.Set(&Q.Y) + p.X.Set(&a.X) + p.Y.Set(&a.Y) return p } -// IsOnCurve returns true if p in on the curve +// IsOnCurve returns true if the Jacobian point p in on the curve. func (p *G1Jac) IsOnCurve() bool { var left, right, tmp, ZZ fp.Element left.Square(&p.Y) @@ -491,13 +508,14 @@ func (p *G1Jac) IsInSubGroup() bool { } -// mulWindowed computes a 2-bits windowed scalar multiplication -func (p *G1Jac) mulWindowed(a *G1Jac, s *big.Int) *G1Jac { +// mulWindowed computes the 2-bits windowed double-and-add scalar +// multiplication p=[s]q in Jacobian coordinates. +func (p *G1Jac) mulWindowed(q *G1Jac, s *big.Int) *G1Jac { var res G1Jac var ops [3]G1Jac - ops[0].Set(a) + ops[0].Set(q) if s.Sign() == -1 { ops[0].Neg(&ops[0]) } @@ -524,17 +542,18 @@ func (p *G1Jac) mulWindowed(a *G1Jac, s *big.Int) *G1Jac { } -// ϕ assigns p to ϕ(a) where ϕ: (x,y) → (w x,y), and returns p -// where w is a third root of unity in 𝔽p -func (p *G1Jac) phi(a *G1Jac) *G1Jac { - p.Set(a) +// phi sets p to ϕ(a) where ϕ: (x,y) → (w x,y), +// where w is a third root of unity. +func (p *G1Jac) phi(q *G1Jac) *G1Jac { + p.Set(q) p.X.Mul(&p.X, &thirdRootOneG1) return p } // mulGLV computes the scalar multiplication using a windowed-GLV method +// // see https://www.iacr.org/archive/crypto2001/21390189.pdf -func (p *G1Jac) mulGLV(a *G1Jac, s *big.Int) *G1Jac { +func (p *G1Jac) mulGLV(q *G1Jac, s *big.Int) *G1Jac { var table [15]G1Jac var res G1Jac @@ -542,11 +561,11 @@ func (p *G1Jac) mulGLV(a *G1Jac, s *big.Int) *G1Jac { res.Set(&g1Infinity) - // table[b3b2b1b0-1] = b3b2 ⋅ ϕ(a) + b1b0*a - table[0].Set(a) - table[3].phi(a) + // table[b3b2b1b0-1] = b3b2 ⋅ ϕ(q) + b1b0*q + table[0].Set(q) + table[3].phi(q) - // split the scalar, modifies ±a, ϕ(a) accordingly + // split the scalar, modifies ±q, ϕ(q) accordingly k := ecc.SplitScalar(s, &glvBasis) if k[0].Sign() == -1 { @@ -559,7 +578,7 @@ func (p *G1Jac) mulGLV(a *G1Jac, s *big.Int) *G1Jac { } // precompute table (2 bits sliding window) - // table[b3b2b1b0-1] = b3b2 ⋅ ϕ(a) + b1b0 ⋅ a if b3b2b1b0 != 0 + // table[b3b2b1b0-1] = b3b2 ⋅ ϕ(q) + b1b0 ⋅ q if b3b2b1b0 != 0 table[1].Double(&table[0]) table[2].Set(&table[1]).AddAssign(&table[0]) table[4].Set(&table[3]).AddAssign(&table[0]) @@ -615,17 +634,17 @@ func (p *G1Affine) ClearCofactor(a *G1Affine) *G1Affine { } // ClearCofactor maps a point in E(Fp) to E(Fp)[r] -func (p *G1Jac) ClearCofactor(a *G1Jac) *G1Jac { +func (p *G1Jac) ClearCofactor(q *G1Jac) *G1Jac { // cf https://eprint.iacr.org/2019/403.pdf, 5 var res G1Jac - res.ScalarMultiplication(a, &xGen).Neg(&res).AddAssign(a) + res.ScalarMultiplication(q, &xGen).Neg(&res).AddAssign(q) p.Set(&res) return p } -// JointScalarMultiplicationBase computes [s1]g+[s2]a using Straus-Shamir technique -// where g is the prime subgroup generator +// JointScalarMultiplicationBase computes [s1]g+[s2]a using Strauss-Shamir technique +// where g is the prime subgroup generator and a is an affine point. func (p *G1Jac) JointScalarMultiplicationBase(a *G1Affine, s1, s2 *big.Int) *G1Jac { var res, p1, p2 G1Jac @@ -696,15 +715,15 @@ func (p *G1Jac) JointScalarMultiplicationBase(a *G1Affine, s1, s2 *big.Int) *G1J } // ------------------------------------------------------------------------------------------------- -// Jacobian extended +// extended Jacobian coordinates -// Set sets p to the provided point -func (p *g1JacExtended) Set(a *g1JacExtended) *g1JacExtended { - p.X, p.Y, p.ZZ, p.ZZZ = a.X, a.Y, a.ZZ, a.ZZZ +// Set sets p to a in extended Jacobian coordinates. +func (p *g1JacExtended) Set(q *g1JacExtended) *g1JacExtended { + p.X, p.Y, p.ZZ, p.ZZZ = q.X, q.Y, q.ZZ, q.ZZZ return p } -// setInfinity sets p to O +// setInfinity sets p to the infinity point (1,1,0,0). func (p *g1JacExtended) setInfinity() *g1JacExtended { p.X.SetOne() p.Y.SetOne() @@ -713,43 +732,45 @@ func (p *g1JacExtended) setInfinity() *g1JacExtended { return p } -func (p *g1JacExtended) IsZero() bool { +// IsInfinity checks if the p is infinity, i.e. p.ZZ=0. +func (p *g1JacExtended) IsInfinity() bool { return p.ZZ.IsZero() } -// fromJacExtended sets Q in affine coordinates -func (p *G1Affine) fromJacExtended(Q *g1JacExtended) *G1Affine { - if Q.ZZ.IsZero() { +// fromJacExtended converts an extended Jacobian point to an affine point. +func (p *G1Affine) fromJacExtended(q *g1JacExtended) *G1Affine { + if q.ZZ.IsZero() { p.X = fp.Element{} p.Y = fp.Element{} return p } - p.X.Inverse(&Q.ZZ).Mul(&p.X, &Q.X) - p.Y.Inverse(&Q.ZZZ).Mul(&p.Y, &Q.Y) + p.X.Inverse(&q.ZZ).Mul(&p.X, &q.X) + p.Y.Inverse(&q.ZZZ).Mul(&p.Y, &q.Y) return p } -// fromJacExtended sets Q in Jacobian coordinates -func (p *G1Jac) fromJacExtended(Q *g1JacExtended) *G1Jac { - if Q.ZZ.IsZero() { +// fromJacExtended converts an extended Jacobian point to a Jacobian point. +func (p *G1Jac) fromJacExtended(q *g1JacExtended) *G1Jac { + if q.ZZ.IsZero() { p.Set(&g1Infinity) return p } - p.X.Mul(&Q.ZZ, &Q.X).Mul(&p.X, &Q.ZZ) - p.Y.Mul(&Q.ZZZ, &Q.Y).Mul(&p.Y, &Q.ZZZ) - p.Z.Set(&Q.ZZZ) + p.X.Mul(&q.ZZ, &q.X).Mul(&p.X, &q.ZZ) + p.Y.Mul(&q.ZZZ, &q.Y).Mul(&p.Y, &q.ZZZ) + p.Z.Set(&q.ZZZ) return p } -// unsafeFromJacExtended sets p in Jacobian coordinates, but don't check for infinity -func (p *G1Jac) unsafeFromJacExtended(Q *g1JacExtended) *G1Jac { - p.X.Square(&Q.ZZ).Mul(&p.X, &Q.X) - p.Y.Square(&Q.ZZZ).Mul(&p.Y, &Q.Y) - p.Z = Q.ZZZ +// unsafeFromJacExtended converts an extended Jacobian point, distinct from Infinity, to a Jacobian point. +func (p *G1Jac) unsafeFromJacExtended(q *g1JacExtended) *G1Jac { + p.X.Square(&q.ZZ).Mul(&p.X, &q.X) + p.Y.Square(&q.ZZZ).Mul(&p.Y, &q.Y) + p.Z = q.ZZZ return p } -// add point in Jacobian extended coordinates +// add sets p to p+q in extended Jacobian coordinates. +// // https://www.hyperelliptic.org/EFD/g1p/auto-shortw-xyzz.html#addition-add-2008-s func (p *g1JacExtended) add(q *g1JacExtended) *g1JacExtended { //if q is infinity return p @@ -805,10 +826,11 @@ func (p *g1JacExtended) add(q *g1JacExtended) *g1JacExtended { return p } -// double point in Jacobian extended coordinates +// double sets p to [2]q in Jacobian extended coordinates. +// // http://www.hyperelliptic.org/EFD/g1p/auto-shortw-xyzz.html#doubling-dbl-2008-s-1 -// since we consider any point on Z=0 as the point at infinity -// this doubling formula works for infinity points as well +// N.B.: since we consider any point on Z=0 as the point at infinity +// this doubling formula works for infinity points as well. func (p *g1JacExtended) double(q *g1JacExtended) *g1JacExtended { var U, V, W, S, XX, M fp.Element @@ -818,7 +840,7 @@ func (p *g1JacExtended) double(q *g1JacExtended) *g1JacExtended { S.Mul(&q.X, &V) XX.Square(&q.X) M.Double(&XX). - Add(&M, &XX) // -> + a, but a=0 here + Add(&M, &XX) // -> + A, but A=0 here U.Mul(&W, &q.Y) p.X.Square(&M). @@ -833,9 +855,10 @@ func (p *g1JacExtended) double(q *g1JacExtended) *g1JacExtended { return p } -// subMixed same as addMixed, but will negate a.Y +// addMixed sets p to p+q in extended Jacobian coordinates, where a.ZZ=1. +// // http://www.hyperelliptic.org/EFD/g1p/auto-shortw-xyzz.html#addition-madd-2008-s -func (p *g1JacExtended) subMixed(a *G1Affine) *g1JacExtended { +func (p *g1JacExtended) addMixed(a *G1Affine) *g1JacExtended { //if a is infinity return p if a.IsInfinity() { @@ -844,7 +867,7 @@ func (p *g1JacExtended) subMixed(a *G1Affine) *g1JacExtended { // p is infinity, return a if p.ZZ.IsZero() { p.X = a.X - p.Y.Neg(&a.Y) + p.Y = a.Y p.ZZ.SetOne() p.ZZZ.SetOne() return p @@ -857,12 +880,11 @@ func (p *g1JacExtended) subMixed(a *G1Affine) *g1JacExtended { P.Sub(&P, &p.X) R.Mul(&a.Y, &p.ZZZ) - R.Neg(&R) R.Sub(&R, &p.Y) if P.IsZero() { if R.IsZero() { - return p.doubleNegMixed(a) + return p.doubleMixed(a) } p.ZZ = fp.Element{} @@ -889,9 +911,10 @@ func (p *g1JacExtended) subMixed(a *G1Affine) *g1JacExtended { } -// addMixed +// subMixed works the same as addMixed, but negates a.Y. +// // http://www.hyperelliptic.org/EFD/g1p/auto-shortw-xyzz.html#addition-madd-2008-s -func (p *g1JacExtended) addMixed(a *G1Affine) *g1JacExtended { +func (p *g1JacExtended) subMixed(a *G1Affine) *g1JacExtended { //if a is infinity return p if a.IsInfinity() { @@ -900,7 +923,7 @@ func (p *g1JacExtended) addMixed(a *G1Affine) *g1JacExtended { // p is infinity, return a if p.ZZ.IsZero() { p.X = a.X - p.Y = a.Y + p.Y.Neg(&a.Y) p.ZZ.SetOne() p.ZZZ.SetOne() return p @@ -913,11 +936,12 @@ func (p *g1JacExtended) addMixed(a *G1Affine) *g1JacExtended { P.Sub(&P, &p.X) R.Mul(&a.Y, &p.ZZZ) + R.Neg(&R) R.Sub(&R, &p.Y) if P.IsZero() { if R.IsZero() { - return p.doubleMixed(a) + return p.doubleNegMixed(a) } p.ZZ = fp.Element{} @@ -944,21 +968,21 @@ func (p *g1JacExtended) addMixed(a *G1Affine) *g1JacExtended { } -// doubleNegMixed same as double, but will negate q.Y -func (p *g1JacExtended) doubleNegMixed(q *G1Affine) *g1JacExtended { +// doubleNegMixed works the same as double, but negates q.Y. +func (p *g1JacExtended) doubleNegMixed(a *G1Affine) *g1JacExtended { var U, V, W, S, XX, M, S2, L fp.Element - U.Double(&q.Y) + U.Double(&a.Y) U.Neg(&U) V.Square(&U) W.Mul(&U, &V) - S.Mul(&q.X, &V) - XX.Square(&q.X) + S.Mul(&a.X, &V) + XX.Square(&a.X) M.Double(&XX). - Add(&M, &XX) // -> + a, but a=0 here + Add(&M, &XX) // -> + A, but A=0 here S2.Double(&S) - L.Mul(&W, &q.Y) + L.Mul(&W, &a.Y) p.X.Square(&M). Sub(&p.X, &S2) @@ -971,21 +995,22 @@ func (p *g1JacExtended) doubleNegMixed(q *G1Affine) *g1JacExtended { return p } -// doubleMixed point in Jacobian extended coordinates +// doubleMixed sets p to [2]a in Jacobian extended coordinates, where a.ZZ=1. +// // http://www.hyperelliptic.org/EFD/g1p/auto-shortw-xyzz.html#doubling-dbl-2008-s-1 -func (p *g1JacExtended) doubleMixed(q *G1Affine) *g1JacExtended { +func (p *g1JacExtended) doubleMixed(a *G1Affine) *g1JacExtended { var U, V, W, S, XX, M, S2, L fp.Element - U.Double(&q.Y) + U.Double(&a.Y) V.Square(&U) W.Mul(&U, &V) - S.Mul(&q.X, &V) - XX.Square(&q.X) + S.Mul(&a.X, &V) + XX.Square(&a.X) M.Double(&XX). - Add(&M, &XX) // -> + a, but a=0 here + Add(&M, &XX) // -> + A, but A=0 here S2.Double(&S) - L.Mul(&W, &q.Y) + L.Mul(&W, &a.Y) p.X.Square(&M). Sub(&p.X, &S2) @@ -999,7 +1024,7 @@ func (p *g1JacExtended) doubleMixed(q *G1Affine) *g1JacExtended { } // BatchJacobianToAffineG1 converts points in Jacobian coordinates to Affine coordinates -// performing a single field inversion (Montgomery batch inversion trick). +// performing a single field inversion using the Montgomery batch inversion trick. func BatchJacobianToAffineG1(points []G1Jac) []G1Affine { result := make([]G1Affine, len(points)) zeroes := make([]bool, len(points)) @@ -1049,7 +1074,7 @@ func BatchJacobianToAffineG1(points []G1Jac) []G1Affine { // BatchScalarMultiplicationG1 multiplies the same base by all scalars // and return resulting points in affine coordinates -// uses a simple windowed-NAF like exponentiation algorithm +// uses a simple windowed-NAF-like multiplication algorithm. func BatchScalarMultiplicationG1(base *G1Affine, scalars []fr.Element) []G1Affine { // approximate cost in group ops is // cost = 2^{c-1} + n(scalar.nbBits+nbChunks) @@ -1131,9 +1156,8 @@ func BatchScalarMultiplicationG1(base *G1Affine, scalars []fr.Element) []G1Affin return toReturnAff } -// batch add affine coordinates -// using batch inversion -// special cases (doubling, infinity) must be filtered out before this call +// batchAddG1Affine adds affine points using the Montgomery batch inversion trick. +// Special cases (doubling, infinity) must be filtered out before this call. func batchAddG1Affine[TP pG1Affine, TPP ppG1Affine, TC cG1Affine](R *TPP, P *TP, batchSize int) { var lambda, lambdain TC diff --git a/ecc/bls12-377/g2.go b/ecc/bls12-377/g2.go index b10ad7f06..03c8037fa 100644 --- a/ecc/bls12-377/g2.go +++ b/ecc/bls12-377/g2.go @@ -25,17 +25,17 @@ import ( "runtime" ) -// G2Affine point in affine coordinates +// G2Affine is a point in affine coordinates (x,y) type G2Affine struct { X, Y fptower.E2 } -// G2Jac is a point with fptower.E2 coordinates +// G2Jac is a point in Jacobian coordinates (x=X/Z², y=Y/Z³) type G2Jac struct { X, Y, Z fptower.E2 } -// g2JacExtended parameterized Jacobian coordinates (x=X/ZZ, y=Y/ZZZ, ZZ³=ZZZ²) +// g2JacExtended is a point in extended Jacobian coordinates (x=X/ZZ, y=Y/ZZZ, ZZ³=ZZZ²) type g2JacExtended struct { X, Y, ZZ, ZZZ fptower.E2 } @@ -46,22 +46,24 @@ type g2Proj struct { } // ------------------------------------------------------------------------------------------------- -// Affine +// Affine coordinates -// Set sets p to the provided point +// Set sets p to a in affine coordinates. func (p *G2Affine) Set(a *G2Affine) *G2Affine { p.X, p.Y = a.X, a.Y return p } -// setInfinity sets p to O +// setInfinity sets p to the infinity point, which is encoded as (0,0). +// N.B.: (0,0) is never on the curve for j=0 curves (Y²=X³+B). func (p *G2Affine) setInfinity() *G2Affine { p.X.SetZero() p.Y.SetZero() return p } -// ScalarMultiplication computes and returns p = a ⋅ s +// ScalarMultiplication computes and returns p = [s]a +// where p and a are affine points. func (p *G2Affine) ScalarMultiplication(a *G2Affine, s *big.Int) *G2Affine { var _p G2Jac _p.FromAffine(a) @@ -70,7 +72,8 @@ func (p *G2Affine) ScalarMultiplication(a *G2Affine, s *big.Int) *G2Affine { return p } -// ScalarMultiplicationBase computes and returns p = g ⋅ s where g is the prime subgroup generator +// ScalarMultiplicationBase computes and returns p = [s]g +// where g is the affine point generating the prime subgroup. func (p *G2Affine) ScalarMultiplicationBase(s *big.Int) *G2Affine { var _p G2Jac _p.mulGLV(&g2Gen, s) @@ -78,8 +81,9 @@ func (p *G2Affine) ScalarMultiplicationBase(s *big.Int) *G2Affine { return p } -// Add adds two point in affine coordinates. -// Jacobian addition with Z1=Z2=1 +// Add adds two points in affine coordinates. +// It uses the Jacobian addition with a.Z=b.Z=1 and converts the result to affine coordinates. +// // https://www.hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html#addition-mmadd-2007-bl func (p *G2Affine) Add(a, b *G2Affine) *G2Affine { var q G2Jac @@ -125,6 +129,10 @@ func (p *G2Affine) Add(a, b *G2Affine) *G2Affine { } // Double doubles a point in affine coordinates. +// It converts the point to Jacobian coordinates, doubles it using Jacobian +// addition with a.Z=1, and converts it back to affine coordinates. +// +// http://www.hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html#doubling-mdbl-2007-bl func (p *G2Affine) Double(a *G2Affine) *G2Affine { var q G2Jac q.FromAffine(a) @@ -133,7 +141,8 @@ func (p *G2Affine) Double(a *G2Affine) *G2Affine { return p } -// Sub subs two point in affine coordinates. +// Sub subtracts two points in affine coordinates. +// It uses a similar approach to Add, but negates the second point before adding. func (p *G2Affine) Sub(a, b *G2Affine) *G2Affine { var bneg G2Affine bneg.Neg(b) @@ -141,19 +150,19 @@ func (p *G2Affine) Sub(a, b *G2Affine) *G2Affine { return p } -// Equal tests if two points (in Affine coordinates) are equal +// Equal tests if two points in affine coordinates are equal. func (p *G2Affine) Equal(a *G2Affine) bool { return p.X.Equal(&a.X) && p.Y.Equal(&a.Y) } -// Neg computes -G +// Neg sets p to the affine negative point -a = (a.X, -a.Y). func (p *G2Affine) Neg(a *G2Affine) *G2Affine { p.X = a.X p.Y.Neg(&a.Y) return p } -// FromJacobian rescales a point in Jacobian coord in z=1 plane +// FromJacobian converts a point p1 from Jacobian to affine coordinates. func (p *G2Affine) FromJacobian(p1 *G2Jac) *G2Affine { var a, b fptower.E2 @@ -172,7 +181,7 @@ func (p *G2Affine) FromJacobian(p1 *G2Jac) *G2Affine { return p } -// String returns the string representation of the point or "O" if it is infinity +// String returns the string representation E(x,y) of the affine point p or "O" if it is infinity. func (p *G2Affine) String() string { if p.IsInfinity() { return "O" @@ -180,21 +189,20 @@ func (p *G2Affine) String() string { return "E([" + p.X.String() + "," + p.Y.String() + "])" } -// IsInfinity checks if the point is infinity -// in affine, it's encoded as (0,0) -// (0,0) is never on the curve for j=0 curves +// IsInfinity checks if the affine point p is infinity, which is encoded as (0,0). +// N.B.: (0,0) is never on the curve for j=0 curves (Y²=X³+B). func (p *G2Affine) IsInfinity() bool { return p.X.IsZero() && p.Y.IsZero() } -// IsOnCurve returns true if p in on the curve +// IsOnCurve returns true if the affine point p in on the curve. func (p *G2Affine) IsOnCurve() bool { var point G2Jac point.FromAffine(p) return point.IsOnCurve() // call this function to handle infinity point } -// IsInSubGroup returns true if p is in the correct subgroup, false otherwise +// IsInSubGroup returns true if the affine point p is in the correct subgroup, false otherwise. func (p *G2Affine) IsInSubGroup() bool { var _p G2Jac _p.FromAffine(p) @@ -202,84 +210,76 @@ func (p *G2Affine) IsInSubGroup() bool { } // ------------------------------------------------------------------------------------------------- -// Jacobian +// Jacobian coordinates -// Set sets p to the provided point -func (p *G2Jac) Set(a *G2Jac) *G2Jac { - p.X, p.Y, p.Z = a.X, a.Y, a.Z +// Set sets p to a in Jacobian coordinates. +func (p *G2Jac) Set(q *G2Jac) *G2Jac { + p.X, p.Y, p.Z = q.X, q.Y, q.Z return p } -// Equal tests if two points (in Jacobian coordinates) are equal -func (p *G2Jac) Equal(a *G2Jac) bool { +// Equal tests if two points in Jacobian coordinates are equal. +func (p *G2Jac) Equal(q *G2Jac) bool { // If one point is infinity, the other must also be infinity. if p.Z.IsZero() { - return a.Z.IsZero() + return q.Z.IsZero() } // If the other point is infinity, return false since we can't // the following checks would be incorrect. - if a.Z.IsZero() { + if q.Z.IsZero() { return false } var pZSquare, aZSquare fptower.E2 pZSquare.Square(&p.Z) - aZSquare.Square(&a.Z) + aZSquare.Square(&q.Z) var lhs, rhs fptower.E2 lhs.Mul(&p.X, &aZSquare) - rhs.Mul(&a.X, &pZSquare) + rhs.Mul(&q.X, &pZSquare) if !lhs.Equal(&rhs) { return false } - lhs.Mul(&p.Y, &aZSquare).Mul(&lhs, &a.Z) - rhs.Mul(&a.Y, &pZSquare).Mul(&rhs, &p.Z) + lhs.Mul(&p.Y, &aZSquare).Mul(&lhs, &q.Z) + rhs.Mul(&q.Y, &pZSquare).Mul(&rhs, &p.Z) return lhs.Equal(&rhs) } -// Neg computes -G -func (p *G2Jac) Neg(a *G2Jac) *G2Jac { - *p = *a - p.Y.Neg(&a.Y) - return p -} - -// SubAssign subtracts two points on the curve -func (p *G2Jac) SubAssign(a *G2Jac) *G2Jac { - var tmp G2Jac - tmp.Set(a) - tmp.Y.Neg(&tmp.Y) - p.AddAssign(&tmp) +// Neg sets p to the Jacobian negative point -q = (q.X, -q.Y, q.Z). +func (p *G2Jac) Neg(q *G2Jac) *G2Jac { + *p = *q + p.Y.Neg(&q.Y) return p } -// AddAssign point addition in montgomery form +// AddAssign sets p to p+a in Jacobian coordinates. +// // https://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-3.html#addition-add-2007-bl -func (p *G2Jac) AddAssign(a *G2Jac) *G2Jac { +func (p *G2Jac) AddAssign(q *G2Jac) *G2Jac { - // p is infinity, return a + // p is infinity, return q if p.Z.IsZero() { - p.Set(a) + p.Set(q) return p } - // a is infinity, return p - if a.Z.IsZero() { + // q is infinity, return p + if q.Z.IsZero() { return p } var Z1Z1, Z2Z2, U1, U2, S1, S2, H, I, J, r, V fptower.E2 - Z1Z1.Square(&a.Z) + Z1Z1.Square(&q.Z) Z2Z2.Square(&p.Z) - U1.Mul(&a.X, &Z2Z2) + U1.Mul(&q.X, &Z2Z2) U2.Mul(&p.X, &Z1Z1) - S1.Mul(&a.Y, &p.Z). + S1.Mul(&q.Y, &p.Z). Mul(&S1, &Z2Z2) - S2.Mul(&p.Y, &a.Z). + S2.Mul(&p.Y, &q.Z). Mul(&S2, &Z1Z1) - // if p == a, we double instead + // if p == q, we double instead if U1.Equal(&U2) && S1.Equal(&S2) { return p.DoubleAssign() } @@ -298,7 +298,7 @@ func (p *G2Jac) AddAssign(a *G2Jac) *G2Jac { Mul(&p.Y, &r) S1.Mul(&S1, &J).Double(&S1) p.Y.Sub(&p.Y, &S1) - p.Z.Add(&p.Z, &a.Z) + p.Z.Add(&p.Z, &q.Z) p.Z.Square(&p.Z). Sub(&p.Z, &Z1Z1). Sub(&p.Z, &Z2Z2). @@ -307,8 +307,19 @@ func (p *G2Jac) AddAssign(a *G2Jac) *G2Jac { return p } -// DoubleMixed point addition -// http://www.hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html#doubling-mdbl-2007-bl +// SubAssign sets p to p-a in Jacobian coordinates. +// It uses a similar approach to AddAssign, but negates the point a before adding. +func (p *G2Jac) SubAssign(q *G2Jac) *G2Jac { + var tmp G2Jac + tmp.Set(q) + tmp.Y.Neg(&tmp.Y) + p.AddAssign(&tmp) + return p +} + +// Double sets p to [2]q in Jacobian coordinates. +// +// https://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-3.html#doubling-dbl-2007-bl func (p *G2Jac) DoubleMixed(a *G2Affine) *G2Jac { var XX, YY, YYYY, S, M, T fptower.E2 XX.Square(&a.X) @@ -320,7 +331,7 @@ func (p *G2Jac) DoubleMixed(a *G2Affine) *G2Jac { Sub(&S, &YYYY). Double(&S) M.Double(&XX). - Add(&M, &XX) // -> + a, but a=0 here + Add(&M, &XX) // -> + A, but A=0 here T.Square(&M). Sub(&T, &S). Sub(&T, &S) @@ -336,7 +347,8 @@ func (p *G2Jac) DoubleMixed(a *G2Affine) *G2Jac { return p } -// AddMixed point addition +// AddMixed sets p to p+a in Jacobian coordinates, where a.Z = 1. +// // http://www.hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html#addition-madd-2007-bl func (p *G2Jac) AddMixed(a *G2Affine) *G2Jac { @@ -385,7 +397,8 @@ func (p *G2Jac) AddMixed(a *G2Affine) *G2Jac { return p } -// Double doubles a point in Jacobian coordinates +// Double sets p to [2]q in Jacobian coordinates. +// // https://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-3.html#doubling-dbl-2007-bl func (p *G2Jac) Double(q *G2Jac) *G2Jac { p.Set(q) @@ -393,7 +406,8 @@ func (p *G2Jac) Double(q *G2Jac) *G2Jac { return p } -// DoubleAssign doubles a point in Jacobian coordinates +// DoubleAssign doubles p in Jacobian coordinates. +// // https://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-3.html#doubling-dbl-2007-bl func (p *G2Jac) DoubleAssign() *G2Jac { @@ -425,34 +439,36 @@ func (p *G2Jac) DoubleAssign() *G2Jac { return p } -// ScalarMultiplication computes and returns p = a ⋅ s +// ScalarMultiplication computes and returns p = [s]a +// where p and a are Jacobian points. +// using the GLV technique. // see https://www.iacr.org/archive/crypto2001/21390189.pdf -func (p *G2Jac) ScalarMultiplication(a *G2Jac, s *big.Int) *G2Jac { - return p.mulGLV(a, s) +func (p *G2Jac) ScalarMultiplication(q *G2Jac, s *big.Int) *G2Jac { + return p.mulGLV(q, s) } -// String returns canonical representation of the point in affine coordinates +// String converts p to affine coordinates and returns its string representation E(x,y) or "O" if it is infinity. func (p *G2Jac) String() string { _p := G2Affine{} _p.FromJacobian(p) return _p.String() } -// FromAffine sets p = Q, p in Jacobian, Q in affine -func (p *G2Jac) FromAffine(Q *G2Affine) *G2Jac { - if Q.IsInfinity() { +// FromAffine converts a point a from affine to Jacobian coordinates. +func (p *G2Jac) FromAffine(a *G2Affine) *G2Jac { + if a.IsInfinity() { p.Z.SetZero() p.X.SetOne() p.Y.SetOne() return p } p.Z.SetOne() - p.X.Set(&Q.X) - p.Y.Set(&Q.Y) + p.X.Set(&a.X) + p.Y.Set(&a.Y) return p } -// IsOnCurve returns true if p in on the curve +// IsOnCurve returns true if the Jacobian point p in on the curve. func (p *G2Jac) IsOnCurve() bool { var left, right, tmp, ZZ fptower.E2 left.Square(&p.Y) @@ -476,13 +492,14 @@ func (p *G2Jac) IsInSubGroup() bool { return res.IsOnCurve() && res.Z.IsZero() } -// mulWindowed computes a 2-bits windowed scalar multiplication -func (p *G2Jac) mulWindowed(a *G2Jac, s *big.Int) *G2Jac { +// mulWindowed computes the 2-bits windowed double-and-add scalar +// multiplication p=[s]q in Jacobian coordinates. +func (p *G2Jac) mulWindowed(q *G2Jac, s *big.Int) *G2Jac { var res G2Jac var ops [3]G2Jac - ops[0].Set(a) + ops[0].Set(q) if s.Sign() == -1 { ops[0].Neg(&ops[0]) } @@ -509,26 +526,27 @@ func (p *G2Jac) mulWindowed(a *G2Jac, s *big.Int) *G2Jac { } -// ψ(p) = u o π o u⁻¹ where u:E'→E iso from the twist to E -func (p *G2Jac) psi(a *G2Jac) *G2Jac { - p.Set(a) +// psi sets p to ψ(q) = u o π o u⁻¹ where u:E'→E is the isomorphism from the twist to the curve E and π is the Frobenius map. +func (p *G2Jac) psi(q *G2Jac) *G2Jac { + p.Set(q) p.X.Conjugate(&p.X).Mul(&p.X, &endo.u) p.Y.Conjugate(&p.Y).Mul(&p.Y, &endo.v) p.Z.Conjugate(&p.Z) return p } -// ϕ assigns p to ϕ(a) where ϕ: (x,y) → (w x,y), and returns p -// where w is a third root of unity in 𝔽p -func (p *G2Jac) phi(a *G2Jac) *G2Jac { - p.Set(a) +// phi sets p to ϕ(a) where ϕ: (x,y) → (w x,y), +// where w is a third root of unity. +func (p *G2Jac) phi(q *G2Jac) *G2Jac { + p.Set(q) p.X.MulByElement(&p.X, &thirdRootOneG2) return p } // mulGLV computes the scalar multiplication using a windowed-GLV method +// // see https://www.iacr.org/archive/crypto2001/21390189.pdf -func (p *G2Jac) mulGLV(a *G2Jac, s *big.Int) *G2Jac { +func (p *G2Jac) mulGLV(q *G2Jac, s *big.Int) *G2Jac { var table [15]G2Jac var res G2Jac @@ -536,11 +554,11 @@ func (p *G2Jac) mulGLV(a *G2Jac, s *big.Int) *G2Jac { res.Set(&g2Infinity) - // table[b3b2b1b0-1] = b3b2 ⋅ ϕ(a) + b1b0*a - table[0].Set(a) - table[3].phi(a) + // table[b3b2b1b0-1] = b3b2 ⋅ ϕ(q) + b1b0*q + table[0].Set(q) + table[3].phi(q) - // split the scalar, modifies ±a, ϕ(a) accordingly + // split the scalar, modifies ±q, ϕ(q) accordingly k := ecc.SplitScalar(s, &glvBasis) if k[0].Sign() == -1 { @@ -553,7 +571,7 @@ func (p *G2Jac) mulGLV(a *G2Jac, s *big.Int) *G2Jac { } // precompute table (2 bits sliding window) - // table[b3b2b1b0-1] = b3b2 ⋅ ϕ(a) + b1b0 ⋅ a if b3b2b1b0 != 0 + // table[b3b2b1b0-1] = b3b2 ⋅ ϕ(q) + b1b0 ⋅ q if b3b2b1b0 != 0 table[1].Double(&table[0]) table[2].Set(&table[1]).AddAssign(&table[0]) table[4].Set(&table[3]).AddAssign(&table[0]) @@ -609,23 +627,23 @@ func (p *G2Affine) ClearCofactor(a *G2Affine) *G2Affine { } // ClearCofactor maps a point in curve to r-torsion -func (p *G2Jac) ClearCofactor(a *G2Jac) *G2Jac { +func (p *G2Jac) ClearCofactor(q *G2Jac) *G2Jac { // https://eprint.iacr.org/2017/419.pdf, 4.1 var xg, xxg, res, t G2Jac - xg.ScalarMultiplication(a, &xGen) + xg.ScalarMultiplication(q, &xGen) xxg.ScalarMultiplication(&xg, &xGen) res.Set(&xxg). SubAssign(&xg). - SubAssign(a) + SubAssign(q) t.Set(&xg). - SubAssign(a). + SubAssign(q). psi(&t) res.AddAssign(&t) - t.Double(a) + t.Double(q) t.X.MulByElement(&t.X, &thirdRootOneG1) res.SubAssign(&t) @@ -637,15 +655,15 @@ func (p *G2Jac) ClearCofactor(a *G2Jac) *G2Jac { } // ------------------------------------------------------------------------------------------------- -// Jacobian extended +// extended Jacobian coordinates -// Set sets p to the provided point -func (p *g2JacExtended) Set(a *g2JacExtended) *g2JacExtended { - p.X, p.Y, p.ZZ, p.ZZZ = a.X, a.Y, a.ZZ, a.ZZZ +// Set sets p to a in extended Jacobian coordinates. +func (p *g2JacExtended) Set(q *g2JacExtended) *g2JacExtended { + p.X, p.Y, p.ZZ, p.ZZZ = q.X, q.Y, q.ZZ, q.ZZZ return p } -// setInfinity sets p to O +// setInfinity sets p to the infinity point (1,1,0,0). func (p *g2JacExtended) setInfinity() *g2JacExtended { p.X.SetOne() p.Y.SetOne() @@ -654,43 +672,45 @@ func (p *g2JacExtended) setInfinity() *g2JacExtended { return p } -func (p *g2JacExtended) IsZero() bool { +// IsInfinity checks if the p is infinity, i.e. p.ZZ=0. +func (p *g2JacExtended) IsInfinity() bool { return p.ZZ.IsZero() } -// fromJacExtended sets Q in affine coordinates -func (p *G2Affine) fromJacExtended(Q *g2JacExtended) *G2Affine { - if Q.ZZ.IsZero() { +// fromJacExtended converts an extended Jacobian point to an affine point. +func (p *G2Affine) fromJacExtended(q *g2JacExtended) *G2Affine { + if q.ZZ.IsZero() { p.X = fptower.E2{} p.Y = fptower.E2{} return p } - p.X.Inverse(&Q.ZZ).Mul(&p.X, &Q.X) - p.Y.Inverse(&Q.ZZZ).Mul(&p.Y, &Q.Y) + p.X.Inverse(&q.ZZ).Mul(&p.X, &q.X) + p.Y.Inverse(&q.ZZZ).Mul(&p.Y, &q.Y) return p } -// fromJacExtended sets Q in Jacobian coordinates -func (p *G2Jac) fromJacExtended(Q *g2JacExtended) *G2Jac { - if Q.ZZ.IsZero() { +// fromJacExtended converts an extended Jacobian point to a Jacobian point. +func (p *G2Jac) fromJacExtended(q *g2JacExtended) *G2Jac { + if q.ZZ.IsZero() { p.Set(&g2Infinity) return p } - p.X.Mul(&Q.ZZ, &Q.X).Mul(&p.X, &Q.ZZ) - p.Y.Mul(&Q.ZZZ, &Q.Y).Mul(&p.Y, &Q.ZZZ) - p.Z.Set(&Q.ZZZ) + p.X.Mul(&q.ZZ, &q.X).Mul(&p.X, &q.ZZ) + p.Y.Mul(&q.ZZZ, &q.Y).Mul(&p.Y, &q.ZZZ) + p.Z.Set(&q.ZZZ) return p } -// unsafeFromJacExtended sets p in Jacobian coordinates, but don't check for infinity -func (p *G2Jac) unsafeFromJacExtended(Q *g2JacExtended) *G2Jac { - p.X.Square(&Q.ZZ).Mul(&p.X, &Q.X) - p.Y.Square(&Q.ZZZ).Mul(&p.Y, &Q.Y) - p.Z = Q.ZZZ +// unsafeFromJacExtended converts an extended Jacobian point, distinct from Infinity, to a Jacobian point. +func (p *G2Jac) unsafeFromJacExtended(q *g2JacExtended) *G2Jac { + p.X.Square(&q.ZZ).Mul(&p.X, &q.X) + p.Y.Square(&q.ZZZ).Mul(&p.Y, &q.Y) + p.Z = q.ZZZ return p } -// add point in Jacobian extended coordinates +// add sets p to p+q in extended Jacobian coordinates. +// // https://www.hyperelliptic.org/EFD/g1p/auto-shortw-xyzz.html#addition-add-2008-s func (p *g2JacExtended) add(q *g2JacExtended) *g2JacExtended { //if q is infinity return p @@ -746,10 +766,11 @@ func (p *g2JacExtended) add(q *g2JacExtended) *g2JacExtended { return p } -// double point in Jacobian extended coordinates +// double sets p to [2]q in Jacobian extended coordinates. +// // http://www.hyperelliptic.org/EFD/g1p/auto-shortw-xyzz.html#doubling-dbl-2008-s-1 -// since we consider any point on Z=0 as the point at infinity -// this doubling formula works for infinity points as well +// N.B.: since we consider any point on Z=0 as the point at infinity +// this doubling formula works for infinity points as well. func (p *g2JacExtended) double(q *g2JacExtended) *g2JacExtended { var U, V, W, S, XX, M fptower.E2 @@ -759,7 +780,7 @@ func (p *g2JacExtended) double(q *g2JacExtended) *g2JacExtended { S.Mul(&q.X, &V) XX.Square(&q.X) M.Double(&XX). - Add(&M, &XX) // -> + a, but a=0 here + Add(&M, &XX) // -> + A, but A=0 here U.Mul(&W, &q.Y) p.X.Square(&M). @@ -774,9 +795,10 @@ func (p *g2JacExtended) double(q *g2JacExtended) *g2JacExtended { return p } -// subMixed same as addMixed, but will negate a.Y +// addMixed sets p to p+q in extended Jacobian coordinates, where a.ZZ=1. +// // http://www.hyperelliptic.org/EFD/g1p/auto-shortw-xyzz.html#addition-madd-2008-s -func (p *g2JacExtended) subMixed(a *G2Affine) *g2JacExtended { +func (p *g2JacExtended) addMixed(a *G2Affine) *g2JacExtended { //if a is infinity return p if a.IsInfinity() { @@ -785,7 +807,7 @@ func (p *g2JacExtended) subMixed(a *G2Affine) *g2JacExtended { // p is infinity, return a if p.ZZ.IsZero() { p.X = a.X - p.Y.Neg(&a.Y) + p.Y = a.Y p.ZZ.SetOne() p.ZZZ.SetOne() return p @@ -798,12 +820,11 @@ func (p *g2JacExtended) subMixed(a *G2Affine) *g2JacExtended { P.Sub(&P, &p.X) R.Mul(&a.Y, &p.ZZZ) - R.Neg(&R) R.Sub(&R, &p.Y) if P.IsZero() { if R.IsZero() { - return p.doubleNegMixed(a) + return p.doubleMixed(a) } p.ZZ = fptower.E2{} @@ -830,9 +851,10 @@ func (p *g2JacExtended) subMixed(a *G2Affine) *g2JacExtended { } -// addMixed +// subMixed works the same as addMixed, but negates a.Y. +// // http://www.hyperelliptic.org/EFD/g1p/auto-shortw-xyzz.html#addition-madd-2008-s -func (p *g2JacExtended) addMixed(a *G2Affine) *g2JacExtended { +func (p *g2JacExtended) subMixed(a *G2Affine) *g2JacExtended { //if a is infinity return p if a.IsInfinity() { @@ -841,7 +863,7 @@ func (p *g2JacExtended) addMixed(a *G2Affine) *g2JacExtended { // p is infinity, return a if p.ZZ.IsZero() { p.X = a.X - p.Y = a.Y + p.Y.Neg(&a.Y) p.ZZ.SetOne() p.ZZZ.SetOne() return p @@ -854,11 +876,12 @@ func (p *g2JacExtended) addMixed(a *G2Affine) *g2JacExtended { P.Sub(&P, &p.X) R.Mul(&a.Y, &p.ZZZ) + R.Neg(&R) R.Sub(&R, &p.Y) if P.IsZero() { if R.IsZero() { - return p.doubleMixed(a) + return p.doubleNegMixed(a) } p.ZZ = fptower.E2{} @@ -885,21 +908,21 @@ func (p *g2JacExtended) addMixed(a *G2Affine) *g2JacExtended { } -// doubleNegMixed same as double, but will negate q.Y -func (p *g2JacExtended) doubleNegMixed(q *G2Affine) *g2JacExtended { +// doubleNegMixed works the same as double, but negates q.Y. +func (p *g2JacExtended) doubleNegMixed(a *G2Affine) *g2JacExtended { var U, V, W, S, XX, M, S2, L fptower.E2 - U.Double(&q.Y) + U.Double(&a.Y) U.Neg(&U) V.Square(&U) W.Mul(&U, &V) - S.Mul(&q.X, &V) - XX.Square(&q.X) + S.Mul(&a.X, &V) + XX.Square(&a.X) M.Double(&XX). - Add(&M, &XX) // -> + a, but a=0 here + Add(&M, &XX) // -> + A, but A=0 here S2.Double(&S) - L.Mul(&W, &q.Y) + L.Mul(&W, &a.Y) p.X.Square(&M). Sub(&p.X, &S2) @@ -912,21 +935,22 @@ func (p *g2JacExtended) doubleNegMixed(q *G2Affine) *g2JacExtended { return p } -// doubleMixed point in Jacobian extended coordinates +// doubleMixed sets p to [2]a in Jacobian extended coordinates, where a.ZZ=1. +// // http://www.hyperelliptic.org/EFD/g1p/auto-shortw-xyzz.html#doubling-dbl-2008-s-1 -func (p *g2JacExtended) doubleMixed(q *G2Affine) *g2JacExtended { +func (p *g2JacExtended) doubleMixed(a *G2Affine) *g2JacExtended { var U, V, W, S, XX, M, S2, L fptower.E2 - U.Double(&q.Y) + U.Double(&a.Y) V.Square(&U) W.Mul(&U, &V) - S.Mul(&q.X, &V) - XX.Square(&q.X) + S.Mul(&a.X, &V) + XX.Square(&a.X) M.Double(&XX). - Add(&M, &XX) // -> + a, but a=0 here + Add(&M, &XX) // -> + A, but A=0 here S2.Double(&S) - L.Mul(&W, &q.Y) + L.Mul(&W, &a.Y) p.X.Square(&M). Sub(&p.X, &S2) @@ -940,38 +964,38 @@ func (p *g2JacExtended) doubleMixed(q *G2Affine) *g2JacExtended { } // ------------------------------------------------------------------------------------------------- -// Homogenous projective +// Homogenous projective coordinates -// Set sets p to the provided point -func (p *g2Proj) Set(a *g2Proj) *g2Proj { - p.x, p.y, p.z = a.x, a.y, a.z +// Set sets p to a in projective coordinates. +func (p *g2Proj) Set(q *g2Proj) *g2Proj { + p.x, p.y, p.z = q.x, q.y, q.z return p } -// Neg computes -G -func (p *g2Proj) Neg(a *g2Proj) *g2Proj { - *p = *a - p.y.Neg(&a.y) +// Neg sets p to the projective negative point -q = (q.X, -q.Y). +func (p *g2Proj) Neg(q *g2Proj) *g2Proj { + *p = *q + p.y.Neg(&q.y) return p } -// FromAffine sets p = Q, p in homogenous projective, Q in affine -func (p *g2Proj) FromAffine(Q *G2Affine) *g2Proj { - if Q.X.IsZero() && Q.Y.IsZero() { +// FromAffine converts q in affine to p in projective coordinates. +func (p *g2Proj) FromAffine(a *G2Affine) *g2Proj { + if a.X.IsZero() && a.Y.IsZero() { p.z.SetZero() p.x.SetOne() p.y.SetOne() return p } p.z.SetOne() - p.x.Set(&Q.X) - p.y.Set(&Q.Y) + p.x.Set(&a.X) + p.y.Set(&a.Y) return p } // BatchScalarMultiplicationG2 multiplies the same base by all scalars // and return resulting points in affine coordinates -// uses a simple windowed-NAF like exponentiation algorithm +// uses a simple windowed-NAF-like multiplication algorithm. func BatchScalarMultiplicationG2(base *G2Affine, scalars []fr.Element) []G2Affine { // approximate cost in group ops is // cost = 2^{c-1} + n(scalar.nbBits+nbChunks) @@ -1050,9 +1074,8 @@ func BatchScalarMultiplicationG2(base *G2Affine, scalars []fr.Element) []G2Affin return toReturn } -// batch add affine coordinates -// using batch inversion -// special cases (doubling, infinity) must be filtered out before this call +// batchAddG1Affine adds affine points using the Montgomery batch inversion trick. +// Special cases (doubling, infinity) must be filtered out before this call. func batchAddG2Affine[TP pG2Affine, TPP ppG2Affine, TC cG2Affine](R *TPP, P *TP, batchSize int) { var lambda, lambdain TC diff --git a/ecc/bls12-377/multiexp_affine.go b/ecc/bls12-377/multiexp_affine.go index 422862c77..0711888e0 100644 --- a/ecc/bls12-377/multiexp_affine.go +++ b/ecc/bls12-377/multiexp_affine.go @@ -226,7 +226,7 @@ func processChunkG1BatchAffine[BJE ibg1JacExtended, B ibG1Affine, BS bitSet, TP total.setInfinity() for k := len(buckets) - 1; k >= 0; k-- { runningSum.addMixed(&buckets[k]) - if !bucketsJE[k].IsZero() { + if !bucketsJE[k].IsInfinity() { runningSum.add(&bucketsJE[k]) } total.add(&runningSum) @@ -554,7 +554,7 @@ func processChunkG2BatchAffine[BJE ibg2JacExtended, B ibG2Affine, BS bitSet, TP total.setInfinity() for k := len(buckets) - 1; k >= 0; k-- { runningSum.addMixed(&buckets[k]) - if !bucketsJE[k].IsZero() { + if !bucketsJE[k].IsInfinity() { runningSum.add(&bucketsJE[k]) } total.add(&runningSum) diff --git a/ecc/bls12-377/multiexp_jacobian.go b/ecc/bls12-377/multiexp_jacobian.go index 0df516f5b..9b2c3d2e2 100644 --- a/ecc/bls12-377/multiexp_jacobian.go +++ b/ecc/bls12-377/multiexp_jacobian.go @@ -56,7 +56,7 @@ func processChunkG1Jacobian[B ibg1JacExtended](chunk uint64, runningSum.setInfinity() total.setInfinity() for k := len(buckets) - 1; k >= 0; k-- { - if !buckets[k].IsZero() { + if !buckets[k].IsInfinity() { runningSum.add(&buckets[k]) } total.add(&runningSum) @@ -145,7 +145,7 @@ func processChunkG2Jacobian[B ibg2JacExtended](chunk uint64, runningSum.setInfinity() total.setInfinity() for k := len(buckets) - 1; k >= 0; k-- { - if !buckets[k].IsZero() { + if !buckets[k].IsInfinity() { runningSum.add(&buckets[k]) } total.add(&runningSum) diff --git a/ecc/bls12-378/g1.go b/ecc/bls12-378/g1.go index 10360478d..690aba6a1 100644 --- a/ecc/bls12-378/g1.go +++ b/ecc/bls12-378/g1.go @@ -25,38 +25,40 @@ import ( "runtime" ) -// G1Affine point in affine coordinates +// G1Affine is a point in affine coordinates (x,y) type G1Affine struct { X, Y fp.Element } -// G1Jac is a point with fp.Element coordinates +// G1Jac is a point in Jacobian coordinates (x=X/Z², y=Y/Z³) type G1Jac struct { X, Y, Z fp.Element } -// g1JacExtended parameterized Jacobian coordinates (x=X/ZZ, y=Y/ZZZ, ZZ³=ZZZ²) +// g1JacExtended is a point in extended Jacobian coordinates (x=X/ZZ, y=Y/ZZZ, ZZ³=ZZZ²) type g1JacExtended struct { X, Y, ZZ, ZZZ fp.Element } // ------------------------------------------------------------------------------------------------- -// Affine +// Affine coordinates -// Set sets p to the provided point +// Set sets p to a in affine coordinates. func (p *G1Affine) Set(a *G1Affine) *G1Affine { p.X, p.Y = a.X, a.Y return p } -// setInfinity sets p to O +// setInfinity sets p to the infinity point, which is encoded as (0,0). +// N.B.: (0,0) is never on the curve for j=0 curves (Y²=X³+B). func (p *G1Affine) setInfinity() *G1Affine { p.X.SetZero() p.Y.SetZero() return p } -// ScalarMultiplication computes and returns p = a ⋅ s +// ScalarMultiplication computes and returns p = [s]a +// where p and a are affine points. func (p *G1Affine) ScalarMultiplication(a *G1Affine, s *big.Int) *G1Affine { var _p G1Jac _p.FromAffine(a) @@ -65,20 +67,22 @@ func (p *G1Affine) ScalarMultiplication(a *G1Affine, s *big.Int) *G1Affine { return p } -// ScalarMultiplicationAffine computes and returns p = a ⋅ s -// Takes an affine point and returns a Jacobian point (useful for KZG) +// ScalarMultiplicationAffine computes and returns p = [s]a +// where a is an affine point and p a Jacobian point (useful for KZG). func (p *G1Jac) ScalarMultiplicationAffine(a *G1Affine, s *big.Int) *G1Jac { p.FromAffine(a) p.mulGLV(p, s) return p } -// ScalarMultiplicationBase computes and returns p = g ⋅ s where g is the prime subgroup generator +// ScalarMultiplicationBase computes and returns p = [s]g +// where g is the Jacobian point generating the prime subgroup. func (p *G1Jac) ScalarMultiplicationBase(s *big.Int) *G1Jac { return p.mulGLV(&g1Gen, s) } -// ScalarMultiplicationBase computes and returns p = g ⋅ s where g is the prime subgroup generator +// ScalarMultiplicationBase computes and returns p = [s]g +// where g is the affine point generating the prime subgroup. func (p *G1Affine) ScalarMultiplicationBase(s *big.Int) *G1Affine { var _p G1Jac _p.mulGLV(&g1Gen, s) @@ -86,8 +90,9 @@ func (p *G1Affine) ScalarMultiplicationBase(s *big.Int) *G1Affine { return p } -// Add adds two point in affine coordinates. -// Jacobian addition with Z1=Z2=1 +// Add adds two points in affine coordinates. +// It uses the Jacobian addition with a.Z=b.Z=1 and converts the result to affine coordinates. +// // https://www.hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html#addition-mmadd-2007-bl func (p *G1Affine) Add(a, b *G1Affine) *G1Affine { var q G1Jac @@ -133,6 +138,10 @@ func (p *G1Affine) Add(a, b *G1Affine) *G1Affine { } // Double doubles a point in affine coordinates. +// It converts the point to Jacobian coordinates, doubles it using Jacobian +// addition with a.Z=1, and converts it back to affine coordinates. +// +// http://www.hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html#doubling-mdbl-2007-bl func (p *G1Affine) Double(a *G1Affine) *G1Affine { var q G1Jac q.FromAffine(a) @@ -141,7 +150,8 @@ func (p *G1Affine) Double(a *G1Affine) *G1Affine { return p } -// Sub subs two point in affine coordinates. +// Sub subtracts two points in affine coordinates. +// It uses a similar approach to Add, but negates the second point before adding. func (p *G1Affine) Sub(a, b *G1Affine) *G1Affine { var bneg G1Affine bneg.Neg(b) @@ -149,19 +159,19 @@ func (p *G1Affine) Sub(a, b *G1Affine) *G1Affine { return p } -// Equal tests if two points (in Affine coordinates) are equal +// Equal tests if two points in affine coordinates are equal. func (p *G1Affine) Equal(a *G1Affine) bool { return p.X.Equal(&a.X) && p.Y.Equal(&a.Y) } -// Neg computes -G +// Neg sets p to the affine negative point -a = (a.X, -a.Y). func (p *G1Affine) Neg(a *G1Affine) *G1Affine { p.X = a.X p.Y.Neg(&a.Y) return p } -// FromJacobian rescales a point in Jacobian coord in z=1 plane +// FromJacobian converts a point p1 from Jacobian to affine coordinates. func (p *G1Affine) FromJacobian(p1 *G1Jac) *G1Affine { var a, b fp.Element @@ -180,7 +190,7 @@ func (p *G1Affine) FromJacobian(p1 *G1Jac) *G1Affine { return p } -// String returns the string representation of the point or "O" if it is infinity +// String returns the string representation E(x,y) of the affine point p or "O" if it is infinity. func (p *G1Affine) String() string { if p.IsInfinity() { return "O" @@ -188,21 +198,20 @@ func (p *G1Affine) String() string { return "E([" + p.X.String() + "," + p.Y.String() + "])" } -// IsInfinity checks if the point is infinity -// in affine, it's encoded as (0,0) -// (0,0) is never on the curve for j=0 curves +// IsInfinity checks if the affine point p is infinity, which is encoded as (0,0). +// N.B.: (0,0) is never on the curve for j=0 curves (Y²=X³+B). func (p *G1Affine) IsInfinity() bool { return p.X.IsZero() && p.Y.IsZero() } -// IsOnCurve returns true if p in on the curve +// IsOnCurve returns true if the affine point p in on the curve. func (p *G1Affine) IsOnCurve() bool { var point G1Jac point.FromAffine(p) return point.IsOnCurve() // call this function to handle infinity point } -// IsInSubGroup returns true if p is in the correct subgroup, false otherwise +// IsInSubGroup returns true if the affine point p is in the correct subgroup, false otherwise. func (p *G1Affine) IsInSubGroup() bool { var _p G1Jac _p.FromAffine(p) @@ -210,84 +219,76 @@ func (p *G1Affine) IsInSubGroup() bool { } // ------------------------------------------------------------------------------------------------- -// Jacobian +// Jacobian coordinates -// Set sets p to the provided point -func (p *G1Jac) Set(a *G1Jac) *G1Jac { - p.X, p.Y, p.Z = a.X, a.Y, a.Z +// Set sets p to a in Jacobian coordinates. +func (p *G1Jac) Set(q *G1Jac) *G1Jac { + p.X, p.Y, p.Z = q.X, q.Y, q.Z return p } -// Equal tests if two points (in Jacobian coordinates) are equal -func (p *G1Jac) Equal(a *G1Jac) bool { +// Equal tests if two points in Jacobian coordinates are equal. +func (p *G1Jac) Equal(q *G1Jac) bool { // If one point is infinity, the other must also be infinity. if p.Z.IsZero() { - return a.Z.IsZero() + return q.Z.IsZero() } // If the other point is infinity, return false since we can't // the following checks would be incorrect. - if a.Z.IsZero() { + if q.Z.IsZero() { return false } var pZSquare, aZSquare fp.Element pZSquare.Square(&p.Z) - aZSquare.Square(&a.Z) + aZSquare.Square(&q.Z) var lhs, rhs fp.Element lhs.Mul(&p.X, &aZSquare) - rhs.Mul(&a.X, &pZSquare) + rhs.Mul(&q.X, &pZSquare) if !lhs.Equal(&rhs) { return false } - lhs.Mul(&p.Y, &aZSquare).Mul(&lhs, &a.Z) - rhs.Mul(&a.Y, &pZSquare).Mul(&rhs, &p.Z) + lhs.Mul(&p.Y, &aZSquare).Mul(&lhs, &q.Z) + rhs.Mul(&q.Y, &pZSquare).Mul(&rhs, &p.Z) return lhs.Equal(&rhs) } -// Neg computes -G -func (p *G1Jac) Neg(a *G1Jac) *G1Jac { - *p = *a - p.Y.Neg(&a.Y) +// Neg sets p to the Jacobian negative point -q = (q.X, -q.Y, q.Z). +func (p *G1Jac) Neg(q *G1Jac) *G1Jac { + *p = *q + p.Y.Neg(&q.Y) return p } -// SubAssign subtracts two points on the curve -func (p *G1Jac) SubAssign(a *G1Jac) *G1Jac { - var tmp G1Jac - tmp.Set(a) - tmp.Y.Neg(&tmp.Y) - p.AddAssign(&tmp) - return p -} - -// AddAssign point addition in montgomery form +// AddAssign sets p to p+a in Jacobian coordinates. +// // https://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-3.html#addition-add-2007-bl -func (p *G1Jac) AddAssign(a *G1Jac) *G1Jac { +func (p *G1Jac) AddAssign(q *G1Jac) *G1Jac { - // p is infinity, return a + // p is infinity, return q if p.Z.IsZero() { - p.Set(a) + p.Set(q) return p } - // a is infinity, return p - if a.Z.IsZero() { + // q is infinity, return p + if q.Z.IsZero() { return p } var Z1Z1, Z2Z2, U1, U2, S1, S2, H, I, J, r, V fp.Element - Z1Z1.Square(&a.Z) + Z1Z1.Square(&q.Z) Z2Z2.Square(&p.Z) - U1.Mul(&a.X, &Z2Z2) + U1.Mul(&q.X, &Z2Z2) U2.Mul(&p.X, &Z1Z1) - S1.Mul(&a.Y, &p.Z). + S1.Mul(&q.Y, &p.Z). Mul(&S1, &Z2Z2) - S2.Mul(&p.Y, &a.Z). + S2.Mul(&p.Y, &q.Z). Mul(&S2, &Z1Z1) - // if p == a, we double instead + // if p == q, we double instead if U1.Equal(&U2) && S1.Equal(&S2) { return p.DoubleAssign() } @@ -306,7 +307,7 @@ func (p *G1Jac) AddAssign(a *G1Jac) *G1Jac { Mul(&p.Y, &r) S1.Mul(&S1, &J).Double(&S1) p.Y.Sub(&p.Y, &S1) - p.Z.Add(&p.Z, &a.Z) + p.Z.Add(&p.Z, &q.Z) p.Z.Square(&p.Z). Sub(&p.Z, &Z1Z1). Sub(&p.Z, &Z2Z2). @@ -315,8 +316,19 @@ func (p *G1Jac) AddAssign(a *G1Jac) *G1Jac { return p } -// DoubleMixed point addition -// http://www.hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html#doubling-mdbl-2007-bl +// SubAssign sets p to p-a in Jacobian coordinates. +// It uses a similar approach to AddAssign, but negates the point a before adding. +func (p *G1Jac) SubAssign(q *G1Jac) *G1Jac { + var tmp G1Jac + tmp.Set(q) + tmp.Y.Neg(&tmp.Y) + p.AddAssign(&tmp) + return p +} + +// Double sets p to [2]q in Jacobian coordinates. +// +// https://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-3.html#doubling-dbl-2007-bl func (p *G1Jac) DoubleMixed(a *G1Affine) *G1Jac { var XX, YY, YYYY, S, M, T fp.Element XX.Square(&a.X) @@ -328,7 +340,7 @@ func (p *G1Jac) DoubleMixed(a *G1Affine) *G1Jac { Sub(&S, &YYYY). Double(&S) M.Double(&XX). - Add(&M, &XX) // -> + a, but a=0 here + Add(&M, &XX) // -> + A, but A=0 here T.Square(&M). Sub(&T, &S). Sub(&T, &S) @@ -344,7 +356,8 @@ func (p *G1Jac) DoubleMixed(a *G1Affine) *G1Jac { return p } -// AddMixed point addition +// AddMixed sets p to p+a in Jacobian coordinates, where a.Z = 1. +// // http://www.hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html#addition-madd-2007-bl func (p *G1Jac) AddMixed(a *G1Affine) *G1Jac { @@ -393,7 +406,8 @@ func (p *G1Jac) AddMixed(a *G1Affine) *G1Jac { return p } -// Double doubles a point in Jacobian coordinates +// Double sets p to [2]q in Jacobian coordinates. +// // https://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-3.html#doubling-dbl-2007-bl func (p *G1Jac) Double(q *G1Jac) *G1Jac { p.Set(q) @@ -401,7 +415,8 @@ func (p *G1Jac) Double(q *G1Jac) *G1Jac { return p } -// DoubleAssign doubles a point in Jacobian coordinates +// DoubleAssign doubles p in Jacobian coordinates. +// // https://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-3.html#doubling-dbl-2007-bl func (p *G1Jac) DoubleAssign() *G1Jac { @@ -433,34 +448,36 @@ func (p *G1Jac) DoubleAssign() *G1Jac { return p } -// ScalarMultiplication computes and returns p = a ⋅ s +// ScalarMultiplication computes and returns p = [s]a +// where p and a are Jacobian points. +// using the GLV technique. // see https://www.iacr.org/archive/crypto2001/21390189.pdf -func (p *G1Jac) ScalarMultiplication(a *G1Jac, s *big.Int) *G1Jac { - return p.mulGLV(a, s) +func (p *G1Jac) ScalarMultiplication(q *G1Jac, s *big.Int) *G1Jac { + return p.mulGLV(q, s) } -// String returns canonical representation of the point in affine coordinates +// String converts p to affine coordinates and returns its string representation E(x,y) or "O" if it is infinity. func (p *G1Jac) String() string { _p := G1Affine{} _p.FromJacobian(p) return _p.String() } -// FromAffine sets p = Q, p in Jacobian, Q in affine -func (p *G1Jac) FromAffine(Q *G1Affine) *G1Jac { - if Q.IsInfinity() { +// FromAffine converts a point a from affine to Jacobian coordinates. +func (p *G1Jac) FromAffine(a *G1Affine) *G1Jac { + if a.IsInfinity() { p.Z.SetZero() p.X.SetOne() p.Y.SetOne() return p } p.Z.SetOne() - p.X.Set(&Q.X) - p.Y.Set(&Q.Y) + p.X.Set(&a.X) + p.Y.Set(&a.Y) return p } -// IsOnCurve returns true if p in on the curve +// IsOnCurve returns true if the Jacobian point p in on the curve. func (p *G1Jac) IsOnCurve() bool { var left, right, tmp, ZZ fp.Element left.Square(&p.Y) @@ -491,13 +508,14 @@ func (p *G1Jac) IsInSubGroup() bool { } -// mulWindowed computes a 2-bits windowed scalar multiplication -func (p *G1Jac) mulWindowed(a *G1Jac, s *big.Int) *G1Jac { +// mulWindowed computes the 2-bits windowed double-and-add scalar +// multiplication p=[s]q in Jacobian coordinates. +func (p *G1Jac) mulWindowed(q *G1Jac, s *big.Int) *G1Jac { var res G1Jac var ops [3]G1Jac - ops[0].Set(a) + ops[0].Set(q) if s.Sign() == -1 { ops[0].Neg(&ops[0]) } @@ -524,17 +542,18 @@ func (p *G1Jac) mulWindowed(a *G1Jac, s *big.Int) *G1Jac { } -// ϕ assigns p to ϕ(a) where ϕ: (x,y) → (w x,y), and returns p -// where w is a third root of unity in 𝔽p -func (p *G1Jac) phi(a *G1Jac) *G1Jac { - p.Set(a) +// phi sets p to ϕ(a) where ϕ: (x,y) → (w x,y), +// where w is a third root of unity. +func (p *G1Jac) phi(q *G1Jac) *G1Jac { + p.Set(q) p.X.Mul(&p.X, &thirdRootOneG1) return p } // mulGLV computes the scalar multiplication using a windowed-GLV method +// // see https://www.iacr.org/archive/crypto2001/21390189.pdf -func (p *G1Jac) mulGLV(a *G1Jac, s *big.Int) *G1Jac { +func (p *G1Jac) mulGLV(q *G1Jac, s *big.Int) *G1Jac { var table [15]G1Jac var res G1Jac @@ -542,11 +561,11 @@ func (p *G1Jac) mulGLV(a *G1Jac, s *big.Int) *G1Jac { res.Set(&g1Infinity) - // table[b3b2b1b0-1] = b3b2 ⋅ ϕ(a) + b1b0*a - table[0].Set(a) - table[3].phi(a) + // table[b3b2b1b0-1] = b3b2 ⋅ ϕ(q) + b1b0*q + table[0].Set(q) + table[3].phi(q) - // split the scalar, modifies ±a, ϕ(a) accordingly + // split the scalar, modifies ±q, ϕ(q) accordingly k := ecc.SplitScalar(s, &glvBasis) if k[0].Sign() == -1 { @@ -559,7 +578,7 @@ func (p *G1Jac) mulGLV(a *G1Jac, s *big.Int) *G1Jac { } // precompute table (2 bits sliding window) - // table[b3b2b1b0-1] = b3b2 ⋅ ϕ(a) + b1b0 ⋅ a if b3b2b1b0 != 0 + // table[b3b2b1b0-1] = b3b2 ⋅ ϕ(q) + b1b0 ⋅ q if b3b2b1b0 != 0 table[1].Double(&table[0]) table[2].Set(&table[1]).AddAssign(&table[0]) table[4].Set(&table[3]).AddAssign(&table[0]) @@ -615,17 +634,17 @@ func (p *G1Affine) ClearCofactor(a *G1Affine) *G1Affine { } // ClearCofactor maps a point in E(Fp) to E(Fp)[r] -func (p *G1Jac) ClearCofactor(a *G1Jac) *G1Jac { +func (p *G1Jac) ClearCofactor(q *G1Jac) *G1Jac { // cf https://eprint.iacr.org/2019/403.pdf, 5 var res G1Jac - res.ScalarMultiplication(a, &xGen).Neg(&res).AddAssign(a) + res.ScalarMultiplication(q, &xGen).Neg(&res).AddAssign(q) p.Set(&res) return p } -// JointScalarMultiplicationBase computes [s1]g+[s2]a using Straus-Shamir technique -// where g is the prime subgroup generator +// JointScalarMultiplicationBase computes [s1]g+[s2]a using Strauss-Shamir technique +// where g is the prime subgroup generator and a is an affine point. func (p *G1Jac) JointScalarMultiplicationBase(a *G1Affine, s1, s2 *big.Int) *G1Jac { var res, p1, p2 G1Jac @@ -696,15 +715,15 @@ func (p *G1Jac) JointScalarMultiplicationBase(a *G1Affine, s1, s2 *big.Int) *G1J } // ------------------------------------------------------------------------------------------------- -// Jacobian extended +// extended Jacobian coordinates -// Set sets p to the provided point -func (p *g1JacExtended) Set(a *g1JacExtended) *g1JacExtended { - p.X, p.Y, p.ZZ, p.ZZZ = a.X, a.Y, a.ZZ, a.ZZZ +// Set sets p to a in extended Jacobian coordinates. +func (p *g1JacExtended) Set(q *g1JacExtended) *g1JacExtended { + p.X, p.Y, p.ZZ, p.ZZZ = q.X, q.Y, q.ZZ, q.ZZZ return p } -// setInfinity sets p to O +// setInfinity sets p to the infinity point (1,1,0,0). func (p *g1JacExtended) setInfinity() *g1JacExtended { p.X.SetOne() p.Y.SetOne() @@ -713,43 +732,45 @@ func (p *g1JacExtended) setInfinity() *g1JacExtended { return p } -func (p *g1JacExtended) IsZero() bool { +// IsInfinity checks if the p is infinity, i.e. p.ZZ=0. +func (p *g1JacExtended) IsInfinity() bool { return p.ZZ.IsZero() } -// fromJacExtended sets Q in affine coordinates -func (p *G1Affine) fromJacExtended(Q *g1JacExtended) *G1Affine { - if Q.ZZ.IsZero() { +// fromJacExtended converts an extended Jacobian point to an affine point. +func (p *G1Affine) fromJacExtended(q *g1JacExtended) *G1Affine { + if q.ZZ.IsZero() { p.X = fp.Element{} p.Y = fp.Element{} return p } - p.X.Inverse(&Q.ZZ).Mul(&p.X, &Q.X) - p.Y.Inverse(&Q.ZZZ).Mul(&p.Y, &Q.Y) + p.X.Inverse(&q.ZZ).Mul(&p.X, &q.X) + p.Y.Inverse(&q.ZZZ).Mul(&p.Y, &q.Y) return p } -// fromJacExtended sets Q in Jacobian coordinates -func (p *G1Jac) fromJacExtended(Q *g1JacExtended) *G1Jac { - if Q.ZZ.IsZero() { +// fromJacExtended converts an extended Jacobian point to a Jacobian point. +func (p *G1Jac) fromJacExtended(q *g1JacExtended) *G1Jac { + if q.ZZ.IsZero() { p.Set(&g1Infinity) return p } - p.X.Mul(&Q.ZZ, &Q.X).Mul(&p.X, &Q.ZZ) - p.Y.Mul(&Q.ZZZ, &Q.Y).Mul(&p.Y, &Q.ZZZ) - p.Z.Set(&Q.ZZZ) + p.X.Mul(&q.ZZ, &q.X).Mul(&p.X, &q.ZZ) + p.Y.Mul(&q.ZZZ, &q.Y).Mul(&p.Y, &q.ZZZ) + p.Z.Set(&q.ZZZ) return p } -// unsafeFromJacExtended sets p in Jacobian coordinates, but don't check for infinity -func (p *G1Jac) unsafeFromJacExtended(Q *g1JacExtended) *G1Jac { - p.X.Square(&Q.ZZ).Mul(&p.X, &Q.X) - p.Y.Square(&Q.ZZZ).Mul(&p.Y, &Q.Y) - p.Z = Q.ZZZ +// unsafeFromJacExtended converts an extended Jacobian point, distinct from Infinity, to a Jacobian point. +func (p *G1Jac) unsafeFromJacExtended(q *g1JacExtended) *G1Jac { + p.X.Square(&q.ZZ).Mul(&p.X, &q.X) + p.Y.Square(&q.ZZZ).Mul(&p.Y, &q.Y) + p.Z = q.ZZZ return p } -// add point in Jacobian extended coordinates +// add sets p to p+q in extended Jacobian coordinates. +// // https://www.hyperelliptic.org/EFD/g1p/auto-shortw-xyzz.html#addition-add-2008-s func (p *g1JacExtended) add(q *g1JacExtended) *g1JacExtended { //if q is infinity return p @@ -805,10 +826,11 @@ func (p *g1JacExtended) add(q *g1JacExtended) *g1JacExtended { return p } -// double point in Jacobian extended coordinates +// double sets p to [2]q in Jacobian extended coordinates. +// // http://www.hyperelliptic.org/EFD/g1p/auto-shortw-xyzz.html#doubling-dbl-2008-s-1 -// since we consider any point on Z=0 as the point at infinity -// this doubling formula works for infinity points as well +// N.B.: since we consider any point on Z=0 as the point at infinity +// this doubling formula works for infinity points as well. func (p *g1JacExtended) double(q *g1JacExtended) *g1JacExtended { var U, V, W, S, XX, M fp.Element @@ -818,7 +840,7 @@ func (p *g1JacExtended) double(q *g1JacExtended) *g1JacExtended { S.Mul(&q.X, &V) XX.Square(&q.X) M.Double(&XX). - Add(&M, &XX) // -> + a, but a=0 here + Add(&M, &XX) // -> + A, but A=0 here U.Mul(&W, &q.Y) p.X.Square(&M). @@ -833,9 +855,10 @@ func (p *g1JacExtended) double(q *g1JacExtended) *g1JacExtended { return p } -// subMixed same as addMixed, but will negate a.Y +// addMixed sets p to p+q in extended Jacobian coordinates, where a.ZZ=1. +// // http://www.hyperelliptic.org/EFD/g1p/auto-shortw-xyzz.html#addition-madd-2008-s -func (p *g1JacExtended) subMixed(a *G1Affine) *g1JacExtended { +func (p *g1JacExtended) addMixed(a *G1Affine) *g1JacExtended { //if a is infinity return p if a.IsInfinity() { @@ -844,7 +867,7 @@ func (p *g1JacExtended) subMixed(a *G1Affine) *g1JacExtended { // p is infinity, return a if p.ZZ.IsZero() { p.X = a.X - p.Y.Neg(&a.Y) + p.Y = a.Y p.ZZ.SetOne() p.ZZZ.SetOne() return p @@ -857,12 +880,11 @@ func (p *g1JacExtended) subMixed(a *G1Affine) *g1JacExtended { P.Sub(&P, &p.X) R.Mul(&a.Y, &p.ZZZ) - R.Neg(&R) R.Sub(&R, &p.Y) if P.IsZero() { if R.IsZero() { - return p.doubleNegMixed(a) + return p.doubleMixed(a) } p.ZZ = fp.Element{} @@ -889,9 +911,10 @@ func (p *g1JacExtended) subMixed(a *G1Affine) *g1JacExtended { } -// addMixed +// subMixed works the same as addMixed, but negates a.Y. +// // http://www.hyperelliptic.org/EFD/g1p/auto-shortw-xyzz.html#addition-madd-2008-s -func (p *g1JacExtended) addMixed(a *G1Affine) *g1JacExtended { +func (p *g1JacExtended) subMixed(a *G1Affine) *g1JacExtended { //if a is infinity return p if a.IsInfinity() { @@ -900,7 +923,7 @@ func (p *g1JacExtended) addMixed(a *G1Affine) *g1JacExtended { // p is infinity, return a if p.ZZ.IsZero() { p.X = a.X - p.Y = a.Y + p.Y.Neg(&a.Y) p.ZZ.SetOne() p.ZZZ.SetOne() return p @@ -913,11 +936,12 @@ func (p *g1JacExtended) addMixed(a *G1Affine) *g1JacExtended { P.Sub(&P, &p.X) R.Mul(&a.Y, &p.ZZZ) + R.Neg(&R) R.Sub(&R, &p.Y) if P.IsZero() { if R.IsZero() { - return p.doubleMixed(a) + return p.doubleNegMixed(a) } p.ZZ = fp.Element{} @@ -944,21 +968,21 @@ func (p *g1JacExtended) addMixed(a *G1Affine) *g1JacExtended { } -// doubleNegMixed same as double, but will negate q.Y -func (p *g1JacExtended) doubleNegMixed(q *G1Affine) *g1JacExtended { +// doubleNegMixed works the same as double, but negates q.Y. +func (p *g1JacExtended) doubleNegMixed(a *G1Affine) *g1JacExtended { var U, V, W, S, XX, M, S2, L fp.Element - U.Double(&q.Y) + U.Double(&a.Y) U.Neg(&U) V.Square(&U) W.Mul(&U, &V) - S.Mul(&q.X, &V) - XX.Square(&q.X) + S.Mul(&a.X, &V) + XX.Square(&a.X) M.Double(&XX). - Add(&M, &XX) // -> + a, but a=0 here + Add(&M, &XX) // -> + A, but A=0 here S2.Double(&S) - L.Mul(&W, &q.Y) + L.Mul(&W, &a.Y) p.X.Square(&M). Sub(&p.X, &S2) @@ -971,21 +995,22 @@ func (p *g1JacExtended) doubleNegMixed(q *G1Affine) *g1JacExtended { return p } -// doubleMixed point in Jacobian extended coordinates +// doubleMixed sets p to [2]a in Jacobian extended coordinates, where a.ZZ=1. +// // http://www.hyperelliptic.org/EFD/g1p/auto-shortw-xyzz.html#doubling-dbl-2008-s-1 -func (p *g1JacExtended) doubleMixed(q *G1Affine) *g1JacExtended { +func (p *g1JacExtended) doubleMixed(a *G1Affine) *g1JacExtended { var U, V, W, S, XX, M, S2, L fp.Element - U.Double(&q.Y) + U.Double(&a.Y) V.Square(&U) W.Mul(&U, &V) - S.Mul(&q.X, &V) - XX.Square(&q.X) + S.Mul(&a.X, &V) + XX.Square(&a.X) M.Double(&XX). - Add(&M, &XX) // -> + a, but a=0 here + Add(&M, &XX) // -> + A, but A=0 here S2.Double(&S) - L.Mul(&W, &q.Y) + L.Mul(&W, &a.Y) p.X.Square(&M). Sub(&p.X, &S2) @@ -999,7 +1024,7 @@ func (p *g1JacExtended) doubleMixed(q *G1Affine) *g1JacExtended { } // BatchJacobianToAffineG1 converts points in Jacobian coordinates to Affine coordinates -// performing a single field inversion (Montgomery batch inversion trick). +// performing a single field inversion using the Montgomery batch inversion trick. func BatchJacobianToAffineG1(points []G1Jac) []G1Affine { result := make([]G1Affine, len(points)) zeroes := make([]bool, len(points)) @@ -1049,7 +1074,7 @@ func BatchJacobianToAffineG1(points []G1Jac) []G1Affine { // BatchScalarMultiplicationG1 multiplies the same base by all scalars // and return resulting points in affine coordinates -// uses a simple windowed-NAF like exponentiation algorithm +// uses a simple windowed-NAF-like multiplication algorithm. func BatchScalarMultiplicationG1(base *G1Affine, scalars []fr.Element) []G1Affine { // approximate cost in group ops is // cost = 2^{c-1} + n(scalar.nbBits+nbChunks) @@ -1131,9 +1156,8 @@ func BatchScalarMultiplicationG1(base *G1Affine, scalars []fr.Element) []G1Affin return toReturnAff } -// batch add affine coordinates -// using batch inversion -// special cases (doubling, infinity) must be filtered out before this call +// batchAddG1Affine adds affine points using the Montgomery batch inversion trick. +// Special cases (doubling, infinity) must be filtered out before this call. func batchAddG1Affine[TP pG1Affine, TPP ppG1Affine, TC cG1Affine](R *TPP, P *TP, batchSize int) { var lambda, lambdain TC diff --git a/ecc/bls12-378/g2.go b/ecc/bls12-378/g2.go index 026bca4ac..b3a47afee 100644 --- a/ecc/bls12-378/g2.go +++ b/ecc/bls12-378/g2.go @@ -25,17 +25,17 @@ import ( "runtime" ) -// G2Affine point in affine coordinates +// G2Affine is a point in affine coordinates (x,y) type G2Affine struct { X, Y fptower.E2 } -// G2Jac is a point with fptower.E2 coordinates +// G2Jac is a point in Jacobian coordinates (x=X/Z², y=Y/Z³) type G2Jac struct { X, Y, Z fptower.E2 } -// g2JacExtended parameterized Jacobian coordinates (x=X/ZZ, y=Y/ZZZ, ZZ³=ZZZ²) +// g2JacExtended is a point in extended Jacobian coordinates (x=X/ZZ, y=Y/ZZZ, ZZ³=ZZZ²) type g2JacExtended struct { X, Y, ZZ, ZZZ fptower.E2 } @@ -46,22 +46,24 @@ type g2Proj struct { } // ------------------------------------------------------------------------------------------------- -// Affine +// Affine coordinates -// Set sets p to the provided point +// Set sets p to a in affine coordinates. func (p *G2Affine) Set(a *G2Affine) *G2Affine { p.X, p.Y = a.X, a.Y return p } -// setInfinity sets p to O +// setInfinity sets p to the infinity point, which is encoded as (0,0). +// N.B.: (0,0) is never on the curve for j=0 curves (Y²=X³+B). func (p *G2Affine) setInfinity() *G2Affine { p.X.SetZero() p.Y.SetZero() return p } -// ScalarMultiplication computes and returns p = a ⋅ s +// ScalarMultiplication computes and returns p = [s]a +// where p and a are affine points. func (p *G2Affine) ScalarMultiplication(a *G2Affine, s *big.Int) *G2Affine { var _p G2Jac _p.FromAffine(a) @@ -70,7 +72,8 @@ func (p *G2Affine) ScalarMultiplication(a *G2Affine, s *big.Int) *G2Affine { return p } -// ScalarMultiplicationBase computes and returns p = g ⋅ s where g is the prime subgroup generator +// ScalarMultiplicationBase computes and returns p = [s]g +// where g is the affine point generating the prime subgroup. func (p *G2Affine) ScalarMultiplicationBase(s *big.Int) *G2Affine { var _p G2Jac _p.mulGLV(&g2Gen, s) @@ -78,8 +81,9 @@ func (p *G2Affine) ScalarMultiplicationBase(s *big.Int) *G2Affine { return p } -// Add adds two point in affine coordinates. -// Jacobian addition with Z1=Z2=1 +// Add adds two points in affine coordinates. +// It uses the Jacobian addition with a.Z=b.Z=1 and converts the result to affine coordinates. +// // https://www.hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html#addition-mmadd-2007-bl func (p *G2Affine) Add(a, b *G2Affine) *G2Affine { var q G2Jac @@ -125,6 +129,10 @@ func (p *G2Affine) Add(a, b *G2Affine) *G2Affine { } // Double doubles a point in affine coordinates. +// It converts the point to Jacobian coordinates, doubles it using Jacobian +// addition with a.Z=1, and converts it back to affine coordinates. +// +// http://www.hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html#doubling-mdbl-2007-bl func (p *G2Affine) Double(a *G2Affine) *G2Affine { var q G2Jac q.FromAffine(a) @@ -133,7 +141,8 @@ func (p *G2Affine) Double(a *G2Affine) *G2Affine { return p } -// Sub subs two point in affine coordinates. +// Sub subtracts two points in affine coordinates. +// It uses a similar approach to Add, but negates the second point before adding. func (p *G2Affine) Sub(a, b *G2Affine) *G2Affine { var bneg G2Affine bneg.Neg(b) @@ -141,19 +150,19 @@ func (p *G2Affine) Sub(a, b *G2Affine) *G2Affine { return p } -// Equal tests if two points (in Affine coordinates) are equal +// Equal tests if two points in affine coordinates are equal. func (p *G2Affine) Equal(a *G2Affine) bool { return p.X.Equal(&a.X) && p.Y.Equal(&a.Y) } -// Neg computes -G +// Neg sets p to the affine negative point -a = (a.X, -a.Y). func (p *G2Affine) Neg(a *G2Affine) *G2Affine { p.X = a.X p.Y.Neg(&a.Y) return p } -// FromJacobian rescales a point in Jacobian coord in z=1 plane +// FromJacobian converts a point p1 from Jacobian to affine coordinates. func (p *G2Affine) FromJacobian(p1 *G2Jac) *G2Affine { var a, b fptower.E2 @@ -172,7 +181,7 @@ func (p *G2Affine) FromJacobian(p1 *G2Jac) *G2Affine { return p } -// String returns the string representation of the point or "O" if it is infinity +// String returns the string representation E(x,y) of the affine point p or "O" if it is infinity. func (p *G2Affine) String() string { if p.IsInfinity() { return "O" @@ -180,21 +189,20 @@ func (p *G2Affine) String() string { return "E([" + p.X.String() + "," + p.Y.String() + "])" } -// IsInfinity checks if the point is infinity -// in affine, it's encoded as (0,0) -// (0,0) is never on the curve for j=0 curves +// IsInfinity checks if the affine point p is infinity, which is encoded as (0,0). +// N.B.: (0,0) is never on the curve for j=0 curves (Y²=X³+B). func (p *G2Affine) IsInfinity() bool { return p.X.IsZero() && p.Y.IsZero() } -// IsOnCurve returns true if p in on the curve +// IsOnCurve returns true if the affine point p in on the curve. func (p *G2Affine) IsOnCurve() bool { var point G2Jac point.FromAffine(p) return point.IsOnCurve() // call this function to handle infinity point } -// IsInSubGroup returns true if p is in the correct subgroup, false otherwise +// IsInSubGroup returns true if the affine point p is in the correct subgroup, false otherwise. func (p *G2Affine) IsInSubGroup() bool { var _p G2Jac _p.FromAffine(p) @@ -202,84 +210,76 @@ func (p *G2Affine) IsInSubGroup() bool { } // ------------------------------------------------------------------------------------------------- -// Jacobian +// Jacobian coordinates -// Set sets p to the provided point -func (p *G2Jac) Set(a *G2Jac) *G2Jac { - p.X, p.Y, p.Z = a.X, a.Y, a.Z +// Set sets p to a in Jacobian coordinates. +func (p *G2Jac) Set(q *G2Jac) *G2Jac { + p.X, p.Y, p.Z = q.X, q.Y, q.Z return p } -// Equal tests if two points (in Jacobian coordinates) are equal -func (p *G2Jac) Equal(a *G2Jac) bool { +// Equal tests if two points in Jacobian coordinates are equal. +func (p *G2Jac) Equal(q *G2Jac) bool { // If one point is infinity, the other must also be infinity. if p.Z.IsZero() { - return a.Z.IsZero() + return q.Z.IsZero() } // If the other point is infinity, return false since we can't // the following checks would be incorrect. - if a.Z.IsZero() { + if q.Z.IsZero() { return false } var pZSquare, aZSquare fptower.E2 pZSquare.Square(&p.Z) - aZSquare.Square(&a.Z) + aZSquare.Square(&q.Z) var lhs, rhs fptower.E2 lhs.Mul(&p.X, &aZSquare) - rhs.Mul(&a.X, &pZSquare) + rhs.Mul(&q.X, &pZSquare) if !lhs.Equal(&rhs) { return false } - lhs.Mul(&p.Y, &aZSquare).Mul(&lhs, &a.Z) - rhs.Mul(&a.Y, &pZSquare).Mul(&rhs, &p.Z) + lhs.Mul(&p.Y, &aZSquare).Mul(&lhs, &q.Z) + rhs.Mul(&q.Y, &pZSquare).Mul(&rhs, &p.Z) return lhs.Equal(&rhs) } -// Neg computes -G -func (p *G2Jac) Neg(a *G2Jac) *G2Jac { - *p = *a - p.Y.Neg(&a.Y) - return p -} - -// SubAssign subtracts two points on the curve -func (p *G2Jac) SubAssign(a *G2Jac) *G2Jac { - var tmp G2Jac - tmp.Set(a) - tmp.Y.Neg(&tmp.Y) - p.AddAssign(&tmp) +// Neg sets p to the Jacobian negative point -q = (q.X, -q.Y, q.Z). +func (p *G2Jac) Neg(q *G2Jac) *G2Jac { + *p = *q + p.Y.Neg(&q.Y) return p } -// AddAssign point addition in montgomery form +// AddAssign sets p to p+a in Jacobian coordinates. +// // https://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-3.html#addition-add-2007-bl -func (p *G2Jac) AddAssign(a *G2Jac) *G2Jac { +func (p *G2Jac) AddAssign(q *G2Jac) *G2Jac { - // p is infinity, return a + // p is infinity, return q if p.Z.IsZero() { - p.Set(a) + p.Set(q) return p } - // a is infinity, return p - if a.Z.IsZero() { + // q is infinity, return p + if q.Z.IsZero() { return p } var Z1Z1, Z2Z2, U1, U2, S1, S2, H, I, J, r, V fptower.E2 - Z1Z1.Square(&a.Z) + Z1Z1.Square(&q.Z) Z2Z2.Square(&p.Z) - U1.Mul(&a.X, &Z2Z2) + U1.Mul(&q.X, &Z2Z2) U2.Mul(&p.X, &Z1Z1) - S1.Mul(&a.Y, &p.Z). + S1.Mul(&q.Y, &p.Z). Mul(&S1, &Z2Z2) - S2.Mul(&p.Y, &a.Z). + S2.Mul(&p.Y, &q.Z). Mul(&S2, &Z1Z1) - // if p == a, we double instead + // if p == q, we double instead if U1.Equal(&U2) && S1.Equal(&S2) { return p.DoubleAssign() } @@ -298,7 +298,7 @@ func (p *G2Jac) AddAssign(a *G2Jac) *G2Jac { Mul(&p.Y, &r) S1.Mul(&S1, &J).Double(&S1) p.Y.Sub(&p.Y, &S1) - p.Z.Add(&p.Z, &a.Z) + p.Z.Add(&p.Z, &q.Z) p.Z.Square(&p.Z). Sub(&p.Z, &Z1Z1). Sub(&p.Z, &Z2Z2). @@ -307,8 +307,19 @@ func (p *G2Jac) AddAssign(a *G2Jac) *G2Jac { return p } -// DoubleMixed point addition -// http://www.hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html#doubling-mdbl-2007-bl +// SubAssign sets p to p-a in Jacobian coordinates. +// It uses a similar approach to AddAssign, but negates the point a before adding. +func (p *G2Jac) SubAssign(q *G2Jac) *G2Jac { + var tmp G2Jac + tmp.Set(q) + tmp.Y.Neg(&tmp.Y) + p.AddAssign(&tmp) + return p +} + +// Double sets p to [2]q in Jacobian coordinates. +// +// https://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-3.html#doubling-dbl-2007-bl func (p *G2Jac) DoubleMixed(a *G2Affine) *G2Jac { var XX, YY, YYYY, S, M, T fptower.E2 XX.Square(&a.X) @@ -320,7 +331,7 @@ func (p *G2Jac) DoubleMixed(a *G2Affine) *G2Jac { Sub(&S, &YYYY). Double(&S) M.Double(&XX). - Add(&M, &XX) // -> + a, but a=0 here + Add(&M, &XX) // -> + A, but A=0 here T.Square(&M). Sub(&T, &S). Sub(&T, &S) @@ -336,7 +347,8 @@ func (p *G2Jac) DoubleMixed(a *G2Affine) *G2Jac { return p } -// AddMixed point addition +// AddMixed sets p to p+a in Jacobian coordinates, where a.Z = 1. +// // http://www.hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html#addition-madd-2007-bl func (p *G2Jac) AddMixed(a *G2Affine) *G2Jac { @@ -385,7 +397,8 @@ func (p *G2Jac) AddMixed(a *G2Affine) *G2Jac { return p } -// Double doubles a point in Jacobian coordinates +// Double sets p to [2]q in Jacobian coordinates. +// // https://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-3.html#doubling-dbl-2007-bl func (p *G2Jac) Double(q *G2Jac) *G2Jac { p.Set(q) @@ -393,7 +406,8 @@ func (p *G2Jac) Double(q *G2Jac) *G2Jac { return p } -// DoubleAssign doubles a point in Jacobian coordinates +// DoubleAssign doubles p in Jacobian coordinates. +// // https://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-3.html#doubling-dbl-2007-bl func (p *G2Jac) DoubleAssign() *G2Jac { @@ -425,34 +439,36 @@ func (p *G2Jac) DoubleAssign() *G2Jac { return p } -// ScalarMultiplication computes and returns p = a ⋅ s +// ScalarMultiplication computes and returns p = [s]a +// where p and a are Jacobian points. +// using the GLV technique. // see https://www.iacr.org/archive/crypto2001/21390189.pdf -func (p *G2Jac) ScalarMultiplication(a *G2Jac, s *big.Int) *G2Jac { - return p.mulGLV(a, s) +func (p *G2Jac) ScalarMultiplication(q *G2Jac, s *big.Int) *G2Jac { + return p.mulGLV(q, s) } -// String returns canonical representation of the point in affine coordinates +// String converts p to affine coordinates and returns its string representation E(x,y) or "O" if it is infinity. func (p *G2Jac) String() string { _p := G2Affine{} _p.FromJacobian(p) return _p.String() } -// FromAffine sets p = Q, p in Jacobian, Q in affine -func (p *G2Jac) FromAffine(Q *G2Affine) *G2Jac { - if Q.IsInfinity() { +// FromAffine converts a point a from affine to Jacobian coordinates. +func (p *G2Jac) FromAffine(a *G2Affine) *G2Jac { + if a.IsInfinity() { p.Z.SetZero() p.X.SetOne() p.Y.SetOne() return p } p.Z.SetOne() - p.X.Set(&Q.X) - p.Y.Set(&Q.Y) + p.X.Set(&a.X) + p.Y.Set(&a.Y) return p } -// IsOnCurve returns true if p in on the curve +// IsOnCurve returns true if the Jacobian point p in on the curve. func (p *G2Jac) IsOnCurve() bool { var left, right, tmp, ZZ fptower.E2 left.Square(&p.Y) @@ -476,13 +492,14 @@ func (p *G2Jac) IsInSubGroup() bool { return res.IsOnCurve() && res.Z.IsZero() } -// mulWindowed computes a 2-bits windowed scalar multiplication -func (p *G2Jac) mulWindowed(a *G2Jac, s *big.Int) *G2Jac { +// mulWindowed computes the 2-bits windowed double-and-add scalar +// multiplication p=[s]q in Jacobian coordinates. +func (p *G2Jac) mulWindowed(q *G2Jac, s *big.Int) *G2Jac { var res G2Jac var ops [3]G2Jac - ops[0].Set(a) + ops[0].Set(q) if s.Sign() == -1 { ops[0].Neg(&ops[0]) } @@ -509,26 +526,27 @@ func (p *G2Jac) mulWindowed(a *G2Jac, s *big.Int) *G2Jac { } -// ψ(p) = u o π o u⁻¹ where u:E'→E iso from the twist to E -func (p *G2Jac) psi(a *G2Jac) *G2Jac { - p.Set(a) +// psi sets p to ψ(q) = u o π o u⁻¹ where u:E'→E is the isomorphism from the twist to the curve E and π is the Frobenius map. +func (p *G2Jac) psi(q *G2Jac) *G2Jac { + p.Set(q) p.X.Conjugate(&p.X).Mul(&p.X, &endo.u) p.Y.Conjugate(&p.Y).Mul(&p.Y, &endo.v) p.Z.Conjugate(&p.Z) return p } -// ϕ assigns p to ϕ(a) where ϕ: (x,y) → (w x,y), and returns p -// where w is a third root of unity in 𝔽p -func (p *G2Jac) phi(a *G2Jac) *G2Jac { - p.Set(a) +// phi sets p to ϕ(a) where ϕ: (x,y) → (w x,y), +// where w is a third root of unity. +func (p *G2Jac) phi(q *G2Jac) *G2Jac { + p.Set(q) p.X.MulByElement(&p.X, &thirdRootOneG2) return p } // mulGLV computes the scalar multiplication using a windowed-GLV method +// // see https://www.iacr.org/archive/crypto2001/21390189.pdf -func (p *G2Jac) mulGLV(a *G2Jac, s *big.Int) *G2Jac { +func (p *G2Jac) mulGLV(q *G2Jac, s *big.Int) *G2Jac { var table [15]G2Jac var res G2Jac @@ -536,11 +554,11 @@ func (p *G2Jac) mulGLV(a *G2Jac, s *big.Int) *G2Jac { res.Set(&g2Infinity) - // table[b3b2b1b0-1] = b3b2 ⋅ ϕ(a) + b1b0*a - table[0].Set(a) - table[3].phi(a) + // table[b3b2b1b0-1] = b3b2 ⋅ ϕ(q) + b1b0*q + table[0].Set(q) + table[3].phi(q) - // split the scalar, modifies ±a, ϕ(a) accordingly + // split the scalar, modifies ±q, ϕ(q) accordingly k := ecc.SplitScalar(s, &glvBasis) if k[0].Sign() == -1 { @@ -553,7 +571,7 @@ func (p *G2Jac) mulGLV(a *G2Jac, s *big.Int) *G2Jac { } // precompute table (2 bits sliding window) - // table[b3b2b1b0-1] = b3b2 ⋅ ϕ(a) + b1b0 ⋅ a if b3b2b1b0 != 0 + // table[b3b2b1b0-1] = b3b2 ⋅ ϕ(q) + b1b0 ⋅ q if b3b2b1b0 != 0 table[1].Double(&table[0]) table[2].Set(&table[1]).AddAssign(&table[0]) table[4].Set(&table[3]).AddAssign(&table[0]) @@ -609,23 +627,23 @@ func (p *G2Affine) ClearCofactor(a *G2Affine) *G2Affine { } // ClearCofactor maps a point in curve to r-torsion -func (p *G2Jac) ClearCofactor(a *G2Jac) *G2Jac { +func (p *G2Jac) ClearCofactor(q *G2Jac) *G2Jac { // https://eprint.iacr.org/2017/419.pdf, 4.1 var xg, xxg, res, t G2Jac - xg.ScalarMultiplication(a, &xGen) + xg.ScalarMultiplication(q, &xGen) xxg.ScalarMultiplication(&xg, &xGen) res.Set(&xxg). SubAssign(&xg). - SubAssign(a) + SubAssign(q) t.Set(&xg). - SubAssign(a). + SubAssign(q). psi(&t) res.AddAssign(&t) - t.Double(a) + t.Double(q) t.X.MulByElement(&t.X, &thirdRootOneG1) res.SubAssign(&t) @@ -637,15 +655,15 @@ func (p *G2Jac) ClearCofactor(a *G2Jac) *G2Jac { } // ------------------------------------------------------------------------------------------------- -// Jacobian extended +// extended Jacobian coordinates -// Set sets p to the provided point -func (p *g2JacExtended) Set(a *g2JacExtended) *g2JacExtended { - p.X, p.Y, p.ZZ, p.ZZZ = a.X, a.Y, a.ZZ, a.ZZZ +// Set sets p to a in extended Jacobian coordinates. +func (p *g2JacExtended) Set(q *g2JacExtended) *g2JacExtended { + p.X, p.Y, p.ZZ, p.ZZZ = q.X, q.Y, q.ZZ, q.ZZZ return p } -// setInfinity sets p to O +// setInfinity sets p to the infinity point (1,1,0,0). func (p *g2JacExtended) setInfinity() *g2JacExtended { p.X.SetOne() p.Y.SetOne() @@ -654,43 +672,45 @@ func (p *g2JacExtended) setInfinity() *g2JacExtended { return p } -func (p *g2JacExtended) IsZero() bool { +// IsInfinity checks if the p is infinity, i.e. p.ZZ=0. +func (p *g2JacExtended) IsInfinity() bool { return p.ZZ.IsZero() } -// fromJacExtended sets Q in affine coordinates -func (p *G2Affine) fromJacExtended(Q *g2JacExtended) *G2Affine { - if Q.ZZ.IsZero() { +// fromJacExtended converts an extended Jacobian point to an affine point. +func (p *G2Affine) fromJacExtended(q *g2JacExtended) *G2Affine { + if q.ZZ.IsZero() { p.X = fptower.E2{} p.Y = fptower.E2{} return p } - p.X.Inverse(&Q.ZZ).Mul(&p.X, &Q.X) - p.Y.Inverse(&Q.ZZZ).Mul(&p.Y, &Q.Y) + p.X.Inverse(&q.ZZ).Mul(&p.X, &q.X) + p.Y.Inverse(&q.ZZZ).Mul(&p.Y, &q.Y) return p } -// fromJacExtended sets Q in Jacobian coordinates -func (p *G2Jac) fromJacExtended(Q *g2JacExtended) *G2Jac { - if Q.ZZ.IsZero() { +// fromJacExtended converts an extended Jacobian point to a Jacobian point. +func (p *G2Jac) fromJacExtended(q *g2JacExtended) *G2Jac { + if q.ZZ.IsZero() { p.Set(&g2Infinity) return p } - p.X.Mul(&Q.ZZ, &Q.X).Mul(&p.X, &Q.ZZ) - p.Y.Mul(&Q.ZZZ, &Q.Y).Mul(&p.Y, &Q.ZZZ) - p.Z.Set(&Q.ZZZ) + p.X.Mul(&q.ZZ, &q.X).Mul(&p.X, &q.ZZ) + p.Y.Mul(&q.ZZZ, &q.Y).Mul(&p.Y, &q.ZZZ) + p.Z.Set(&q.ZZZ) return p } -// unsafeFromJacExtended sets p in Jacobian coordinates, but don't check for infinity -func (p *G2Jac) unsafeFromJacExtended(Q *g2JacExtended) *G2Jac { - p.X.Square(&Q.ZZ).Mul(&p.X, &Q.X) - p.Y.Square(&Q.ZZZ).Mul(&p.Y, &Q.Y) - p.Z = Q.ZZZ +// unsafeFromJacExtended converts an extended Jacobian point, distinct from Infinity, to a Jacobian point. +func (p *G2Jac) unsafeFromJacExtended(q *g2JacExtended) *G2Jac { + p.X.Square(&q.ZZ).Mul(&p.X, &q.X) + p.Y.Square(&q.ZZZ).Mul(&p.Y, &q.Y) + p.Z = q.ZZZ return p } -// add point in Jacobian extended coordinates +// add sets p to p+q in extended Jacobian coordinates. +// // https://www.hyperelliptic.org/EFD/g1p/auto-shortw-xyzz.html#addition-add-2008-s func (p *g2JacExtended) add(q *g2JacExtended) *g2JacExtended { //if q is infinity return p @@ -746,10 +766,11 @@ func (p *g2JacExtended) add(q *g2JacExtended) *g2JacExtended { return p } -// double point in Jacobian extended coordinates +// double sets p to [2]q in Jacobian extended coordinates. +// // http://www.hyperelliptic.org/EFD/g1p/auto-shortw-xyzz.html#doubling-dbl-2008-s-1 -// since we consider any point on Z=0 as the point at infinity -// this doubling formula works for infinity points as well +// N.B.: since we consider any point on Z=0 as the point at infinity +// this doubling formula works for infinity points as well. func (p *g2JacExtended) double(q *g2JacExtended) *g2JacExtended { var U, V, W, S, XX, M fptower.E2 @@ -759,7 +780,7 @@ func (p *g2JacExtended) double(q *g2JacExtended) *g2JacExtended { S.Mul(&q.X, &V) XX.Square(&q.X) M.Double(&XX). - Add(&M, &XX) // -> + a, but a=0 here + Add(&M, &XX) // -> + A, but A=0 here U.Mul(&W, &q.Y) p.X.Square(&M). @@ -774,9 +795,10 @@ func (p *g2JacExtended) double(q *g2JacExtended) *g2JacExtended { return p } -// subMixed same as addMixed, but will negate a.Y +// addMixed sets p to p+q in extended Jacobian coordinates, where a.ZZ=1. +// // http://www.hyperelliptic.org/EFD/g1p/auto-shortw-xyzz.html#addition-madd-2008-s -func (p *g2JacExtended) subMixed(a *G2Affine) *g2JacExtended { +func (p *g2JacExtended) addMixed(a *G2Affine) *g2JacExtended { //if a is infinity return p if a.IsInfinity() { @@ -785,7 +807,7 @@ func (p *g2JacExtended) subMixed(a *G2Affine) *g2JacExtended { // p is infinity, return a if p.ZZ.IsZero() { p.X = a.X - p.Y.Neg(&a.Y) + p.Y = a.Y p.ZZ.SetOne() p.ZZZ.SetOne() return p @@ -798,12 +820,11 @@ func (p *g2JacExtended) subMixed(a *G2Affine) *g2JacExtended { P.Sub(&P, &p.X) R.Mul(&a.Y, &p.ZZZ) - R.Neg(&R) R.Sub(&R, &p.Y) if P.IsZero() { if R.IsZero() { - return p.doubleNegMixed(a) + return p.doubleMixed(a) } p.ZZ = fptower.E2{} @@ -830,9 +851,10 @@ func (p *g2JacExtended) subMixed(a *G2Affine) *g2JacExtended { } -// addMixed +// subMixed works the same as addMixed, but negates a.Y. +// // http://www.hyperelliptic.org/EFD/g1p/auto-shortw-xyzz.html#addition-madd-2008-s -func (p *g2JacExtended) addMixed(a *G2Affine) *g2JacExtended { +func (p *g2JacExtended) subMixed(a *G2Affine) *g2JacExtended { //if a is infinity return p if a.IsInfinity() { @@ -841,7 +863,7 @@ func (p *g2JacExtended) addMixed(a *G2Affine) *g2JacExtended { // p is infinity, return a if p.ZZ.IsZero() { p.X = a.X - p.Y = a.Y + p.Y.Neg(&a.Y) p.ZZ.SetOne() p.ZZZ.SetOne() return p @@ -854,11 +876,12 @@ func (p *g2JacExtended) addMixed(a *G2Affine) *g2JacExtended { P.Sub(&P, &p.X) R.Mul(&a.Y, &p.ZZZ) + R.Neg(&R) R.Sub(&R, &p.Y) if P.IsZero() { if R.IsZero() { - return p.doubleMixed(a) + return p.doubleNegMixed(a) } p.ZZ = fptower.E2{} @@ -885,21 +908,21 @@ func (p *g2JacExtended) addMixed(a *G2Affine) *g2JacExtended { } -// doubleNegMixed same as double, but will negate q.Y -func (p *g2JacExtended) doubleNegMixed(q *G2Affine) *g2JacExtended { +// doubleNegMixed works the same as double, but negates q.Y. +func (p *g2JacExtended) doubleNegMixed(a *G2Affine) *g2JacExtended { var U, V, W, S, XX, M, S2, L fptower.E2 - U.Double(&q.Y) + U.Double(&a.Y) U.Neg(&U) V.Square(&U) W.Mul(&U, &V) - S.Mul(&q.X, &V) - XX.Square(&q.X) + S.Mul(&a.X, &V) + XX.Square(&a.X) M.Double(&XX). - Add(&M, &XX) // -> + a, but a=0 here + Add(&M, &XX) // -> + A, but A=0 here S2.Double(&S) - L.Mul(&W, &q.Y) + L.Mul(&W, &a.Y) p.X.Square(&M). Sub(&p.X, &S2) @@ -912,21 +935,22 @@ func (p *g2JacExtended) doubleNegMixed(q *G2Affine) *g2JacExtended { return p } -// doubleMixed point in Jacobian extended coordinates +// doubleMixed sets p to [2]a in Jacobian extended coordinates, where a.ZZ=1. +// // http://www.hyperelliptic.org/EFD/g1p/auto-shortw-xyzz.html#doubling-dbl-2008-s-1 -func (p *g2JacExtended) doubleMixed(q *G2Affine) *g2JacExtended { +func (p *g2JacExtended) doubleMixed(a *G2Affine) *g2JacExtended { var U, V, W, S, XX, M, S2, L fptower.E2 - U.Double(&q.Y) + U.Double(&a.Y) V.Square(&U) W.Mul(&U, &V) - S.Mul(&q.X, &V) - XX.Square(&q.X) + S.Mul(&a.X, &V) + XX.Square(&a.X) M.Double(&XX). - Add(&M, &XX) // -> + a, but a=0 here + Add(&M, &XX) // -> + A, but A=0 here S2.Double(&S) - L.Mul(&W, &q.Y) + L.Mul(&W, &a.Y) p.X.Square(&M). Sub(&p.X, &S2) @@ -940,38 +964,38 @@ func (p *g2JacExtended) doubleMixed(q *G2Affine) *g2JacExtended { } // ------------------------------------------------------------------------------------------------- -// Homogenous projective +// Homogenous projective coordinates -// Set sets p to the provided point -func (p *g2Proj) Set(a *g2Proj) *g2Proj { - p.x, p.y, p.z = a.x, a.y, a.z +// Set sets p to a in projective coordinates. +func (p *g2Proj) Set(q *g2Proj) *g2Proj { + p.x, p.y, p.z = q.x, q.y, q.z return p } -// Neg computes -G -func (p *g2Proj) Neg(a *g2Proj) *g2Proj { - *p = *a - p.y.Neg(&a.y) +// Neg sets p to the projective negative point -q = (q.X, -q.Y). +func (p *g2Proj) Neg(q *g2Proj) *g2Proj { + *p = *q + p.y.Neg(&q.y) return p } -// FromAffine sets p = Q, p in homogenous projective, Q in affine -func (p *g2Proj) FromAffine(Q *G2Affine) *g2Proj { - if Q.X.IsZero() && Q.Y.IsZero() { +// FromAffine converts q in affine to p in projective coordinates. +func (p *g2Proj) FromAffine(a *G2Affine) *g2Proj { + if a.X.IsZero() && a.Y.IsZero() { p.z.SetZero() p.x.SetOne() p.y.SetOne() return p } p.z.SetOne() - p.x.Set(&Q.X) - p.y.Set(&Q.Y) + p.x.Set(&a.X) + p.y.Set(&a.Y) return p } // BatchScalarMultiplicationG2 multiplies the same base by all scalars // and return resulting points in affine coordinates -// uses a simple windowed-NAF like exponentiation algorithm +// uses a simple windowed-NAF-like multiplication algorithm. func BatchScalarMultiplicationG2(base *G2Affine, scalars []fr.Element) []G2Affine { // approximate cost in group ops is // cost = 2^{c-1} + n(scalar.nbBits+nbChunks) @@ -1050,9 +1074,8 @@ func BatchScalarMultiplicationG2(base *G2Affine, scalars []fr.Element) []G2Affin return toReturn } -// batch add affine coordinates -// using batch inversion -// special cases (doubling, infinity) must be filtered out before this call +// batchAddG1Affine adds affine points using the Montgomery batch inversion trick. +// Special cases (doubling, infinity) must be filtered out before this call. func batchAddG2Affine[TP pG2Affine, TPP ppG2Affine, TC cG2Affine](R *TPP, P *TP, batchSize int) { var lambda, lambdain TC diff --git a/ecc/bls12-378/multiexp_affine.go b/ecc/bls12-378/multiexp_affine.go index 276ef2e4d..53459815f 100644 --- a/ecc/bls12-378/multiexp_affine.go +++ b/ecc/bls12-378/multiexp_affine.go @@ -226,7 +226,7 @@ func processChunkG1BatchAffine[BJE ibg1JacExtended, B ibG1Affine, BS bitSet, TP total.setInfinity() for k := len(buckets) - 1; k >= 0; k-- { runningSum.addMixed(&buckets[k]) - if !bucketsJE[k].IsZero() { + if !bucketsJE[k].IsInfinity() { runningSum.add(&bucketsJE[k]) } total.add(&runningSum) @@ -554,7 +554,7 @@ func processChunkG2BatchAffine[BJE ibg2JacExtended, B ibG2Affine, BS bitSet, TP total.setInfinity() for k := len(buckets) - 1; k >= 0; k-- { runningSum.addMixed(&buckets[k]) - if !bucketsJE[k].IsZero() { + if !bucketsJE[k].IsInfinity() { runningSum.add(&bucketsJE[k]) } total.add(&runningSum) diff --git a/ecc/bls12-378/multiexp_jacobian.go b/ecc/bls12-378/multiexp_jacobian.go index 866b5b98f..952a76711 100644 --- a/ecc/bls12-378/multiexp_jacobian.go +++ b/ecc/bls12-378/multiexp_jacobian.go @@ -56,7 +56,7 @@ func processChunkG1Jacobian[B ibg1JacExtended](chunk uint64, runningSum.setInfinity() total.setInfinity() for k := len(buckets) - 1; k >= 0; k-- { - if !buckets[k].IsZero() { + if !buckets[k].IsInfinity() { runningSum.add(&buckets[k]) } total.add(&runningSum) @@ -147,7 +147,7 @@ func processChunkG2Jacobian[B ibg2JacExtended](chunk uint64, runningSum.setInfinity() total.setInfinity() for k := len(buckets) - 1; k >= 0; k-- { - if !buckets[k].IsZero() { + if !buckets[k].IsInfinity() { runningSum.add(&buckets[k]) } total.add(&runningSum) diff --git a/ecc/bls12-381/g1.go b/ecc/bls12-381/g1.go index 019a96203..356f5de99 100644 --- a/ecc/bls12-381/g1.go +++ b/ecc/bls12-381/g1.go @@ -25,38 +25,40 @@ import ( "runtime" ) -// G1Affine point in affine coordinates +// G1Affine is a point in affine coordinates (x,y) type G1Affine struct { X, Y fp.Element } -// G1Jac is a point with fp.Element coordinates +// G1Jac is a point in Jacobian coordinates (x=X/Z², y=Y/Z³) type G1Jac struct { X, Y, Z fp.Element } -// g1JacExtended parameterized Jacobian coordinates (x=X/ZZ, y=Y/ZZZ, ZZ³=ZZZ²) +// g1JacExtended is a point in extended Jacobian coordinates (x=X/ZZ, y=Y/ZZZ, ZZ³=ZZZ²) type g1JacExtended struct { X, Y, ZZ, ZZZ fp.Element } // ------------------------------------------------------------------------------------------------- -// Affine +// Affine coordinates -// Set sets p to the provided point +// Set sets p to a in affine coordinates. func (p *G1Affine) Set(a *G1Affine) *G1Affine { p.X, p.Y = a.X, a.Y return p } -// setInfinity sets p to O +// setInfinity sets p to the infinity point, which is encoded as (0,0). +// N.B.: (0,0) is never on the curve for j=0 curves (Y²=X³+B). func (p *G1Affine) setInfinity() *G1Affine { p.X.SetZero() p.Y.SetZero() return p } -// ScalarMultiplication computes and returns p = a ⋅ s +// ScalarMultiplication computes and returns p = [s]a +// where p and a are affine points. func (p *G1Affine) ScalarMultiplication(a *G1Affine, s *big.Int) *G1Affine { var _p G1Jac _p.FromAffine(a) @@ -65,20 +67,22 @@ func (p *G1Affine) ScalarMultiplication(a *G1Affine, s *big.Int) *G1Affine { return p } -// ScalarMultiplicationAffine computes and returns p = a ⋅ s -// Takes an affine point and returns a Jacobian point (useful for KZG) +// ScalarMultiplicationAffine computes and returns p = [s]a +// where a is an affine point and p a Jacobian point (useful for KZG). func (p *G1Jac) ScalarMultiplicationAffine(a *G1Affine, s *big.Int) *G1Jac { p.FromAffine(a) p.mulGLV(p, s) return p } -// ScalarMultiplicationBase computes and returns p = g ⋅ s where g is the prime subgroup generator +// ScalarMultiplicationBase computes and returns p = [s]g +// where g is the Jacobian point generating the prime subgroup. func (p *G1Jac) ScalarMultiplicationBase(s *big.Int) *G1Jac { return p.mulGLV(&g1Gen, s) } -// ScalarMultiplicationBase computes and returns p = g ⋅ s where g is the prime subgroup generator +// ScalarMultiplicationBase computes and returns p = [s]g +// where g is the affine point generating the prime subgroup. func (p *G1Affine) ScalarMultiplicationBase(s *big.Int) *G1Affine { var _p G1Jac _p.mulGLV(&g1Gen, s) @@ -86,8 +90,9 @@ func (p *G1Affine) ScalarMultiplicationBase(s *big.Int) *G1Affine { return p } -// Add adds two point in affine coordinates. -// Jacobian addition with Z1=Z2=1 +// Add adds two points in affine coordinates. +// It uses the Jacobian addition with a.Z=b.Z=1 and converts the result to affine coordinates. +// // https://www.hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html#addition-mmadd-2007-bl func (p *G1Affine) Add(a, b *G1Affine) *G1Affine { var q G1Jac @@ -133,6 +138,10 @@ func (p *G1Affine) Add(a, b *G1Affine) *G1Affine { } // Double doubles a point in affine coordinates. +// It converts the point to Jacobian coordinates, doubles it using Jacobian +// addition with a.Z=1, and converts it back to affine coordinates. +// +// http://www.hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html#doubling-mdbl-2007-bl func (p *G1Affine) Double(a *G1Affine) *G1Affine { var q G1Jac q.FromAffine(a) @@ -141,7 +150,8 @@ func (p *G1Affine) Double(a *G1Affine) *G1Affine { return p } -// Sub subs two point in affine coordinates. +// Sub subtracts two points in affine coordinates. +// It uses a similar approach to Add, but negates the second point before adding. func (p *G1Affine) Sub(a, b *G1Affine) *G1Affine { var bneg G1Affine bneg.Neg(b) @@ -149,19 +159,19 @@ func (p *G1Affine) Sub(a, b *G1Affine) *G1Affine { return p } -// Equal tests if two points (in Affine coordinates) are equal +// Equal tests if two points in affine coordinates are equal. func (p *G1Affine) Equal(a *G1Affine) bool { return p.X.Equal(&a.X) && p.Y.Equal(&a.Y) } -// Neg computes -G +// Neg sets p to the affine negative point -a = (a.X, -a.Y). func (p *G1Affine) Neg(a *G1Affine) *G1Affine { p.X = a.X p.Y.Neg(&a.Y) return p } -// FromJacobian rescales a point in Jacobian coord in z=1 plane +// FromJacobian converts a point p1 from Jacobian to affine coordinates. func (p *G1Affine) FromJacobian(p1 *G1Jac) *G1Affine { var a, b fp.Element @@ -180,7 +190,7 @@ func (p *G1Affine) FromJacobian(p1 *G1Jac) *G1Affine { return p } -// String returns the string representation of the point or "O" if it is infinity +// String returns the string representation E(x,y) of the affine point p or "O" if it is infinity. func (p *G1Affine) String() string { if p.IsInfinity() { return "O" @@ -188,21 +198,20 @@ func (p *G1Affine) String() string { return "E([" + p.X.String() + "," + p.Y.String() + "])" } -// IsInfinity checks if the point is infinity -// in affine, it's encoded as (0,0) -// (0,0) is never on the curve for j=0 curves +// IsInfinity checks if the affine point p is infinity, which is encoded as (0,0). +// N.B.: (0,0) is never on the curve for j=0 curves (Y²=X³+B). func (p *G1Affine) IsInfinity() bool { return p.X.IsZero() && p.Y.IsZero() } -// IsOnCurve returns true if p in on the curve +// IsOnCurve returns true if the affine point p in on the curve. func (p *G1Affine) IsOnCurve() bool { var point G1Jac point.FromAffine(p) return point.IsOnCurve() // call this function to handle infinity point } -// IsInSubGroup returns true if p is in the correct subgroup, false otherwise +// IsInSubGroup returns true if the affine point p is in the correct subgroup, false otherwise. func (p *G1Affine) IsInSubGroup() bool { var _p G1Jac _p.FromAffine(p) @@ -210,84 +219,76 @@ func (p *G1Affine) IsInSubGroup() bool { } // ------------------------------------------------------------------------------------------------- -// Jacobian +// Jacobian coordinates -// Set sets p to the provided point -func (p *G1Jac) Set(a *G1Jac) *G1Jac { - p.X, p.Y, p.Z = a.X, a.Y, a.Z +// Set sets p to a in Jacobian coordinates. +func (p *G1Jac) Set(q *G1Jac) *G1Jac { + p.X, p.Y, p.Z = q.X, q.Y, q.Z return p } -// Equal tests if two points (in Jacobian coordinates) are equal -func (p *G1Jac) Equal(a *G1Jac) bool { +// Equal tests if two points in Jacobian coordinates are equal. +func (p *G1Jac) Equal(q *G1Jac) bool { // If one point is infinity, the other must also be infinity. if p.Z.IsZero() { - return a.Z.IsZero() + return q.Z.IsZero() } // If the other point is infinity, return false since we can't // the following checks would be incorrect. - if a.Z.IsZero() { + if q.Z.IsZero() { return false } var pZSquare, aZSquare fp.Element pZSquare.Square(&p.Z) - aZSquare.Square(&a.Z) + aZSquare.Square(&q.Z) var lhs, rhs fp.Element lhs.Mul(&p.X, &aZSquare) - rhs.Mul(&a.X, &pZSquare) + rhs.Mul(&q.X, &pZSquare) if !lhs.Equal(&rhs) { return false } - lhs.Mul(&p.Y, &aZSquare).Mul(&lhs, &a.Z) - rhs.Mul(&a.Y, &pZSquare).Mul(&rhs, &p.Z) + lhs.Mul(&p.Y, &aZSquare).Mul(&lhs, &q.Z) + rhs.Mul(&q.Y, &pZSquare).Mul(&rhs, &p.Z) return lhs.Equal(&rhs) } -// Neg computes -G -func (p *G1Jac) Neg(a *G1Jac) *G1Jac { - *p = *a - p.Y.Neg(&a.Y) +// Neg sets p to the Jacobian negative point -q = (q.X, -q.Y, q.Z). +func (p *G1Jac) Neg(q *G1Jac) *G1Jac { + *p = *q + p.Y.Neg(&q.Y) return p } -// SubAssign subtracts two points on the curve -func (p *G1Jac) SubAssign(a *G1Jac) *G1Jac { - var tmp G1Jac - tmp.Set(a) - tmp.Y.Neg(&tmp.Y) - p.AddAssign(&tmp) - return p -} - -// AddAssign point addition in montgomery form +// AddAssign sets p to p+a in Jacobian coordinates. +// // https://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-3.html#addition-add-2007-bl -func (p *G1Jac) AddAssign(a *G1Jac) *G1Jac { +func (p *G1Jac) AddAssign(q *G1Jac) *G1Jac { - // p is infinity, return a + // p is infinity, return q if p.Z.IsZero() { - p.Set(a) + p.Set(q) return p } - // a is infinity, return p - if a.Z.IsZero() { + // q is infinity, return p + if q.Z.IsZero() { return p } var Z1Z1, Z2Z2, U1, U2, S1, S2, H, I, J, r, V fp.Element - Z1Z1.Square(&a.Z) + Z1Z1.Square(&q.Z) Z2Z2.Square(&p.Z) - U1.Mul(&a.X, &Z2Z2) + U1.Mul(&q.X, &Z2Z2) U2.Mul(&p.X, &Z1Z1) - S1.Mul(&a.Y, &p.Z). + S1.Mul(&q.Y, &p.Z). Mul(&S1, &Z2Z2) - S2.Mul(&p.Y, &a.Z). + S2.Mul(&p.Y, &q.Z). Mul(&S2, &Z1Z1) - // if p == a, we double instead + // if p == q, we double instead if U1.Equal(&U2) && S1.Equal(&S2) { return p.DoubleAssign() } @@ -306,7 +307,7 @@ func (p *G1Jac) AddAssign(a *G1Jac) *G1Jac { Mul(&p.Y, &r) S1.Mul(&S1, &J).Double(&S1) p.Y.Sub(&p.Y, &S1) - p.Z.Add(&p.Z, &a.Z) + p.Z.Add(&p.Z, &q.Z) p.Z.Square(&p.Z). Sub(&p.Z, &Z1Z1). Sub(&p.Z, &Z2Z2). @@ -315,8 +316,19 @@ func (p *G1Jac) AddAssign(a *G1Jac) *G1Jac { return p } -// DoubleMixed point addition -// http://www.hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html#doubling-mdbl-2007-bl +// SubAssign sets p to p-a in Jacobian coordinates. +// It uses a similar approach to AddAssign, but negates the point a before adding. +func (p *G1Jac) SubAssign(q *G1Jac) *G1Jac { + var tmp G1Jac + tmp.Set(q) + tmp.Y.Neg(&tmp.Y) + p.AddAssign(&tmp) + return p +} + +// Double sets p to [2]q in Jacobian coordinates. +// +// https://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-3.html#doubling-dbl-2007-bl func (p *G1Jac) DoubleMixed(a *G1Affine) *G1Jac { var XX, YY, YYYY, S, M, T fp.Element XX.Square(&a.X) @@ -328,7 +340,7 @@ func (p *G1Jac) DoubleMixed(a *G1Affine) *G1Jac { Sub(&S, &YYYY). Double(&S) M.Double(&XX). - Add(&M, &XX) // -> + a, but a=0 here + Add(&M, &XX) // -> + A, but A=0 here T.Square(&M). Sub(&T, &S). Sub(&T, &S) @@ -344,7 +356,8 @@ func (p *G1Jac) DoubleMixed(a *G1Affine) *G1Jac { return p } -// AddMixed point addition +// AddMixed sets p to p+a in Jacobian coordinates, where a.Z = 1. +// // http://www.hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html#addition-madd-2007-bl func (p *G1Jac) AddMixed(a *G1Affine) *G1Jac { @@ -393,7 +406,8 @@ func (p *G1Jac) AddMixed(a *G1Affine) *G1Jac { return p } -// Double doubles a point in Jacobian coordinates +// Double sets p to [2]q in Jacobian coordinates. +// // https://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-3.html#doubling-dbl-2007-bl func (p *G1Jac) Double(q *G1Jac) *G1Jac { p.Set(q) @@ -401,7 +415,8 @@ func (p *G1Jac) Double(q *G1Jac) *G1Jac { return p } -// DoubleAssign doubles a point in Jacobian coordinates +// DoubleAssign doubles p in Jacobian coordinates. +// // https://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-3.html#doubling-dbl-2007-bl func (p *G1Jac) DoubleAssign() *G1Jac { @@ -433,34 +448,36 @@ func (p *G1Jac) DoubleAssign() *G1Jac { return p } -// ScalarMultiplication computes and returns p = a ⋅ s +// ScalarMultiplication computes and returns p = [s]a +// where p and a are Jacobian points. +// using the GLV technique. // see https://www.iacr.org/archive/crypto2001/21390189.pdf -func (p *G1Jac) ScalarMultiplication(a *G1Jac, s *big.Int) *G1Jac { - return p.mulGLV(a, s) +func (p *G1Jac) ScalarMultiplication(q *G1Jac, s *big.Int) *G1Jac { + return p.mulGLV(q, s) } -// String returns canonical representation of the point in affine coordinates +// String converts p to affine coordinates and returns its string representation E(x,y) or "O" if it is infinity. func (p *G1Jac) String() string { _p := G1Affine{} _p.FromJacobian(p) return _p.String() } -// FromAffine sets p = Q, p in Jacobian, Q in affine -func (p *G1Jac) FromAffine(Q *G1Affine) *G1Jac { - if Q.IsInfinity() { +// FromAffine converts a point a from affine to Jacobian coordinates. +func (p *G1Jac) FromAffine(a *G1Affine) *G1Jac { + if a.IsInfinity() { p.Z.SetZero() p.X.SetOne() p.Y.SetOne() return p } p.Z.SetOne() - p.X.Set(&Q.X) - p.Y.Set(&Q.Y) + p.X.Set(&a.X) + p.Y.Set(&a.Y) return p } -// IsOnCurve returns true if p in on the curve +// IsOnCurve returns true if the Jacobian point p in on the curve. func (p *G1Jac) IsOnCurve() bool { var left, right, tmp, ZZ fp.Element left.Square(&p.Y) @@ -492,13 +509,14 @@ func (p *G1Jac) IsInSubGroup() bool { } -// mulWindowed computes a 2-bits windowed scalar multiplication -func (p *G1Jac) mulWindowed(a *G1Jac, s *big.Int) *G1Jac { +// mulWindowed computes the 2-bits windowed double-and-add scalar +// multiplication p=[s]q in Jacobian coordinates. +func (p *G1Jac) mulWindowed(q *G1Jac, s *big.Int) *G1Jac { var res G1Jac var ops [3]G1Jac - ops[0].Set(a) + ops[0].Set(q) if s.Sign() == -1 { ops[0].Neg(&ops[0]) } @@ -525,17 +543,18 @@ func (p *G1Jac) mulWindowed(a *G1Jac, s *big.Int) *G1Jac { } -// ϕ assigns p to ϕ(a) where ϕ: (x,y) → (w x,y), and returns p -// where w is a third root of unity in 𝔽p -func (p *G1Jac) phi(a *G1Jac) *G1Jac { - p.Set(a) +// phi sets p to ϕ(a) where ϕ: (x,y) → (w x,y), +// where w is a third root of unity. +func (p *G1Jac) phi(q *G1Jac) *G1Jac { + p.Set(q) p.X.Mul(&p.X, &thirdRootOneG1) return p } // mulGLV computes the scalar multiplication using a windowed-GLV method +// // see https://www.iacr.org/archive/crypto2001/21390189.pdf -func (p *G1Jac) mulGLV(a *G1Jac, s *big.Int) *G1Jac { +func (p *G1Jac) mulGLV(q *G1Jac, s *big.Int) *G1Jac { var table [15]G1Jac var res G1Jac @@ -543,11 +562,11 @@ func (p *G1Jac) mulGLV(a *G1Jac, s *big.Int) *G1Jac { res.Set(&g1Infinity) - // table[b3b2b1b0-1] = b3b2 ⋅ ϕ(a) + b1b0*a - table[0].Set(a) - table[3].phi(a) + // table[b3b2b1b0-1] = b3b2 ⋅ ϕ(q) + b1b0*q + table[0].Set(q) + table[3].phi(q) - // split the scalar, modifies ±a, ϕ(a) accordingly + // split the scalar, modifies ±q, ϕ(q) accordingly k := ecc.SplitScalar(s, &glvBasis) if k[0].Sign() == -1 { @@ -560,7 +579,7 @@ func (p *G1Jac) mulGLV(a *G1Jac, s *big.Int) *G1Jac { } // precompute table (2 bits sliding window) - // table[b3b2b1b0-1] = b3b2 ⋅ ϕ(a) + b1b0 ⋅ a if b3b2b1b0 != 0 + // table[b3b2b1b0-1] = b3b2 ⋅ ϕ(q) + b1b0 ⋅ q if b3b2b1b0 != 0 table[1].Double(&table[0]) table[2].Set(&table[1]).AddAssign(&table[0]) table[4].Set(&table[3]).AddAssign(&table[0]) @@ -616,17 +635,17 @@ func (p *G1Affine) ClearCofactor(a *G1Affine) *G1Affine { } // ClearCofactor maps a point in E(Fp) to E(Fp)[r] -func (p *G1Jac) ClearCofactor(a *G1Jac) *G1Jac { +func (p *G1Jac) ClearCofactor(q *G1Jac) *G1Jac { // cf https://eprint.iacr.org/2019/403.pdf, 5 var res G1Jac - res.ScalarMultiplication(a, &xGen).AddAssign(a) + res.ScalarMultiplication(q, &xGen).AddAssign(q) p.Set(&res) return p } -// JointScalarMultiplicationBase computes [s1]g+[s2]a using Straus-Shamir technique -// where g is the prime subgroup generator +// JointScalarMultiplicationBase computes [s1]g+[s2]a using Strauss-Shamir technique +// where g is the prime subgroup generator and a is an affine point. func (p *G1Jac) JointScalarMultiplicationBase(a *G1Affine, s1, s2 *big.Int) *G1Jac { var res, p1, p2 G1Jac @@ -697,15 +716,15 @@ func (p *G1Jac) JointScalarMultiplicationBase(a *G1Affine, s1, s2 *big.Int) *G1J } // ------------------------------------------------------------------------------------------------- -// Jacobian extended +// extended Jacobian coordinates -// Set sets p to the provided point -func (p *g1JacExtended) Set(a *g1JacExtended) *g1JacExtended { - p.X, p.Y, p.ZZ, p.ZZZ = a.X, a.Y, a.ZZ, a.ZZZ +// Set sets p to a in extended Jacobian coordinates. +func (p *g1JacExtended) Set(q *g1JacExtended) *g1JacExtended { + p.X, p.Y, p.ZZ, p.ZZZ = q.X, q.Y, q.ZZ, q.ZZZ return p } -// setInfinity sets p to O +// setInfinity sets p to the infinity point (1,1,0,0). func (p *g1JacExtended) setInfinity() *g1JacExtended { p.X.SetOne() p.Y.SetOne() @@ -714,43 +733,45 @@ func (p *g1JacExtended) setInfinity() *g1JacExtended { return p } -func (p *g1JacExtended) IsZero() bool { +// IsInfinity checks if the p is infinity, i.e. p.ZZ=0. +func (p *g1JacExtended) IsInfinity() bool { return p.ZZ.IsZero() } -// fromJacExtended sets Q in affine coordinates -func (p *G1Affine) fromJacExtended(Q *g1JacExtended) *G1Affine { - if Q.ZZ.IsZero() { +// fromJacExtended converts an extended Jacobian point to an affine point. +func (p *G1Affine) fromJacExtended(q *g1JacExtended) *G1Affine { + if q.ZZ.IsZero() { p.X = fp.Element{} p.Y = fp.Element{} return p } - p.X.Inverse(&Q.ZZ).Mul(&p.X, &Q.X) - p.Y.Inverse(&Q.ZZZ).Mul(&p.Y, &Q.Y) + p.X.Inverse(&q.ZZ).Mul(&p.X, &q.X) + p.Y.Inverse(&q.ZZZ).Mul(&p.Y, &q.Y) return p } -// fromJacExtended sets Q in Jacobian coordinates -func (p *G1Jac) fromJacExtended(Q *g1JacExtended) *G1Jac { - if Q.ZZ.IsZero() { +// fromJacExtended converts an extended Jacobian point to a Jacobian point. +func (p *G1Jac) fromJacExtended(q *g1JacExtended) *G1Jac { + if q.ZZ.IsZero() { p.Set(&g1Infinity) return p } - p.X.Mul(&Q.ZZ, &Q.X).Mul(&p.X, &Q.ZZ) - p.Y.Mul(&Q.ZZZ, &Q.Y).Mul(&p.Y, &Q.ZZZ) - p.Z.Set(&Q.ZZZ) + p.X.Mul(&q.ZZ, &q.X).Mul(&p.X, &q.ZZ) + p.Y.Mul(&q.ZZZ, &q.Y).Mul(&p.Y, &q.ZZZ) + p.Z.Set(&q.ZZZ) return p } -// unsafeFromJacExtended sets p in Jacobian coordinates, but don't check for infinity -func (p *G1Jac) unsafeFromJacExtended(Q *g1JacExtended) *G1Jac { - p.X.Square(&Q.ZZ).Mul(&p.X, &Q.X) - p.Y.Square(&Q.ZZZ).Mul(&p.Y, &Q.Y) - p.Z = Q.ZZZ +// unsafeFromJacExtended converts an extended Jacobian point, distinct from Infinity, to a Jacobian point. +func (p *G1Jac) unsafeFromJacExtended(q *g1JacExtended) *G1Jac { + p.X.Square(&q.ZZ).Mul(&p.X, &q.X) + p.Y.Square(&q.ZZZ).Mul(&p.Y, &q.Y) + p.Z = q.ZZZ return p } -// add point in Jacobian extended coordinates +// add sets p to p+q in extended Jacobian coordinates. +// // https://www.hyperelliptic.org/EFD/g1p/auto-shortw-xyzz.html#addition-add-2008-s func (p *g1JacExtended) add(q *g1JacExtended) *g1JacExtended { //if q is infinity return p @@ -806,10 +827,11 @@ func (p *g1JacExtended) add(q *g1JacExtended) *g1JacExtended { return p } -// double point in Jacobian extended coordinates +// double sets p to [2]q in Jacobian extended coordinates. +// // http://www.hyperelliptic.org/EFD/g1p/auto-shortw-xyzz.html#doubling-dbl-2008-s-1 -// since we consider any point on Z=0 as the point at infinity -// this doubling formula works for infinity points as well +// N.B.: since we consider any point on Z=0 as the point at infinity +// this doubling formula works for infinity points as well. func (p *g1JacExtended) double(q *g1JacExtended) *g1JacExtended { var U, V, W, S, XX, M fp.Element @@ -819,7 +841,7 @@ func (p *g1JacExtended) double(q *g1JacExtended) *g1JacExtended { S.Mul(&q.X, &V) XX.Square(&q.X) M.Double(&XX). - Add(&M, &XX) // -> + a, but a=0 here + Add(&M, &XX) // -> + A, but A=0 here U.Mul(&W, &q.Y) p.X.Square(&M). @@ -834,9 +856,10 @@ func (p *g1JacExtended) double(q *g1JacExtended) *g1JacExtended { return p } -// subMixed same as addMixed, but will negate a.Y +// addMixed sets p to p+q in extended Jacobian coordinates, where a.ZZ=1. +// // http://www.hyperelliptic.org/EFD/g1p/auto-shortw-xyzz.html#addition-madd-2008-s -func (p *g1JacExtended) subMixed(a *G1Affine) *g1JacExtended { +func (p *g1JacExtended) addMixed(a *G1Affine) *g1JacExtended { //if a is infinity return p if a.IsInfinity() { @@ -845,7 +868,7 @@ func (p *g1JacExtended) subMixed(a *G1Affine) *g1JacExtended { // p is infinity, return a if p.ZZ.IsZero() { p.X = a.X - p.Y.Neg(&a.Y) + p.Y = a.Y p.ZZ.SetOne() p.ZZZ.SetOne() return p @@ -858,12 +881,11 @@ func (p *g1JacExtended) subMixed(a *G1Affine) *g1JacExtended { P.Sub(&P, &p.X) R.Mul(&a.Y, &p.ZZZ) - R.Neg(&R) R.Sub(&R, &p.Y) if P.IsZero() { if R.IsZero() { - return p.doubleNegMixed(a) + return p.doubleMixed(a) } p.ZZ = fp.Element{} @@ -890,9 +912,10 @@ func (p *g1JacExtended) subMixed(a *G1Affine) *g1JacExtended { } -// addMixed +// subMixed works the same as addMixed, but negates a.Y. +// // http://www.hyperelliptic.org/EFD/g1p/auto-shortw-xyzz.html#addition-madd-2008-s -func (p *g1JacExtended) addMixed(a *G1Affine) *g1JacExtended { +func (p *g1JacExtended) subMixed(a *G1Affine) *g1JacExtended { //if a is infinity return p if a.IsInfinity() { @@ -901,7 +924,7 @@ func (p *g1JacExtended) addMixed(a *G1Affine) *g1JacExtended { // p is infinity, return a if p.ZZ.IsZero() { p.X = a.X - p.Y = a.Y + p.Y.Neg(&a.Y) p.ZZ.SetOne() p.ZZZ.SetOne() return p @@ -914,11 +937,12 @@ func (p *g1JacExtended) addMixed(a *G1Affine) *g1JacExtended { P.Sub(&P, &p.X) R.Mul(&a.Y, &p.ZZZ) + R.Neg(&R) R.Sub(&R, &p.Y) if P.IsZero() { if R.IsZero() { - return p.doubleMixed(a) + return p.doubleNegMixed(a) } p.ZZ = fp.Element{} @@ -945,21 +969,21 @@ func (p *g1JacExtended) addMixed(a *G1Affine) *g1JacExtended { } -// doubleNegMixed same as double, but will negate q.Y -func (p *g1JacExtended) doubleNegMixed(q *G1Affine) *g1JacExtended { +// doubleNegMixed works the same as double, but negates q.Y. +func (p *g1JacExtended) doubleNegMixed(a *G1Affine) *g1JacExtended { var U, V, W, S, XX, M, S2, L fp.Element - U.Double(&q.Y) + U.Double(&a.Y) U.Neg(&U) V.Square(&U) W.Mul(&U, &V) - S.Mul(&q.X, &V) - XX.Square(&q.X) + S.Mul(&a.X, &V) + XX.Square(&a.X) M.Double(&XX). - Add(&M, &XX) // -> + a, but a=0 here + Add(&M, &XX) // -> + A, but A=0 here S2.Double(&S) - L.Mul(&W, &q.Y) + L.Mul(&W, &a.Y) p.X.Square(&M). Sub(&p.X, &S2) @@ -972,21 +996,22 @@ func (p *g1JacExtended) doubleNegMixed(q *G1Affine) *g1JacExtended { return p } -// doubleMixed point in Jacobian extended coordinates +// doubleMixed sets p to [2]a in Jacobian extended coordinates, where a.ZZ=1. +// // http://www.hyperelliptic.org/EFD/g1p/auto-shortw-xyzz.html#doubling-dbl-2008-s-1 -func (p *g1JacExtended) doubleMixed(q *G1Affine) *g1JacExtended { +func (p *g1JacExtended) doubleMixed(a *G1Affine) *g1JacExtended { var U, V, W, S, XX, M, S2, L fp.Element - U.Double(&q.Y) + U.Double(&a.Y) V.Square(&U) W.Mul(&U, &V) - S.Mul(&q.X, &V) - XX.Square(&q.X) + S.Mul(&a.X, &V) + XX.Square(&a.X) M.Double(&XX). - Add(&M, &XX) // -> + a, but a=0 here + Add(&M, &XX) // -> + A, but A=0 here S2.Double(&S) - L.Mul(&W, &q.Y) + L.Mul(&W, &a.Y) p.X.Square(&M). Sub(&p.X, &S2) @@ -1000,7 +1025,7 @@ func (p *g1JacExtended) doubleMixed(q *G1Affine) *g1JacExtended { } // BatchJacobianToAffineG1 converts points in Jacobian coordinates to Affine coordinates -// performing a single field inversion (Montgomery batch inversion trick). +// performing a single field inversion using the Montgomery batch inversion trick. func BatchJacobianToAffineG1(points []G1Jac) []G1Affine { result := make([]G1Affine, len(points)) zeroes := make([]bool, len(points)) @@ -1050,7 +1075,7 @@ func BatchJacobianToAffineG1(points []G1Jac) []G1Affine { // BatchScalarMultiplicationG1 multiplies the same base by all scalars // and return resulting points in affine coordinates -// uses a simple windowed-NAF like exponentiation algorithm +// uses a simple windowed-NAF-like multiplication algorithm. func BatchScalarMultiplicationG1(base *G1Affine, scalars []fr.Element) []G1Affine { // approximate cost in group ops is // cost = 2^{c-1} + n(scalar.nbBits+nbChunks) @@ -1132,9 +1157,8 @@ func BatchScalarMultiplicationG1(base *G1Affine, scalars []fr.Element) []G1Affin return toReturnAff } -// batch add affine coordinates -// using batch inversion -// special cases (doubling, infinity) must be filtered out before this call +// batchAddG1Affine adds affine points using the Montgomery batch inversion trick. +// Special cases (doubling, infinity) must be filtered out before this call. func batchAddG1Affine[TP pG1Affine, TPP ppG1Affine, TC cG1Affine](R *TPP, P *TP, batchSize int) { var lambda, lambdain TC diff --git a/ecc/bls12-381/g2.go b/ecc/bls12-381/g2.go index 7f08b2662..795667e63 100644 --- a/ecc/bls12-381/g2.go +++ b/ecc/bls12-381/g2.go @@ -25,17 +25,17 @@ import ( "runtime" ) -// G2Affine point in affine coordinates +// G2Affine is a point in affine coordinates (x,y) type G2Affine struct { X, Y fptower.E2 } -// G2Jac is a point with fptower.E2 coordinates +// G2Jac is a point in Jacobian coordinates (x=X/Z², y=Y/Z³) type G2Jac struct { X, Y, Z fptower.E2 } -// g2JacExtended parameterized Jacobian coordinates (x=X/ZZ, y=Y/ZZZ, ZZ³=ZZZ²) +// g2JacExtended is a point in extended Jacobian coordinates (x=X/ZZ, y=Y/ZZZ, ZZ³=ZZZ²) type g2JacExtended struct { X, Y, ZZ, ZZZ fptower.E2 } @@ -46,22 +46,24 @@ type g2Proj struct { } // ------------------------------------------------------------------------------------------------- -// Affine +// Affine coordinates -// Set sets p to the provided point +// Set sets p to a in affine coordinates. func (p *G2Affine) Set(a *G2Affine) *G2Affine { p.X, p.Y = a.X, a.Y return p } -// setInfinity sets p to O +// setInfinity sets p to the infinity point, which is encoded as (0,0). +// N.B.: (0,0) is never on the curve for j=0 curves (Y²=X³+B). func (p *G2Affine) setInfinity() *G2Affine { p.X.SetZero() p.Y.SetZero() return p } -// ScalarMultiplication computes and returns p = a ⋅ s +// ScalarMultiplication computes and returns p = [s]a +// where p and a are affine points. func (p *G2Affine) ScalarMultiplication(a *G2Affine, s *big.Int) *G2Affine { var _p G2Jac _p.FromAffine(a) @@ -70,7 +72,8 @@ func (p *G2Affine) ScalarMultiplication(a *G2Affine, s *big.Int) *G2Affine { return p } -// ScalarMultiplicationBase computes and returns p = g ⋅ s where g is the prime subgroup generator +// ScalarMultiplicationBase computes and returns p = [s]g +// where g is the affine point generating the prime subgroup. func (p *G2Affine) ScalarMultiplicationBase(s *big.Int) *G2Affine { var _p G2Jac _p.mulGLV(&g2Gen, s) @@ -78,8 +81,9 @@ func (p *G2Affine) ScalarMultiplicationBase(s *big.Int) *G2Affine { return p } -// Add adds two point in affine coordinates. -// Jacobian addition with Z1=Z2=1 +// Add adds two points in affine coordinates. +// It uses the Jacobian addition with a.Z=b.Z=1 and converts the result to affine coordinates. +// // https://www.hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html#addition-mmadd-2007-bl func (p *G2Affine) Add(a, b *G2Affine) *G2Affine { var q G2Jac @@ -125,6 +129,10 @@ func (p *G2Affine) Add(a, b *G2Affine) *G2Affine { } // Double doubles a point in affine coordinates. +// It converts the point to Jacobian coordinates, doubles it using Jacobian +// addition with a.Z=1, and converts it back to affine coordinates. +// +// http://www.hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html#doubling-mdbl-2007-bl func (p *G2Affine) Double(a *G2Affine) *G2Affine { var q G2Jac q.FromAffine(a) @@ -133,7 +141,8 @@ func (p *G2Affine) Double(a *G2Affine) *G2Affine { return p } -// Sub subs two point in affine coordinates. +// Sub subtracts two points in affine coordinates. +// It uses a similar approach to Add, but negates the second point before adding. func (p *G2Affine) Sub(a, b *G2Affine) *G2Affine { var bneg G2Affine bneg.Neg(b) @@ -141,19 +150,19 @@ func (p *G2Affine) Sub(a, b *G2Affine) *G2Affine { return p } -// Equal tests if two points (in Affine coordinates) are equal +// Equal tests if two points in affine coordinates are equal. func (p *G2Affine) Equal(a *G2Affine) bool { return p.X.Equal(&a.X) && p.Y.Equal(&a.Y) } -// Neg computes -G +// Neg sets p to the affine negative point -a = (a.X, -a.Y). func (p *G2Affine) Neg(a *G2Affine) *G2Affine { p.X = a.X p.Y.Neg(&a.Y) return p } -// FromJacobian rescales a point in Jacobian coord in z=1 plane +// FromJacobian converts a point p1 from Jacobian to affine coordinates. func (p *G2Affine) FromJacobian(p1 *G2Jac) *G2Affine { var a, b fptower.E2 @@ -172,7 +181,7 @@ func (p *G2Affine) FromJacobian(p1 *G2Jac) *G2Affine { return p } -// String returns the string representation of the point or "O" if it is infinity +// String returns the string representation E(x,y) of the affine point p or "O" if it is infinity. func (p *G2Affine) String() string { if p.IsInfinity() { return "O" @@ -180,21 +189,20 @@ func (p *G2Affine) String() string { return "E([" + p.X.String() + "," + p.Y.String() + "])" } -// IsInfinity checks if the point is infinity -// in affine, it's encoded as (0,0) -// (0,0) is never on the curve for j=0 curves +// IsInfinity checks if the affine point p is infinity, which is encoded as (0,0). +// N.B.: (0,0) is never on the curve for j=0 curves (Y²=X³+B). func (p *G2Affine) IsInfinity() bool { return p.X.IsZero() && p.Y.IsZero() } -// IsOnCurve returns true if p in on the curve +// IsOnCurve returns true if the affine point p in on the curve. func (p *G2Affine) IsOnCurve() bool { var point G2Jac point.FromAffine(p) return point.IsOnCurve() // call this function to handle infinity point } -// IsInSubGroup returns true if p is in the correct subgroup, false otherwise +// IsInSubGroup returns true if the affine point p is in the correct subgroup, false otherwise. func (p *G2Affine) IsInSubGroup() bool { var _p G2Jac _p.FromAffine(p) @@ -202,84 +210,76 @@ func (p *G2Affine) IsInSubGroup() bool { } // ------------------------------------------------------------------------------------------------- -// Jacobian +// Jacobian coordinates -// Set sets p to the provided point -func (p *G2Jac) Set(a *G2Jac) *G2Jac { - p.X, p.Y, p.Z = a.X, a.Y, a.Z +// Set sets p to a in Jacobian coordinates. +func (p *G2Jac) Set(q *G2Jac) *G2Jac { + p.X, p.Y, p.Z = q.X, q.Y, q.Z return p } -// Equal tests if two points (in Jacobian coordinates) are equal -func (p *G2Jac) Equal(a *G2Jac) bool { +// Equal tests if two points in Jacobian coordinates are equal. +func (p *G2Jac) Equal(q *G2Jac) bool { // If one point is infinity, the other must also be infinity. if p.Z.IsZero() { - return a.Z.IsZero() + return q.Z.IsZero() } // If the other point is infinity, return false since we can't // the following checks would be incorrect. - if a.Z.IsZero() { + if q.Z.IsZero() { return false } var pZSquare, aZSquare fptower.E2 pZSquare.Square(&p.Z) - aZSquare.Square(&a.Z) + aZSquare.Square(&q.Z) var lhs, rhs fptower.E2 lhs.Mul(&p.X, &aZSquare) - rhs.Mul(&a.X, &pZSquare) + rhs.Mul(&q.X, &pZSquare) if !lhs.Equal(&rhs) { return false } - lhs.Mul(&p.Y, &aZSquare).Mul(&lhs, &a.Z) - rhs.Mul(&a.Y, &pZSquare).Mul(&rhs, &p.Z) + lhs.Mul(&p.Y, &aZSquare).Mul(&lhs, &q.Z) + rhs.Mul(&q.Y, &pZSquare).Mul(&rhs, &p.Z) return lhs.Equal(&rhs) } -// Neg computes -G -func (p *G2Jac) Neg(a *G2Jac) *G2Jac { - *p = *a - p.Y.Neg(&a.Y) - return p -} - -// SubAssign subtracts two points on the curve -func (p *G2Jac) SubAssign(a *G2Jac) *G2Jac { - var tmp G2Jac - tmp.Set(a) - tmp.Y.Neg(&tmp.Y) - p.AddAssign(&tmp) +// Neg sets p to the Jacobian negative point -q = (q.X, -q.Y, q.Z). +func (p *G2Jac) Neg(q *G2Jac) *G2Jac { + *p = *q + p.Y.Neg(&q.Y) return p } -// AddAssign point addition in montgomery form +// AddAssign sets p to p+a in Jacobian coordinates. +// // https://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-3.html#addition-add-2007-bl -func (p *G2Jac) AddAssign(a *G2Jac) *G2Jac { +func (p *G2Jac) AddAssign(q *G2Jac) *G2Jac { - // p is infinity, return a + // p is infinity, return q if p.Z.IsZero() { - p.Set(a) + p.Set(q) return p } - // a is infinity, return p - if a.Z.IsZero() { + // q is infinity, return p + if q.Z.IsZero() { return p } var Z1Z1, Z2Z2, U1, U2, S1, S2, H, I, J, r, V fptower.E2 - Z1Z1.Square(&a.Z) + Z1Z1.Square(&q.Z) Z2Z2.Square(&p.Z) - U1.Mul(&a.X, &Z2Z2) + U1.Mul(&q.X, &Z2Z2) U2.Mul(&p.X, &Z1Z1) - S1.Mul(&a.Y, &p.Z). + S1.Mul(&q.Y, &p.Z). Mul(&S1, &Z2Z2) - S2.Mul(&p.Y, &a.Z). + S2.Mul(&p.Y, &q.Z). Mul(&S2, &Z1Z1) - // if p == a, we double instead + // if p == q, we double instead if U1.Equal(&U2) && S1.Equal(&S2) { return p.DoubleAssign() } @@ -298,7 +298,7 @@ func (p *G2Jac) AddAssign(a *G2Jac) *G2Jac { Mul(&p.Y, &r) S1.Mul(&S1, &J).Double(&S1) p.Y.Sub(&p.Y, &S1) - p.Z.Add(&p.Z, &a.Z) + p.Z.Add(&p.Z, &q.Z) p.Z.Square(&p.Z). Sub(&p.Z, &Z1Z1). Sub(&p.Z, &Z2Z2). @@ -307,8 +307,19 @@ func (p *G2Jac) AddAssign(a *G2Jac) *G2Jac { return p } -// DoubleMixed point addition -// http://www.hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html#doubling-mdbl-2007-bl +// SubAssign sets p to p-a in Jacobian coordinates. +// It uses a similar approach to AddAssign, but negates the point a before adding. +func (p *G2Jac) SubAssign(q *G2Jac) *G2Jac { + var tmp G2Jac + tmp.Set(q) + tmp.Y.Neg(&tmp.Y) + p.AddAssign(&tmp) + return p +} + +// Double sets p to [2]q in Jacobian coordinates. +// +// https://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-3.html#doubling-dbl-2007-bl func (p *G2Jac) DoubleMixed(a *G2Affine) *G2Jac { var XX, YY, YYYY, S, M, T fptower.E2 XX.Square(&a.X) @@ -320,7 +331,7 @@ func (p *G2Jac) DoubleMixed(a *G2Affine) *G2Jac { Sub(&S, &YYYY). Double(&S) M.Double(&XX). - Add(&M, &XX) // -> + a, but a=0 here + Add(&M, &XX) // -> + A, but A=0 here T.Square(&M). Sub(&T, &S). Sub(&T, &S) @@ -336,7 +347,8 @@ func (p *G2Jac) DoubleMixed(a *G2Affine) *G2Jac { return p } -// AddMixed point addition +// AddMixed sets p to p+a in Jacobian coordinates, where a.Z = 1. +// // http://www.hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html#addition-madd-2007-bl func (p *G2Jac) AddMixed(a *G2Affine) *G2Jac { @@ -385,7 +397,8 @@ func (p *G2Jac) AddMixed(a *G2Affine) *G2Jac { return p } -// Double doubles a point in Jacobian coordinates +// Double sets p to [2]q in Jacobian coordinates. +// // https://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-3.html#doubling-dbl-2007-bl func (p *G2Jac) Double(q *G2Jac) *G2Jac { p.Set(q) @@ -393,7 +406,8 @@ func (p *G2Jac) Double(q *G2Jac) *G2Jac { return p } -// DoubleAssign doubles a point in Jacobian coordinates +// DoubleAssign doubles p in Jacobian coordinates. +// // https://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-3.html#doubling-dbl-2007-bl func (p *G2Jac) DoubleAssign() *G2Jac { @@ -425,34 +439,36 @@ func (p *G2Jac) DoubleAssign() *G2Jac { return p } -// ScalarMultiplication computes and returns p = a ⋅ s +// ScalarMultiplication computes and returns p = [s]a +// where p and a are Jacobian points. +// using the GLV technique. // see https://www.iacr.org/archive/crypto2001/21390189.pdf -func (p *G2Jac) ScalarMultiplication(a *G2Jac, s *big.Int) *G2Jac { - return p.mulGLV(a, s) +func (p *G2Jac) ScalarMultiplication(q *G2Jac, s *big.Int) *G2Jac { + return p.mulGLV(q, s) } -// String returns canonical representation of the point in affine coordinates +// String converts p to affine coordinates and returns its string representation E(x,y) or "O" if it is infinity. func (p *G2Jac) String() string { _p := G2Affine{} _p.FromJacobian(p) return _p.String() } -// FromAffine sets p = Q, p in Jacobian, Q in affine -func (p *G2Jac) FromAffine(Q *G2Affine) *G2Jac { - if Q.IsInfinity() { +// FromAffine converts a point a from affine to Jacobian coordinates. +func (p *G2Jac) FromAffine(a *G2Affine) *G2Jac { + if a.IsInfinity() { p.Z.SetZero() p.X.SetOne() p.Y.SetOne() return p } p.Z.SetOne() - p.X.Set(&Q.X) - p.Y.Set(&Q.Y) + p.X.Set(&a.X) + p.Y.Set(&a.Y) return p } -// IsOnCurve returns true if p in on the curve +// IsOnCurve returns true if the Jacobian point p in on the curve. func (p *G2Jac) IsOnCurve() bool { var left, right, tmp, ZZ fptower.E2 left.Square(&p.Y) @@ -477,13 +493,14 @@ func (p *G2Jac) IsInSubGroup() bool { return res.IsOnCurve() && res.Z.IsZero() } -// mulWindowed computes a 2-bits windowed scalar multiplication -func (p *G2Jac) mulWindowed(a *G2Jac, s *big.Int) *G2Jac { +// mulWindowed computes the 2-bits windowed double-and-add scalar +// multiplication p=[s]q in Jacobian coordinates. +func (p *G2Jac) mulWindowed(q *G2Jac, s *big.Int) *G2Jac { var res G2Jac var ops [3]G2Jac - ops[0].Set(a) + ops[0].Set(q) if s.Sign() == -1 { ops[0].Neg(&ops[0]) } @@ -510,26 +527,27 @@ func (p *G2Jac) mulWindowed(a *G2Jac, s *big.Int) *G2Jac { } -// ψ(p) = u o π o u⁻¹ where u:E'→E iso from the twist to E -func (p *G2Jac) psi(a *G2Jac) *G2Jac { - p.Set(a) +// psi sets p to ψ(q) = u o π o u⁻¹ where u:E'→E is the isomorphism from the twist to the curve E and π is the Frobenius map. +func (p *G2Jac) psi(q *G2Jac) *G2Jac { + p.Set(q) p.X.Conjugate(&p.X).Mul(&p.X, &endo.u) p.Y.Conjugate(&p.Y).Mul(&p.Y, &endo.v) p.Z.Conjugate(&p.Z) return p } -// ϕ assigns p to ϕ(a) where ϕ: (x,y) → (w x,y), and returns p -// where w is a third root of unity in 𝔽p -func (p *G2Jac) phi(a *G2Jac) *G2Jac { - p.Set(a) +// phi sets p to ϕ(a) where ϕ: (x,y) → (w x,y), +// where w is a third root of unity. +func (p *G2Jac) phi(q *G2Jac) *G2Jac { + p.Set(q) p.X.MulByElement(&p.X, &thirdRootOneG2) return p } // mulGLV computes the scalar multiplication using a windowed-GLV method +// // see https://www.iacr.org/archive/crypto2001/21390189.pdf -func (p *G2Jac) mulGLV(a *G2Jac, s *big.Int) *G2Jac { +func (p *G2Jac) mulGLV(q *G2Jac, s *big.Int) *G2Jac { var table [15]G2Jac var res G2Jac @@ -537,11 +555,11 @@ func (p *G2Jac) mulGLV(a *G2Jac, s *big.Int) *G2Jac { res.Set(&g2Infinity) - // table[b3b2b1b0-1] = b3b2 ⋅ ϕ(a) + b1b0*a - table[0].Set(a) - table[3].phi(a) + // table[b3b2b1b0-1] = b3b2 ⋅ ϕ(q) + b1b0*q + table[0].Set(q) + table[3].phi(q) - // split the scalar, modifies ±a, ϕ(a) accordingly + // split the scalar, modifies ±q, ϕ(q) accordingly k := ecc.SplitScalar(s, &glvBasis) if k[0].Sign() == -1 { @@ -554,7 +572,7 @@ func (p *G2Jac) mulGLV(a *G2Jac, s *big.Int) *G2Jac { } // precompute table (2 bits sliding window) - // table[b3b2b1b0-1] = b3b2 ⋅ ϕ(a) + b1b0 ⋅ a if b3b2b1b0 != 0 + // table[b3b2b1b0-1] = b3b2 ⋅ ϕ(q) + b1b0 ⋅ q if b3b2b1b0 != 0 table[1].Double(&table[0]) table[2].Set(&table[1]).AddAssign(&table[0]) table[4].Set(&table[3]).AddAssign(&table[0]) @@ -610,23 +628,23 @@ func (p *G2Affine) ClearCofactor(a *G2Affine) *G2Affine { } // ClearCofactor maps a point in curve to r-torsion -func (p *G2Jac) ClearCofactor(a *G2Jac) *G2Jac { +func (p *G2Jac) ClearCofactor(q *G2Jac) *G2Jac { // https://eprint.iacr.org/2017/419.pdf, 4.1 var xg, xxg, res, t G2Jac - xg.ScalarMultiplication(a, &xGen).Neg(&xg) + xg.ScalarMultiplication(q, &xGen).Neg(&xg) xxg.ScalarMultiplication(&xg, &xGen).Neg(&xxg) res.Set(&xxg). SubAssign(&xg). - SubAssign(a) + SubAssign(q) t.Set(&xg). - SubAssign(a). + SubAssign(q). psi(&t) res.AddAssign(&t) - t.Double(a) + t.Double(q) t.X.MulByElement(&t.X, &thirdRootOneG1) res.SubAssign(&t) @@ -638,15 +656,15 @@ func (p *G2Jac) ClearCofactor(a *G2Jac) *G2Jac { } // ------------------------------------------------------------------------------------------------- -// Jacobian extended +// extended Jacobian coordinates -// Set sets p to the provided point -func (p *g2JacExtended) Set(a *g2JacExtended) *g2JacExtended { - p.X, p.Y, p.ZZ, p.ZZZ = a.X, a.Y, a.ZZ, a.ZZZ +// Set sets p to a in extended Jacobian coordinates. +func (p *g2JacExtended) Set(q *g2JacExtended) *g2JacExtended { + p.X, p.Y, p.ZZ, p.ZZZ = q.X, q.Y, q.ZZ, q.ZZZ return p } -// setInfinity sets p to O +// setInfinity sets p to the infinity point (1,1,0,0). func (p *g2JacExtended) setInfinity() *g2JacExtended { p.X.SetOne() p.Y.SetOne() @@ -655,43 +673,45 @@ func (p *g2JacExtended) setInfinity() *g2JacExtended { return p } -func (p *g2JacExtended) IsZero() bool { +// IsInfinity checks if the p is infinity, i.e. p.ZZ=0. +func (p *g2JacExtended) IsInfinity() bool { return p.ZZ.IsZero() } -// fromJacExtended sets Q in affine coordinates -func (p *G2Affine) fromJacExtended(Q *g2JacExtended) *G2Affine { - if Q.ZZ.IsZero() { +// fromJacExtended converts an extended Jacobian point to an affine point. +func (p *G2Affine) fromJacExtended(q *g2JacExtended) *G2Affine { + if q.ZZ.IsZero() { p.X = fptower.E2{} p.Y = fptower.E2{} return p } - p.X.Inverse(&Q.ZZ).Mul(&p.X, &Q.X) - p.Y.Inverse(&Q.ZZZ).Mul(&p.Y, &Q.Y) + p.X.Inverse(&q.ZZ).Mul(&p.X, &q.X) + p.Y.Inverse(&q.ZZZ).Mul(&p.Y, &q.Y) return p } -// fromJacExtended sets Q in Jacobian coordinates -func (p *G2Jac) fromJacExtended(Q *g2JacExtended) *G2Jac { - if Q.ZZ.IsZero() { +// fromJacExtended converts an extended Jacobian point to a Jacobian point. +func (p *G2Jac) fromJacExtended(q *g2JacExtended) *G2Jac { + if q.ZZ.IsZero() { p.Set(&g2Infinity) return p } - p.X.Mul(&Q.ZZ, &Q.X).Mul(&p.X, &Q.ZZ) - p.Y.Mul(&Q.ZZZ, &Q.Y).Mul(&p.Y, &Q.ZZZ) - p.Z.Set(&Q.ZZZ) + p.X.Mul(&q.ZZ, &q.X).Mul(&p.X, &q.ZZ) + p.Y.Mul(&q.ZZZ, &q.Y).Mul(&p.Y, &q.ZZZ) + p.Z.Set(&q.ZZZ) return p } -// unsafeFromJacExtended sets p in Jacobian coordinates, but don't check for infinity -func (p *G2Jac) unsafeFromJacExtended(Q *g2JacExtended) *G2Jac { - p.X.Square(&Q.ZZ).Mul(&p.X, &Q.X) - p.Y.Square(&Q.ZZZ).Mul(&p.Y, &Q.Y) - p.Z = Q.ZZZ +// unsafeFromJacExtended converts an extended Jacobian point, distinct from Infinity, to a Jacobian point. +func (p *G2Jac) unsafeFromJacExtended(q *g2JacExtended) *G2Jac { + p.X.Square(&q.ZZ).Mul(&p.X, &q.X) + p.Y.Square(&q.ZZZ).Mul(&p.Y, &q.Y) + p.Z = q.ZZZ return p } -// add point in Jacobian extended coordinates +// add sets p to p+q in extended Jacobian coordinates. +// // https://www.hyperelliptic.org/EFD/g1p/auto-shortw-xyzz.html#addition-add-2008-s func (p *g2JacExtended) add(q *g2JacExtended) *g2JacExtended { //if q is infinity return p @@ -747,10 +767,11 @@ func (p *g2JacExtended) add(q *g2JacExtended) *g2JacExtended { return p } -// double point in Jacobian extended coordinates +// double sets p to [2]q in Jacobian extended coordinates. +// // http://www.hyperelliptic.org/EFD/g1p/auto-shortw-xyzz.html#doubling-dbl-2008-s-1 -// since we consider any point on Z=0 as the point at infinity -// this doubling formula works for infinity points as well +// N.B.: since we consider any point on Z=0 as the point at infinity +// this doubling formula works for infinity points as well. func (p *g2JacExtended) double(q *g2JacExtended) *g2JacExtended { var U, V, W, S, XX, M fptower.E2 @@ -760,7 +781,7 @@ func (p *g2JacExtended) double(q *g2JacExtended) *g2JacExtended { S.Mul(&q.X, &V) XX.Square(&q.X) M.Double(&XX). - Add(&M, &XX) // -> + a, but a=0 here + Add(&M, &XX) // -> + A, but A=0 here U.Mul(&W, &q.Y) p.X.Square(&M). @@ -775,9 +796,10 @@ func (p *g2JacExtended) double(q *g2JacExtended) *g2JacExtended { return p } -// subMixed same as addMixed, but will negate a.Y +// addMixed sets p to p+q in extended Jacobian coordinates, where a.ZZ=1. +// // http://www.hyperelliptic.org/EFD/g1p/auto-shortw-xyzz.html#addition-madd-2008-s -func (p *g2JacExtended) subMixed(a *G2Affine) *g2JacExtended { +func (p *g2JacExtended) addMixed(a *G2Affine) *g2JacExtended { //if a is infinity return p if a.IsInfinity() { @@ -786,7 +808,7 @@ func (p *g2JacExtended) subMixed(a *G2Affine) *g2JacExtended { // p is infinity, return a if p.ZZ.IsZero() { p.X = a.X - p.Y.Neg(&a.Y) + p.Y = a.Y p.ZZ.SetOne() p.ZZZ.SetOne() return p @@ -799,12 +821,11 @@ func (p *g2JacExtended) subMixed(a *G2Affine) *g2JacExtended { P.Sub(&P, &p.X) R.Mul(&a.Y, &p.ZZZ) - R.Neg(&R) R.Sub(&R, &p.Y) if P.IsZero() { if R.IsZero() { - return p.doubleNegMixed(a) + return p.doubleMixed(a) } p.ZZ = fptower.E2{} @@ -831,9 +852,10 @@ func (p *g2JacExtended) subMixed(a *G2Affine) *g2JacExtended { } -// addMixed +// subMixed works the same as addMixed, but negates a.Y. +// // http://www.hyperelliptic.org/EFD/g1p/auto-shortw-xyzz.html#addition-madd-2008-s -func (p *g2JacExtended) addMixed(a *G2Affine) *g2JacExtended { +func (p *g2JacExtended) subMixed(a *G2Affine) *g2JacExtended { //if a is infinity return p if a.IsInfinity() { @@ -842,7 +864,7 @@ func (p *g2JacExtended) addMixed(a *G2Affine) *g2JacExtended { // p is infinity, return a if p.ZZ.IsZero() { p.X = a.X - p.Y = a.Y + p.Y.Neg(&a.Y) p.ZZ.SetOne() p.ZZZ.SetOne() return p @@ -855,11 +877,12 @@ func (p *g2JacExtended) addMixed(a *G2Affine) *g2JacExtended { P.Sub(&P, &p.X) R.Mul(&a.Y, &p.ZZZ) + R.Neg(&R) R.Sub(&R, &p.Y) if P.IsZero() { if R.IsZero() { - return p.doubleMixed(a) + return p.doubleNegMixed(a) } p.ZZ = fptower.E2{} @@ -886,21 +909,21 @@ func (p *g2JacExtended) addMixed(a *G2Affine) *g2JacExtended { } -// doubleNegMixed same as double, but will negate q.Y -func (p *g2JacExtended) doubleNegMixed(q *G2Affine) *g2JacExtended { +// doubleNegMixed works the same as double, but negates q.Y. +func (p *g2JacExtended) doubleNegMixed(a *G2Affine) *g2JacExtended { var U, V, W, S, XX, M, S2, L fptower.E2 - U.Double(&q.Y) + U.Double(&a.Y) U.Neg(&U) V.Square(&U) W.Mul(&U, &V) - S.Mul(&q.X, &V) - XX.Square(&q.X) + S.Mul(&a.X, &V) + XX.Square(&a.X) M.Double(&XX). - Add(&M, &XX) // -> + a, but a=0 here + Add(&M, &XX) // -> + A, but A=0 here S2.Double(&S) - L.Mul(&W, &q.Y) + L.Mul(&W, &a.Y) p.X.Square(&M). Sub(&p.X, &S2) @@ -913,21 +936,22 @@ func (p *g2JacExtended) doubleNegMixed(q *G2Affine) *g2JacExtended { return p } -// doubleMixed point in Jacobian extended coordinates +// doubleMixed sets p to [2]a in Jacobian extended coordinates, where a.ZZ=1. +// // http://www.hyperelliptic.org/EFD/g1p/auto-shortw-xyzz.html#doubling-dbl-2008-s-1 -func (p *g2JacExtended) doubleMixed(q *G2Affine) *g2JacExtended { +func (p *g2JacExtended) doubleMixed(a *G2Affine) *g2JacExtended { var U, V, W, S, XX, M, S2, L fptower.E2 - U.Double(&q.Y) + U.Double(&a.Y) V.Square(&U) W.Mul(&U, &V) - S.Mul(&q.X, &V) - XX.Square(&q.X) + S.Mul(&a.X, &V) + XX.Square(&a.X) M.Double(&XX). - Add(&M, &XX) // -> + a, but a=0 here + Add(&M, &XX) // -> + A, but A=0 here S2.Double(&S) - L.Mul(&W, &q.Y) + L.Mul(&W, &a.Y) p.X.Square(&M). Sub(&p.X, &S2) @@ -941,38 +965,38 @@ func (p *g2JacExtended) doubleMixed(q *G2Affine) *g2JacExtended { } // ------------------------------------------------------------------------------------------------- -// Homogenous projective +// Homogenous projective coordinates -// Set sets p to the provided point -func (p *g2Proj) Set(a *g2Proj) *g2Proj { - p.x, p.y, p.z = a.x, a.y, a.z +// Set sets p to a in projective coordinates. +func (p *g2Proj) Set(q *g2Proj) *g2Proj { + p.x, p.y, p.z = q.x, q.y, q.z return p } -// Neg computes -G -func (p *g2Proj) Neg(a *g2Proj) *g2Proj { - *p = *a - p.y.Neg(&a.y) +// Neg sets p to the projective negative point -q = (q.X, -q.Y). +func (p *g2Proj) Neg(q *g2Proj) *g2Proj { + *p = *q + p.y.Neg(&q.y) return p } -// FromAffine sets p = Q, p in homogenous projective, Q in affine -func (p *g2Proj) FromAffine(Q *G2Affine) *g2Proj { - if Q.X.IsZero() && Q.Y.IsZero() { +// FromAffine converts q in affine to p in projective coordinates. +func (p *g2Proj) FromAffine(a *G2Affine) *g2Proj { + if a.X.IsZero() && a.Y.IsZero() { p.z.SetZero() p.x.SetOne() p.y.SetOne() return p } p.z.SetOne() - p.x.Set(&Q.X) - p.y.Set(&Q.Y) + p.x.Set(&a.X) + p.y.Set(&a.Y) return p } // BatchScalarMultiplicationG2 multiplies the same base by all scalars // and return resulting points in affine coordinates -// uses a simple windowed-NAF like exponentiation algorithm +// uses a simple windowed-NAF-like multiplication algorithm. func BatchScalarMultiplicationG2(base *G2Affine, scalars []fr.Element) []G2Affine { // approximate cost in group ops is // cost = 2^{c-1} + n(scalar.nbBits+nbChunks) @@ -1051,9 +1075,8 @@ func BatchScalarMultiplicationG2(base *G2Affine, scalars []fr.Element) []G2Affin return toReturn } -// batch add affine coordinates -// using batch inversion -// special cases (doubling, infinity) must be filtered out before this call +// batchAddG1Affine adds affine points using the Montgomery batch inversion trick. +// Special cases (doubling, infinity) must be filtered out before this call. func batchAddG2Affine[TP pG2Affine, TPP ppG2Affine, TC cG2Affine](R *TPP, P *TP, batchSize int) { var lambda, lambdain TC diff --git a/ecc/bls12-381/multiexp_affine.go b/ecc/bls12-381/multiexp_affine.go index 937a43c9d..3b3fa855f 100644 --- a/ecc/bls12-381/multiexp_affine.go +++ b/ecc/bls12-381/multiexp_affine.go @@ -226,7 +226,7 @@ func processChunkG1BatchAffine[BJE ibg1JacExtended, B ibG1Affine, BS bitSet, TP total.setInfinity() for k := len(buckets) - 1; k >= 0; k-- { runningSum.addMixed(&buckets[k]) - if !bucketsJE[k].IsZero() { + if !bucketsJE[k].IsInfinity() { runningSum.add(&bucketsJE[k]) } total.add(&runningSum) @@ -554,7 +554,7 @@ func processChunkG2BatchAffine[BJE ibg2JacExtended, B ibG2Affine, BS bitSet, TP total.setInfinity() for k := len(buckets) - 1; k >= 0; k-- { runningSum.addMixed(&buckets[k]) - if !bucketsJE[k].IsZero() { + if !bucketsJE[k].IsInfinity() { runningSum.add(&bucketsJE[k]) } total.add(&runningSum) diff --git a/ecc/bls12-381/multiexp_jacobian.go b/ecc/bls12-381/multiexp_jacobian.go index 1b8c0e79a..80b042d8d 100644 --- a/ecc/bls12-381/multiexp_jacobian.go +++ b/ecc/bls12-381/multiexp_jacobian.go @@ -56,7 +56,7 @@ func processChunkG1Jacobian[B ibg1JacExtended](chunk uint64, runningSum.setInfinity() total.setInfinity() for k := len(buckets) - 1; k >= 0; k-- { - if !buckets[k].IsZero() { + if !buckets[k].IsInfinity() { runningSum.add(&buckets[k]) } total.add(&runningSum) @@ -145,7 +145,7 @@ func processChunkG2Jacobian[B ibg2JacExtended](chunk uint64, runningSum.setInfinity() total.setInfinity() for k := len(buckets) - 1; k >= 0; k-- { - if !buckets[k].IsZero() { + if !buckets[k].IsInfinity() { runningSum.add(&buckets[k]) } total.add(&runningSum) diff --git a/ecc/bls24-315/g1.go b/ecc/bls24-315/g1.go index 9672e7b2c..e5b4897cd 100644 --- a/ecc/bls24-315/g1.go +++ b/ecc/bls24-315/g1.go @@ -25,38 +25,40 @@ import ( "runtime" ) -// G1Affine point in affine coordinates +// G1Affine is a point in affine coordinates (x,y) type G1Affine struct { X, Y fp.Element } -// G1Jac is a point with fp.Element coordinates +// G1Jac is a point in Jacobian coordinates (x=X/Z², y=Y/Z³) type G1Jac struct { X, Y, Z fp.Element } -// g1JacExtended parameterized Jacobian coordinates (x=X/ZZ, y=Y/ZZZ, ZZ³=ZZZ²) +// g1JacExtended is a point in extended Jacobian coordinates (x=X/ZZ, y=Y/ZZZ, ZZ³=ZZZ²) type g1JacExtended struct { X, Y, ZZ, ZZZ fp.Element } // ------------------------------------------------------------------------------------------------- -// Affine +// Affine coordinates -// Set sets p to the provided point +// Set sets p to a in affine coordinates. func (p *G1Affine) Set(a *G1Affine) *G1Affine { p.X, p.Y = a.X, a.Y return p } -// setInfinity sets p to O +// setInfinity sets p to the infinity point, which is encoded as (0,0). +// N.B.: (0,0) is never on the curve for j=0 curves (Y²=X³+B). func (p *G1Affine) setInfinity() *G1Affine { p.X.SetZero() p.Y.SetZero() return p } -// ScalarMultiplication computes and returns p = a ⋅ s +// ScalarMultiplication computes and returns p = [s]a +// where p and a are affine points. func (p *G1Affine) ScalarMultiplication(a *G1Affine, s *big.Int) *G1Affine { var _p G1Jac _p.FromAffine(a) @@ -65,20 +67,22 @@ func (p *G1Affine) ScalarMultiplication(a *G1Affine, s *big.Int) *G1Affine { return p } -// ScalarMultiplicationAffine computes and returns p = a ⋅ s -// Takes an affine point and returns a Jacobian point (useful for KZG) +// ScalarMultiplicationAffine computes and returns p = [s]a +// where a is an affine point and p a Jacobian point (useful for KZG). func (p *G1Jac) ScalarMultiplicationAffine(a *G1Affine, s *big.Int) *G1Jac { p.FromAffine(a) p.mulGLV(p, s) return p } -// ScalarMultiplicationBase computes and returns p = g ⋅ s where g is the prime subgroup generator +// ScalarMultiplicationBase computes and returns p = [s]g +// where g is the Jacobian point generating the prime subgroup. func (p *G1Jac) ScalarMultiplicationBase(s *big.Int) *G1Jac { return p.mulGLV(&g1Gen, s) } -// ScalarMultiplicationBase computes and returns p = g ⋅ s where g is the prime subgroup generator +// ScalarMultiplicationBase computes and returns p = [s]g +// where g is the affine point generating the prime subgroup. func (p *G1Affine) ScalarMultiplicationBase(s *big.Int) *G1Affine { var _p G1Jac _p.mulGLV(&g1Gen, s) @@ -86,8 +90,9 @@ func (p *G1Affine) ScalarMultiplicationBase(s *big.Int) *G1Affine { return p } -// Add adds two point in affine coordinates. -// Jacobian addition with Z1=Z2=1 +// Add adds two points in affine coordinates. +// It uses the Jacobian addition with a.Z=b.Z=1 and converts the result to affine coordinates. +// // https://www.hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html#addition-mmadd-2007-bl func (p *G1Affine) Add(a, b *G1Affine) *G1Affine { var q G1Jac @@ -133,6 +138,10 @@ func (p *G1Affine) Add(a, b *G1Affine) *G1Affine { } // Double doubles a point in affine coordinates. +// It converts the point to Jacobian coordinates, doubles it using Jacobian +// addition with a.Z=1, and converts it back to affine coordinates. +// +// http://www.hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html#doubling-mdbl-2007-bl func (p *G1Affine) Double(a *G1Affine) *G1Affine { var q G1Jac q.FromAffine(a) @@ -141,7 +150,8 @@ func (p *G1Affine) Double(a *G1Affine) *G1Affine { return p } -// Sub subs two point in affine coordinates. +// Sub subtracts two points in affine coordinates. +// It uses a similar approach to Add, but negates the second point before adding. func (p *G1Affine) Sub(a, b *G1Affine) *G1Affine { var bneg G1Affine bneg.Neg(b) @@ -149,19 +159,19 @@ func (p *G1Affine) Sub(a, b *G1Affine) *G1Affine { return p } -// Equal tests if two points (in Affine coordinates) are equal +// Equal tests if two points in affine coordinates are equal. func (p *G1Affine) Equal(a *G1Affine) bool { return p.X.Equal(&a.X) && p.Y.Equal(&a.Y) } -// Neg computes -G +// Neg sets p to the affine negative point -a = (a.X, -a.Y). func (p *G1Affine) Neg(a *G1Affine) *G1Affine { p.X = a.X p.Y.Neg(&a.Y) return p } -// FromJacobian rescales a point in Jacobian coord in z=1 plane +// FromJacobian converts a point p1 from Jacobian to affine coordinates. func (p *G1Affine) FromJacobian(p1 *G1Jac) *G1Affine { var a, b fp.Element @@ -180,7 +190,7 @@ func (p *G1Affine) FromJacobian(p1 *G1Jac) *G1Affine { return p } -// String returns the string representation of the point or "O" if it is infinity +// String returns the string representation E(x,y) of the affine point p or "O" if it is infinity. func (p *G1Affine) String() string { if p.IsInfinity() { return "O" @@ -188,21 +198,20 @@ func (p *G1Affine) String() string { return "E([" + p.X.String() + "," + p.Y.String() + "])" } -// IsInfinity checks if the point is infinity -// in affine, it's encoded as (0,0) -// (0,0) is never on the curve for j=0 curves +// IsInfinity checks if the affine point p is infinity, which is encoded as (0,0). +// N.B.: (0,0) is never on the curve for j=0 curves (Y²=X³+B). func (p *G1Affine) IsInfinity() bool { return p.X.IsZero() && p.Y.IsZero() } -// IsOnCurve returns true if p in on the curve +// IsOnCurve returns true if the affine point p in on the curve. func (p *G1Affine) IsOnCurve() bool { var point G1Jac point.FromAffine(p) return point.IsOnCurve() // call this function to handle infinity point } -// IsInSubGroup returns true if p is in the correct subgroup, false otherwise +// IsInSubGroup returns true if the affine point p is in the correct subgroup, false otherwise. func (p *G1Affine) IsInSubGroup() bool { var _p G1Jac _p.FromAffine(p) @@ -210,84 +219,76 @@ func (p *G1Affine) IsInSubGroup() bool { } // ------------------------------------------------------------------------------------------------- -// Jacobian +// Jacobian coordinates -// Set sets p to the provided point -func (p *G1Jac) Set(a *G1Jac) *G1Jac { - p.X, p.Y, p.Z = a.X, a.Y, a.Z +// Set sets p to a in Jacobian coordinates. +func (p *G1Jac) Set(q *G1Jac) *G1Jac { + p.X, p.Y, p.Z = q.X, q.Y, q.Z return p } -// Equal tests if two points (in Jacobian coordinates) are equal -func (p *G1Jac) Equal(a *G1Jac) bool { +// Equal tests if two points in Jacobian coordinates are equal. +func (p *G1Jac) Equal(q *G1Jac) bool { // If one point is infinity, the other must also be infinity. if p.Z.IsZero() { - return a.Z.IsZero() + return q.Z.IsZero() } // If the other point is infinity, return false since we can't // the following checks would be incorrect. - if a.Z.IsZero() { + if q.Z.IsZero() { return false } var pZSquare, aZSquare fp.Element pZSquare.Square(&p.Z) - aZSquare.Square(&a.Z) + aZSquare.Square(&q.Z) var lhs, rhs fp.Element lhs.Mul(&p.X, &aZSquare) - rhs.Mul(&a.X, &pZSquare) + rhs.Mul(&q.X, &pZSquare) if !lhs.Equal(&rhs) { return false } - lhs.Mul(&p.Y, &aZSquare).Mul(&lhs, &a.Z) - rhs.Mul(&a.Y, &pZSquare).Mul(&rhs, &p.Z) + lhs.Mul(&p.Y, &aZSquare).Mul(&lhs, &q.Z) + rhs.Mul(&q.Y, &pZSquare).Mul(&rhs, &p.Z) return lhs.Equal(&rhs) } -// Neg computes -G -func (p *G1Jac) Neg(a *G1Jac) *G1Jac { - *p = *a - p.Y.Neg(&a.Y) +// Neg sets p to the Jacobian negative point -q = (q.X, -q.Y, q.Z). +func (p *G1Jac) Neg(q *G1Jac) *G1Jac { + *p = *q + p.Y.Neg(&q.Y) return p } -// SubAssign subtracts two points on the curve -func (p *G1Jac) SubAssign(a *G1Jac) *G1Jac { - var tmp G1Jac - tmp.Set(a) - tmp.Y.Neg(&tmp.Y) - p.AddAssign(&tmp) - return p -} - -// AddAssign point addition in montgomery form +// AddAssign sets p to p+a in Jacobian coordinates. +// // https://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-3.html#addition-add-2007-bl -func (p *G1Jac) AddAssign(a *G1Jac) *G1Jac { +func (p *G1Jac) AddAssign(q *G1Jac) *G1Jac { - // p is infinity, return a + // p is infinity, return q if p.Z.IsZero() { - p.Set(a) + p.Set(q) return p } - // a is infinity, return p - if a.Z.IsZero() { + // q is infinity, return p + if q.Z.IsZero() { return p } var Z1Z1, Z2Z2, U1, U2, S1, S2, H, I, J, r, V fp.Element - Z1Z1.Square(&a.Z) + Z1Z1.Square(&q.Z) Z2Z2.Square(&p.Z) - U1.Mul(&a.X, &Z2Z2) + U1.Mul(&q.X, &Z2Z2) U2.Mul(&p.X, &Z1Z1) - S1.Mul(&a.Y, &p.Z). + S1.Mul(&q.Y, &p.Z). Mul(&S1, &Z2Z2) - S2.Mul(&p.Y, &a.Z). + S2.Mul(&p.Y, &q.Z). Mul(&S2, &Z1Z1) - // if p == a, we double instead + // if p == q, we double instead if U1.Equal(&U2) && S1.Equal(&S2) { return p.DoubleAssign() } @@ -306,7 +307,7 @@ func (p *G1Jac) AddAssign(a *G1Jac) *G1Jac { Mul(&p.Y, &r) S1.Mul(&S1, &J).Double(&S1) p.Y.Sub(&p.Y, &S1) - p.Z.Add(&p.Z, &a.Z) + p.Z.Add(&p.Z, &q.Z) p.Z.Square(&p.Z). Sub(&p.Z, &Z1Z1). Sub(&p.Z, &Z2Z2). @@ -315,8 +316,19 @@ func (p *G1Jac) AddAssign(a *G1Jac) *G1Jac { return p } -// DoubleMixed point addition -// http://www.hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html#doubling-mdbl-2007-bl +// SubAssign sets p to p-a in Jacobian coordinates. +// It uses a similar approach to AddAssign, but negates the point a before adding. +func (p *G1Jac) SubAssign(q *G1Jac) *G1Jac { + var tmp G1Jac + tmp.Set(q) + tmp.Y.Neg(&tmp.Y) + p.AddAssign(&tmp) + return p +} + +// Double sets p to [2]q in Jacobian coordinates. +// +// https://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-3.html#doubling-dbl-2007-bl func (p *G1Jac) DoubleMixed(a *G1Affine) *G1Jac { var XX, YY, YYYY, S, M, T fp.Element XX.Square(&a.X) @@ -328,7 +340,7 @@ func (p *G1Jac) DoubleMixed(a *G1Affine) *G1Jac { Sub(&S, &YYYY). Double(&S) M.Double(&XX). - Add(&M, &XX) // -> + a, but a=0 here + Add(&M, &XX) // -> + A, but A=0 here T.Square(&M). Sub(&T, &S). Sub(&T, &S) @@ -344,7 +356,8 @@ func (p *G1Jac) DoubleMixed(a *G1Affine) *G1Jac { return p } -// AddMixed point addition +// AddMixed sets p to p+a in Jacobian coordinates, where a.Z = 1. +// // http://www.hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html#addition-madd-2007-bl func (p *G1Jac) AddMixed(a *G1Affine) *G1Jac { @@ -393,7 +406,8 @@ func (p *G1Jac) AddMixed(a *G1Affine) *G1Jac { return p } -// Double doubles a point in Jacobian coordinates +// Double sets p to [2]q in Jacobian coordinates. +// // https://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-3.html#doubling-dbl-2007-bl func (p *G1Jac) Double(q *G1Jac) *G1Jac { p.Set(q) @@ -401,7 +415,8 @@ func (p *G1Jac) Double(q *G1Jac) *G1Jac { return p } -// DoubleAssign doubles a point in Jacobian coordinates +// DoubleAssign doubles p in Jacobian coordinates. +// // https://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-3.html#doubling-dbl-2007-bl func (p *G1Jac) DoubleAssign() *G1Jac { @@ -433,34 +448,36 @@ func (p *G1Jac) DoubleAssign() *G1Jac { return p } -// ScalarMultiplication computes and returns p = a ⋅ s +// ScalarMultiplication computes and returns p = [s]a +// where p and a are Jacobian points. +// using the GLV technique. // see https://www.iacr.org/archive/crypto2001/21390189.pdf -func (p *G1Jac) ScalarMultiplication(a *G1Jac, s *big.Int) *G1Jac { - return p.mulGLV(a, s) +func (p *G1Jac) ScalarMultiplication(q *G1Jac, s *big.Int) *G1Jac { + return p.mulGLV(q, s) } -// String returns canonical representation of the point in affine coordinates +// String converts p to affine coordinates and returns its string representation E(x,y) or "O" if it is infinity. func (p *G1Jac) String() string { _p := G1Affine{} _p.FromJacobian(p) return _p.String() } -// FromAffine sets p = Q, p in Jacobian, Q in affine -func (p *G1Jac) FromAffine(Q *G1Affine) *G1Jac { - if Q.IsInfinity() { +// FromAffine converts a point a from affine to Jacobian coordinates. +func (p *G1Jac) FromAffine(a *G1Affine) *G1Jac { + if a.IsInfinity() { p.Z.SetZero() p.X.SetOne() p.Y.SetOne() return p } p.Z.SetOne() - p.X.Set(&Q.X) - p.Y.Set(&Q.Y) + p.X.Set(&a.X) + p.Y.Set(&a.Y) return p } -// IsOnCurve returns true if p in on the curve +// IsOnCurve returns true if the Jacobian point p in on the curve. func (p *G1Jac) IsOnCurve() bool { var left, right, tmp, ZZ fp.Element left.Square(&p.Y) @@ -493,13 +510,14 @@ func (p *G1Jac) IsInSubGroup() bool { } -// mulWindowed computes a 2-bits windowed scalar multiplication -func (p *G1Jac) mulWindowed(a *G1Jac, s *big.Int) *G1Jac { +// mulWindowed computes the 2-bits windowed double-and-add scalar +// multiplication p=[s]q in Jacobian coordinates. +func (p *G1Jac) mulWindowed(q *G1Jac, s *big.Int) *G1Jac { var res G1Jac var ops [3]G1Jac - ops[0].Set(a) + ops[0].Set(q) if s.Sign() == -1 { ops[0].Neg(&ops[0]) } @@ -526,17 +544,18 @@ func (p *G1Jac) mulWindowed(a *G1Jac, s *big.Int) *G1Jac { } -// ϕ assigns p to ϕ(a) where ϕ: (x,y) → (w x,y), and returns p -// where w is a third root of unity in 𝔽p -func (p *G1Jac) phi(a *G1Jac) *G1Jac { - p.Set(a) +// phi sets p to ϕ(a) where ϕ: (x,y) → (w x,y), +// where w is a third root of unity. +func (p *G1Jac) phi(q *G1Jac) *G1Jac { + p.Set(q) p.X.Mul(&p.X, &thirdRootOneG1) return p } // mulGLV computes the scalar multiplication using a windowed-GLV method +// // see https://www.iacr.org/archive/crypto2001/21390189.pdf -func (p *G1Jac) mulGLV(a *G1Jac, s *big.Int) *G1Jac { +func (p *G1Jac) mulGLV(q *G1Jac, s *big.Int) *G1Jac { var table [15]G1Jac var res G1Jac @@ -544,11 +563,11 @@ func (p *G1Jac) mulGLV(a *G1Jac, s *big.Int) *G1Jac { res.Set(&g1Infinity) - // table[b3b2b1b0-1] = b3b2 ⋅ ϕ(a) + b1b0*a - table[0].Set(a) - table[3].phi(a) + // table[b3b2b1b0-1] = b3b2 ⋅ ϕ(q) + b1b0*q + table[0].Set(q) + table[3].phi(q) - // split the scalar, modifies ±a, ϕ(a) accordingly + // split the scalar, modifies ±q, ϕ(q) accordingly k := ecc.SplitScalar(s, &glvBasis) if k[0].Sign() == -1 { @@ -561,7 +580,7 @@ func (p *G1Jac) mulGLV(a *G1Jac, s *big.Int) *G1Jac { } // precompute table (2 bits sliding window) - // table[b3b2b1b0-1] = b3b2 ⋅ ϕ(a) + b1b0 ⋅ a if b3b2b1b0 != 0 + // table[b3b2b1b0-1] = b3b2 ⋅ ϕ(q) + b1b0 ⋅ q if b3b2b1b0 != 0 table[1].Double(&table[0]) table[2].Set(&table[1]).AddAssign(&table[0]) table[4].Set(&table[3]).AddAssign(&table[0]) @@ -617,17 +636,17 @@ func (p *G1Affine) ClearCofactor(a *G1Affine) *G1Affine { } // ClearCofactor maps a point in E(Fp) to E(Fp)[r] -func (p *G1Jac) ClearCofactor(a *G1Jac) *G1Jac { +func (p *G1Jac) ClearCofactor(q *G1Jac) *G1Jac { // cf https://eprint.iacr.org/2019/403.pdf, 5 var res G1Jac - res.ScalarMultiplication(a, &xGen).AddAssign(a) + res.ScalarMultiplication(q, &xGen).AddAssign(q) p.Set(&res) return p } -// JointScalarMultiplicationBase computes [s1]g+[s2]a using Straus-Shamir technique -// where g is the prime subgroup generator +// JointScalarMultiplicationBase computes [s1]g+[s2]a using Strauss-Shamir technique +// where g is the prime subgroup generator and a is an affine point. func (p *G1Jac) JointScalarMultiplicationBase(a *G1Affine, s1, s2 *big.Int) *G1Jac { var res, p1, p2 G1Jac @@ -698,15 +717,15 @@ func (p *G1Jac) JointScalarMultiplicationBase(a *G1Affine, s1, s2 *big.Int) *G1J } // ------------------------------------------------------------------------------------------------- -// Jacobian extended +// extended Jacobian coordinates -// Set sets p to the provided point -func (p *g1JacExtended) Set(a *g1JacExtended) *g1JacExtended { - p.X, p.Y, p.ZZ, p.ZZZ = a.X, a.Y, a.ZZ, a.ZZZ +// Set sets p to a in extended Jacobian coordinates. +func (p *g1JacExtended) Set(q *g1JacExtended) *g1JacExtended { + p.X, p.Y, p.ZZ, p.ZZZ = q.X, q.Y, q.ZZ, q.ZZZ return p } -// setInfinity sets p to O +// setInfinity sets p to the infinity point (1,1,0,0). func (p *g1JacExtended) setInfinity() *g1JacExtended { p.X.SetOne() p.Y.SetOne() @@ -715,43 +734,45 @@ func (p *g1JacExtended) setInfinity() *g1JacExtended { return p } -func (p *g1JacExtended) IsZero() bool { +// IsInfinity checks if the p is infinity, i.e. p.ZZ=0. +func (p *g1JacExtended) IsInfinity() bool { return p.ZZ.IsZero() } -// fromJacExtended sets Q in affine coordinates -func (p *G1Affine) fromJacExtended(Q *g1JacExtended) *G1Affine { - if Q.ZZ.IsZero() { +// fromJacExtended converts an extended Jacobian point to an affine point. +func (p *G1Affine) fromJacExtended(q *g1JacExtended) *G1Affine { + if q.ZZ.IsZero() { p.X = fp.Element{} p.Y = fp.Element{} return p } - p.X.Inverse(&Q.ZZ).Mul(&p.X, &Q.X) - p.Y.Inverse(&Q.ZZZ).Mul(&p.Y, &Q.Y) + p.X.Inverse(&q.ZZ).Mul(&p.X, &q.X) + p.Y.Inverse(&q.ZZZ).Mul(&p.Y, &q.Y) return p } -// fromJacExtended sets Q in Jacobian coordinates -func (p *G1Jac) fromJacExtended(Q *g1JacExtended) *G1Jac { - if Q.ZZ.IsZero() { +// fromJacExtended converts an extended Jacobian point to a Jacobian point. +func (p *G1Jac) fromJacExtended(q *g1JacExtended) *G1Jac { + if q.ZZ.IsZero() { p.Set(&g1Infinity) return p } - p.X.Mul(&Q.ZZ, &Q.X).Mul(&p.X, &Q.ZZ) - p.Y.Mul(&Q.ZZZ, &Q.Y).Mul(&p.Y, &Q.ZZZ) - p.Z.Set(&Q.ZZZ) + p.X.Mul(&q.ZZ, &q.X).Mul(&p.X, &q.ZZ) + p.Y.Mul(&q.ZZZ, &q.Y).Mul(&p.Y, &q.ZZZ) + p.Z.Set(&q.ZZZ) return p } -// unsafeFromJacExtended sets p in Jacobian coordinates, but don't check for infinity -func (p *G1Jac) unsafeFromJacExtended(Q *g1JacExtended) *G1Jac { - p.X.Square(&Q.ZZ).Mul(&p.X, &Q.X) - p.Y.Square(&Q.ZZZ).Mul(&p.Y, &Q.Y) - p.Z = Q.ZZZ +// unsafeFromJacExtended converts an extended Jacobian point, distinct from Infinity, to a Jacobian point. +func (p *G1Jac) unsafeFromJacExtended(q *g1JacExtended) *G1Jac { + p.X.Square(&q.ZZ).Mul(&p.X, &q.X) + p.Y.Square(&q.ZZZ).Mul(&p.Y, &q.Y) + p.Z = q.ZZZ return p } -// add point in Jacobian extended coordinates +// add sets p to p+q in extended Jacobian coordinates. +// // https://www.hyperelliptic.org/EFD/g1p/auto-shortw-xyzz.html#addition-add-2008-s func (p *g1JacExtended) add(q *g1JacExtended) *g1JacExtended { //if q is infinity return p @@ -807,10 +828,11 @@ func (p *g1JacExtended) add(q *g1JacExtended) *g1JacExtended { return p } -// double point in Jacobian extended coordinates +// double sets p to [2]q in Jacobian extended coordinates. +// // http://www.hyperelliptic.org/EFD/g1p/auto-shortw-xyzz.html#doubling-dbl-2008-s-1 -// since we consider any point on Z=0 as the point at infinity -// this doubling formula works for infinity points as well +// N.B.: since we consider any point on Z=0 as the point at infinity +// this doubling formula works for infinity points as well. func (p *g1JacExtended) double(q *g1JacExtended) *g1JacExtended { var U, V, W, S, XX, M fp.Element @@ -820,7 +842,7 @@ func (p *g1JacExtended) double(q *g1JacExtended) *g1JacExtended { S.Mul(&q.X, &V) XX.Square(&q.X) M.Double(&XX). - Add(&M, &XX) // -> + a, but a=0 here + Add(&M, &XX) // -> + A, but A=0 here U.Mul(&W, &q.Y) p.X.Square(&M). @@ -835,9 +857,10 @@ func (p *g1JacExtended) double(q *g1JacExtended) *g1JacExtended { return p } -// subMixed same as addMixed, but will negate a.Y +// addMixed sets p to p+q in extended Jacobian coordinates, where a.ZZ=1. +// // http://www.hyperelliptic.org/EFD/g1p/auto-shortw-xyzz.html#addition-madd-2008-s -func (p *g1JacExtended) subMixed(a *G1Affine) *g1JacExtended { +func (p *g1JacExtended) addMixed(a *G1Affine) *g1JacExtended { //if a is infinity return p if a.IsInfinity() { @@ -846,7 +869,7 @@ func (p *g1JacExtended) subMixed(a *G1Affine) *g1JacExtended { // p is infinity, return a if p.ZZ.IsZero() { p.X = a.X - p.Y.Neg(&a.Y) + p.Y = a.Y p.ZZ.SetOne() p.ZZZ.SetOne() return p @@ -859,12 +882,11 @@ func (p *g1JacExtended) subMixed(a *G1Affine) *g1JacExtended { P.Sub(&P, &p.X) R.Mul(&a.Y, &p.ZZZ) - R.Neg(&R) R.Sub(&R, &p.Y) if P.IsZero() { if R.IsZero() { - return p.doubleNegMixed(a) + return p.doubleMixed(a) } p.ZZ = fp.Element{} @@ -891,9 +913,10 @@ func (p *g1JacExtended) subMixed(a *G1Affine) *g1JacExtended { } -// addMixed +// subMixed works the same as addMixed, but negates a.Y. +// // http://www.hyperelliptic.org/EFD/g1p/auto-shortw-xyzz.html#addition-madd-2008-s -func (p *g1JacExtended) addMixed(a *G1Affine) *g1JacExtended { +func (p *g1JacExtended) subMixed(a *G1Affine) *g1JacExtended { //if a is infinity return p if a.IsInfinity() { @@ -902,7 +925,7 @@ func (p *g1JacExtended) addMixed(a *G1Affine) *g1JacExtended { // p is infinity, return a if p.ZZ.IsZero() { p.X = a.X - p.Y = a.Y + p.Y.Neg(&a.Y) p.ZZ.SetOne() p.ZZZ.SetOne() return p @@ -915,11 +938,12 @@ func (p *g1JacExtended) addMixed(a *G1Affine) *g1JacExtended { P.Sub(&P, &p.X) R.Mul(&a.Y, &p.ZZZ) + R.Neg(&R) R.Sub(&R, &p.Y) if P.IsZero() { if R.IsZero() { - return p.doubleMixed(a) + return p.doubleNegMixed(a) } p.ZZ = fp.Element{} @@ -946,21 +970,21 @@ func (p *g1JacExtended) addMixed(a *G1Affine) *g1JacExtended { } -// doubleNegMixed same as double, but will negate q.Y -func (p *g1JacExtended) doubleNegMixed(q *G1Affine) *g1JacExtended { +// doubleNegMixed works the same as double, but negates q.Y. +func (p *g1JacExtended) doubleNegMixed(a *G1Affine) *g1JacExtended { var U, V, W, S, XX, M, S2, L fp.Element - U.Double(&q.Y) + U.Double(&a.Y) U.Neg(&U) V.Square(&U) W.Mul(&U, &V) - S.Mul(&q.X, &V) - XX.Square(&q.X) + S.Mul(&a.X, &V) + XX.Square(&a.X) M.Double(&XX). - Add(&M, &XX) // -> + a, but a=0 here + Add(&M, &XX) // -> + A, but A=0 here S2.Double(&S) - L.Mul(&W, &q.Y) + L.Mul(&W, &a.Y) p.X.Square(&M). Sub(&p.X, &S2) @@ -973,21 +997,22 @@ func (p *g1JacExtended) doubleNegMixed(q *G1Affine) *g1JacExtended { return p } -// doubleMixed point in Jacobian extended coordinates +// doubleMixed sets p to [2]a in Jacobian extended coordinates, where a.ZZ=1. +// // http://www.hyperelliptic.org/EFD/g1p/auto-shortw-xyzz.html#doubling-dbl-2008-s-1 -func (p *g1JacExtended) doubleMixed(q *G1Affine) *g1JacExtended { +func (p *g1JacExtended) doubleMixed(a *G1Affine) *g1JacExtended { var U, V, W, S, XX, M, S2, L fp.Element - U.Double(&q.Y) + U.Double(&a.Y) V.Square(&U) W.Mul(&U, &V) - S.Mul(&q.X, &V) - XX.Square(&q.X) + S.Mul(&a.X, &V) + XX.Square(&a.X) M.Double(&XX). - Add(&M, &XX) // -> + a, but a=0 here + Add(&M, &XX) // -> + A, but A=0 here S2.Double(&S) - L.Mul(&W, &q.Y) + L.Mul(&W, &a.Y) p.X.Square(&M). Sub(&p.X, &S2) @@ -1001,7 +1026,7 @@ func (p *g1JacExtended) doubleMixed(q *G1Affine) *g1JacExtended { } // BatchJacobianToAffineG1 converts points in Jacobian coordinates to Affine coordinates -// performing a single field inversion (Montgomery batch inversion trick). +// performing a single field inversion using the Montgomery batch inversion trick. func BatchJacobianToAffineG1(points []G1Jac) []G1Affine { result := make([]G1Affine, len(points)) zeroes := make([]bool, len(points)) @@ -1051,7 +1076,7 @@ func BatchJacobianToAffineG1(points []G1Jac) []G1Affine { // BatchScalarMultiplicationG1 multiplies the same base by all scalars // and return resulting points in affine coordinates -// uses a simple windowed-NAF like exponentiation algorithm +// uses a simple windowed-NAF-like multiplication algorithm. func BatchScalarMultiplicationG1(base *G1Affine, scalars []fr.Element) []G1Affine { // approximate cost in group ops is // cost = 2^{c-1} + n(scalar.nbBits+nbChunks) @@ -1133,9 +1158,8 @@ func BatchScalarMultiplicationG1(base *G1Affine, scalars []fr.Element) []G1Affin return toReturnAff } -// batch add affine coordinates -// using batch inversion -// special cases (doubling, infinity) must be filtered out before this call +// batchAddG1Affine adds affine points using the Montgomery batch inversion trick. +// Special cases (doubling, infinity) must be filtered out before this call. func batchAddG1Affine[TP pG1Affine, TPP ppG1Affine, TC cG1Affine](R *TPP, P *TP, batchSize int) { var lambda, lambdain TC diff --git a/ecc/bls24-315/g2.go b/ecc/bls24-315/g2.go index 6f529fc37..8dea01a97 100644 --- a/ecc/bls24-315/g2.go +++ b/ecc/bls24-315/g2.go @@ -25,17 +25,17 @@ import ( "runtime" ) -// G2Affine point in affine coordinates +// G2Affine is a point in affine coordinates (x,y) type G2Affine struct { X, Y fptower.E4 } -// G2Jac is a point with fptower.E4 coordinates +// G2Jac is a point in Jacobian coordinates (x=X/Z², y=Y/Z³) type G2Jac struct { X, Y, Z fptower.E4 } -// g2JacExtended parameterized Jacobian coordinates (x=X/ZZ, y=Y/ZZZ, ZZ³=ZZZ²) +// g2JacExtended is a point in extended Jacobian coordinates (x=X/ZZ, y=Y/ZZZ, ZZ³=ZZZ²) type g2JacExtended struct { X, Y, ZZ, ZZZ fptower.E4 } @@ -46,22 +46,24 @@ type g2Proj struct { } // ------------------------------------------------------------------------------------------------- -// Affine +// Affine coordinates -// Set sets p to the provided point +// Set sets p to a in affine coordinates. func (p *G2Affine) Set(a *G2Affine) *G2Affine { p.X, p.Y = a.X, a.Y return p } -// setInfinity sets p to O +// setInfinity sets p to the infinity point, which is encoded as (0,0). +// N.B.: (0,0) is never on the curve for j=0 curves (Y²=X³+B). func (p *G2Affine) setInfinity() *G2Affine { p.X.SetZero() p.Y.SetZero() return p } -// ScalarMultiplication computes and returns p = a ⋅ s +// ScalarMultiplication computes and returns p = [s]a +// where p and a are affine points. func (p *G2Affine) ScalarMultiplication(a *G2Affine, s *big.Int) *G2Affine { var _p G2Jac _p.FromAffine(a) @@ -70,7 +72,8 @@ func (p *G2Affine) ScalarMultiplication(a *G2Affine, s *big.Int) *G2Affine { return p } -// ScalarMultiplicationBase computes and returns p = g ⋅ s where g is the prime subgroup generator +// ScalarMultiplicationBase computes and returns p = [s]g +// where g is the affine point generating the prime subgroup. func (p *G2Affine) ScalarMultiplicationBase(s *big.Int) *G2Affine { var _p G2Jac _p.mulGLV(&g2Gen, s) @@ -78,8 +81,9 @@ func (p *G2Affine) ScalarMultiplicationBase(s *big.Int) *G2Affine { return p } -// Add adds two point in affine coordinates. -// Jacobian addition with Z1=Z2=1 +// Add adds two points in affine coordinates. +// It uses the Jacobian addition with a.Z=b.Z=1 and converts the result to affine coordinates. +// // https://www.hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html#addition-mmadd-2007-bl func (p *G2Affine) Add(a, b *G2Affine) *G2Affine { var q G2Jac @@ -125,6 +129,10 @@ func (p *G2Affine) Add(a, b *G2Affine) *G2Affine { } // Double doubles a point in affine coordinates. +// It converts the point to Jacobian coordinates, doubles it using Jacobian +// addition with a.Z=1, and converts it back to affine coordinates. +// +// http://www.hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html#doubling-mdbl-2007-bl func (p *G2Affine) Double(a *G2Affine) *G2Affine { var q G2Jac q.FromAffine(a) @@ -133,7 +141,8 @@ func (p *G2Affine) Double(a *G2Affine) *G2Affine { return p } -// Sub subs two point in affine coordinates. +// Sub subtracts two points in affine coordinates. +// It uses a similar approach to Add, but negates the second point before adding. func (p *G2Affine) Sub(a, b *G2Affine) *G2Affine { var bneg G2Affine bneg.Neg(b) @@ -141,19 +150,19 @@ func (p *G2Affine) Sub(a, b *G2Affine) *G2Affine { return p } -// Equal tests if two points (in Affine coordinates) are equal +// Equal tests if two points in affine coordinates are equal. func (p *G2Affine) Equal(a *G2Affine) bool { return p.X.Equal(&a.X) && p.Y.Equal(&a.Y) } -// Neg computes -G +// Neg sets p to the affine negative point -a = (a.X, -a.Y). func (p *G2Affine) Neg(a *G2Affine) *G2Affine { p.X = a.X p.Y.Neg(&a.Y) return p } -// FromJacobian rescales a point in Jacobian coord in z=1 plane +// FromJacobian converts a point p1 from Jacobian to affine coordinates. func (p *G2Affine) FromJacobian(p1 *G2Jac) *G2Affine { var a, b fptower.E4 @@ -172,7 +181,7 @@ func (p *G2Affine) FromJacobian(p1 *G2Jac) *G2Affine { return p } -// String returns the string representation of the point or "O" if it is infinity +// String returns the string representation E(x,y) of the affine point p or "O" if it is infinity. func (p *G2Affine) String() string { if p.IsInfinity() { return "O" @@ -180,21 +189,20 @@ func (p *G2Affine) String() string { return "E([" + p.X.String() + "," + p.Y.String() + "])" } -// IsInfinity checks if the point is infinity -// in affine, it's encoded as (0,0) -// (0,0) is never on the curve for j=0 curves +// IsInfinity checks if the affine point p is infinity, which is encoded as (0,0). +// N.B.: (0,0) is never on the curve for j=0 curves (Y²=X³+B). func (p *G2Affine) IsInfinity() bool { return p.X.IsZero() && p.Y.IsZero() } -// IsOnCurve returns true if p in on the curve +// IsOnCurve returns true if the affine point p in on the curve. func (p *G2Affine) IsOnCurve() bool { var point G2Jac point.FromAffine(p) return point.IsOnCurve() // call this function to handle infinity point } -// IsInSubGroup returns true if p is in the correct subgroup, false otherwise +// IsInSubGroup returns true if the affine point p is in the correct subgroup, false otherwise. func (p *G2Affine) IsInSubGroup() bool { var _p G2Jac _p.FromAffine(p) @@ -202,84 +210,76 @@ func (p *G2Affine) IsInSubGroup() bool { } // ------------------------------------------------------------------------------------------------- -// Jacobian +// Jacobian coordinates -// Set sets p to the provided point -func (p *G2Jac) Set(a *G2Jac) *G2Jac { - p.X, p.Y, p.Z = a.X, a.Y, a.Z +// Set sets p to a in Jacobian coordinates. +func (p *G2Jac) Set(q *G2Jac) *G2Jac { + p.X, p.Y, p.Z = q.X, q.Y, q.Z return p } -// Equal tests if two points (in Jacobian coordinates) are equal -func (p *G2Jac) Equal(a *G2Jac) bool { +// Equal tests if two points in Jacobian coordinates are equal. +func (p *G2Jac) Equal(q *G2Jac) bool { // If one point is infinity, the other must also be infinity. if p.Z.IsZero() { - return a.Z.IsZero() + return q.Z.IsZero() } // If the other point is infinity, return false since we can't // the following checks would be incorrect. - if a.Z.IsZero() { + if q.Z.IsZero() { return false } var pZSquare, aZSquare fptower.E4 pZSquare.Square(&p.Z) - aZSquare.Square(&a.Z) + aZSquare.Square(&q.Z) var lhs, rhs fptower.E4 lhs.Mul(&p.X, &aZSquare) - rhs.Mul(&a.X, &pZSquare) + rhs.Mul(&q.X, &pZSquare) if !lhs.Equal(&rhs) { return false } - lhs.Mul(&p.Y, &aZSquare).Mul(&lhs, &a.Z) - rhs.Mul(&a.Y, &pZSquare).Mul(&rhs, &p.Z) + lhs.Mul(&p.Y, &aZSquare).Mul(&lhs, &q.Z) + rhs.Mul(&q.Y, &pZSquare).Mul(&rhs, &p.Z) return lhs.Equal(&rhs) } -// Neg computes -G -func (p *G2Jac) Neg(a *G2Jac) *G2Jac { - *p = *a - p.Y.Neg(&a.Y) - return p -} - -// SubAssign subtracts two points on the curve -func (p *G2Jac) SubAssign(a *G2Jac) *G2Jac { - var tmp G2Jac - tmp.Set(a) - tmp.Y.Neg(&tmp.Y) - p.AddAssign(&tmp) +// Neg sets p to the Jacobian negative point -q = (q.X, -q.Y, q.Z). +func (p *G2Jac) Neg(q *G2Jac) *G2Jac { + *p = *q + p.Y.Neg(&q.Y) return p } -// AddAssign point addition in montgomery form +// AddAssign sets p to p+a in Jacobian coordinates. +// // https://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-3.html#addition-add-2007-bl -func (p *G2Jac) AddAssign(a *G2Jac) *G2Jac { +func (p *G2Jac) AddAssign(q *G2Jac) *G2Jac { - // p is infinity, return a + // p is infinity, return q if p.Z.IsZero() { - p.Set(a) + p.Set(q) return p } - // a is infinity, return p - if a.Z.IsZero() { + // q is infinity, return p + if q.Z.IsZero() { return p } var Z1Z1, Z2Z2, U1, U2, S1, S2, H, I, J, r, V fptower.E4 - Z1Z1.Square(&a.Z) + Z1Z1.Square(&q.Z) Z2Z2.Square(&p.Z) - U1.Mul(&a.X, &Z2Z2) + U1.Mul(&q.X, &Z2Z2) U2.Mul(&p.X, &Z1Z1) - S1.Mul(&a.Y, &p.Z). + S1.Mul(&q.Y, &p.Z). Mul(&S1, &Z2Z2) - S2.Mul(&p.Y, &a.Z). + S2.Mul(&p.Y, &q.Z). Mul(&S2, &Z1Z1) - // if p == a, we double instead + // if p == q, we double instead if U1.Equal(&U2) && S1.Equal(&S2) { return p.DoubleAssign() } @@ -298,7 +298,7 @@ func (p *G2Jac) AddAssign(a *G2Jac) *G2Jac { Mul(&p.Y, &r) S1.Mul(&S1, &J).Double(&S1) p.Y.Sub(&p.Y, &S1) - p.Z.Add(&p.Z, &a.Z) + p.Z.Add(&p.Z, &q.Z) p.Z.Square(&p.Z). Sub(&p.Z, &Z1Z1). Sub(&p.Z, &Z2Z2). @@ -307,8 +307,19 @@ func (p *G2Jac) AddAssign(a *G2Jac) *G2Jac { return p } -// DoubleMixed point addition -// http://www.hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html#doubling-mdbl-2007-bl +// SubAssign sets p to p-a in Jacobian coordinates. +// It uses a similar approach to AddAssign, but negates the point a before adding. +func (p *G2Jac) SubAssign(q *G2Jac) *G2Jac { + var tmp G2Jac + tmp.Set(q) + tmp.Y.Neg(&tmp.Y) + p.AddAssign(&tmp) + return p +} + +// Double sets p to [2]q in Jacobian coordinates. +// +// https://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-3.html#doubling-dbl-2007-bl func (p *G2Jac) DoubleMixed(a *G2Affine) *G2Jac { var XX, YY, YYYY, S, M, T fptower.E4 XX.Square(&a.X) @@ -320,7 +331,7 @@ func (p *G2Jac) DoubleMixed(a *G2Affine) *G2Jac { Sub(&S, &YYYY). Double(&S) M.Double(&XX). - Add(&M, &XX) // -> + a, but a=0 here + Add(&M, &XX) // -> + A, but A=0 here T.Square(&M). Sub(&T, &S). Sub(&T, &S) @@ -336,7 +347,8 @@ func (p *G2Jac) DoubleMixed(a *G2Affine) *G2Jac { return p } -// AddMixed point addition +// AddMixed sets p to p+a in Jacobian coordinates, where a.Z = 1. +// // http://www.hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html#addition-madd-2007-bl func (p *G2Jac) AddMixed(a *G2Affine) *G2Jac { @@ -385,7 +397,8 @@ func (p *G2Jac) AddMixed(a *G2Affine) *G2Jac { return p } -// Double doubles a point in Jacobian coordinates +// Double sets p to [2]q in Jacobian coordinates. +// // https://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-3.html#doubling-dbl-2007-bl func (p *G2Jac) Double(q *G2Jac) *G2Jac { p.Set(q) @@ -393,7 +406,8 @@ func (p *G2Jac) Double(q *G2Jac) *G2Jac { return p } -// DoubleAssign doubles a point in Jacobian coordinates +// DoubleAssign doubles p in Jacobian coordinates. +// // https://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-3.html#doubling-dbl-2007-bl func (p *G2Jac) DoubleAssign() *G2Jac { @@ -425,34 +439,36 @@ func (p *G2Jac) DoubleAssign() *G2Jac { return p } -// ScalarMultiplication computes and returns p = a ⋅ s +// ScalarMultiplication computes and returns p = [s]a +// where p and a are Jacobian points. +// using the GLV technique. // see https://www.iacr.org/archive/crypto2001/21390189.pdf -func (p *G2Jac) ScalarMultiplication(a *G2Jac, s *big.Int) *G2Jac { - return p.mulGLV(a, s) +func (p *G2Jac) ScalarMultiplication(q *G2Jac, s *big.Int) *G2Jac { + return p.mulGLV(q, s) } -// String returns canonical representation of the point in affine coordinates +// String converts p to affine coordinates and returns its string representation E(x,y) or "O" if it is infinity. func (p *G2Jac) String() string { _p := G2Affine{} _p.FromJacobian(p) return _p.String() } -// FromAffine sets p = Q, p in Jacobian, Q in affine -func (p *G2Jac) FromAffine(Q *G2Affine) *G2Jac { - if Q.IsInfinity() { +// FromAffine converts a point a from affine to Jacobian coordinates. +func (p *G2Jac) FromAffine(a *G2Affine) *G2Jac { + if a.IsInfinity() { p.Z.SetZero() p.X.SetOne() p.Y.SetOne() return p } p.Z.SetOne() - p.X.Set(&Q.X) - p.Y.Set(&Q.Y) + p.X.Set(&a.X) + p.Y.Set(&a.Y) return p } -// IsOnCurve returns true if p in on the curve +// IsOnCurve returns true if the Jacobian point p in on the curve. func (p *G2Jac) IsOnCurve() bool { var left, right, tmp, ZZ fptower.E4 left.Square(&p.Y) @@ -478,13 +494,14 @@ func (p *G2Jac) IsInSubGroup() bool { } -// mulWindowed computes a 2-bits windowed scalar multiplication -func (p *G2Jac) mulWindowed(a *G2Jac, s *big.Int) *G2Jac { +// mulWindowed computes the 2-bits windowed double-and-add scalar +// multiplication p=[s]q in Jacobian coordinates. +func (p *G2Jac) mulWindowed(q *G2Jac, s *big.Int) *G2Jac { var res G2Jac var ops [3]G2Jac - ops[0].Set(a) + ops[0].Set(q) if s.Sign() == -1 { ops[0].Neg(&ops[0]) } @@ -511,26 +528,27 @@ func (p *G2Jac) mulWindowed(a *G2Jac, s *big.Int) *G2Jac { } -// ψ(p) = u o π o u⁻¹ where u:E'→E iso from the twist to E -func (p *G2Jac) psi(a *G2Jac) *G2Jac { - p.Set(a) +// psi sets p to ψ(q) = u o π o u⁻¹ where u:E'→E is the isomorphism from the twist to the curve E and π is the Frobenius map. +func (p *G2Jac) psi(q *G2Jac) *G2Jac { + p.Set(q) p.X.Frobenius(&p.X).Mul(&p.X, &endo.u) p.Y.Frobenius(&p.Y).Mul(&p.Y, &endo.v) p.Z.Frobenius(&p.Z) return p } -// ϕ assigns p to ϕ(a) where ϕ: (x,y) → (w x,y), and returns p -// where w is a third root of unity in 𝔽p -func (p *G2Jac) phi(a *G2Jac) *G2Jac { - p.Set(a) +// phi sets p to ϕ(a) where ϕ: (x,y) → (w x,y), +// where w is a third root of unity. +func (p *G2Jac) phi(q *G2Jac) *G2Jac { + p.Set(q) p.X.MulByElement(&p.X, &thirdRootOneG2) return p } // mulGLV computes the scalar multiplication using a windowed-GLV method +// // see https://www.iacr.org/archive/crypto2001/21390189.pdf -func (p *G2Jac) mulGLV(a *G2Jac, s *big.Int) *G2Jac { +func (p *G2Jac) mulGLV(q *G2Jac, s *big.Int) *G2Jac { var table [15]G2Jac var res G2Jac @@ -538,11 +556,11 @@ func (p *G2Jac) mulGLV(a *G2Jac, s *big.Int) *G2Jac { res.Set(&g2Infinity) - // table[b3b2b1b0-1] = b3b2 ⋅ ϕ(a) + b1b0*a - table[0].Set(a) - table[3].phi(a) + // table[b3b2b1b0-1] = b3b2 ⋅ ϕ(q) + b1b0*q + table[0].Set(q) + table[3].phi(q) - // split the scalar, modifies ±a, ϕ(a) accordingly + // split the scalar, modifies ±q, ϕ(q) accordingly k := ecc.SplitScalar(s, &glvBasis) if k[0].Sign() == -1 { @@ -555,7 +573,7 @@ func (p *G2Jac) mulGLV(a *G2Jac, s *big.Int) *G2Jac { } // precompute table (2 bits sliding window) - // table[b3b2b1b0-1] = b3b2 ⋅ ϕ(a) + b1b0 ⋅ a if b3b2b1b0 != 0 + // table[b3b2b1b0-1] = b3b2 ⋅ ϕ(q) + b1b0 ⋅ q if b3b2b1b0 != 0 table[1].Double(&table[0]) table[2].Set(&table[1]).AddAssign(&table[0]) table[4].Set(&table[3]).AddAssign(&table[0]) @@ -611,18 +629,18 @@ func (p *G2Affine) ClearCofactor(a *G2Affine) *G2Affine { } // ClearCofactor maps a point in curve to r-torsion -func (p *G2Jac) ClearCofactor(a *G2Jac) *G2Jac { +func (p *G2Jac) ClearCofactor(q *G2Jac) *G2Jac { // https://eprint.iacr.org/2017/419.pdf, section 4.2 // multiply by (3x⁴-3)*cofacor var xg, xxg, xxxg, xxxxg, res, t G2Jac - xg.ScalarMultiplication(a, &xGen).Neg(&xg).SubAssign(a) + xg.ScalarMultiplication(q, &xGen).Neg(&xg).SubAssign(q) xxg.ScalarMultiplication(&xg, &xGen).Neg(&xxg) xxxg.ScalarMultiplication(&xxg, &xGen).Neg(&xxxg) xxxxg.ScalarMultiplication(&xxxg, &xGen).Neg(&xxxxg) res.Set(&xxxxg). - SubAssign(a) + SubAssign(q) t.Set(&xxxg). psi(&t). @@ -639,7 +657,7 @@ func (p *G2Jac) ClearCofactor(a *G2Jac) *G2Jac { psi(&t). AddAssign(&res) - res.Double(a). + res.Double(q). psi(&res). psi(&res). psi(&res). @@ -653,15 +671,15 @@ func (p *G2Jac) ClearCofactor(a *G2Jac) *G2Jac { } // ------------------------------------------------------------------------------------------------- -// Jacobian extended +// extended Jacobian coordinates -// Set sets p to the provided point -func (p *g2JacExtended) Set(a *g2JacExtended) *g2JacExtended { - p.X, p.Y, p.ZZ, p.ZZZ = a.X, a.Y, a.ZZ, a.ZZZ +// Set sets p to a in extended Jacobian coordinates. +func (p *g2JacExtended) Set(q *g2JacExtended) *g2JacExtended { + p.X, p.Y, p.ZZ, p.ZZZ = q.X, q.Y, q.ZZ, q.ZZZ return p } -// setInfinity sets p to O +// setInfinity sets p to the infinity point (1,1,0,0). func (p *g2JacExtended) setInfinity() *g2JacExtended { p.X.SetOne() p.Y.SetOne() @@ -670,43 +688,45 @@ func (p *g2JacExtended) setInfinity() *g2JacExtended { return p } -func (p *g2JacExtended) IsZero() bool { +// IsInfinity checks if the p is infinity, i.e. p.ZZ=0. +func (p *g2JacExtended) IsInfinity() bool { return p.ZZ.IsZero() } -// fromJacExtended sets Q in affine coordinates -func (p *G2Affine) fromJacExtended(Q *g2JacExtended) *G2Affine { - if Q.ZZ.IsZero() { +// fromJacExtended converts an extended Jacobian point to an affine point. +func (p *G2Affine) fromJacExtended(q *g2JacExtended) *G2Affine { + if q.ZZ.IsZero() { p.X = fptower.E4{} p.Y = fptower.E4{} return p } - p.X.Inverse(&Q.ZZ).Mul(&p.X, &Q.X) - p.Y.Inverse(&Q.ZZZ).Mul(&p.Y, &Q.Y) + p.X.Inverse(&q.ZZ).Mul(&p.X, &q.X) + p.Y.Inverse(&q.ZZZ).Mul(&p.Y, &q.Y) return p } -// fromJacExtended sets Q in Jacobian coordinates -func (p *G2Jac) fromJacExtended(Q *g2JacExtended) *G2Jac { - if Q.ZZ.IsZero() { +// fromJacExtended converts an extended Jacobian point to a Jacobian point. +func (p *G2Jac) fromJacExtended(q *g2JacExtended) *G2Jac { + if q.ZZ.IsZero() { p.Set(&g2Infinity) return p } - p.X.Mul(&Q.ZZ, &Q.X).Mul(&p.X, &Q.ZZ) - p.Y.Mul(&Q.ZZZ, &Q.Y).Mul(&p.Y, &Q.ZZZ) - p.Z.Set(&Q.ZZZ) + p.X.Mul(&q.ZZ, &q.X).Mul(&p.X, &q.ZZ) + p.Y.Mul(&q.ZZZ, &q.Y).Mul(&p.Y, &q.ZZZ) + p.Z.Set(&q.ZZZ) return p } -// unsafeFromJacExtended sets p in Jacobian coordinates, but don't check for infinity -func (p *G2Jac) unsafeFromJacExtended(Q *g2JacExtended) *G2Jac { - p.X.Square(&Q.ZZ).Mul(&p.X, &Q.X) - p.Y.Square(&Q.ZZZ).Mul(&p.Y, &Q.Y) - p.Z = Q.ZZZ +// unsafeFromJacExtended converts an extended Jacobian point, distinct from Infinity, to a Jacobian point. +func (p *G2Jac) unsafeFromJacExtended(q *g2JacExtended) *G2Jac { + p.X.Square(&q.ZZ).Mul(&p.X, &q.X) + p.Y.Square(&q.ZZZ).Mul(&p.Y, &q.Y) + p.Z = q.ZZZ return p } -// add point in Jacobian extended coordinates +// add sets p to p+q in extended Jacobian coordinates. +// // https://www.hyperelliptic.org/EFD/g1p/auto-shortw-xyzz.html#addition-add-2008-s func (p *g2JacExtended) add(q *g2JacExtended) *g2JacExtended { //if q is infinity return p @@ -762,10 +782,11 @@ func (p *g2JacExtended) add(q *g2JacExtended) *g2JacExtended { return p } -// double point in Jacobian extended coordinates +// double sets p to [2]q in Jacobian extended coordinates. +// // http://www.hyperelliptic.org/EFD/g1p/auto-shortw-xyzz.html#doubling-dbl-2008-s-1 -// since we consider any point on Z=0 as the point at infinity -// this doubling formula works for infinity points as well +// N.B.: since we consider any point on Z=0 as the point at infinity +// this doubling formula works for infinity points as well. func (p *g2JacExtended) double(q *g2JacExtended) *g2JacExtended { var U, V, W, S, XX, M fptower.E4 @@ -775,7 +796,7 @@ func (p *g2JacExtended) double(q *g2JacExtended) *g2JacExtended { S.Mul(&q.X, &V) XX.Square(&q.X) M.Double(&XX). - Add(&M, &XX) // -> + a, but a=0 here + Add(&M, &XX) // -> + A, but A=0 here U.Mul(&W, &q.Y) p.X.Square(&M). @@ -790,9 +811,10 @@ func (p *g2JacExtended) double(q *g2JacExtended) *g2JacExtended { return p } -// subMixed same as addMixed, but will negate a.Y +// addMixed sets p to p+q in extended Jacobian coordinates, where a.ZZ=1. +// // http://www.hyperelliptic.org/EFD/g1p/auto-shortw-xyzz.html#addition-madd-2008-s -func (p *g2JacExtended) subMixed(a *G2Affine) *g2JacExtended { +func (p *g2JacExtended) addMixed(a *G2Affine) *g2JacExtended { //if a is infinity return p if a.IsInfinity() { @@ -801,7 +823,7 @@ func (p *g2JacExtended) subMixed(a *G2Affine) *g2JacExtended { // p is infinity, return a if p.ZZ.IsZero() { p.X = a.X - p.Y.Neg(&a.Y) + p.Y = a.Y p.ZZ.SetOne() p.ZZZ.SetOne() return p @@ -814,12 +836,11 @@ func (p *g2JacExtended) subMixed(a *G2Affine) *g2JacExtended { P.Sub(&P, &p.X) R.Mul(&a.Y, &p.ZZZ) - R.Neg(&R) R.Sub(&R, &p.Y) if P.IsZero() { if R.IsZero() { - return p.doubleNegMixed(a) + return p.doubleMixed(a) } p.ZZ = fptower.E4{} @@ -846,9 +867,10 @@ func (p *g2JacExtended) subMixed(a *G2Affine) *g2JacExtended { } -// addMixed +// subMixed works the same as addMixed, but negates a.Y. +// // http://www.hyperelliptic.org/EFD/g1p/auto-shortw-xyzz.html#addition-madd-2008-s -func (p *g2JacExtended) addMixed(a *G2Affine) *g2JacExtended { +func (p *g2JacExtended) subMixed(a *G2Affine) *g2JacExtended { //if a is infinity return p if a.IsInfinity() { @@ -857,7 +879,7 @@ func (p *g2JacExtended) addMixed(a *G2Affine) *g2JacExtended { // p is infinity, return a if p.ZZ.IsZero() { p.X = a.X - p.Y = a.Y + p.Y.Neg(&a.Y) p.ZZ.SetOne() p.ZZZ.SetOne() return p @@ -870,11 +892,12 @@ func (p *g2JacExtended) addMixed(a *G2Affine) *g2JacExtended { P.Sub(&P, &p.X) R.Mul(&a.Y, &p.ZZZ) + R.Neg(&R) R.Sub(&R, &p.Y) if P.IsZero() { if R.IsZero() { - return p.doubleMixed(a) + return p.doubleNegMixed(a) } p.ZZ = fptower.E4{} @@ -901,21 +924,21 @@ func (p *g2JacExtended) addMixed(a *G2Affine) *g2JacExtended { } -// doubleNegMixed same as double, but will negate q.Y -func (p *g2JacExtended) doubleNegMixed(q *G2Affine) *g2JacExtended { +// doubleNegMixed works the same as double, but negates q.Y. +func (p *g2JacExtended) doubleNegMixed(a *G2Affine) *g2JacExtended { var U, V, W, S, XX, M, S2, L fptower.E4 - U.Double(&q.Y) + U.Double(&a.Y) U.Neg(&U) V.Square(&U) W.Mul(&U, &V) - S.Mul(&q.X, &V) - XX.Square(&q.X) + S.Mul(&a.X, &V) + XX.Square(&a.X) M.Double(&XX). - Add(&M, &XX) // -> + a, but a=0 here + Add(&M, &XX) // -> + A, but A=0 here S2.Double(&S) - L.Mul(&W, &q.Y) + L.Mul(&W, &a.Y) p.X.Square(&M). Sub(&p.X, &S2) @@ -928,21 +951,22 @@ func (p *g2JacExtended) doubleNegMixed(q *G2Affine) *g2JacExtended { return p } -// doubleMixed point in Jacobian extended coordinates +// doubleMixed sets p to [2]a in Jacobian extended coordinates, where a.ZZ=1. +// // http://www.hyperelliptic.org/EFD/g1p/auto-shortw-xyzz.html#doubling-dbl-2008-s-1 -func (p *g2JacExtended) doubleMixed(q *G2Affine) *g2JacExtended { +func (p *g2JacExtended) doubleMixed(a *G2Affine) *g2JacExtended { var U, V, W, S, XX, M, S2, L fptower.E4 - U.Double(&q.Y) + U.Double(&a.Y) V.Square(&U) W.Mul(&U, &V) - S.Mul(&q.X, &V) - XX.Square(&q.X) + S.Mul(&a.X, &V) + XX.Square(&a.X) M.Double(&XX). - Add(&M, &XX) // -> + a, but a=0 here + Add(&M, &XX) // -> + A, but A=0 here S2.Double(&S) - L.Mul(&W, &q.Y) + L.Mul(&W, &a.Y) p.X.Square(&M). Sub(&p.X, &S2) @@ -956,38 +980,38 @@ func (p *g2JacExtended) doubleMixed(q *G2Affine) *g2JacExtended { } // ------------------------------------------------------------------------------------------------- -// Homogenous projective +// Homogenous projective coordinates -// Set sets p to the provided point -func (p *g2Proj) Set(a *g2Proj) *g2Proj { - p.x, p.y, p.z = a.x, a.y, a.z +// Set sets p to a in projective coordinates. +func (p *g2Proj) Set(q *g2Proj) *g2Proj { + p.x, p.y, p.z = q.x, q.y, q.z return p } -// Neg computes -G -func (p *g2Proj) Neg(a *g2Proj) *g2Proj { - *p = *a - p.y.Neg(&a.y) +// Neg sets p to the projective negative point -q = (q.X, -q.Y). +func (p *g2Proj) Neg(q *g2Proj) *g2Proj { + *p = *q + p.y.Neg(&q.y) return p } -// FromAffine sets p = Q, p in homogenous projective, Q in affine -func (p *g2Proj) FromAffine(Q *G2Affine) *g2Proj { - if Q.X.IsZero() && Q.Y.IsZero() { +// FromAffine converts q in affine to p in projective coordinates. +func (p *g2Proj) FromAffine(a *G2Affine) *g2Proj { + if a.X.IsZero() && a.Y.IsZero() { p.z.SetZero() p.x.SetOne() p.y.SetOne() return p } p.z.SetOne() - p.x.Set(&Q.X) - p.y.Set(&Q.Y) + p.x.Set(&a.X) + p.y.Set(&a.Y) return p } // BatchScalarMultiplicationG2 multiplies the same base by all scalars // and return resulting points in affine coordinates -// uses a simple windowed-NAF like exponentiation algorithm +// uses a simple windowed-NAF-like multiplication algorithm. func BatchScalarMultiplicationG2(base *G2Affine, scalars []fr.Element) []G2Affine { // approximate cost in group ops is // cost = 2^{c-1} + n(scalar.nbBits+nbChunks) @@ -1066,9 +1090,8 @@ func BatchScalarMultiplicationG2(base *G2Affine, scalars []fr.Element) []G2Affin return toReturn } -// batch add affine coordinates -// using batch inversion -// special cases (doubling, infinity) must be filtered out before this call +// batchAddG1Affine adds affine points using the Montgomery batch inversion trick. +// Special cases (doubling, infinity) must be filtered out before this call. func batchAddG2Affine[TP pG2Affine, TPP ppG2Affine, TC cG2Affine](R *TPP, P *TP, batchSize int) { var lambda, lambdain TC diff --git a/ecc/bls24-315/multiexp_affine.go b/ecc/bls24-315/multiexp_affine.go index 65c478570..ebe85c751 100644 --- a/ecc/bls24-315/multiexp_affine.go +++ b/ecc/bls24-315/multiexp_affine.go @@ -226,7 +226,7 @@ func processChunkG1BatchAffine[BJE ibg1JacExtended, B ibG1Affine, BS bitSet, TP total.setInfinity() for k := len(buckets) - 1; k >= 0; k-- { runningSum.addMixed(&buckets[k]) - if !bucketsJE[k].IsZero() { + if !bucketsJE[k].IsInfinity() { runningSum.add(&bucketsJE[k]) } total.add(&runningSum) @@ -554,7 +554,7 @@ func processChunkG2BatchAffine[BJE ibg2JacExtended, B ibG2Affine, BS bitSet, TP total.setInfinity() for k := len(buckets) - 1; k >= 0; k-- { runningSum.addMixed(&buckets[k]) - if !bucketsJE[k].IsZero() { + if !bucketsJE[k].IsInfinity() { runningSum.add(&bucketsJE[k]) } total.add(&runningSum) diff --git a/ecc/bls24-315/multiexp_jacobian.go b/ecc/bls24-315/multiexp_jacobian.go index c55478337..76d08a460 100644 --- a/ecc/bls24-315/multiexp_jacobian.go +++ b/ecc/bls24-315/multiexp_jacobian.go @@ -56,7 +56,7 @@ func processChunkG1Jacobian[B ibg1JacExtended](chunk uint64, runningSum.setInfinity() total.setInfinity() for k := len(buckets) - 1; k >= 0; k-- { - if !buckets[k].IsZero() { + if !buckets[k].IsInfinity() { runningSum.add(&buckets[k]) } total.add(&runningSum) @@ -145,7 +145,7 @@ func processChunkG2Jacobian[B ibg2JacExtended](chunk uint64, runningSum.setInfinity() total.setInfinity() for k := len(buckets) - 1; k >= 0; k-- { - if !buckets[k].IsZero() { + if !buckets[k].IsInfinity() { runningSum.add(&buckets[k]) } total.add(&runningSum) diff --git a/ecc/bls24-317/g1.go b/ecc/bls24-317/g1.go index 892353cac..014baae64 100644 --- a/ecc/bls24-317/g1.go +++ b/ecc/bls24-317/g1.go @@ -25,38 +25,40 @@ import ( "runtime" ) -// G1Affine point in affine coordinates +// G1Affine is a point in affine coordinates (x,y) type G1Affine struct { X, Y fp.Element } -// G1Jac is a point with fp.Element coordinates +// G1Jac is a point in Jacobian coordinates (x=X/Z², y=Y/Z³) type G1Jac struct { X, Y, Z fp.Element } -// g1JacExtended parameterized Jacobian coordinates (x=X/ZZ, y=Y/ZZZ, ZZ³=ZZZ²) +// g1JacExtended is a point in extended Jacobian coordinates (x=X/ZZ, y=Y/ZZZ, ZZ³=ZZZ²) type g1JacExtended struct { X, Y, ZZ, ZZZ fp.Element } // ------------------------------------------------------------------------------------------------- -// Affine +// Affine coordinates -// Set sets p to the provided point +// Set sets p to a in affine coordinates. func (p *G1Affine) Set(a *G1Affine) *G1Affine { p.X, p.Y = a.X, a.Y return p } -// setInfinity sets p to O +// setInfinity sets p to the infinity point, which is encoded as (0,0). +// N.B.: (0,0) is never on the curve for j=0 curves (Y²=X³+B). func (p *G1Affine) setInfinity() *G1Affine { p.X.SetZero() p.Y.SetZero() return p } -// ScalarMultiplication computes and returns p = a ⋅ s +// ScalarMultiplication computes and returns p = [s]a +// where p and a are affine points. func (p *G1Affine) ScalarMultiplication(a *G1Affine, s *big.Int) *G1Affine { var _p G1Jac _p.FromAffine(a) @@ -65,20 +67,22 @@ func (p *G1Affine) ScalarMultiplication(a *G1Affine, s *big.Int) *G1Affine { return p } -// ScalarMultiplicationAffine computes and returns p = a ⋅ s -// Takes an affine point and returns a Jacobian point (useful for KZG) +// ScalarMultiplicationAffine computes and returns p = [s]a +// where a is an affine point and p a Jacobian point (useful for KZG). func (p *G1Jac) ScalarMultiplicationAffine(a *G1Affine, s *big.Int) *G1Jac { p.FromAffine(a) p.mulGLV(p, s) return p } -// ScalarMultiplicationBase computes and returns p = g ⋅ s where g is the prime subgroup generator +// ScalarMultiplicationBase computes and returns p = [s]g +// where g is the Jacobian point generating the prime subgroup. func (p *G1Jac) ScalarMultiplicationBase(s *big.Int) *G1Jac { return p.mulGLV(&g1Gen, s) } -// ScalarMultiplicationBase computes and returns p = g ⋅ s where g is the prime subgroup generator +// ScalarMultiplicationBase computes and returns p = [s]g +// where g is the affine point generating the prime subgroup. func (p *G1Affine) ScalarMultiplicationBase(s *big.Int) *G1Affine { var _p G1Jac _p.mulGLV(&g1Gen, s) @@ -86,8 +90,9 @@ func (p *G1Affine) ScalarMultiplicationBase(s *big.Int) *G1Affine { return p } -// Add adds two point in affine coordinates. -// Jacobian addition with Z1=Z2=1 +// Add adds two points in affine coordinates. +// It uses the Jacobian addition with a.Z=b.Z=1 and converts the result to affine coordinates. +// // https://www.hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html#addition-mmadd-2007-bl func (p *G1Affine) Add(a, b *G1Affine) *G1Affine { var q G1Jac @@ -133,6 +138,10 @@ func (p *G1Affine) Add(a, b *G1Affine) *G1Affine { } // Double doubles a point in affine coordinates. +// It converts the point to Jacobian coordinates, doubles it using Jacobian +// addition with a.Z=1, and converts it back to affine coordinates. +// +// http://www.hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html#doubling-mdbl-2007-bl func (p *G1Affine) Double(a *G1Affine) *G1Affine { var q G1Jac q.FromAffine(a) @@ -141,7 +150,8 @@ func (p *G1Affine) Double(a *G1Affine) *G1Affine { return p } -// Sub subs two point in affine coordinates. +// Sub subtracts two points in affine coordinates. +// It uses a similar approach to Add, but negates the second point before adding. func (p *G1Affine) Sub(a, b *G1Affine) *G1Affine { var bneg G1Affine bneg.Neg(b) @@ -149,19 +159,19 @@ func (p *G1Affine) Sub(a, b *G1Affine) *G1Affine { return p } -// Equal tests if two points (in Affine coordinates) are equal +// Equal tests if two points in affine coordinates are equal. func (p *G1Affine) Equal(a *G1Affine) bool { return p.X.Equal(&a.X) && p.Y.Equal(&a.Y) } -// Neg computes -G +// Neg sets p to the affine negative point -a = (a.X, -a.Y). func (p *G1Affine) Neg(a *G1Affine) *G1Affine { p.X = a.X p.Y.Neg(&a.Y) return p } -// FromJacobian rescales a point in Jacobian coord in z=1 plane +// FromJacobian converts a point p1 from Jacobian to affine coordinates. func (p *G1Affine) FromJacobian(p1 *G1Jac) *G1Affine { var a, b fp.Element @@ -180,7 +190,7 @@ func (p *G1Affine) FromJacobian(p1 *G1Jac) *G1Affine { return p } -// String returns the string representation of the point or "O" if it is infinity +// String returns the string representation E(x,y) of the affine point p or "O" if it is infinity. func (p *G1Affine) String() string { if p.IsInfinity() { return "O" @@ -188,21 +198,20 @@ func (p *G1Affine) String() string { return "E([" + p.X.String() + "," + p.Y.String() + "])" } -// IsInfinity checks if the point is infinity -// in affine, it's encoded as (0,0) -// (0,0) is never on the curve for j=0 curves +// IsInfinity checks if the affine point p is infinity, which is encoded as (0,0). +// N.B.: (0,0) is never on the curve for j=0 curves (Y²=X³+B). func (p *G1Affine) IsInfinity() bool { return p.X.IsZero() && p.Y.IsZero() } -// IsOnCurve returns true if p in on the curve +// IsOnCurve returns true if the affine point p in on the curve. func (p *G1Affine) IsOnCurve() bool { var point G1Jac point.FromAffine(p) return point.IsOnCurve() // call this function to handle infinity point } -// IsInSubGroup returns true if p is in the correct subgroup, false otherwise +// IsInSubGroup returns true if the affine point p is in the correct subgroup, false otherwise. func (p *G1Affine) IsInSubGroup() bool { var _p G1Jac _p.FromAffine(p) @@ -210,84 +219,76 @@ func (p *G1Affine) IsInSubGroup() bool { } // ------------------------------------------------------------------------------------------------- -// Jacobian +// Jacobian coordinates -// Set sets p to the provided point -func (p *G1Jac) Set(a *G1Jac) *G1Jac { - p.X, p.Y, p.Z = a.X, a.Y, a.Z +// Set sets p to a in Jacobian coordinates. +func (p *G1Jac) Set(q *G1Jac) *G1Jac { + p.X, p.Y, p.Z = q.X, q.Y, q.Z return p } -// Equal tests if two points (in Jacobian coordinates) are equal -func (p *G1Jac) Equal(a *G1Jac) bool { +// Equal tests if two points in Jacobian coordinates are equal. +func (p *G1Jac) Equal(q *G1Jac) bool { // If one point is infinity, the other must also be infinity. if p.Z.IsZero() { - return a.Z.IsZero() + return q.Z.IsZero() } // If the other point is infinity, return false since we can't // the following checks would be incorrect. - if a.Z.IsZero() { + if q.Z.IsZero() { return false } var pZSquare, aZSquare fp.Element pZSquare.Square(&p.Z) - aZSquare.Square(&a.Z) + aZSquare.Square(&q.Z) var lhs, rhs fp.Element lhs.Mul(&p.X, &aZSquare) - rhs.Mul(&a.X, &pZSquare) + rhs.Mul(&q.X, &pZSquare) if !lhs.Equal(&rhs) { return false } - lhs.Mul(&p.Y, &aZSquare).Mul(&lhs, &a.Z) - rhs.Mul(&a.Y, &pZSquare).Mul(&rhs, &p.Z) + lhs.Mul(&p.Y, &aZSquare).Mul(&lhs, &q.Z) + rhs.Mul(&q.Y, &pZSquare).Mul(&rhs, &p.Z) return lhs.Equal(&rhs) } -// Neg computes -G -func (p *G1Jac) Neg(a *G1Jac) *G1Jac { - *p = *a - p.Y.Neg(&a.Y) +// Neg sets p to the Jacobian negative point -q = (q.X, -q.Y, q.Z). +func (p *G1Jac) Neg(q *G1Jac) *G1Jac { + *p = *q + p.Y.Neg(&q.Y) return p } -// SubAssign subtracts two points on the curve -func (p *G1Jac) SubAssign(a *G1Jac) *G1Jac { - var tmp G1Jac - tmp.Set(a) - tmp.Y.Neg(&tmp.Y) - p.AddAssign(&tmp) - return p -} - -// AddAssign point addition in montgomery form +// AddAssign sets p to p+a in Jacobian coordinates. +// // https://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-3.html#addition-add-2007-bl -func (p *G1Jac) AddAssign(a *G1Jac) *G1Jac { +func (p *G1Jac) AddAssign(q *G1Jac) *G1Jac { - // p is infinity, return a + // p is infinity, return q if p.Z.IsZero() { - p.Set(a) + p.Set(q) return p } - // a is infinity, return p - if a.Z.IsZero() { + // q is infinity, return p + if q.Z.IsZero() { return p } var Z1Z1, Z2Z2, U1, U2, S1, S2, H, I, J, r, V fp.Element - Z1Z1.Square(&a.Z) + Z1Z1.Square(&q.Z) Z2Z2.Square(&p.Z) - U1.Mul(&a.X, &Z2Z2) + U1.Mul(&q.X, &Z2Z2) U2.Mul(&p.X, &Z1Z1) - S1.Mul(&a.Y, &p.Z). + S1.Mul(&q.Y, &p.Z). Mul(&S1, &Z2Z2) - S2.Mul(&p.Y, &a.Z). + S2.Mul(&p.Y, &q.Z). Mul(&S2, &Z1Z1) - // if p == a, we double instead + // if p == q, we double instead if U1.Equal(&U2) && S1.Equal(&S2) { return p.DoubleAssign() } @@ -306,7 +307,7 @@ func (p *G1Jac) AddAssign(a *G1Jac) *G1Jac { Mul(&p.Y, &r) S1.Mul(&S1, &J).Double(&S1) p.Y.Sub(&p.Y, &S1) - p.Z.Add(&p.Z, &a.Z) + p.Z.Add(&p.Z, &q.Z) p.Z.Square(&p.Z). Sub(&p.Z, &Z1Z1). Sub(&p.Z, &Z2Z2). @@ -315,8 +316,19 @@ func (p *G1Jac) AddAssign(a *G1Jac) *G1Jac { return p } -// DoubleMixed point addition -// http://www.hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html#doubling-mdbl-2007-bl +// SubAssign sets p to p-a in Jacobian coordinates. +// It uses a similar approach to AddAssign, but negates the point a before adding. +func (p *G1Jac) SubAssign(q *G1Jac) *G1Jac { + var tmp G1Jac + tmp.Set(q) + tmp.Y.Neg(&tmp.Y) + p.AddAssign(&tmp) + return p +} + +// Double sets p to [2]q in Jacobian coordinates. +// +// https://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-3.html#doubling-dbl-2007-bl func (p *G1Jac) DoubleMixed(a *G1Affine) *G1Jac { var XX, YY, YYYY, S, M, T fp.Element XX.Square(&a.X) @@ -328,7 +340,7 @@ func (p *G1Jac) DoubleMixed(a *G1Affine) *G1Jac { Sub(&S, &YYYY). Double(&S) M.Double(&XX). - Add(&M, &XX) // -> + a, but a=0 here + Add(&M, &XX) // -> + A, but A=0 here T.Square(&M). Sub(&T, &S). Sub(&T, &S) @@ -344,7 +356,8 @@ func (p *G1Jac) DoubleMixed(a *G1Affine) *G1Jac { return p } -// AddMixed point addition +// AddMixed sets p to p+a in Jacobian coordinates, where a.Z = 1. +// // http://www.hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html#addition-madd-2007-bl func (p *G1Jac) AddMixed(a *G1Affine) *G1Jac { @@ -393,7 +406,8 @@ func (p *G1Jac) AddMixed(a *G1Affine) *G1Jac { return p } -// Double doubles a point in Jacobian coordinates +// Double sets p to [2]q in Jacobian coordinates. +// // https://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-3.html#doubling-dbl-2007-bl func (p *G1Jac) Double(q *G1Jac) *G1Jac { p.Set(q) @@ -401,7 +415,8 @@ func (p *G1Jac) Double(q *G1Jac) *G1Jac { return p } -// DoubleAssign doubles a point in Jacobian coordinates +// DoubleAssign doubles p in Jacobian coordinates. +// // https://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-3.html#doubling-dbl-2007-bl func (p *G1Jac) DoubleAssign() *G1Jac { @@ -433,34 +448,36 @@ func (p *G1Jac) DoubleAssign() *G1Jac { return p } -// ScalarMultiplication computes and returns p = a ⋅ s +// ScalarMultiplication computes and returns p = [s]a +// where p and a are Jacobian points. +// using the GLV technique. // see https://www.iacr.org/archive/crypto2001/21390189.pdf -func (p *G1Jac) ScalarMultiplication(a *G1Jac, s *big.Int) *G1Jac { - return p.mulGLV(a, s) +func (p *G1Jac) ScalarMultiplication(q *G1Jac, s *big.Int) *G1Jac { + return p.mulGLV(q, s) } -// String returns canonical representation of the point in affine coordinates +// String converts p to affine coordinates and returns its string representation E(x,y) or "O" if it is infinity. func (p *G1Jac) String() string { _p := G1Affine{} _p.FromJacobian(p) return _p.String() } -// FromAffine sets p = Q, p in Jacobian, Q in affine -func (p *G1Jac) FromAffine(Q *G1Affine) *G1Jac { - if Q.IsInfinity() { +// FromAffine converts a point a from affine to Jacobian coordinates. +func (p *G1Jac) FromAffine(a *G1Affine) *G1Jac { + if a.IsInfinity() { p.Z.SetZero() p.X.SetOne() p.Y.SetOne() return p } p.Z.SetOne() - p.X.Set(&Q.X) - p.Y.Set(&Q.Y) + p.X.Set(&a.X) + p.Y.Set(&a.Y) return p } -// IsOnCurve returns true if p in on the curve +// IsOnCurve returns true if the Jacobian point p in on the curve. func (p *G1Jac) IsOnCurve() bool { var left, right, tmp, ZZ fp.Element left.Square(&p.Y) @@ -494,13 +511,14 @@ func (p *G1Jac) IsInSubGroup() bool { } -// mulWindowed computes a 2-bits windowed scalar multiplication -func (p *G1Jac) mulWindowed(a *G1Jac, s *big.Int) *G1Jac { +// mulWindowed computes the 2-bits windowed double-and-add scalar +// multiplication p=[s]q in Jacobian coordinates. +func (p *G1Jac) mulWindowed(q *G1Jac, s *big.Int) *G1Jac { var res G1Jac var ops [3]G1Jac - ops[0].Set(a) + ops[0].Set(q) if s.Sign() == -1 { ops[0].Neg(&ops[0]) } @@ -527,17 +545,18 @@ func (p *G1Jac) mulWindowed(a *G1Jac, s *big.Int) *G1Jac { } -// ϕ assigns p to ϕ(a) where ϕ: (x,y) → (w x,y), and returns p -// where w is a third root of unity in 𝔽p -func (p *G1Jac) phi(a *G1Jac) *G1Jac { - p.Set(a) +// phi sets p to ϕ(a) where ϕ: (x,y) → (w x,y), +// where w is a third root of unity. +func (p *G1Jac) phi(q *G1Jac) *G1Jac { + p.Set(q) p.X.Mul(&p.X, &thirdRootOneG1) return p } // mulGLV computes the scalar multiplication using a windowed-GLV method +// // see https://www.iacr.org/archive/crypto2001/21390189.pdf -func (p *G1Jac) mulGLV(a *G1Jac, s *big.Int) *G1Jac { +func (p *G1Jac) mulGLV(q *G1Jac, s *big.Int) *G1Jac { var table [15]G1Jac var res G1Jac @@ -545,11 +564,11 @@ func (p *G1Jac) mulGLV(a *G1Jac, s *big.Int) *G1Jac { res.Set(&g1Infinity) - // table[b3b2b1b0-1] = b3b2 ⋅ ϕ(a) + b1b0*a - table[0].Set(a) - table[3].phi(a) + // table[b3b2b1b0-1] = b3b2 ⋅ ϕ(q) + b1b0*q + table[0].Set(q) + table[3].phi(q) - // split the scalar, modifies ±a, ϕ(a) accordingly + // split the scalar, modifies ±q, ϕ(q) accordingly k := ecc.SplitScalar(s, &glvBasis) if k[0].Sign() == -1 { @@ -562,7 +581,7 @@ func (p *G1Jac) mulGLV(a *G1Jac, s *big.Int) *G1Jac { } // precompute table (2 bits sliding window) - // table[b3b2b1b0-1] = b3b2 ⋅ ϕ(a) + b1b0 ⋅ a if b3b2b1b0 != 0 + // table[b3b2b1b0-1] = b3b2 ⋅ ϕ(q) + b1b0 ⋅ q if b3b2b1b0 != 0 table[1].Double(&table[0]) table[2].Set(&table[1]).AddAssign(&table[0]) table[4].Set(&table[3]).AddAssign(&table[0]) @@ -618,17 +637,17 @@ func (p *G1Affine) ClearCofactor(a *G1Affine) *G1Affine { } // ClearCofactor maps a point in E(Fp) to E(Fp)[r] -func (p *G1Jac) ClearCofactor(a *G1Jac) *G1Jac { +func (p *G1Jac) ClearCofactor(q *G1Jac) *G1Jac { // cf https://eprint.iacr.org/2019/403.pdf, 5 var res G1Jac - res.ScalarMultiplication(a, &xGen).Neg(&res).AddAssign(a) + res.ScalarMultiplication(q, &xGen).Neg(&res).AddAssign(q) p.Set(&res) return p } -// JointScalarMultiplicationBase computes [s1]g+[s2]a using Straus-Shamir technique -// where g is the prime subgroup generator +// JointScalarMultiplicationBase computes [s1]g+[s2]a using Strauss-Shamir technique +// where g is the prime subgroup generator and a is an affine point. func (p *G1Jac) JointScalarMultiplicationBase(a *G1Affine, s1, s2 *big.Int) *G1Jac { var res, p1, p2 G1Jac @@ -699,15 +718,15 @@ func (p *G1Jac) JointScalarMultiplicationBase(a *G1Affine, s1, s2 *big.Int) *G1J } // ------------------------------------------------------------------------------------------------- -// Jacobian extended +// extended Jacobian coordinates -// Set sets p to the provided point -func (p *g1JacExtended) Set(a *g1JacExtended) *g1JacExtended { - p.X, p.Y, p.ZZ, p.ZZZ = a.X, a.Y, a.ZZ, a.ZZZ +// Set sets p to a in extended Jacobian coordinates. +func (p *g1JacExtended) Set(q *g1JacExtended) *g1JacExtended { + p.X, p.Y, p.ZZ, p.ZZZ = q.X, q.Y, q.ZZ, q.ZZZ return p } -// setInfinity sets p to O +// setInfinity sets p to the infinity point (1,1,0,0). func (p *g1JacExtended) setInfinity() *g1JacExtended { p.X.SetOne() p.Y.SetOne() @@ -716,43 +735,45 @@ func (p *g1JacExtended) setInfinity() *g1JacExtended { return p } -func (p *g1JacExtended) IsZero() bool { +// IsInfinity checks if the p is infinity, i.e. p.ZZ=0. +func (p *g1JacExtended) IsInfinity() bool { return p.ZZ.IsZero() } -// fromJacExtended sets Q in affine coordinates -func (p *G1Affine) fromJacExtended(Q *g1JacExtended) *G1Affine { - if Q.ZZ.IsZero() { +// fromJacExtended converts an extended Jacobian point to an affine point. +func (p *G1Affine) fromJacExtended(q *g1JacExtended) *G1Affine { + if q.ZZ.IsZero() { p.X = fp.Element{} p.Y = fp.Element{} return p } - p.X.Inverse(&Q.ZZ).Mul(&p.X, &Q.X) - p.Y.Inverse(&Q.ZZZ).Mul(&p.Y, &Q.Y) + p.X.Inverse(&q.ZZ).Mul(&p.X, &q.X) + p.Y.Inverse(&q.ZZZ).Mul(&p.Y, &q.Y) return p } -// fromJacExtended sets Q in Jacobian coordinates -func (p *G1Jac) fromJacExtended(Q *g1JacExtended) *G1Jac { - if Q.ZZ.IsZero() { +// fromJacExtended converts an extended Jacobian point to a Jacobian point. +func (p *G1Jac) fromJacExtended(q *g1JacExtended) *G1Jac { + if q.ZZ.IsZero() { p.Set(&g1Infinity) return p } - p.X.Mul(&Q.ZZ, &Q.X).Mul(&p.X, &Q.ZZ) - p.Y.Mul(&Q.ZZZ, &Q.Y).Mul(&p.Y, &Q.ZZZ) - p.Z.Set(&Q.ZZZ) + p.X.Mul(&q.ZZ, &q.X).Mul(&p.X, &q.ZZ) + p.Y.Mul(&q.ZZZ, &q.Y).Mul(&p.Y, &q.ZZZ) + p.Z.Set(&q.ZZZ) return p } -// unsafeFromJacExtended sets p in Jacobian coordinates, but don't check for infinity -func (p *G1Jac) unsafeFromJacExtended(Q *g1JacExtended) *G1Jac { - p.X.Square(&Q.ZZ).Mul(&p.X, &Q.X) - p.Y.Square(&Q.ZZZ).Mul(&p.Y, &Q.Y) - p.Z = Q.ZZZ +// unsafeFromJacExtended converts an extended Jacobian point, distinct from Infinity, to a Jacobian point. +func (p *G1Jac) unsafeFromJacExtended(q *g1JacExtended) *G1Jac { + p.X.Square(&q.ZZ).Mul(&p.X, &q.X) + p.Y.Square(&q.ZZZ).Mul(&p.Y, &q.Y) + p.Z = q.ZZZ return p } -// add point in Jacobian extended coordinates +// add sets p to p+q in extended Jacobian coordinates. +// // https://www.hyperelliptic.org/EFD/g1p/auto-shortw-xyzz.html#addition-add-2008-s func (p *g1JacExtended) add(q *g1JacExtended) *g1JacExtended { //if q is infinity return p @@ -808,10 +829,11 @@ func (p *g1JacExtended) add(q *g1JacExtended) *g1JacExtended { return p } -// double point in Jacobian extended coordinates +// double sets p to [2]q in Jacobian extended coordinates. +// // http://www.hyperelliptic.org/EFD/g1p/auto-shortw-xyzz.html#doubling-dbl-2008-s-1 -// since we consider any point on Z=0 as the point at infinity -// this doubling formula works for infinity points as well +// N.B.: since we consider any point on Z=0 as the point at infinity +// this doubling formula works for infinity points as well. func (p *g1JacExtended) double(q *g1JacExtended) *g1JacExtended { var U, V, W, S, XX, M fp.Element @@ -821,7 +843,7 @@ func (p *g1JacExtended) double(q *g1JacExtended) *g1JacExtended { S.Mul(&q.X, &V) XX.Square(&q.X) M.Double(&XX). - Add(&M, &XX) // -> + a, but a=0 here + Add(&M, &XX) // -> + A, but A=0 here U.Mul(&W, &q.Y) p.X.Square(&M). @@ -836,9 +858,10 @@ func (p *g1JacExtended) double(q *g1JacExtended) *g1JacExtended { return p } -// subMixed same as addMixed, but will negate a.Y +// addMixed sets p to p+q in extended Jacobian coordinates, where a.ZZ=1. +// // http://www.hyperelliptic.org/EFD/g1p/auto-shortw-xyzz.html#addition-madd-2008-s -func (p *g1JacExtended) subMixed(a *G1Affine) *g1JacExtended { +func (p *g1JacExtended) addMixed(a *G1Affine) *g1JacExtended { //if a is infinity return p if a.IsInfinity() { @@ -847,7 +870,7 @@ func (p *g1JacExtended) subMixed(a *G1Affine) *g1JacExtended { // p is infinity, return a if p.ZZ.IsZero() { p.X = a.X - p.Y.Neg(&a.Y) + p.Y = a.Y p.ZZ.SetOne() p.ZZZ.SetOne() return p @@ -860,12 +883,11 @@ func (p *g1JacExtended) subMixed(a *G1Affine) *g1JacExtended { P.Sub(&P, &p.X) R.Mul(&a.Y, &p.ZZZ) - R.Neg(&R) R.Sub(&R, &p.Y) if P.IsZero() { if R.IsZero() { - return p.doubleNegMixed(a) + return p.doubleMixed(a) } p.ZZ = fp.Element{} @@ -892,9 +914,10 @@ func (p *g1JacExtended) subMixed(a *G1Affine) *g1JacExtended { } -// addMixed +// subMixed works the same as addMixed, but negates a.Y. +// // http://www.hyperelliptic.org/EFD/g1p/auto-shortw-xyzz.html#addition-madd-2008-s -func (p *g1JacExtended) addMixed(a *G1Affine) *g1JacExtended { +func (p *g1JacExtended) subMixed(a *G1Affine) *g1JacExtended { //if a is infinity return p if a.IsInfinity() { @@ -903,7 +926,7 @@ func (p *g1JacExtended) addMixed(a *G1Affine) *g1JacExtended { // p is infinity, return a if p.ZZ.IsZero() { p.X = a.X - p.Y = a.Y + p.Y.Neg(&a.Y) p.ZZ.SetOne() p.ZZZ.SetOne() return p @@ -916,11 +939,12 @@ func (p *g1JacExtended) addMixed(a *G1Affine) *g1JacExtended { P.Sub(&P, &p.X) R.Mul(&a.Y, &p.ZZZ) + R.Neg(&R) R.Sub(&R, &p.Y) if P.IsZero() { if R.IsZero() { - return p.doubleMixed(a) + return p.doubleNegMixed(a) } p.ZZ = fp.Element{} @@ -947,21 +971,21 @@ func (p *g1JacExtended) addMixed(a *G1Affine) *g1JacExtended { } -// doubleNegMixed same as double, but will negate q.Y -func (p *g1JacExtended) doubleNegMixed(q *G1Affine) *g1JacExtended { +// doubleNegMixed works the same as double, but negates q.Y. +func (p *g1JacExtended) doubleNegMixed(a *G1Affine) *g1JacExtended { var U, V, W, S, XX, M, S2, L fp.Element - U.Double(&q.Y) + U.Double(&a.Y) U.Neg(&U) V.Square(&U) W.Mul(&U, &V) - S.Mul(&q.X, &V) - XX.Square(&q.X) + S.Mul(&a.X, &V) + XX.Square(&a.X) M.Double(&XX). - Add(&M, &XX) // -> + a, but a=0 here + Add(&M, &XX) // -> + A, but A=0 here S2.Double(&S) - L.Mul(&W, &q.Y) + L.Mul(&W, &a.Y) p.X.Square(&M). Sub(&p.X, &S2) @@ -974,21 +998,22 @@ func (p *g1JacExtended) doubleNegMixed(q *G1Affine) *g1JacExtended { return p } -// doubleMixed point in Jacobian extended coordinates +// doubleMixed sets p to [2]a in Jacobian extended coordinates, where a.ZZ=1. +// // http://www.hyperelliptic.org/EFD/g1p/auto-shortw-xyzz.html#doubling-dbl-2008-s-1 -func (p *g1JacExtended) doubleMixed(q *G1Affine) *g1JacExtended { +func (p *g1JacExtended) doubleMixed(a *G1Affine) *g1JacExtended { var U, V, W, S, XX, M, S2, L fp.Element - U.Double(&q.Y) + U.Double(&a.Y) V.Square(&U) W.Mul(&U, &V) - S.Mul(&q.X, &V) - XX.Square(&q.X) + S.Mul(&a.X, &V) + XX.Square(&a.X) M.Double(&XX). - Add(&M, &XX) // -> + a, but a=0 here + Add(&M, &XX) // -> + A, but A=0 here S2.Double(&S) - L.Mul(&W, &q.Y) + L.Mul(&W, &a.Y) p.X.Square(&M). Sub(&p.X, &S2) @@ -1002,7 +1027,7 @@ func (p *g1JacExtended) doubleMixed(q *G1Affine) *g1JacExtended { } // BatchJacobianToAffineG1 converts points in Jacobian coordinates to Affine coordinates -// performing a single field inversion (Montgomery batch inversion trick). +// performing a single field inversion using the Montgomery batch inversion trick. func BatchJacobianToAffineG1(points []G1Jac) []G1Affine { result := make([]G1Affine, len(points)) zeroes := make([]bool, len(points)) @@ -1052,7 +1077,7 @@ func BatchJacobianToAffineG1(points []G1Jac) []G1Affine { // BatchScalarMultiplicationG1 multiplies the same base by all scalars // and return resulting points in affine coordinates -// uses a simple windowed-NAF like exponentiation algorithm +// uses a simple windowed-NAF-like multiplication algorithm. func BatchScalarMultiplicationG1(base *G1Affine, scalars []fr.Element) []G1Affine { // approximate cost in group ops is // cost = 2^{c-1} + n(scalar.nbBits+nbChunks) @@ -1134,9 +1159,8 @@ func BatchScalarMultiplicationG1(base *G1Affine, scalars []fr.Element) []G1Affin return toReturnAff } -// batch add affine coordinates -// using batch inversion -// special cases (doubling, infinity) must be filtered out before this call +// batchAddG1Affine adds affine points using the Montgomery batch inversion trick. +// Special cases (doubling, infinity) must be filtered out before this call. func batchAddG1Affine[TP pG1Affine, TPP ppG1Affine, TC cG1Affine](R *TPP, P *TP, batchSize int) { var lambda, lambdain TC diff --git a/ecc/bls24-317/g2.go b/ecc/bls24-317/g2.go index 120c08dfc..c5c924a71 100644 --- a/ecc/bls24-317/g2.go +++ b/ecc/bls24-317/g2.go @@ -25,17 +25,17 @@ import ( "runtime" ) -// G2Affine point in affine coordinates +// G2Affine is a point in affine coordinates (x,y) type G2Affine struct { X, Y fptower.E4 } -// G2Jac is a point with fptower.E4 coordinates +// G2Jac is a point in Jacobian coordinates (x=X/Z², y=Y/Z³) type G2Jac struct { X, Y, Z fptower.E4 } -// g2JacExtended parameterized Jacobian coordinates (x=X/ZZ, y=Y/ZZZ, ZZ³=ZZZ²) +// g2JacExtended is a point in extended Jacobian coordinates (x=X/ZZ, y=Y/ZZZ, ZZ³=ZZZ²) type g2JacExtended struct { X, Y, ZZ, ZZZ fptower.E4 } @@ -46,22 +46,24 @@ type g2Proj struct { } // ------------------------------------------------------------------------------------------------- -// Affine +// Affine coordinates -// Set sets p to the provided point +// Set sets p to a in affine coordinates. func (p *G2Affine) Set(a *G2Affine) *G2Affine { p.X, p.Y = a.X, a.Y return p } -// setInfinity sets p to O +// setInfinity sets p to the infinity point, which is encoded as (0,0). +// N.B.: (0,0) is never on the curve for j=0 curves (Y²=X³+B). func (p *G2Affine) setInfinity() *G2Affine { p.X.SetZero() p.Y.SetZero() return p } -// ScalarMultiplication computes and returns p = a ⋅ s +// ScalarMultiplication computes and returns p = [s]a +// where p and a are affine points. func (p *G2Affine) ScalarMultiplication(a *G2Affine, s *big.Int) *G2Affine { var _p G2Jac _p.FromAffine(a) @@ -70,7 +72,8 @@ func (p *G2Affine) ScalarMultiplication(a *G2Affine, s *big.Int) *G2Affine { return p } -// ScalarMultiplicationBase computes and returns p = g ⋅ s where g is the prime subgroup generator +// ScalarMultiplicationBase computes and returns p = [s]g +// where g is the affine point generating the prime subgroup. func (p *G2Affine) ScalarMultiplicationBase(s *big.Int) *G2Affine { var _p G2Jac _p.mulGLV(&g2Gen, s) @@ -78,8 +81,9 @@ func (p *G2Affine) ScalarMultiplicationBase(s *big.Int) *G2Affine { return p } -// Add adds two point in affine coordinates. -// Jacobian addition with Z1=Z2=1 +// Add adds two points in affine coordinates. +// It uses the Jacobian addition with a.Z=b.Z=1 and converts the result to affine coordinates. +// // https://www.hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html#addition-mmadd-2007-bl func (p *G2Affine) Add(a, b *G2Affine) *G2Affine { var q G2Jac @@ -125,6 +129,10 @@ func (p *G2Affine) Add(a, b *G2Affine) *G2Affine { } // Double doubles a point in affine coordinates. +// It converts the point to Jacobian coordinates, doubles it using Jacobian +// addition with a.Z=1, and converts it back to affine coordinates. +// +// http://www.hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html#doubling-mdbl-2007-bl func (p *G2Affine) Double(a *G2Affine) *G2Affine { var q G2Jac q.FromAffine(a) @@ -133,7 +141,8 @@ func (p *G2Affine) Double(a *G2Affine) *G2Affine { return p } -// Sub subs two point in affine coordinates. +// Sub subtracts two points in affine coordinates. +// It uses a similar approach to Add, but negates the second point before adding. func (p *G2Affine) Sub(a, b *G2Affine) *G2Affine { var bneg G2Affine bneg.Neg(b) @@ -141,19 +150,19 @@ func (p *G2Affine) Sub(a, b *G2Affine) *G2Affine { return p } -// Equal tests if two points (in Affine coordinates) are equal +// Equal tests if two points in affine coordinates are equal. func (p *G2Affine) Equal(a *G2Affine) bool { return p.X.Equal(&a.X) && p.Y.Equal(&a.Y) } -// Neg computes -G +// Neg sets p to the affine negative point -a = (a.X, -a.Y). func (p *G2Affine) Neg(a *G2Affine) *G2Affine { p.X = a.X p.Y.Neg(&a.Y) return p } -// FromJacobian rescales a point in Jacobian coord in z=1 plane +// FromJacobian converts a point p1 from Jacobian to affine coordinates. func (p *G2Affine) FromJacobian(p1 *G2Jac) *G2Affine { var a, b fptower.E4 @@ -172,7 +181,7 @@ func (p *G2Affine) FromJacobian(p1 *G2Jac) *G2Affine { return p } -// String returns the string representation of the point or "O" if it is infinity +// String returns the string representation E(x,y) of the affine point p or "O" if it is infinity. func (p *G2Affine) String() string { if p.IsInfinity() { return "O" @@ -180,21 +189,20 @@ func (p *G2Affine) String() string { return "E([" + p.X.String() + "," + p.Y.String() + "])" } -// IsInfinity checks if the point is infinity -// in affine, it's encoded as (0,0) -// (0,0) is never on the curve for j=0 curves +// IsInfinity checks if the affine point p is infinity, which is encoded as (0,0). +// N.B.: (0,0) is never on the curve for j=0 curves (Y²=X³+B). func (p *G2Affine) IsInfinity() bool { return p.X.IsZero() && p.Y.IsZero() } -// IsOnCurve returns true if p in on the curve +// IsOnCurve returns true if the affine point p in on the curve. func (p *G2Affine) IsOnCurve() bool { var point G2Jac point.FromAffine(p) return point.IsOnCurve() // call this function to handle infinity point } -// IsInSubGroup returns true if p is in the correct subgroup, false otherwise +// IsInSubGroup returns true if the affine point p is in the correct subgroup, false otherwise. func (p *G2Affine) IsInSubGroup() bool { var _p G2Jac _p.FromAffine(p) @@ -202,84 +210,76 @@ func (p *G2Affine) IsInSubGroup() bool { } // ------------------------------------------------------------------------------------------------- -// Jacobian +// Jacobian coordinates -// Set sets p to the provided point -func (p *G2Jac) Set(a *G2Jac) *G2Jac { - p.X, p.Y, p.Z = a.X, a.Y, a.Z +// Set sets p to a in Jacobian coordinates. +func (p *G2Jac) Set(q *G2Jac) *G2Jac { + p.X, p.Y, p.Z = q.X, q.Y, q.Z return p } -// Equal tests if two points (in Jacobian coordinates) are equal -func (p *G2Jac) Equal(a *G2Jac) bool { +// Equal tests if two points in Jacobian coordinates are equal. +func (p *G2Jac) Equal(q *G2Jac) bool { // If one point is infinity, the other must also be infinity. if p.Z.IsZero() { - return a.Z.IsZero() + return q.Z.IsZero() } // If the other point is infinity, return false since we can't // the following checks would be incorrect. - if a.Z.IsZero() { + if q.Z.IsZero() { return false } var pZSquare, aZSquare fptower.E4 pZSquare.Square(&p.Z) - aZSquare.Square(&a.Z) + aZSquare.Square(&q.Z) var lhs, rhs fptower.E4 lhs.Mul(&p.X, &aZSquare) - rhs.Mul(&a.X, &pZSquare) + rhs.Mul(&q.X, &pZSquare) if !lhs.Equal(&rhs) { return false } - lhs.Mul(&p.Y, &aZSquare).Mul(&lhs, &a.Z) - rhs.Mul(&a.Y, &pZSquare).Mul(&rhs, &p.Z) + lhs.Mul(&p.Y, &aZSquare).Mul(&lhs, &q.Z) + rhs.Mul(&q.Y, &pZSquare).Mul(&rhs, &p.Z) return lhs.Equal(&rhs) } -// Neg computes -G -func (p *G2Jac) Neg(a *G2Jac) *G2Jac { - *p = *a - p.Y.Neg(&a.Y) - return p -} - -// SubAssign subtracts two points on the curve -func (p *G2Jac) SubAssign(a *G2Jac) *G2Jac { - var tmp G2Jac - tmp.Set(a) - tmp.Y.Neg(&tmp.Y) - p.AddAssign(&tmp) +// Neg sets p to the Jacobian negative point -q = (q.X, -q.Y, q.Z). +func (p *G2Jac) Neg(q *G2Jac) *G2Jac { + *p = *q + p.Y.Neg(&q.Y) return p } -// AddAssign point addition in montgomery form +// AddAssign sets p to p+a in Jacobian coordinates. +// // https://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-3.html#addition-add-2007-bl -func (p *G2Jac) AddAssign(a *G2Jac) *G2Jac { +func (p *G2Jac) AddAssign(q *G2Jac) *G2Jac { - // p is infinity, return a + // p is infinity, return q if p.Z.IsZero() { - p.Set(a) + p.Set(q) return p } - // a is infinity, return p - if a.Z.IsZero() { + // q is infinity, return p + if q.Z.IsZero() { return p } var Z1Z1, Z2Z2, U1, U2, S1, S2, H, I, J, r, V fptower.E4 - Z1Z1.Square(&a.Z) + Z1Z1.Square(&q.Z) Z2Z2.Square(&p.Z) - U1.Mul(&a.X, &Z2Z2) + U1.Mul(&q.X, &Z2Z2) U2.Mul(&p.X, &Z1Z1) - S1.Mul(&a.Y, &p.Z). + S1.Mul(&q.Y, &p.Z). Mul(&S1, &Z2Z2) - S2.Mul(&p.Y, &a.Z). + S2.Mul(&p.Y, &q.Z). Mul(&S2, &Z1Z1) - // if p == a, we double instead + // if p == q, we double instead if U1.Equal(&U2) && S1.Equal(&S2) { return p.DoubleAssign() } @@ -298,7 +298,7 @@ func (p *G2Jac) AddAssign(a *G2Jac) *G2Jac { Mul(&p.Y, &r) S1.Mul(&S1, &J).Double(&S1) p.Y.Sub(&p.Y, &S1) - p.Z.Add(&p.Z, &a.Z) + p.Z.Add(&p.Z, &q.Z) p.Z.Square(&p.Z). Sub(&p.Z, &Z1Z1). Sub(&p.Z, &Z2Z2). @@ -307,8 +307,19 @@ func (p *G2Jac) AddAssign(a *G2Jac) *G2Jac { return p } -// DoubleMixed point addition -// http://www.hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html#doubling-mdbl-2007-bl +// SubAssign sets p to p-a in Jacobian coordinates. +// It uses a similar approach to AddAssign, but negates the point a before adding. +func (p *G2Jac) SubAssign(q *G2Jac) *G2Jac { + var tmp G2Jac + tmp.Set(q) + tmp.Y.Neg(&tmp.Y) + p.AddAssign(&tmp) + return p +} + +// Double sets p to [2]q in Jacobian coordinates. +// +// https://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-3.html#doubling-dbl-2007-bl func (p *G2Jac) DoubleMixed(a *G2Affine) *G2Jac { var XX, YY, YYYY, S, M, T fptower.E4 XX.Square(&a.X) @@ -320,7 +331,7 @@ func (p *G2Jac) DoubleMixed(a *G2Affine) *G2Jac { Sub(&S, &YYYY). Double(&S) M.Double(&XX). - Add(&M, &XX) // -> + a, but a=0 here + Add(&M, &XX) // -> + A, but A=0 here T.Square(&M). Sub(&T, &S). Sub(&T, &S) @@ -336,7 +347,8 @@ func (p *G2Jac) DoubleMixed(a *G2Affine) *G2Jac { return p } -// AddMixed point addition +// AddMixed sets p to p+a in Jacobian coordinates, where a.Z = 1. +// // http://www.hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html#addition-madd-2007-bl func (p *G2Jac) AddMixed(a *G2Affine) *G2Jac { @@ -385,7 +397,8 @@ func (p *G2Jac) AddMixed(a *G2Affine) *G2Jac { return p } -// Double doubles a point in Jacobian coordinates +// Double sets p to [2]q in Jacobian coordinates. +// // https://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-3.html#doubling-dbl-2007-bl func (p *G2Jac) Double(q *G2Jac) *G2Jac { p.Set(q) @@ -393,7 +406,8 @@ func (p *G2Jac) Double(q *G2Jac) *G2Jac { return p } -// DoubleAssign doubles a point in Jacobian coordinates +// DoubleAssign doubles p in Jacobian coordinates. +// // https://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-3.html#doubling-dbl-2007-bl func (p *G2Jac) DoubleAssign() *G2Jac { @@ -425,34 +439,36 @@ func (p *G2Jac) DoubleAssign() *G2Jac { return p } -// ScalarMultiplication computes and returns p = a ⋅ s +// ScalarMultiplication computes and returns p = [s]a +// where p and a are Jacobian points. +// using the GLV technique. // see https://www.iacr.org/archive/crypto2001/21390189.pdf -func (p *G2Jac) ScalarMultiplication(a *G2Jac, s *big.Int) *G2Jac { - return p.mulGLV(a, s) +func (p *G2Jac) ScalarMultiplication(q *G2Jac, s *big.Int) *G2Jac { + return p.mulGLV(q, s) } -// String returns canonical representation of the point in affine coordinates +// String converts p to affine coordinates and returns its string representation E(x,y) or "O" if it is infinity. func (p *G2Jac) String() string { _p := G2Affine{} _p.FromJacobian(p) return _p.String() } -// FromAffine sets p = Q, p in Jacobian, Q in affine -func (p *G2Jac) FromAffine(Q *G2Affine) *G2Jac { - if Q.IsInfinity() { +// FromAffine converts a point a from affine to Jacobian coordinates. +func (p *G2Jac) FromAffine(a *G2Affine) *G2Jac { + if a.IsInfinity() { p.Z.SetZero() p.X.SetOne() p.Y.SetOne() return p } p.Z.SetOne() - p.X.Set(&Q.X) - p.Y.Set(&Q.Y) + p.X.Set(&a.X) + p.Y.Set(&a.Y) return p } -// IsOnCurve returns true if p in on the curve +// IsOnCurve returns true if the Jacobian point p in on the curve. func (p *G2Jac) IsOnCurve() bool { var left, right, tmp, ZZ fptower.E4 left.Square(&p.Y) @@ -478,13 +494,14 @@ func (p *G2Jac) IsInSubGroup() bool { } -// mulWindowed computes a 2-bits windowed scalar multiplication -func (p *G2Jac) mulWindowed(a *G2Jac, s *big.Int) *G2Jac { +// mulWindowed computes the 2-bits windowed double-and-add scalar +// multiplication p=[s]q in Jacobian coordinates. +func (p *G2Jac) mulWindowed(q *G2Jac, s *big.Int) *G2Jac { var res G2Jac var ops [3]G2Jac - ops[0].Set(a) + ops[0].Set(q) if s.Sign() == -1 { ops[0].Neg(&ops[0]) } @@ -511,26 +528,27 @@ func (p *G2Jac) mulWindowed(a *G2Jac, s *big.Int) *G2Jac { } -// ψ(p) = u o π o u⁻¹ where u:E'→E iso from the twist to E -func (p *G2Jac) psi(a *G2Jac) *G2Jac { - p.Set(a) +// psi sets p to ψ(q) = u o π o u⁻¹ where u:E'→E is the isomorphism from the twist to the curve E and π is the Frobenius map. +func (p *G2Jac) psi(q *G2Jac) *G2Jac { + p.Set(q) p.X.Frobenius(&p.X).Mul(&p.X, &endo.u) p.Y.Frobenius(&p.Y).Mul(&p.Y, &endo.v) p.Z.Frobenius(&p.Z) return p } -// ϕ assigns p to ϕ(a) where ϕ: (x,y) → (w x,y), and returns p -// where w is a third root of unity in 𝔽p -func (p *G2Jac) phi(a *G2Jac) *G2Jac { - p.Set(a) +// phi sets p to ϕ(a) where ϕ: (x,y) → (w x,y), +// where w is a third root of unity. +func (p *G2Jac) phi(q *G2Jac) *G2Jac { + p.Set(q) p.X.MulByElement(&p.X, &thirdRootOneG2) return p } // mulGLV computes the scalar multiplication using a windowed-GLV method +// // see https://www.iacr.org/archive/crypto2001/21390189.pdf -func (p *G2Jac) mulGLV(a *G2Jac, s *big.Int) *G2Jac { +func (p *G2Jac) mulGLV(q *G2Jac, s *big.Int) *G2Jac { var table [15]G2Jac var res G2Jac @@ -538,11 +556,11 @@ func (p *G2Jac) mulGLV(a *G2Jac, s *big.Int) *G2Jac { res.Set(&g2Infinity) - // table[b3b2b1b0-1] = b3b2 ⋅ ϕ(a) + b1b0*a - table[0].Set(a) - table[3].phi(a) + // table[b3b2b1b0-1] = b3b2 ⋅ ϕ(q) + b1b0*q + table[0].Set(q) + table[3].phi(q) - // split the scalar, modifies ±a, ϕ(a) accordingly + // split the scalar, modifies ±q, ϕ(q) accordingly k := ecc.SplitScalar(s, &glvBasis) if k[0].Sign() == -1 { @@ -555,7 +573,7 @@ func (p *G2Jac) mulGLV(a *G2Jac, s *big.Int) *G2Jac { } // precompute table (2 bits sliding window) - // table[b3b2b1b0-1] = b3b2 ⋅ ϕ(a) + b1b0 ⋅ a if b3b2b1b0 != 0 + // table[b3b2b1b0-1] = b3b2 ⋅ ϕ(q) + b1b0 ⋅ q if b3b2b1b0 != 0 table[1].Double(&table[0]) table[2].Set(&table[1]).AddAssign(&table[0]) table[4].Set(&table[3]).AddAssign(&table[0]) @@ -611,18 +629,18 @@ func (p *G2Affine) ClearCofactor(a *G2Affine) *G2Affine { } // ClearCofactor maps a point in curve to r-torsion -func (p *G2Jac) ClearCofactor(a *G2Jac) *G2Jac { +func (p *G2Jac) ClearCofactor(q *G2Jac) *G2Jac { // https://eprint.iacr.org/2017/419.pdf, section 4.2 // multiply by (3x⁴-3)*cofacor var xg, xxg, xxxg, xxxxg, res, t G2Jac - xg.ScalarMultiplication(a, &xGen).SubAssign(a) + xg.ScalarMultiplication(q, &xGen).SubAssign(q) xxg.ScalarMultiplication(&xg, &xGen) xxxg.ScalarMultiplication(&xxg, &xGen) xxxxg.ScalarMultiplication(&xxxg, &xGen) res.Set(&xxxxg). - SubAssign(a) + SubAssign(q) t.Set(&xxxg). psi(&t). @@ -639,7 +657,7 @@ func (p *G2Jac) ClearCofactor(a *G2Jac) *G2Jac { psi(&t). AddAssign(&res) - res.Double(a). + res.Double(q). psi(&res). psi(&res). psi(&res). @@ -653,15 +671,15 @@ func (p *G2Jac) ClearCofactor(a *G2Jac) *G2Jac { } // ------------------------------------------------------------------------------------------------- -// Jacobian extended +// extended Jacobian coordinates -// Set sets p to the provided point -func (p *g2JacExtended) Set(a *g2JacExtended) *g2JacExtended { - p.X, p.Y, p.ZZ, p.ZZZ = a.X, a.Y, a.ZZ, a.ZZZ +// Set sets p to a in extended Jacobian coordinates. +func (p *g2JacExtended) Set(q *g2JacExtended) *g2JacExtended { + p.X, p.Y, p.ZZ, p.ZZZ = q.X, q.Y, q.ZZ, q.ZZZ return p } -// setInfinity sets p to O +// setInfinity sets p to the infinity point (1,1,0,0). func (p *g2JacExtended) setInfinity() *g2JacExtended { p.X.SetOne() p.Y.SetOne() @@ -670,43 +688,45 @@ func (p *g2JacExtended) setInfinity() *g2JacExtended { return p } -func (p *g2JacExtended) IsZero() bool { +// IsInfinity checks if the p is infinity, i.e. p.ZZ=0. +func (p *g2JacExtended) IsInfinity() bool { return p.ZZ.IsZero() } -// fromJacExtended sets Q in affine coordinates -func (p *G2Affine) fromJacExtended(Q *g2JacExtended) *G2Affine { - if Q.ZZ.IsZero() { +// fromJacExtended converts an extended Jacobian point to an affine point. +func (p *G2Affine) fromJacExtended(q *g2JacExtended) *G2Affine { + if q.ZZ.IsZero() { p.X = fptower.E4{} p.Y = fptower.E4{} return p } - p.X.Inverse(&Q.ZZ).Mul(&p.X, &Q.X) - p.Y.Inverse(&Q.ZZZ).Mul(&p.Y, &Q.Y) + p.X.Inverse(&q.ZZ).Mul(&p.X, &q.X) + p.Y.Inverse(&q.ZZZ).Mul(&p.Y, &q.Y) return p } -// fromJacExtended sets Q in Jacobian coordinates -func (p *G2Jac) fromJacExtended(Q *g2JacExtended) *G2Jac { - if Q.ZZ.IsZero() { +// fromJacExtended converts an extended Jacobian point to a Jacobian point. +func (p *G2Jac) fromJacExtended(q *g2JacExtended) *G2Jac { + if q.ZZ.IsZero() { p.Set(&g2Infinity) return p } - p.X.Mul(&Q.ZZ, &Q.X).Mul(&p.X, &Q.ZZ) - p.Y.Mul(&Q.ZZZ, &Q.Y).Mul(&p.Y, &Q.ZZZ) - p.Z.Set(&Q.ZZZ) + p.X.Mul(&q.ZZ, &q.X).Mul(&p.X, &q.ZZ) + p.Y.Mul(&q.ZZZ, &q.Y).Mul(&p.Y, &q.ZZZ) + p.Z.Set(&q.ZZZ) return p } -// unsafeFromJacExtended sets p in Jacobian coordinates, but don't check for infinity -func (p *G2Jac) unsafeFromJacExtended(Q *g2JacExtended) *G2Jac { - p.X.Square(&Q.ZZ).Mul(&p.X, &Q.X) - p.Y.Square(&Q.ZZZ).Mul(&p.Y, &Q.Y) - p.Z = Q.ZZZ +// unsafeFromJacExtended converts an extended Jacobian point, distinct from Infinity, to a Jacobian point. +func (p *G2Jac) unsafeFromJacExtended(q *g2JacExtended) *G2Jac { + p.X.Square(&q.ZZ).Mul(&p.X, &q.X) + p.Y.Square(&q.ZZZ).Mul(&p.Y, &q.Y) + p.Z = q.ZZZ return p } -// add point in Jacobian extended coordinates +// add sets p to p+q in extended Jacobian coordinates. +// // https://www.hyperelliptic.org/EFD/g1p/auto-shortw-xyzz.html#addition-add-2008-s func (p *g2JacExtended) add(q *g2JacExtended) *g2JacExtended { //if q is infinity return p @@ -762,10 +782,11 @@ func (p *g2JacExtended) add(q *g2JacExtended) *g2JacExtended { return p } -// double point in Jacobian extended coordinates +// double sets p to [2]q in Jacobian extended coordinates. +// // http://www.hyperelliptic.org/EFD/g1p/auto-shortw-xyzz.html#doubling-dbl-2008-s-1 -// since we consider any point on Z=0 as the point at infinity -// this doubling formula works for infinity points as well +// N.B.: since we consider any point on Z=0 as the point at infinity +// this doubling formula works for infinity points as well. func (p *g2JacExtended) double(q *g2JacExtended) *g2JacExtended { var U, V, W, S, XX, M fptower.E4 @@ -775,7 +796,7 @@ func (p *g2JacExtended) double(q *g2JacExtended) *g2JacExtended { S.Mul(&q.X, &V) XX.Square(&q.X) M.Double(&XX). - Add(&M, &XX) // -> + a, but a=0 here + Add(&M, &XX) // -> + A, but A=0 here U.Mul(&W, &q.Y) p.X.Square(&M). @@ -790,9 +811,10 @@ func (p *g2JacExtended) double(q *g2JacExtended) *g2JacExtended { return p } -// subMixed same as addMixed, but will negate a.Y +// addMixed sets p to p+q in extended Jacobian coordinates, where a.ZZ=1. +// // http://www.hyperelliptic.org/EFD/g1p/auto-shortw-xyzz.html#addition-madd-2008-s -func (p *g2JacExtended) subMixed(a *G2Affine) *g2JacExtended { +func (p *g2JacExtended) addMixed(a *G2Affine) *g2JacExtended { //if a is infinity return p if a.IsInfinity() { @@ -801,7 +823,7 @@ func (p *g2JacExtended) subMixed(a *G2Affine) *g2JacExtended { // p is infinity, return a if p.ZZ.IsZero() { p.X = a.X - p.Y.Neg(&a.Y) + p.Y = a.Y p.ZZ.SetOne() p.ZZZ.SetOne() return p @@ -814,12 +836,11 @@ func (p *g2JacExtended) subMixed(a *G2Affine) *g2JacExtended { P.Sub(&P, &p.X) R.Mul(&a.Y, &p.ZZZ) - R.Neg(&R) R.Sub(&R, &p.Y) if P.IsZero() { if R.IsZero() { - return p.doubleNegMixed(a) + return p.doubleMixed(a) } p.ZZ = fptower.E4{} @@ -846,9 +867,10 @@ func (p *g2JacExtended) subMixed(a *G2Affine) *g2JacExtended { } -// addMixed +// subMixed works the same as addMixed, but negates a.Y. +// // http://www.hyperelliptic.org/EFD/g1p/auto-shortw-xyzz.html#addition-madd-2008-s -func (p *g2JacExtended) addMixed(a *G2Affine) *g2JacExtended { +func (p *g2JacExtended) subMixed(a *G2Affine) *g2JacExtended { //if a is infinity return p if a.IsInfinity() { @@ -857,7 +879,7 @@ func (p *g2JacExtended) addMixed(a *G2Affine) *g2JacExtended { // p is infinity, return a if p.ZZ.IsZero() { p.X = a.X - p.Y = a.Y + p.Y.Neg(&a.Y) p.ZZ.SetOne() p.ZZZ.SetOne() return p @@ -870,11 +892,12 @@ func (p *g2JacExtended) addMixed(a *G2Affine) *g2JacExtended { P.Sub(&P, &p.X) R.Mul(&a.Y, &p.ZZZ) + R.Neg(&R) R.Sub(&R, &p.Y) if P.IsZero() { if R.IsZero() { - return p.doubleMixed(a) + return p.doubleNegMixed(a) } p.ZZ = fptower.E4{} @@ -901,21 +924,21 @@ func (p *g2JacExtended) addMixed(a *G2Affine) *g2JacExtended { } -// doubleNegMixed same as double, but will negate q.Y -func (p *g2JacExtended) doubleNegMixed(q *G2Affine) *g2JacExtended { +// doubleNegMixed works the same as double, but negates q.Y. +func (p *g2JacExtended) doubleNegMixed(a *G2Affine) *g2JacExtended { var U, V, W, S, XX, M, S2, L fptower.E4 - U.Double(&q.Y) + U.Double(&a.Y) U.Neg(&U) V.Square(&U) W.Mul(&U, &V) - S.Mul(&q.X, &V) - XX.Square(&q.X) + S.Mul(&a.X, &V) + XX.Square(&a.X) M.Double(&XX). - Add(&M, &XX) // -> + a, but a=0 here + Add(&M, &XX) // -> + A, but A=0 here S2.Double(&S) - L.Mul(&W, &q.Y) + L.Mul(&W, &a.Y) p.X.Square(&M). Sub(&p.X, &S2) @@ -928,21 +951,22 @@ func (p *g2JacExtended) doubleNegMixed(q *G2Affine) *g2JacExtended { return p } -// doubleMixed point in Jacobian extended coordinates +// doubleMixed sets p to [2]a in Jacobian extended coordinates, where a.ZZ=1. +// // http://www.hyperelliptic.org/EFD/g1p/auto-shortw-xyzz.html#doubling-dbl-2008-s-1 -func (p *g2JacExtended) doubleMixed(q *G2Affine) *g2JacExtended { +func (p *g2JacExtended) doubleMixed(a *G2Affine) *g2JacExtended { var U, V, W, S, XX, M, S2, L fptower.E4 - U.Double(&q.Y) + U.Double(&a.Y) V.Square(&U) W.Mul(&U, &V) - S.Mul(&q.X, &V) - XX.Square(&q.X) + S.Mul(&a.X, &V) + XX.Square(&a.X) M.Double(&XX). - Add(&M, &XX) // -> + a, but a=0 here + Add(&M, &XX) // -> + A, but A=0 here S2.Double(&S) - L.Mul(&W, &q.Y) + L.Mul(&W, &a.Y) p.X.Square(&M). Sub(&p.X, &S2) @@ -956,38 +980,38 @@ func (p *g2JacExtended) doubleMixed(q *G2Affine) *g2JacExtended { } // ------------------------------------------------------------------------------------------------- -// Homogenous projective +// Homogenous projective coordinates -// Set sets p to the provided point -func (p *g2Proj) Set(a *g2Proj) *g2Proj { - p.x, p.y, p.z = a.x, a.y, a.z +// Set sets p to a in projective coordinates. +func (p *g2Proj) Set(q *g2Proj) *g2Proj { + p.x, p.y, p.z = q.x, q.y, q.z return p } -// Neg computes -G -func (p *g2Proj) Neg(a *g2Proj) *g2Proj { - *p = *a - p.y.Neg(&a.y) +// Neg sets p to the projective negative point -q = (q.X, -q.Y). +func (p *g2Proj) Neg(q *g2Proj) *g2Proj { + *p = *q + p.y.Neg(&q.y) return p } -// FromAffine sets p = Q, p in homogenous projective, Q in affine -func (p *g2Proj) FromAffine(Q *G2Affine) *g2Proj { - if Q.X.IsZero() && Q.Y.IsZero() { +// FromAffine converts q in affine to p in projective coordinates. +func (p *g2Proj) FromAffine(a *G2Affine) *g2Proj { + if a.X.IsZero() && a.Y.IsZero() { p.z.SetZero() p.x.SetOne() p.y.SetOne() return p } p.z.SetOne() - p.x.Set(&Q.X) - p.y.Set(&Q.Y) + p.x.Set(&a.X) + p.y.Set(&a.Y) return p } // BatchScalarMultiplicationG2 multiplies the same base by all scalars // and return resulting points in affine coordinates -// uses a simple windowed-NAF like exponentiation algorithm +// uses a simple windowed-NAF-like multiplication algorithm. func BatchScalarMultiplicationG2(base *G2Affine, scalars []fr.Element) []G2Affine { // approximate cost in group ops is // cost = 2^{c-1} + n(scalar.nbBits+nbChunks) @@ -1066,9 +1090,8 @@ func BatchScalarMultiplicationG2(base *G2Affine, scalars []fr.Element) []G2Affin return toReturn } -// batch add affine coordinates -// using batch inversion -// special cases (doubling, infinity) must be filtered out before this call +// batchAddG1Affine adds affine points using the Montgomery batch inversion trick. +// Special cases (doubling, infinity) must be filtered out before this call. func batchAddG2Affine[TP pG2Affine, TPP ppG2Affine, TC cG2Affine](R *TPP, P *TP, batchSize int) { var lambda, lambdain TC diff --git a/ecc/bls24-317/multiexp_affine.go b/ecc/bls24-317/multiexp_affine.go index 7affe92ae..ffae06cc2 100644 --- a/ecc/bls24-317/multiexp_affine.go +++ b/ecc/bls24-317/multiexp_affine.go @@ -226,7 +226,7 @@ func processChunkG1BatchAffine[BJE ibg1JacExtended, B ibG1Affine, BS bitSet, TP total.setInfinity() for k := len(buckets) - 1; k >= 0; k-- { runningSum.addMixed(&buckets[k]) - if !bucketsJE[k].IsZero() { + if !bucketsJE[k].IsInfinity() { runningSum.add(&bucketsJE[k]) } total.add(&runningSum) @@ -554,7 +554,7 @@ func processChunkG2BatchAffine[BJE ibg2JacExtended, B ibG2Affine, BS bitSet, TP total.setInfinity() for k := len(buckets) - 1; k >= 0; k-- { runningSum.addMixed(&buckets[k]) - if !bucketsJE[k].IsZero() { + if !bucketsJE[k].IsInfinity() { runningSum.add(&bucketsJE[k]) } total.add(&runningSum) diff --git a/ecc/bls24-317/multiexp_jacobian.go b/ecc/bls24-317/multiexp_jacobian.go index 9eda05280..c7178af02 100644 --- a/ecc/bls24-317/multiexp_jacobian.go +++ b/ecc/bls24-317/multiexp_jacobian.go @@ -56,7 +56,7 @@ func processChunkG1Jacobian[B ibg1JacExtended](chunk uint64, runningSum.setInfinity() total.setInfinity() for k := len(buckets) - 1; k >= 0; k-- { - if !buckets[k].IsZero() { + if !buckets[k].IsInfinity() { runningSum.add(&buckets[k]) } total.add(&runningSum) @@ -145,7 +145,7 @@ func processChunkG2Jacobian[B ibg2JacExtended](chunk uint64, runningSum.setInfinity() total.setInfinity() for k := len(buckets) - 1; k >= 0; k-- { - if !buckets[k].IsZero() { + if !buckets[k].IsInfinity() { runningSum.add(&buckets[k]) } total.add(&runningSum) diff --git a/ecc/bn254/g1.go b/ecc/bn254/g1.go index 59387cea9..e4d573275 100644 --- a/ecc/bn254/g1.go +++ b/ecc/bn254/g1.go @@ -25,38 +25,40 @@ import ( "runtime" ) -// G1Affine point in affine coordinates +// G1Affine is a point in affine coordinates (x,y) type G1Affine struct { X, Y fp.Element } -// G1Jac is a point with fp.Element coordinates +// G1Jac is a point in Jacobian coordinates (x=X/Z², y=Y/Z³) type G1Jac struct { X, Y, Z fp.Element } -// g1JacExtended parameterized Jacobian coordinates (x=X/ZZ, y=Y/ZZZ, ZZ³=ZZZ²) +// g1JacExtended is a point in extended Jacobian coordinates (x=X/ZZ, y=Y/ZZZ, ZZ³=ZZZ²) type g1JacExtended struct { X, Y, ZZ, ZZZ fp.Element } // ------------------------------------------------------------------------------------------------- -// Affine +// Affine coordinates -// Set sets p to the provided point +// Set sets p to a in affine coordinates. func (p *G1Affine) Set(a *G1Affine) *G1Affine { p.X, p.Y = a.X, a.Y return p } -// setInfinity sets p to O +// setInfinity sets p to the infinity point, which is encoded as (0,0). +// N.B.: (0,0) is never on the curve for j=0 curves (Y²=X³+B). func (p *G1Affine) setInfinity() *G1Affine { p.X.SetZero() p.Y.SetZero() return p } -// ScalarMultiplication computes and returns p = a ⋅ s +// ScalarMultiplication computes and returns p = [s]a +// where p and a are affine points. func (p *G1Affine) ScalarMultiplication(a *G1Affine, s *big.Int) *G1Affine { var _p G1Jac _p.FromAffine(a) @@ -65,20 +67,22 @@ func (p *G1Affine) ScalarMultiplication(a *G1Affine, s *big.Int) *G1Affine { return p } -// ScalarMultiplicationAffine computes and returns p = a ⋅ s -// Takes an affine point and returns a Jacobian point (useful for KZG) +// ScalarMultiplicationAffine computes and returns p = [s]a +// where a is an affine point and p a Jacobian point (useful for KZG). func (p *G1Jac) ScalarMultiplicationAffine(a *G1Affine, s *big.Int) *G1Jac { p.FromAffine(a) p.mulGLV(p, s) return p } -// ScalarMultiplicationBase computes and returns p = g ⋅ s where g is the prime subgroup generator +// ScalarMultiplicationBase computes and returns p = [s]g +// where g is the Jacobian point generating the prime subgroup. func (p *G1Jac) ScalarMultiplicationBase(s *big.Int) *G1Jac { return p.mulGLV(&g1Gen, s) } -// ScalarMultiplicationBase computes and returns p = g ⋅ s where g is the prime subgroup generator +// ScalarMultiplicationBase computes and returns p = [s]g +// where g is the affine point generating the prime subgroup. func (p *G1Affine) ScalarMultiplicationBase(s *big.Int) *G1Affine { var _p G1Jac _p.mulGLV(&g1Gen, s) @@ -86,8 +90,9 @@ func (p *G1Affine) ScalarMultiplicationBase(s *big.Int) *G1Affine { return p } -// Add adds two point in affine coordinates. -// Jacobian addition with Z1=Z2=1 +// Add adds two points in affine coordinates. +// It uses the Jacobian addition with a.Z=b.Z=1 and converts the result to affine coordinates. +// // https://www.hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html#addition-mmadd-2007-bl func (p *G1Affine) Add(a, b *G1Affine) *G1Affine { var q G1Jac @@ -133,6 +138,10 @@ func (p *G1Affine) Add(a, b *G1Affine) *G1Affine { } // Double doubles a point in affine coordinates. +// It converts the point to Jacobian coordinates, doubles it using Jacobian +// addition with a.Z=1, and converts it back to affine coordinates. +// +// http://www.hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html#doubling-mdbl-2007-bl func (p *G1Affine) Double(a *G1Affine) *G1Affine { var q G1Jac q.FromAffine(a) @@ -141,7 +150,8 @@ func (p *G1Affine) Double(a *G1Affine) *G1Affine { return p } -// Sub subs two point in affine coordinates. +// Sub subtracts two points in affine coordinates. +// It uses a similar approach to Add, but negates the second point before adding. func (p *G1Affine) Sub(a, b *G1Affine) *G1Affine { var bneg G1Affine bneg.Neg(b) @@ -149,19 +159,19 @@ func (p *G1Affine) Sub(a, b *G1Affine) *G1Affine { return p } -// Equal tests if two points (in Affine coordinates) are equal +// Equal tests if two points in affine coordinates are equal. func (p *G1Affine) Equal(a *G1Affine) bool { return p.X.Equal(&a.X) && p.Y.Equal(&a.Y) } -// Neg computes -G +// Neg sets p to the affine negative point -a = (a.X, -a.Y). func (p *G1Affine) Neg(a *G1Affine) *G1Affine { p.X = a.X p.Y.Neg(&a.Y) return p } -// FromJacobian rescales a point in Jacobian coord in z=1 plane +// FromJacobian converts a point p1 from Jacobian to affine coordinates. func (p *G1Affine) FromJacobian(p1 *G1Jac) *G1Affine { var a, b fp.Element @@ -180,7 +190,7 @@ func (p *G1Affine) FromJacobian(p1 *G1Jac) *G1Affine { return p } -// String returns the string representation of the point or "O" if it is infinity +// String returns the string representation E(x,y) of the affine point p or "O" if it is infinity. func (p *G1Affine) String() string { if p.IsInfinity() { return "O" @@ -188,21 +198,20 @@ func (p *G1Affine) String() string { return "E([" + p.X.String() + "," + p.Y.String() + "])" } -// IsInfinity checks if the point is infinity -// in affine, it's encoded as (0,0) -// (0,0) is never on the curve for j=0 curves +// IsInfinity checks if the affine point p is infinity, which is encoded as (0,0). +// N.B.: (0,0) is never on the curve for j=0 curves (Y²=X³+B). func (p *G1Affine) IsInfinity() bool { return p.X.IsZero() && p.Y.IsZero() } -// IsOnCurve returns true if p in on the curve +// IsOnCurve returns true if the affine point p in on the curve. func (p *G1Affine) IsOnCurve() bool { var point G1Jac point.FromAffine(p) return point.IsOnCurve() // call this function to handle infinity point } -// IsInSubGroup returns true if p is in the correct subgroup, false otherwise +// IsInSubGroup returns true if the affine point p is in the correct subgroup, false otherwise. func (p *G1Affine) IsInSubGroup() bool { var _p G1Jac _p.FromAffine(p) @@ -210,84 +219,76 @@ func (p *G1Affine) IsInSubGroup() bool { } // ------------------------------------------------------------------------------------------------- -// Jacobian +// Jacobian coordinates -// Set sets p to the provided point -func (p *G1Jac) Set(a *G1Jac) *G1Jac { - p.X, p.Y, p.Z = a.X, a.Y, a.Z +// Set sets p to a in Jacobian coordinates. +func (p *G1Jac) Set(q *G1Jac) *G1Jac { + p.X, p.Y, p.Z = q.X, q.Y, q.Z return p } -// Equal tests if two points (in Jacobian coordinates) are equal -func (p *G1Jac) Equal(a *G1Jac) bool { +// Equal tests if two points in Jacobian coordinates are equal. +func (p *G1Jac) Equal(q *G1Jac) bool { // If one point is infinity, the other must also be infinity. if p.Z.IsZero() { - return a.Z.IsZero() + return q.Z.IsZero() } // If the other point is infinity, return false since we can't // the following checks would be incorrect. - if a.Z.IsZero() { + if q.Z.IsZero() { return false } var pZSquare, aZSquare fp.Element pZSquare.Square(&p.Z) - aZSquare.Square(&a.Z) + aZSquare.Square(&q.Z) var lhs, rhs fp.Element lhs.Mul(&p.X, &aZSquare) - rhs.Mul(&a.X, &pZSquare) + rhs.Mul(&q.X, &pZSquare) if !lhs.Equal(&rhs) { return false } - lhs.Mul(&p.Y, &aZSquare).Mul(&lhs, &a.Z) - rhs.Mul(&a.Y, &pZSquare).Mul(&rhs, &p.Z) + lhs.Mul(&p.Y, &aZSquare).Mul(&lhs, &q.Z) + rhs.Mul(&q.Y, &pZSquare).Mul(&rhs, &p.Z) return lhs.Equal(&rhs) } -// Neg computes -G -func (p *G1Jac) Neg(a *G1Jac) *G1Jac { - *p = *a - p.Y.Neg(&a.Y) +// Neg sets p to the Jacobian negative point -q = (q.X, -q.Y, q.Z). +func (p *G1Jac) Neg(q *G1Jac) *G1Jac { + *p = *q + p.Y.Neg(&q.Y) return p } -// SubAssign subtracts two points on the curve -func (p *G1Jac) SubAssign(a *G1Jac) *G1Jac { - var tmp G1Jac - tmp.Set(a) - tmp.Y.Neg(&tmp.Y) - p.AddAssign(&tmp) - return p -} - -// AddAssign point addition in montgomery form +// AddAssign sets p to p+a in Jacobian coordinates. +// // https://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-3.html#addition-add-2007-bl -func (p *G1Jac) AddAssign(a *G1Jac) *G1Jac { +func (p *G1Jac) AddAssign(q *G1Jac) *G1Jac { - // p is infinity, return a + // p is infinity, return q if p.Z.IsZero() { - p.Set(a) + p.Set(q) return p } - // a is infinity, return p - if a.Z.IsZero() { + // q is infinity, return p + if q.Z.IsZero() { return p } var Z1Z1, Z2Z2, U1, U2, S1, S2, H, I, J, r, V fp.Element - Z1Z1.Square(&a.Z) + Z1Z1.Square(&q.Z) Z2Z2.Square(&p.Z) - U1.Mul(&a.X, &Z2Z2) + U1.Mul(&q.X, &Z2Z2) U2.Mul(&p.X, &Z1Z1) - S1.Mul(&a.Y, &p.Z). + S1.Mul(&q.Y, &p.Z). Mul(&S1, &Z2Z2) - S2.Mul(&p.Y, &a.Z). + S2.Mul(&p.Y, &q.Z). Mul(&S2, &Z1Z1) - // if p == a, we double instead + // if p == q, we double instead if U1.Equal(&U2) && S1.Equal(&S2) { return p.DoubleAssign() } @@ -306,7 +307,7 @@ func (p *G1Jac) AddAssign(a *G1Jac) *G1Jac { Mul(&p.Y, &r) S1.Mul(&S1, &J).Double(&S1) p.Y.Sub(&p.Y, &S1) - p.Z.Add(&p.Z, &a.Z) + p.Z.Add(&p.Z, &q.Z) p.Z.Square(&p.Z). Sub(&p.Z, &Z1Z1). Sub(&p.Z, &Z2Z2). @@ -315,8 +316,19 @@ func (p *G1Jac) AddAssign(a *G1Jac) *G1Jac { return p } -// DoubleMixed point addition -// http://www.hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html#doubling-mdbl-2007-bl +// SubAssign sets p to p-a in Jacobian coordinates. +// It uses a similar approach to AddAssign, but negates the point a before adding. +func (p *G1Jac) SubAssign(q *G1Jac) *G1Jac { + var tmp G1Jac + tmp.Set(q) + tmp.Y.Neg(&tmp.Y) + p.AddAssign(&tmp) + return p +} + +// Double sets p to [2]q in Jacobian coordinates. +// +// https://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-3.html#doubling-dbl-2007-bl func (p *G1Jac) DoubleMixed(a *G1Affine) *G1Jac { var XX, YY, YYYY, S, M, T fp.Element XX.Square(&a.X) @@ -328,7 +340,7 @@ func (p *G1Jac) DoubleMixed(a *G1Affine) *G1Jac { Sub(&S, &YYYY). Double(&S) M.Double(&XX). - Add(&M, &XX) // -> + a, but a=0 here + Add(&M, &XX) // -> + A, but A=0 here T.Square(&M). Sub(&T, &S). Sub(&T, &S) @@ -344,7 +356,8 @@ func (p *G1Jac) DoubleMixed(a *G1Affine) *G1Jac { return p } -// AddMixed point addition +// AddMixed sets p to p+a in Jacobian coordinates, where a.Z = 1. +// // http://www.hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html#addition-madd-2007-bl func (p *G1Jac) AddMixed(a *G1Affine) *G1Jac { @@ -393,7 +406,8 @@ func (p *G1Jac) AddMixed(a *G1Affine) *G1Jac { return p } -// Double doubles a point in Jacobian coordinates +// Double sets p to [2]q in Jacobian coordinates. +// // https://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-3.html#doubling-dbl-2007-bl func (p *G1Jac) Double(q *G1Jac) *G1Jac { p.Set(q) @@ -401,7 +415,8 @@ func (p *G1Jac) Double(q *G1Jac) *G1Jac { return p } -// DoubleAssign doubles a point in Jacobian coordinates +// DoubleAssign doubles p in Jacobian coordinates. +// // https://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-3.html#doubling-dbl-2007-bl func (p *G1Jac) DoubleAssign() *G1Jac { @@ -433,34 +448,36 @@ func (p *G1Jac) DoubleAssign() *G1Jac { return p } -// ScalarMultiplication computes and returns p = a ⋅ s +// ScalarMultiplication computes and returns p = [s]a +// where p and a are Jacobian points. +// using the GLV technique. // see https://www.iacr.org/archive/crypto2001/21390189.pdf -func (p *G1Jac) ScalarMultiplication(a *G1Jac, s *big.Int) *G1Jac { - return p.mulGLV(a, s) +func (p *G1Jac) ScalarMultiplication(q *G1Jac, s *big.Int) *G1Jac { + return p.mulGLV(q, s) } -// String returns canonical representation of the point in affine coordinates +// String converts p to affine coordinates and returns its string representation E(x,y) or "O" if it is infinity. func (p *G1Jac) String() string { _p := G1Affine{} _p.FromJacobian(p) return _p.String() } -// FromAffine sets p = Q, p in Jacobian, Q in affine -func (p *G1Jac) FromAffine(Q *G1Affine) *G1Jac { - if Q.IsInfinity() { +// FromAffine converts a point a from affine to Jacobian coordinates. +func (p *G1Jac) FromAffine(a *G1Affine) *G1Jac { + if a.IsInfinity() { p.Z.SetZero() p.X.SetOne() p.Y.SetOne() return p } p.Z.SetOne() - p.X.Set(&Q.X) - p.Y.Set(&Q.Y) + p.X.Set(&a.X) + p.Y.Set(&a.Y) return p } -// IsOnCurve returns true if p in on the curve +// IsOnCurve returns true if the Jacobian point p in on the curve. func (p *G1Jac) IsOnCurve() bool { var left, right, tmp, ZZ fp.Element left.Square(&p.Y) @@ -482,13 +499,14 @@ func (p *G1Jac) IsInSubGroup() bool { } -// mulWindowed computes a 2-bits windowed scalar multiplication -func (p *G1Jac) mulWindowed(a *G1Jac, s *big.Int) *G1Jac { +// mulWindowed computes the 2-bits windowed double-and-add scalar +// multiplication p=[s]q in Jacobian coordinates. +func (p *G1Jac) mulWindowed(q *G1Jac, s *big.Int) *G1Jac { var res G1Jac var ops [3]G1Jac - ops[0].Set(a) + ops[0].Set(q) if s.Sign() == -1 { ops[0].Neg(&ops[0]) } @@ -515,17 +533,18 @@ func (p *G1Jac) mulWindowed(a *G1Jac, s *big.Int) *G1Jac { } -// ϕ assigns p to ϕ(a) where ϕ: (x,y) → (w x,y), and returns p -// where w is a third root of unity in 𝔽p -func (p *G1Jac) phi(a *G1Jac) *G1Jac { - p.Set(a) +// phi sets p to ϕ(a) where ϕ: (x,y) → (w x,y), +// where w is a third root of unity. +func (p *G1Jac) phi(q *G1Jac) *G1Jac { + p.Set(q) p.X.Mul(&p.X, &thirdRootOneG1) return p } // mulGLV computes the scalar multiplication using a windowed-GLV method +// // see https://www.iacr.org/archive/crypto2001/21390189.pdf -func (p *G1Jac) mulGLV(a *G1Jac, s *big.Int) *G1Jac { +func (p *G1Jac) mulGLV(q *G1Jac, s *big.Int) *G1Jac { var table [15]G1Jac var res G1Jac @@ -533,11 +552,11 @@ func (p *G1Jac) mulGLV(a *G1Jac, s *big.Int) *G1Jac { res.Set(&g1Infinity) - // table[b3b2b1b0-1] = b3b2 ⋅ ϕ(a) + b1b0*a - table[0].Set(a) - table[3].phi(a) + // table[b3b2b1b0-1] = b3b2 ⋅ ϕ(q) + b1b0*q + table[0].Set(q) + table[3].phi(q) - // split the scalar, modifies ±a, ϕ(a) accordingly + // split the scalar, modifies ±q, ϕ(q) accordingly k := ecc.SplitScalar(s, &glvBasis) if k[0].Sign() == -1 { @@ -550,7 +569,7 @@ func (p *G1Jac) mulGLV(a *G1Jac, s *big.Int) *G1Jac { } // precompute table (2 bits sliding window) - // table[b3b2b1b0-1] = b3b2 ⋅ ϕ(a) + b1b0 ⋅ a if b3b2b1b0 != 0 + // table[b3b2b1b0-1] = b3b2 ⋅ ϕ(q) + b1b0 ⋅ q if b3b2b1b0 != 0 table[1].Double(&table[0]) table[2].Set(&table[1]).AddAssign(&table[0]) table[4].Set(&table[3]).AddAssign(&table[0]) @@ -596,8 +615,8 @@ func (p *G1Jac) mulGLV(a *G1Jac, s *big.Int) *G1Jac { return p } -// JointScalarMultiplicationBase computes [s1]g+[s2]a using Straus-Shamir technique -// where g is the prime subgroup generator +// JointScalarMultiplicationBase computes [s1]g+[s2]a using Strauss-Shamir technique +// where g is the prime subgroup generator and a is an affine point. func (p *G1Jac) JointScalarMultiplicationBase(a *G1Affine, s1, s2 *big.Int) *G1Jac { var res, p1, p2 G1Jac @@ -668,15 +687,15 @@ func (p *G1Jac) JointScalarMultiplicationBase(a *G1Affine, s1, s2 *big.Int) *G1J } // ------------------------------------------------------------------------------------------------- -// Jacobian extended +// extended Jacobian coordinates -// Set sets p to the provided point -func (p *g1JacExtended) Set(a *g1JacExtended) *g1JacExtended { - p.X, p.Y, p.ZZ, p.ZZZ = a.X, a.Y, a.ZZ, a.ZZZ +// Set sets p to a in extended Jacobian coordinates. +func (p *g1JacExtended) Set(q *g1JacExtended) *g1JacExtended { + p.X, p.Y, p.ZZ, p.ZZZ = q.X, q.Y, q.ZZ, q.ZZZ return p } -// setInfinity sets p to O +// setInfinity sets p to the infinity point (1,1,0,0). func (p *g1JacExtended) setInfinity() *g1JacExtended { p.X.SetOne() p.Y.SetOne() @@ -685,43 +704,45 @@ func (p *g1JacExtended) setInfinity() *g1JacExtended { return p } -func (p *g1JacExtended) IsZero() bool { +// IsInfinity checks if the p is infinity, i.e. p.ZZ=0. +func (p *g1JacExtended) IsInfinity() bool { return p.ZZ.IsZero() } -// fromJacExtended sets Q in affine coordinates -func (p *G1Affine) fromJacExtended(Q *g1JacExtended) *G1Affine { - if Q.ZZ.IsZero() { +// fromJacExtended converts an extended Jacobian point to an affine point. +func (p *G1Affine) fromJacExtended(q *g1JacExtended) *G1Affine { + if q.ZZ.IsZero() { p.X = fp.Element{} p.Y = fp.Element{} return p } - p.X.Inverse(&Q.ZZ).Mul(&p.X, &Q.X) - p.Y.Inverse(&Q.ZZZ).Mul(&p.Y, &Q.Y) + p.X.Inverse(&q.ZZ).Mul(&p.X, &q.X) + p.Y.Inverse(&q.ZZZ).Mul(&p.Y, &q.Y) return p } -// fromJacExtended sets Q in Jacobian coordinates -func (p *G1Jac) fromJacExtended(Q *g1JacExtended) *G1Jac { - if Q.ZZ.IsZero() { +// fromJacExtended converts an extended Jacobian point to a Jacobian point. +func (p *G1Jac) fromJacExtended(q *g1JacExtended) *G1Jac { + if q.ZZ.IsZero() { p.Set(&g1Infinity) return p } - p.X.Mul(&Q.ZZ, &Q.X).Mul(&p.X, &Q.ZZ) - p.Y.Mul(&Q.ZZZ, &Q.Y).Mul(&p.Y, &Q.ZZZ) - p.Z.Set(&Q.ZZZ) + p.X.Mul(&q.ZZ, &q.X).Mul(&p.X, &q.ZZ) + p.Y.Mul(&q.ZZZ, &q.Y).Mul(&p.Y, &q.ZZZ) + p.Z.Set(&q.ZZZ) return p } -// unsafeFromJacExtended sets p in Jacobian coordinates, but don't check for infinity -func (p *G1Jac) unsafeFromJacExtended(Q *g1JacExtended) *G1Jac { - p.X.Square(&Q.ZZ).Mul(&p.X, &Q.X) - p.Y.Square(&Q.ZZZ).Mul(&p.Y, &Q.Y) - p.Z = Q.ZZZ +// unsafeFromJacExtended converts an extended Jacobian point, distinct from Infinity, to a Jacobian point. +func (p *G1Jac) unsafeFromJacExtended(q *g1JacExtended) *G1Jac { + p.X.Square(&q.ZZ).Mul(&p.X, &q.X) + p.Y.Square(&q.ZZZ).Mul(&p.Y, &q.Y) + p.Z = q.ZZZ return p } -// add point in Jacobian extended coordinates +// add sets p to p+q in extended Jacobian coordinates. +// // https://www.hyperelliptic.org/EFD/g1p/auto-shortw-xyzz.html#addition-add-2008-s func (p *g1JacExtended) add(q *g1JacExtended) *g1JacExtended { //if q is infinity return p @@ -777,10 +798,11 @@ func (p *g1JacExtended) add(q *g1JacExtended) *g1JacExtended { return p } -// double point in Jacobian extended coordinates +// double sets p to [2]q in Jacobian extended coordinates. +// // http://www.hyperelliptic.org/EFD/g1p/auto-shortw-xyzz.html#doubling-dbl-2008-s-1 -// since we consider any point on Z=0 as the point at infinity -// this doubling formula works for infinity points as well +// N.B.: since we consider any point on Z=0 as the point at infinity +// this doubling formula works for infinity points as well. func (p *g1JacExtended) double(q *g1JacExtended) *g1JacExtended { var U, V, W, S, XX, M fp.Element @@ -790,7 +812,7 @@ func (p *g1JacExtended) double(q *g1JacExtended) *g1JacExtended { S.Mul(&q.X, &V) XX.Square(&q.X) M.Double(&XX). - Add(&M, &XX) // -> + a, but a=0 here + Add(&M, &XX) // -> + A, but A=0 here U.Mul(&W, &q.Y) p.X.Square(&M). @@ -805,9 +827,10 @@ func (p *g1JacExtended) double(q *g1JacExtended) *g1JacExtended { return p } -// subMixed same as addMixed, but will negate a.Y +// addMixed sets p to p+q in extended Jacobian coordinates, where a.ZZ=1. +// // http://www.hyperelliptic.org/EFD/g1p/auto-shortw-xyzz.html#addition-madd-2008-s -func (p *g1JacExtended) subMixed(a *G1Affine) *g1JacExtended { +func (p *g1JacExtended) addMixed(a *G1Affine) *g1JacExtended { //if a is infinity return p if a.IsInfinity() { @@ -816,7 +839,7 @@ func (p *g1JacExtended) subMixed(a *G1Affine) *g1JacExtended { // p is infinity, return a if p.ZZ.IsZero() { p.X = a.X - p.Y.Neg(&a.Y) + p.Y = a.Y p.ZZ.SetOne() p.ZZZ.SetOne() return p @@ -829,12 +852,11 @@ func (p *g1JacExtended) subMixed(a *G1Affine) *g1JacExtended { P.Sub(&P, &p.X) R.Mul(&a.Y, &p.ZZZ) - R.Neg(&R) R.Sub(&R, &p.Y) if P.IsZero() { if R.IsZero() { - return p.doubleNegMixed(a) + return p.doubleMixed(a) } p.ZZ = fp.Element{} @@ -861,9 +883,10 @@ func (p *g1JacExtended) subMixed(a *G1Affine) *g1JacExtended { } -// addMixed +// subMixed works the same as addMixed, but negates a.Y. +// // http://www.hyperelliptic.org/EFD/g1p/auto-shortw-xyzz.html#addition-madd-2008-s -func (p *g1JacExtended) addMixed(a *G1Affine) *g1JacExtended { +func (p *g1JacExtended) subMixed(a *G1Affine) *g1JacExtended { //if a is infinity return p if a.IsInfinity() { @@ -872,7 +895,7 @@ func (p *g1JacExtended) addMixed(a *G1Affine) *g1JacExtended { // p is infinity, return a if p.ZZ.IsZero() { p.X = a.X - p.Y = a.Y + p.Y.Neg(&a.Y) p.ZZ.SetOne() p.ZZZ.SetOne() return p @@ -885,11 +908,12 @@ func (p *g1JacExtended) addMixed(a *G1Affine) *g1JacExtended { P.Sub(&P, &p.X) R.Mul(&a.Y, &p.ZZZ) + R.Neg(&R) R.Sub(&R, &p.Y) if P.IsZero() { if R.IsZero() { - return p.doubleMixed(a) + return p.doubleNegMixed(a) } p.ZZ = fp.Element{} @@ -916,21 +940,21 @@ func (p *g1JacExtended) addMixed(a *G1Affine) *g1JacExtended { } -// doubleNegMixed same as double, but will negate q.Y -func (p *g1JacExtended) doubleNegMixed(q *G1Affine) *g1JacExtended { +// doubleNegMixed works the same as double, but negates q.Y. +func (p *g1JacExtended) doubleNegMixed(a *G1Affine) *g1JacExtended { var U, V, W, S, XX, M, S2, L fp.Element - U.Double(&q.Y) + U.Double(&a.Y) U.Neg(&U) V.Square(&U) W.Mul(&U, &V) - S.Mul(&q.X, &V) - XX.Square(&q.X) + S.Mul(&a.X, &V) + XX.Square(&a.X) M.Double(&XX). - Add(&M, &XX) // -> + a, but a=0 here + Add(&M, &XX) // -> + A, but A=0 here S2.Double(&S) - L.Mul(&W, &q.Y) + L.Mul(&W, &a.Y) p.X.Square(&M). Sub(&p.X, &S2) @@ -943,21 +967,22 @@ func (p *g1JacExtended) doubleNegMixed(q *G1Affine) *g1JacExtended { return p } -// doubleMixed point in Jacobian extended coordinates +// doubleMixed sets p to [2]a in Jacobian extended coordinates, where a.ZZ=1. +// // http://www.hyperelliptic.org/EFD/g1p/auto-shortw-xyzz.html#doubling-dbl-2008-s-1 -func (p *g1JacExtended) doubleMixed(q *G1Affine) *g1JacExtended { +func (p *g1JacExtended) doubleMixed(a *G1Affine) *g1JacExtended { var U, V, W, S, XX, M, S2, L fp.Element - U.Double(&q.Y) + U.Double(&a.Y) V.Square(&U) W.Mul(&U, &V) - S.Mul(&q.X, &V) - XX.Square(&q.X) + S.Mul(&a.X, &V) + XX.Square(&a.X) M.Double(&XX). - Add(&M, &XX) // -> + a, but a=0 here + Add(&M, &XX) // -> + A, but A=0 here S2.Double(&S) - L.Mul(&W, &q.Y) + L.Mul(&W, &a.Y) p.X.Square(&M). Sub(&p.X, &S2) @@ -971,7 +996,7 @@ func (p *g1JacExtended) doubleMixed(q *G1Affine) *g1JacExtended { } // BatchJacobianToAffineG1 converts points in Jacobian coordinates to Affine coordinates -// performing a single field inversion (Montgomery batch inversion trick). +// performing a single field inversion using the Montgomery batch inversion trick. func BatchJacobianToAffineG1(points []G1Jac) []G1Affine { result := make([]G1Affine, len(points)) zeroes := make([]bool, len(points)) @@ -1021,7 +1046,7 @@ func BatchJacobianToAffineG1(points []G1Jac) []G1Affine { // BatchScalarMultiplicationG1 multiplies the same base by all scalars // and return resulting points in affine coordinates -// uses a simple windowed-NAF like exponentiation algorithm +// uses a simple windowed-NAF-like multiplication algorithm. func BatchScalarMultiplicationG1(base *G1Affine, scalars []fr.Element) []G1Affine { // approximate cost in group ops is // cost = 2^{c-1} + n(scalar.nbBits+nbChunks) @@ -1103,9 +1128,8 @@ func BatchScalarMultiplicationG1(base *G1Affine, scalars []fr.Element) []G1Affin return toReturnAff } -// batch add affine coordinates -// using batch inversion -// special cases (doubling, infinity) must be filtered out before this call +// batchAddG1Affine adds affine points using the Montgomery batch inversion trick. +// Special cases (doubling, infinity) must be filtered out before this call. func batchAddG1Affine[TP pG1Affine, TPP ppG1Affine, TC cG1Affine](R *TPP, P *TP, batchSize int) { var lambda, lambdain TC diff --git a/ecc/bn254/g2.go b/ecc/bn254/g2.go index 2e850ea71..bbdc9ca67 100644 --- a/ecc/bn254/g2.go +++ b/ecc/bn254/g2.go @@ -25,17 +25,17 @@ import ( "runtime" ) -// G2Affine point in affine coordinates +// G2Affine is a point in affine coordinates (x,y) type G2Affine struct { X, Y fptower.E2 } -// G2Jac is a point with fptower.E2 coordinates +// G2Jac is a point in Jacobian coordinates (x=X/Z², y=Y/Z³) type G2Jac struct { X, Y, Z fptower.E2 } -// g2JacExtended parameterized Jacobian coordinates (x=X/ZZ, y=Y/ZZZ, ZZ³=ZZZ²) +// g2JacExtended is a point in extended Jacobian coordinates (x=X/ZZ, y=Y/ZZZ, ZZ³=ZZZ²) type g2JacExtended struct { X, Y, ZZ, ZZZ fptower.E2 } @@ -46,22 +46,24 @@ type g2Proj struct { } // ------------------------------------------------------------------------------------------------- -// Affine +// Affine coordinates -// Set sets p to the provided point +// Set sets p to a in affine coordinates. func (p *G2Affine) Set(a *G2Affine) *G2Affine { p.X, p.Y = a.X, a.Y return p } -// setInfinity sets p to O +// setInfinity sets p to the infinity point, which is encoded as (0,0). +// N.B.: (0,0) is never on the curve for j=0 curves (Y²=X³+B). func (p *G2Affine) setInfinity() *G2Affine { p.X.SetZero() p.Y.SetZero() return p } -// ScalarMultiplication computes and returns p = a ⋅ s +// ScalarMultiplication computes and returns p = [s]a +// where p and a are affine points. func (p *G2Affine) ScalarMultiplication(a *G2Affine, s *big.Int) *G2Affine { var _p G2Jac _p.FromAffine(a) @@ -70,7 +72,8 @@ func (p *G2Affine) ScalarMultiplication(a *G2Affine, s *big.Int) *G2Affine { return p } -// ScalarMultiplicationBase computes and returns p = g ⋅ s where g is the prime subgroup generator +// ScalarMultiplicationBase computes and returns p = [s]g +// where g is the affine point generating the prime subgroup. func (p *G2Affine) ScalarMultiplicationBase(s *big.Int) *G2Affine { var _p G2Jac _p.mulGLV(&g2Gen, s) @@ -78,8 +81,9 @@ func (p *G2Affine) ScalarMultiplicationBase(s *big.Int) *G2Affine { return p } -// Add adds two point in affine coordinates. -// Jacobian addition with Z1=Z2=1 +// Add adds two points in affine coordinates. +// It uses the Jacobian addition with a.Z=b.Z=1 and converts the result to affine coordinates. +// // https://www.hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html#addition-mmadd-2007-bl func (p *G2Affine) Add(a, b *G2Affine) *G2Affine { var q G2Jac @@ -125,6 +129,10 @@ func (p *G2Affine) Add(a, b *G2Affine) *G2Affine { } // Double doubles a point in affine coordinates. +// It converts the point to Jacobian coordinates, doubles it using Jacobian +// addition with a.Z=1, and converts it back to affine coordinates. +// +// http://www.hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html#doubling-mdbl-2007-bl func (p *G2Affine) Double(a *G2Affine) *G2Affine { var q G2Jac q.FromAffine(a) @@ -133,7 +141,8 @@ func (p *G2Affine) Double(a *G2Affine) *G2Affine { return p } -// Sub subs two point in affine coordinates. +// Sub subtracts two points in affine coordinates. +// It uses a similar approach to Add, but negates the second point before adding. func (p *G2Affine) Sub(a, b *G2Affine) *G2Affine { var bneg G2Affine bneg.Neg(b) @@ -141,19 +150,19 @@ func (p *G2Affine) Sub(a, b *G2Affine) *G2Affine { return p } -// Equal tests if two points (in Affine coordinates) are equal +// Equal tests if two points in affine coordinates are equal. func (p *G2Affine) Equal(a *G2Affine) bool { return p.X.Equal(&a.X) && p.Y.Equal(&a.Y) } -// Neg computes -G +// Neg sets p to the affine negative point -a = (a.X, -a.Y). func (p *G2Affine) Neg(a *G2Affine) *G2Affine { p.X = a.X p.Y.Neg(&a.Y) return p } -// FromJacobian rescales a point in Jacobian coord in z=1 plane +// FromJacobian converts a point p1 from Jacobian to affine coordinates. func (p *G2Affine) FromJacobian(p1 *G2Jac) *G2Affine { var a, b fptower.E2 @@ -172,7 +181,7 @@ func (p *G2Affine) FromJacobian(p1 *G2Jac) *G2Affine { return p } -// String returns the string representation of the point or "O" if it is infinity +// String returns the string representation E(x,y) of the affine point p or "O" if it is infinity. func (p *G2Affine) String() string { if p.IsInfinity() { return "O" @@ -180,21 +189,20 @@ func (p *G2Affine) String() string { return "E([" + p.X.String() + "," + p.Y.String() + "])" } -// IsInfinity checks if the point is infinity -// in affine, it's encoded as (0,0) -// (0,0) is never on the curve for j=0 curves +// IsInfinity checks if the affine point p is infinity, which is encoded as (0,0). +// N.B.: (0,0) is never on the curve for j=0 curves (Y²=X³+B). func (p *G2Affine) IsInfinity() bool { return p.X.IsZero() && p.Y.IsZero() } -// IsOnCurve returns true if p in on the curve +// IsOnCurve returns true if the affine point p in on the curve. func (p *G2Affine) IsOnCurve() bool { var point G2Jac point.FromAffine(p) return point.IsOnCurve() // call this function to handle infinity point } -// IsInSubGroup returns true if p is in the correct subgroup, false otherwise +// IsInSubGroup returns true if the affine point p is in the correct subgroup, false otherwise. func (p *G2Affine) IsInSubGroup() bool { var _p G2Jac _p.FromAffine(p) @@ -202,84 +210,76 @@ func (p *G2Affine) IsInSubGroup() bool { } // ------------------------------------------------------------------------------------------------- -// Jacobian +// Jacobian coordinates -// Set sets p to the provided point -func (p *G2Jac) Set(a *G2Jac) *G2Jac { - p.X, p.Y, p.Z = a.X, a.Y, a.Z +// Set sets p to a in Jacobian coordinates. +func (p *G2Jac) Set(q *G2Jac) *G2Jac { + p.X, p.Y, p.Z = q.X, q.Y, q.Z return p } -// Equal tests if two points (in Jacobian coordinates) are equal -func (p *G2Jac) Equal(a *G2Jac) bool { +// Equal tests if two points in Jacobian coordinates are equal. +func (p *G2Jac) Equal(q *G2Jac) bool { // If one point is infinity, the other must also be infinity. if p.Z.IsZero() { - return a.Z.IsZero() + return q.Z.IsZero() } // If the other point is infinity, return false since we can't // the following checks would be incorrect. - if a.Z.IsZero() { + if q.Z.IsZero() { return false } var pZSquare, aZSquare fptower.E2 pZSquare.Square(&p.Z) - aZSquare.Square(&a.Z) + aZSquare.Square(&q.Z) var lhs, rhs fptower.E2 lhs.Mul(&p.X, &aZSquare) - rhs.Mul(&a.X, &pZSquare) + rhs.Mul(&q.X, &pZSquare) if !lhs.Equal(&rhs) { return false } - lhs.Mul(&p.Y, &aZSquare).Mul(&lhs, &a.Z) - rhs.Mul(&a.Y, &pZSquare).Mul(&rhs, &p.Z) + lhs.Mul(&p.Y, &aZSquare).Mul(&lhs, &q.Z) + rhs.Mul(&q.Y, &pZSquare).Mul(&rhs, &p.Z) return lhs.Equal(&rhs) } -// Neg computes -G -func (p *G2Jac) Neg(a *G2Jac) *G2Jac { - *p = *a - p.Y.Neg(&a.Y) - return p -} - -// SubAssign subtracts two points on the curve -func (p *G2Jac) SubAssign(a *G2Jac) *G2Jac { - var tmp G2Jac - tmp.Set(a) - tmp.Y.Neg(&tmp.Y) - p.AddAssign(&tmp) +// Neg sets p to the Jacobian negative point -q = (q.X, -q.Y, q.Z). +func (p *G2Jac) Neg(q *G2Jac) *G2Jac { + *p = *q + p.Y.Neg(&q.Y) return p } -// AddAssign point addition in montgomery form +// AddAssign sets p to p+a in Jacobian coordinates. +// // https://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-3.html#addition-add-2007-bl -func (p *G2Jac) AddAssign(a *G2Jac) *G2Jac { +func (p *G2Jac) AddAssign(q *G2Jac) *G2Jac { - // p is infinity, return a + // p is infinity, return q if p.Z.IsZero() { - p.Set(a) + p.Set(q) return p } - // a is infinity, return p - if a.Z.IsZero() { + // q is infinity, return p + if q.Z.IsZero() { return p } var Z1Z1, Z2Z2, U1, U2, S1, S2, H, I, J, r, V fptower.E2 - Z1Z1.Square(&a.Z) + Z1Z1.Square(&q.Z) Z2Z2.Square(&p.Z) - U1.Mul(&a.X, &Z2Z2) + U1.Mul(&q.X, &Z2Z2) U2.Mul(&p.X, &Z1Z1) - S1.Mul(&a.Y, &p.Z). + S1.Mul(&q.Y, &p.Z). Mul(&S1, &Z2Z2) - S2.Mul(&p.Y, &a.Z). + S2.Mul(&p.Y, &q.Z). Mul(&S2, &Z1Z1) - // if p == a, we double instead + // if p == q, we double instead if U1.Equal(&U2) && S1.Equal(&S2) { return p.DoubleAssign() } @@ -298,7 +298,7 @@ func (p *G2Jac) AddAssign(a *G2Jac) *G2Jac { Mul(&p.Y, &r) S1.Mul(&S1, &J).Double(&S1) p.Y.Sub(&p.Y, &S1) - p.Z.Add(&p.Z, &a.Z) + p.Z.Add(&p.Z, &q.Z) p.Z.Square(&p.Z). Sub(&p.Z, &Z1Z1). Sub(&p.Z, &Z2Z2). @@ -307,8 +307,19 @@ func (p *G2Jac) AddAssign(a *G2Jac) *G2Jac { return p } -// DoubleMixed point addition -// http://www.hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html#doubling-mdbl-2007-bl +// SubAssign sets p to p-a in Jacobian coordinates. +// It uses a similar approach to AddAssign, but negates the point a before adding. +func (p *G2Jac) SubAssign(q *G2Jac) *G2Jac { + var tmp G2Jac + tmp.Set(q) + tmp.Y.Neg(&tmp.Y) + p.AddAssign(&tmp) + return p +} + +// Double sets p to [2]q in Jacobian coordinates. +// +// https://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-3.html#doubling-dbl-2007-bl func (p *G2Jac) DoubleMixed(a *G2Affine) *G2Jac { var XX, YY, YYYY, S, M, T fptower.E2 XX.Square(&a.X) @@ -320,7 +331,7 @@ func (p *G2Jac) DoubleMixed(a *G2Affine) *G2Jac { Sub(&S, &YYYY). Double(&S) M.Double(&XX). - Add(&M, &XX) // -> + a, but a=0 here + Add(&M, &XX) // -> + A, but A=0 here T.Square(&M). Sub(&T, &S). Sub(&T, &S) @@ -336,7 +347,8 @@ func (p *G2Jac) DoubleMixed(a *G2Affine) *G2Jac { return p } -// AddMixed point addition +// AddMixed sets p to p+a in Jacobian coordinates, where a.Z = 1. +// // http://www.hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html#addition-madd-2007-bl func (p *G2Jac) AddMixed(a *G2Affine) *G2Jac { @@ -385,7 +397,8 @@ func (p *G2Jac) AddMixed(a *G2Affine) *G2Jac { return p } -// Double doubles a point in Jacobian coordinates +// Double sets p to [2]q in Jacobian coordinates. +// // https://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-3.html#doubling-dbl-2007-bl func (p *G2Jac) Double(q *G2Jac) *G2Jac { p.Set(q) @@ -393,7 +406,8 @@ func (p *G2Jac) Double(q *G2Jac) *G2Jac { return p } -// DoubleAssign doubles a point in Jacobian coordinates +// DoubleAssign doubles p in Jacobian coordinates. +// // https://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-3.html#doubling-dbl-2007-bl func (p *G2Jac) DoubleAssign() *G2Jac { @@ -425,34 +439,36 @@ func (p *G2Jac) DoubleAssign() *G2Jac { return p } -// ScalarMultiplication computes and returns p = a ⋅ s +// ScalarMultiplication computes and returns p = [s]a +// where p and a are Jacobian points. +// using the GLV technique. // see https://www.iacr.org/archive/crypto2001/21390189.pdf -func (p *G2Jac) ScalarMultiplication(a *G2Jac, s *big.Int) *G2Jac { - return p.mulGLV(a, s) +func (p *G2Jac) ScalarMultiplication(q *G2Jac, s *big.Int) *G2Jac { + return p.mulGLV(q, s) } -// String returns canonical representation of the point in affine coordinates +// String converts p to affine coordinates and returns its string representation E(x,y) or "O" if it is infinity. func (p *G2Jac) String() string { _p := G2Affine{} _p.FromJacobian(p) return _p.String() } -// FromAffine sets p = Q, p in Jacobian, Q in affine -func (p *G2Jac) FromAffine(Q *G2Affine) *G2Jac { - if Q.IsInfinity() { +// FromAffine converts a point a from affine to Jacobian coordinates. +func (p *G2Jac) FromAffine(a *G2Affine) *G2Jac { + if a.IsInfinity() { p.Z.SetZero() p.X.SetOne() p.Y.SetOne() return p } p.Z.SetOne() - p.X.Set(&Q.X) - p.Y.Set(&Q.Y) + p.X.Set(&a.X) + p.Y.Set(&a.Y) return p } -// IsOnCurve returns true if p in on the curve +// IsOnCurve returns true if the Jacobian point p in on the curve. func (p *G2Jac) IsOnCurve() bool { var left, right, tmp, ZZ fptower.E2 left.Square(&p.Y) @@ -483,13 +499,14 @@ func (p *G2Jac) IsInSubGroup() bool { return res.IsOnCurve() && res.Z.IsZero() } -// mulWindowed computes a 2-bits windowed scalar multiplication -func (p *G2Jac) mulWindowed(a *G2Jac, s *big.Int) *G2Jac { +// mulWindowed computes the 2-bits windowed double-and-add scalar +// multiplication p=[s]q in Jacobian coordinates. +func (p *G2Jac) mulWindowed(q *G2Jac, s *big.Int) *G2Jac { var res G2Jac var ops [3]G2Jac - ops[0].Set(a) + ops[0].Set(q) if s.Sign() == -1 { ops[0].Neg(&ops[0]) } @@ -516,26 +533,27 @@ func (p *G2Jac) mulWindowed(a *G2Jac, s *big.Int) *G2Jac { } -// ψ(p) = u o π o u⁻¹ where u:E'→E iso from the twist to E -func (p *G2Jac) psi(a *G2Jac) *G2Jac { - p.Set(a) +// psi sets p to ψ(q) = u o π o u⁻¹ where u:E'→E is the isomorphism from the twist to the curve E and π is the Frobenius map. +func (p *G2Jac) psi(q *G2Jac) *G2Jac { + p.Set(q) p.X.Conjugate(&p.X).Mul(&p.X, &endo.u) p.Y.Conjugate(&p.Y).Mul(&p.Y, &endo.v) p.Z.Conjugate(&p.Z) return p } -// ϕ assigns p to ϕ(a) where ϕ: (x,y) → (w x,y), and returns p -// where w is a third root of unity in 𝔽p -func (p *G2Jac) phi(a *G2Jac) *G2Jac { - p.Set(a) +// phi sets p to ϕ(a) where ϕ: (x,y) → (w x,y), +// where w is a third root of unity. +func (p *G2Jac) phi(q *G2Jac) *G2Jac { + p.Set(q) p.X.MulByElement(&p.X, &thirdRootOneG2) return p } // mulGLV computes the scalar multiplication using a windowed-GLV method +// // see https://www.iacr.org/archive/crypto2001/21390189.pdf -func (p *G2Jac) mulGLV(a *G2Jac, s *big.Int) *G2Jac { +func (p *G2Jac) mulGLV(q *G2Jac, s *big.Int) *G2Jac { var table [15]G2Jac var res G2Jac @@ -543,11 +561,11 @@ func (p *G2Jac) mulGLV(a *G2Jac, s *big.Int) *G2Jac { res.Set(&g2Infinity) - // table[b3b2b1b0-1] = b3b2 ⋅ ϕ(a) + b1b0*a - table[0].Set(a) - table[3].phi(a) + // table[b3b2b1b0-1] = b3b2 ⋅ ϕ(q) + b1b0*q + table[0].Set(q) + table[3].phi(q) - // split the scalar, modifies ±a, ϕ(a) accordingly + // split the scalar, modifies ±q, ϕ(q) accordingly k := ecc.SplitScalar(s, &glvBasis) if k[0].Sign() == -1 { @@ -560,7 +578,7 @@ func (p *G2Jac) mulGLV(a *G2Jac, s *big.Int) *G2Jac { } // precompute table (2 bits sliding window) - // table[b3b2b1b0-1] = b3b2 ⋅ ϕ(a) + b1b0 ⋅ a if b3b2b1b0 != 0 + // table[b3b2b1b0-1] = b3b2 ⋅ ϕ(q) + b1b0 ⋅ q if b3b2b1b0 != 0 table[1].Double(&table[0]) table[2].Set(&table[1]).AddAssign(&table[0]) table[4].Set(&table[3]).AddAssign(&table[0]) @@ -616,11 +634,11 @@ func (p *G2Affine) ClearCofactor(a *G2Affine) *G2Affine { } // ClearCofactor maps a point in curve to r-torsion -func (p *G2Jac) ClearCofactor(a *G2Jac) *G2Jac { +func (p *G2Jac) ClearCofactor(q *G2Jac) *G2Jac { // cf http://cacr.uwaterloo.ca/techreports/2011/cacr2011-26.pdf, 6.1 var points [4]G2Jac - points[0].ScalarMultiplication(a, &xGen) + points[0].ScalarMultiplication(q, &xGen) points[1].Double(&points[0]). AddAssign(&points[0]). @@ -629,7 +647,7 @@ func (p *G2Jac) ClearCofactor(a *G2Jac) *G2Jac { points[2].psi(&points[0]). psi(&points[2]) - points[3].psi(a).psi(&points[3]).psi(&points[3]) + points[3].psi(q).psi(&points[3]).psi(&points[3]) var res G2Jac res.Set(&g2Infinity) @@ -642,15 +660,15 @@ func (p *G2Jac) ClearCofactor(a *G2Jac) *G2Jac { } // ------------------------------------------------------------------------------------------------- -// Jacobian extended +// extended Jacobian coordinates -// Set sets p to the provided point -func (p *g2JacExtended) Set(a *g2JacExtended) *g2JacExtended { - p.X, p.Y, p.ZZ, p.ZZZ = a.X, a.Y, a.ZZ, a.ZZZ +// Set sets p to a in extended Jacobian coordinates. +func (p *g2JacExtended) Set(q *g2JacExtended) *g2JacExtended { + p.X, p.Y, p.ZZ, p.ZZZ = q.X, q.Y, q.ZZ, q.ZZZ return p } -// setInfinity sets p to O +// setInfinity sets p to the infinity point (1,1,0,0). func (p *g2JacExtended) setInfinity() *g2JacExtended { p.X.SetOne() p.Y.SetOne() @@ -659,43 +677,45 @@ func (p *g2JacExtended) setInfinity() *g2JacExtended { return p } -func (p *g2JacExtended) IsZero() bool { +// IsInfinity checks if the p is infinity, i.e. p.ZZ=0. +func (p *g2JacExtended) IsInfinity() bool { return p.ZZ.IsZero() } -// fromJacExtended sets Q in affine coordinates -func (p *G2Affine) fromJacExtended(Q *g2JacExtended) *G2Affine { - if Q.ZZ.IsZero() { +// fromJacExtended converts an extended Jacobian point to an affine point. +func (p *G2Affine) fromJacExtended(q *g2JacExtended) *G2Affine { + if q.ZZ.IsZero() { p.X = fptower.E2{} p.Y = fptower.E2{} return p } - p.X.Inverse(&Q.ZZ).Mul(&p.X, &Q.X) - p.Y.Inverse(&Q.ZZZ).Mul(&p.Y, &Q.Y) + p.X.Inverse(&q.ZZ).Mul(&p.X, &q.X) + p.Y.Inverse(&q.ZZZ).Mul(&p.Y, &q.Y) return p } -// fromJacExtended sets Q in Jacobian coordinates -func (p *G2Jac) fromJacExtended(Q *g2JacExtended) *G2Jac { - if Q.ZZ.IsZero() { +// fromJacExtended converts an extended Jacobian point to a Jacobian point. +func (p *G2Jac) fromJacExtended(q *g2JacExtended) *G2Jac { + if q.ZZ.IsZero() { p.Set(&g2Infinity) return p } - p.X.Mul(&Q.ZZ, &Q.X).Mul(&p.X, &Q.ZZ) - p.Y.Mul(&Q.ZZZ, &Q.Y).Mul(&p.Y, &Q.ZZZ) - p.Z.Set(&Q.ZZZ) + p.X.Mul(&q.ZZ, &q.X).Mul(&p.X, &q.ZZ) + p.Y.Mul(&q.ZZZ, &q.Y).Mul(&p.Y, &q.ZZZ) + p.Z.Set(&q.ZZZ) return p } -// unsafeFromJacExtended sets p in Jacobian coordinates, but don't check for infinity -func (p *G2Jac) unsafeFromJacExtended(Q *g2JacExtended) *G2Jac { - p.X.Square(&Q.ZZ).Mul(&p.X, &Q.X) - p.Y.Square(&Q.ZZZ).Mul(&p.Y, &Q.Y) - p.Z = Q.ZZZ +// unsafeFromJacExtended converts an extended Jacobian point, distinct from Infinity, to a Jacobian point. +func (p *G2Jac) unsafeFromJacExtended(q *g2JacExtended) *G2Jac { + p.X.Square(&q.ZZ).Mul(&p.X, &q.X) + p.Y.Square(&q.ZZZ).Mul(&p.Y, &q.Y) + p.Z = q.ZZZ return p } -// add point in Jacobian extended coordinates +// add sets p to p+q in extended Jacobian coordinates. +// // https://www.hyperelliptic.org/EFD/g1p/auto-shortw-xyzz.html#addition-add-2008-s func (p *g2JacExtended) add(q *g2JacExtended) *g2JacExtended { //if q is infinity return p @@ -751,10 +771,11 @@ func (p *g2JacExtended) add(q *g2JacExtended) *g2JacExtended { return p } -// double point in Jacobian extended coordinates +// double sets p to [2]q in Jacobian extended coordinates. +// // http://www.hyperelliptic.org/EFD/g1p/auto-shortw-xyzz.html#doubling-dbl-2008-s-1 -// since we consider any point on Z=0 as the point at infinity -// this doubling formula works for infinity points as well +// N.B.: since we consider any point on Z=0 as the point at infinity +// this doubling formula works for infinity points as well. func (p *g2JacExtended) double(q *g2JacExtended) *g2JacExtended { var U, V, W, S, XX, M fptower.E2 @@ -764,7 +785,7 @@ func (p *g2JacExtended) double(q *g2JacExtended) *g2JacExtended { S.Mul(&q.X, &V) XX.Square(&q.X) M.Double(&XX). - Add(&M, &XX) // -> + a, but a=0 here + Add(&M, &XX) // -> + A, but A=0 here U.Mul(&W, &q.Y) p.X.Square(&M). @@ -779,9 +800,10 @@ func (p *g2JacExtended) double(q *g2JacExtended) *g2JacExtended { return p } -// subMixed same as addMixed, but will negate a.Y +// addMixed sets p to p+q in extended Jacobian coordinates, where a.ZZ=1. +// // http://www.hyperelliptic.org/EFD/g1p/auto-shortw-xyzz.html#addition-madd-2008-s -func (p *g2JacExtended) subMixed(a *G2Affine) *g2JacExtended { +func (p *g2JacExtended) addMixed(a *G2Affine) *g2JacExtended { //if a is infinity return p if a.IsInfinity() { @@ -790,7 +812,7 @@ func (p *g2JacExtended) subMixed(a *G2Affine) *g2JacExtended { // p is infinity, return a if p.ZZ.IsZero() { p.X = a.X - p.Y.Neg(&a.Y) + p.Y = a.Y p.ZZ.SetOne() p.ZZZ.SetOne() return p @@ -803,12 +825,11 @@ func (p *g2JacExtended) subMixed(a *G2Affine) *g2JacExtended { P.Sub(&P, &p.X) R.Mul(&a.Y, &p.ZZZ) - R.Neg(&R) R.Sub(&R, &p.Y) if P.IsZero() { if R.IsZero() { - return p.doubleNegMixed(a) + return p.doubleMixed(a) } p.ZZ = fptower.E2{} @@ -835,9 +856,10 @@ func (p *g2JacExtended) subMixed(a *G2Affine) *g2JacExtended { } -// addMixed +// subMixed works the same as addMixed, but negates a.Y. +// // http://www.hyperelliptic.org/EFD/g1p/auto-shortw-xyzz.html#addition-madd-2008-s -func (p *g2JacExtended) addMixed(a *G2Affine) *g2JacExtended { +func (p *g2JacExtended) subMixed(a *G2Affine) *g2JacExtended { //if a is infinity return p if a.IsInfinity() { @@ -846,7 +868,7 @@ func (p *g2JacExtended) addMixed(a *G2Affine) *g2JacExtended { // p is infinity, return a if p.ZZ.IsZero() { p.X = a.X - p.Y = a.Y + p.Y.Neg(&a.Y) p.ZZ.SetOne() p.ZZZ.SetOne() return p @@ -859,11 +881,12 @@ func (p *g2JacExtended) addMixed(a *G2Affine) *g2JacExtended { P.Sub(&P, &p.X) R.Mul(&a.Y, &p.ZZZ) + R.Neg(&R) R.Sub(&R, &p.Y) if P.IsZero() { if R.IsZero() { - return p.doubleMixed(a) + return p.doubleNegMixed(a) } p.ZZ = fptower.E2{} @@ -890,21 +913,21 @@ func (p *g2JacExtended) addMixed(a *G2Affine) *g2JacExtended { } -// doubleNegMixed same as double, but will negate q.Y -func (p *g2JacExtended) doubleNegMixed(q *G2Affine) *g2JacExtended { +// doubleNegMixed works the same as double, but negates q.Y. +func (p *g2JacExtended) doubleNegMixed(a *G2Affine) *g2JacExtended { var U, V, W, S, XX, M, S2, L fptower.E2 - U.Double(&q.Y) + U.Double(&a.Y) U.Neg(&U) V.Square(&U) W.Mul(&U, &V) - S.Mul(&q.X, &V) - XX.Square(&q.X) + S.Mul(&a.X, &V) + XX.Square(&a.X) M.Double(&XX). - Add(&M, &XX) // -> + a, but a=0 here + Add(&M, &XX) // -> + A, but A=0 here S2.Double(&S) - L.Mul(&W, &q.Y) + L.Mul(&W, &a.Y) p.X.Square(&M). Sub(&p.X, &S2) @@ -917,21 +940,22 @@ func (p *g2JacExtended) doubleNegMixed(q *G2Affine) *g2JacExtended { return p } -// doubleMixed point in Jacobian extended coordinates +// doubleMixed sets p to [2]a in Jacobian extended coordinates, where a.ZZ=1. +// // http://www.hyperelliptic.org/EFD/g1p/auto-shortw-xyzz.html#doubling-dbl-2008-s-1 -func (p *g2JacExtended) doubleMixed(q *G2Affine) *g2JacExtended { +func (p *g2JacExtended) doubleMixed(a *G2Affine) *g2JacExtended { var U, V, W, S, XX, M, S2, L fptower.E2 - U.Double(&q.Y) + U.Double(&a.Y) V.Square(&U) W.Mul(&U, &V) - S.Mul(&q.X, &V) - XX.Square(&q.X) + S.Mul(&a.X, &V) + XX.Square(&a.X) M.Double(&XX). - Add(&M, &XX) // -> + a, but a=0 here + Add(&M, &XX) // -> + A, but A=0 here S2.Double(&S) - L.Mul(&W, &q.Y) + L.Mul(&W, &a.Y) p.X.Square(&M). Sub(&p.X, &S2) @@ -945,38 +969,38 @@ func (p *g2JacExtended) doubleMixed(q *G2Affine) *g2JacExtended { } // ------------------------------------------------------------------------------------------------- -// Homogenous projective +// Homogenous projective coordinates -// Set sets p to the provided point -func (p *g2Proj) Set(a *g2Proj) *g2Proj { - p.x, p.y, p.z = a.x, a.y, a.z +// Set sets p to a in projective coordinates. +func (p *g2Proj) Set(q *g2Proj) *g2Proj { + p.x, p.y, p.z = q.x, q.y, q.z return p } -// Neg computes -G -func (p *g2Proj) Neg(a *g2Proj) *g2Proj { - *p = *a - p.y.Neg(&a.y) +// Neg sets p to the projective negative point -q = (q.X, -q.Y). +func (p *g2Proj) Neg(q *g2Proj) *g2Proj { + *p = *q + p.y.Neg(&q.y) return p } -// FromAffine sets p = Q, p in homogenous projective, Q in affine -func (p *g2Proj) FromAffine(Q *G2Affine) *g2Proj { - if Q.X.IsZero() && Q.Y.IsZero() { +// FromAffine converts q in affine to p in projective coordinates. +func (p *g2Proj) FromAffine(a *G2Affine) *g2Proj { + if a.X.IsZero() && a.Y.IsZero() { p.z.SetZero() p.x.SetOne() p.y.SetOne() return p } p.z.SetOne() - p.x.Set(&Q.X) - p.y.Set(&Q.Y) + p.x.Set(&a.X) + p.y.Set(&a.Y) return p } // BatchScalarMultiplicationG2 multiplies the same base by all scalars // and return resulting points in affine coordinates -// uses a simple windowed-NAF like exponentiation algorithm +// uses a simple windowed-NAF-like multiplication algorithm. func BatchScalarMultiplicationG2(base *G2Affine, scalars []fr.Element) []G2Affine { // approximate cost in group ops is // cost = 2^{c-1} + n(scalar.nbBits+nbChunks) @@ -1055,9 +1079,8 @@ func BatchScalarMultiplicationG2(base *G2Affine, scalars []fr.Element) []G2Affin return toReturn } -// batch add affine coordinates -// using batch inversion -// special cases (doubling, infinity) must be filtered out before this call +// batchAddG1Affine adds affine points using the Montgomery batch inversion trick. +// Special cases (doubling, infinity) must be filtered out before this call. func batchAddG2Affine[TP pG2Affine, TPP ppG2Affine, TC cG2Affine](R *TPP, P *TP, batchSize int) { var lambda, lambdain TC diff --git a/ecc/bn254/multiexp_affine.go b/ecc/bn254/multiexp_affine.go index 0958526ea..5b1b7ecbd 100644 --- a/ecc/bn254/multiexp_affine.go +++ b/ecc/bn254/multiexp_affine.go @@ -226,7 +226,7 @@ func processChunkG1BatchAffine[BJE ibg1JacExtended, B ibG1Affine, BS bitSet, TP total.setInfinity() for k := len(buckets) - 1; k >= 0; k-- { runningSum.addMixed(&buckets[k]) - if !bucketsJE[k].IsZero() { + if !bucketsJE[k].IsInfinity() { runningSum.add(&bucketsJE[k]) } total.add(&runningSum) @@ -554,7 +554,7 @@ func processChunkG2BatchAffine[BJE ibg2JacExtended, B ibG2Affine, BS bitSet, TP total.setInfinity() for k := len(buckets) - 1; k >= 0; k-- { runningSum.addMixed(&buckets[k]) - if !bucketsJE[k].IsZero() { + if !bucketsJE[k].IsInfinity() { runningSum.add(&bucketsJE[k]) } total.add(&runningSum) diff --git a/ecc/bn254/multiexp_jacobian.go b/ecc/bn254/multiexp_jacobian.go index 32f728fc0..f9a3df9d3 100644 --- a/ecc/bn254/multiexp_jacobian.go +++ b/ecc/bn254/multiexp_jacobian.go @@ -56,7 +56,7 @@ func processChunkG1Jacobian[B ibg1JacExtended](chunk uint64, runningSum.setInfinity() total.setInfinity() for k := len(buckets) - 1; k >= 0; k-- { - if !buckets[k].IsZero() { + if !buckets[k].IsInfinity() { runningSum.add(&buckets[k]) } total.add(&runningSum) @@ -147,7 +147,7 @@ func processChunkG2Jacobian[B ibg2JacExtended](chunk uint64, runningSum.setInfinity() total.setInfinity() for k := len(buckets) - 1; k >= 0; k-- { - if !buckets[k].IsZero() { + if !buckets[k].IsInfinity() { runningSum.add(&buckets[k]) } total.add(&runningSum) diff --git a/ecc/bw6-633/g1.go b/ecc/bw6-633/g1.go index 5f889c88c..7394fc348 100644 --- a/ecc/bw6-633/g1.go +++ b/ecc/bw6-633/g1.go @@ -25,38 +25,40 @@ import ( "runtime" ) -// G1Affine point in affine coordinates +// G1Affine is a point in affine coordinates (x,y) type G1Affine struct { X, Y fp.Element } -// G1Jac is a point with fp.Element coordinates +// G1Jac is a point in Jacobian coordinates (x=X/Z², y=Y/Z³) type G1Jac struct { X, Y, Z fp.Element } -// g1JacExtended parameterized Jacobian coordinates (x=X/ZZ, y=Y/ZZZ, ZZ³=ZZZ²) +// g1JacExtended is a point in extended Jacobian coordinates (x=X/ZZ, y=Y/ZZZ, ZZ³=ZZZ²) type g1JacExtended struct { X, Y, ZZ, ZZZ fp.Element } // ------------------------------------------------------------------------------------------------- -// Affine +// Affine coordinates -// Set sets p to the provided point +// Set sets p to a in affine coordinates. func (p *G1Affine) Set(a *G1Affine) *G1Affine { p.X, p.Y = a.X, a.Y return p } -// setInfinity sets p to O +// setInfinity sets p to the infinity point, which is encoded as (0,0). +// N.B.: (0,0) is never on the curve for j=0 curves (Y²=X³+B). func (p *G1Affine) setInfinity() *G1Affine { p.X.SetZero() p.Y.SetZero() return p } -// ScalarMultiplication computes and returns p = a ⋅ s +// ScalarMultiplication computes and returns p = [s]a +// where p and a are affine points. func (p *G1Affine) ScalarMultiplication(a *G1Affine, s *big.Int) *G1Affine { var _p G1Jac _p.FromAffine(a) @@ -65,20 +67,22 @@ func (p *G1Affine) ScalarMultiplication(a *G1Affine, s *big.Int) *G1Affine { return p } -// ScalarMultiplicationAffine computes and returns p = a ⋅ s -// Takes an affine point and returns a Jacobian point (useful for KZG) +// ScalarMultiplicationAffine computes and returns p = [s]a +// where a is an affine point and p a Jacobian point (useful for KZG). func (p *G1Jac) ScalarMultiplicationAffine(a *G1Affine, s *big.Int) *G1Jac { p.FromAffine(a) p.mulGLV(p, s) return p } -// ScalarMultiplicationBase computes and returns p = g ⋅ s where g is the prime subgroup generator +// ScalarMultiplicationBase computes and returns p = [s]g +// where g is the Jacobian point generating the prime subgroup. func (p *G1Jac) ScalarMultiplicationBase(s *big.Int) *G1Jac { return p.mulGLV(&g1Gen, s) } -// ScalarMultiplicationBase computes and returns p = g ⋅ s where g is the prime subgroup generator +// ScalarMultiplicationBase computes and returns p = [s]g +// where g is the affine point generating the prime subgroup. func (p *G1Affine) ScalarMultiplicationBase(s *big.Int) *G1Affine { var _p G1Jac _p.mulGLV(&g1Gen, s) @@ -86,8 +90,9 @@ func (p *G1Affine) ScalarMultiplicationBase(s *big.Int) *G1Affine { return p } -// Add adds two point in affine coordinates. -// Jacobian addition with Z1=Z2=1 +// Add adds two points in affine coordinates. +// It uses the Jacobian addition with a.Z=b.Z=1 and converts the result to affine coordinates. +// // https://www.hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html#addition-mmadd-2007-bl func (p *G1Affine) Add(a, b *G1Affine) *G1Affine { var q G1Jac @@ -133,6 +138,10 @@ func (p *G1Affine) Add(a, b *G1Affine) *G1Affine { } // Double doubles a point in affine coordinates. +// It converts the point to Jacobian coordinates, doubles it using Jacobian +// addition with a.Z=1, and converts it back to affine coordinates. +// +// http://www.hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html#doubling-mdbl-2007-bl func (p *G1Affine) Double(a *G1Affine) *G1Affine { var q G1Jac q.FromAffine(a) @@ -141,7 +150,8 @@ func (p *G1Affine) Double(a *G1Affine) *G1Affine { return p } -// Sub subs two point in affine coordinates. +// Sub subtracts two points in affine coordinates. +// It uses a similar approach to Add, but negates the second point before adding. func (p *G1Affine) Sub(a, b *G1Affine) *G1Affine { var bneg G1Affine bneg.Neg(b) @@ -149,19 +159,19 @@ func (p *G1Affine) Sub(a, b *G1Affine) *G1Affine { return p } -// Equal tests if two points (in Affine coordinates) are equal +// Equal tests if two points in affine coordinates are equal. func (p *G1Affine) Equal(a *G1Affine) bool { return p.X.Equal(&a.X) && p.Y.Equal(&a.Y) } -// Neg computes -G +// Neg sets p to the affine negative point -a = (a.X, -a.Y). func (p *G1Affine) Neg(a *G1Affine) *G1Affine { p.X = a.X p.Y.Neg(&a.Y) return p } -// FromJacobian rescales a point in Jacobian coord in z=1 plane +// FromJacobian converts a point p1 from Jacobian to affine coordinates. func (p *G1Affine) FromJacobian(p1 *G1Jac) *G1Affine { var a, b fp.Element @@ -180,7 +190,7 @@ func (p *G1Affine) FromJacobian(p1 *G1Jac) *G1Affine { return p } -// String returns the string representation of the point or "O" if it is infinity +// String returns the string representation E(x,y) of the affine point p or "O" if it is infinity. func (p *G1Affine) String() string { if p.IsInfinity() { return "O" @@ -188,21 +198,20 @@ func (p *G1Affine) String() string { return "E([" + p.X.String() + "," + p.Y.String() + "])" } -// IsInfinity checks if the point is infinity -// in affine, it's encoded as (0,0) -// (0,0) is never on the curve for j=0 curves +// IsInfinity checks if the affine point p is infinity, which is encoded as (0,0). +// N.B.: (0,0) is never on the curve for j=0 curves (Y²=X³+B). func (p *G1Affine) IsInfinity() bool { return p.X.IsZero() && p.Y.IsZero() } -// IsOnCurve returns true if p in on the curve +// IsOnCurve returns true if the affine point p in on the curve. func (p *G1Affine) IsOnCurve() bool { var point G1Jac point.FromAffine(p) return point.IsOnCurve() // call this function to handle infinity point } -// IsInSubGroup returns true if p is in the correct subgroup, false otherwise +// IsInSubGroup returns true if the affine point p is in the correct subgroup, false otherwise. func (p *G1Affine) IsInSubGroup() bool { var _p G1Jac _p.FromAffine(p) @@ -210,84 +219,76 @@ func (p *G1Affine) IsInSubGroup() bool { } // ------------------------------------------------------------------------------------------------- -// Jacobian +// Jacobian coordinates -// Set sets p to the provided point -func (p *G1Jac) Set(a *G1Jac) *G1Jac { - p.X, p.Y, p.Z = a.X, a.Y, a.Z +// Set sets p to a in Jacobian coordinates. +func (p *G1Jac) Set(q *G1Jac) *G1Jac { + p.X, p.Y, p.Z = q.X, q.Y, q.Z return p } -// Equal tests if two points (in Jacobian coordinates) are equal -func (p *G1Jac) Equal(a *G1Jac) bool { +// Equal tests if two points in Jacobian coordinates are equal. +func (p *G1Jac) Equal(q *G1Jac) bool { // If one point is infinity, the other must also be infinity. if p.Z.IsZero() { - return a.Z.IsZero() + return q.Z.IsZero() } // If the other point is infinity, return false since we can't // the following checks would be incorrect. - if a.Z.IsZero() { + if q.Z.IsZero() { return false } var pZSquare, aZSquare fp.Element pZSquare.Square(&p.Z) - aZSquare.Square(&a.Z) + aZSquare.Square(&q.Z) var lhs, rhs fp.Element lhs.Mul(&p.X, &aZSquare) - rhs.Mul(&a.X, &pZSquare) + rhs.Mul(&q.X, &pZSquare) if !lhs.Equal(&rhs) { return false } - lhs.Mul(&p.Y, &aZSquare).Mul(&lhs, &a.Z) - rhs.Mul(&a.Y, &pZSquare).Mul(&rhs, &p.Z) + lhs.Mul(&p.Y, &aZSquare).Mul(&lhs, &q.Z) + rhs.Mul(&q.Y, &pZSquare).Mul(&rhs, &p.Z) return lhs.Equal(&rhs) } -// Neg computes -G -func (p *G1Jac) Neg(a *G1Jac) *G1Jac { - *p = *a - p.Y.Neg(&a.Y) +// Neg sets p to the Jacobian negative point -q = (q.X, -q.Y, q.Z). +func (p *G1Jac) Neg(q *G1Jac) *G1Jac { + *p = *q + p.Y.Neg(&q.Y) return p } -// SubAssign subtracts two points on the curve -func (p *G1Jac) SubAssign(a *G1Jac) *G1Jac { - var tmp G1Jac - tmp.Set(a) - tmp.Y.Neg(&tmp.Y) - p.AddAssign(&tmp) - return p -} - -// AddAssign point addition in montgomery form +// AddAssign sets p to p+a in Jacobian coordinates. +// // https://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-3.html#addition-add-2007-bl -func (p *G1Jac) AddAssign(a *G1Jac) *G1Jac { +func (p *G1Jac) AddAssign(q *G1Jac) *G1Jac { - // p is infinity, return a + // p is infinity, return q if p.Z.IsZero() { - p.Set(a) + p.Set(q) return p } - // a is infinity, return p - if a.Z.IsZero() { + // q is infinity, return p + if q.Z.IsZero() { return p } var Z1Z1, Z2Z2, U1, U2, S1, S2, H, I, J, r, V fp.Element - Z1Z1.Square(&a.Z) + Z1Z1.Square(&q.Z) Z2Z2.Square(&p.Z) - U1.Mul(&a.X, &Z2Z2) + U1.Mul(&q.X, &Z2Z2) U2.Mul(&p.X, &Z1Z1) - S1.Mul(&a.Y, &p.Z). + S1.Mul(&q.Y, &p.Z). Mul(&S1, &Z2Z2) - S2.Mul(&p.Y, &a.Z). + S2.Mul(&p.Y, &q.Z). Mul(&S2, &Z1Z1) - // if p == a, we double instead + // if p == q, we double instead if U1.Equal(&U2) && S1.Equal(&S2) { return p.DoubleAssign() } @@ -306,7 +307,7 @@ func (p *G1Jac) AddAssign(a *G1Jac) *G1Jac { Mul(&p.Y, &r) S1.Mul(&S1, &J).Double(&S1) p.Y.Sub(&p.Y, &S1) - p.Z.Add(&p.Z, &a.Z) + p.Z.Add(&p.Z, &q.Z) p.Z.Square(&p.Z). Sub(&p.Z, &Z1Z1). Sub(&p.Z, &Z2Z2). @@ -315,8 +316,19 @@ func (p *G1Jac) AddAssign(a *G1Jac) *G1Jac { return p } -// DoubleMixed point addition -// http://www.hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html#doubling-mdbl-2007-bl +// SubAssign sets p to p-a in Jacobian coordinates. +// It uses a similar approach to AddAssign, but negates the point a before adding. +func (p *G1Jac) SubAssign(q *G1Jac) *G1Jac { + var tmp G1Jac + tmp.Set(q) + tmp.Y.Neg(&tmp.Y) + p.AddAssign(&tmp) + return p +} + +// Double sets p to [2]q in Jacobian coordinates. +// +// https://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-3.html#doubling-dbl-2007-bl func (p *G1Jac) DoubleMixed(a *G1Affine) *G1Jac { var XX, YY, YYYY, S, M, T fp.Element XX.Square(&a.X) @@ -328,7 +340,7 @@ func (p *G1Jac) DoubleMixed(a *G1Affine) *G1Jac { Sub(&S, &YYYY). Double(&S) M.Double(&XX). - Add(&M, &XX) // -> + a, but a=0 here + Add(&M, &XX) // -> + A, but A=0 here T.Square(&M). Sub(&T, &S). Sub(&T, &S) @@ -344,7 +356,8 @@ func (p *G1Jac) DoubleMixed(a *G1Affine) *G1Jac { return p } -// AddMixed point addition +// AddMixed sets p to p+a in Jacobian coordinates, where a.Z = 1. +// // http://www.hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html#addition-madd-2007-bl func (p *G1Jac) AddMixed(a *G1Affine) *G1Jac { @@ -393,7 +406,8 @@ func (p *G1Jac) AddMixed(a *G1Affine) *G1Jac { return p } -// Double doubles a point in Jacobian coordinates +// Double sets p to [2]q in Jacobian coordinates. +// // https://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-3.html#doubling-dbl-2007-bl func (p *G1Jac) Double(q *G1Jac) *G1Jac { p.Set(q) @@ -401,7 +415,8 @@ func (p *G1Jac) Double(q *G1Jac) *G1Jac { return p } -// DoubleAssign doubles a point in Jacobian coordinates +// DoubleAssign doubles p in Jacobian coordinates. +// // https://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-3.html#doubling-dbl-2007-bl func (p *G1Jac) DoubleAssign() *G1Jac { @@ -433,34 +448,36 @@ func (p *G1Jac) DoubleAssign() *G1Jac { return p } -// ScalarMultiplication computes and returns p = a ⋅ s +// ScalarMultiplication computes and returns p = [s]a +// where p and a are Jacobian points. +// using the GLV technique. // see https://www.iacr.org/archive/crypto2001/21390189.pdf -func (p *G1Jac) ScalarMultiplication(a *G1Jac, s *big.Int) *G1Jac { - return p.mulGLV(a, s) +func (p *G1Jac) ScalarMultiplication(q *G1Jac, s *big.Int) *G1Jac { + return p.mulGLV(q, s) } -// String returns canonical representation of the point in affine coordinates +// String converts p to affine coordinates and returns its string representation E(x,y) or "O" if it is infinity. func (p *G1Jac) String() string { _p := G1Affine{} _p.FromJacobian(p) return _p.String() } -// FromAffine sets p = Q, p in Jacobian, Q in affine -func (p *G1Jac) FromAffine(Q *G1Affine) *G1Jac { - if Q.IsInfinity() { +// FromAffine converts a point a from affine to Jacobian coordinates. +func (p *G1Jac) FromAffine(a *G1Affine) *G1Jac { + if a.IsInfinity() { p.Z.SetZero() p.X.SetOne() p.Y.SetOne() return p } p.Z.SetOne() - p.X.Set(&Q.X) - p.Y.Set(&Q.Y) + p.X.Set(&a.X) + p.Y.Set(&a.Y) return p } -// IsOnCurve returns true if p in on the curve +// IsOnCurve returns true if the Jacobian point p in on the curve. func (p *G1Jac) IsOnCurve() bool { var left, right, tmp, ZZ fp.Element left.Square(&p.Y) @@ -492,13 +509,14 @@ func (p *G1Jac) IsInSubGroup() bool { return r.IsOnCurve() && r.Z.IsZero() } -// mulWindowed computes a 2-bits windowed scalar multiplication -func (p *G1Jac) mulWindowed(a *G1Jac, s *big.Int) *G1Jac { +// mulWindowed computes the 2-bits windowed double-and-add scalar +// multiplication p=[s]q in Jacobian coordinates. +func (p *G1Jac) mulWindowed(q *G1Jac, s *big.Int) *G1Jac { var res G1Jac var ops [3]G1Jac - ops[0].Set(a) + ops[0].Set(q) if s.Sign() == -1 { ops[0].Neg(&ops[0]) } @@ -525,17 +543,18 @@ func (p *G1Jac) mulWindowed(a *G1Jac, s *big.Int) *G1Jac { } -// ϕ assigns p to ϕ(a) where ϕ: (x,y) → (w x,y), and returns p -// where w is a third root of unity in 𝔽p -func (p *G1Jac) phi(a *G1Jac) *G1Jac { - p.Set(a) +// phi sets p to ϕ(a) where ϕ: (x,y) → (w x,y), +// where w is a third root of unity. +func (p *G1Jac) phi(q *G1Jac) *G1Jac { + p.Set(q) p.X.Mul(&p.X, &thirdRootOneG1) return p } // mulGLV computes the scalar multiplication using a windowed-GLV method +// // see https://www.iacr.org/archive/crypto2001/21390189.pdf -func (p *G1Jac) mulGLV(a *G1Jac, s *big.Int) *G1Jac { +func (p *G1Jac) mulGLV(q *G1Jac, s *big.Int) *G1Jac { var table [15]G1Jac var res G1Jac @@ -543,11 +562,11 @@ func (p *G1Jac) mulGLV(a *G1Jac, s *big.Int) *G1Jac { res.Set(&g1Infinity) - // table[b3b2b1b0-1] = b3b2 ⋅ ϕ(a) + b1b0*a - table[0].Set(a) - table[3].phi(a) + // table[b3b2b1b0-1] = b3b2 ⋅ ϕ(q) + b1b0*q + table[0].Set(q) + table[3].phi(q) - // split the scalar, modifies ±a, ϕ(a) accordingly + // split the scalar, modifies ±q, ϕ(q) accordingly k := ecc.SplitScalar(s, &glvBasis) if k[0].Sign() == -1 { @@ -560,7 +579,7 @@ func (p *G1Jac) mulGLV(a *G1Jac, s *big.Int) *G1Jac { } // precompute table (2 bits sliding window) - // table[b3b2b1b0-1] = b3b2 ⋅ ϕ(a) + b1b0 ⋅ a if b3b2b1b0 != 0 + // table[b3b2b1b0-1] = b3b2 ⋅ ϕ(q) + b1b0 ⋅ q if b3b2b1b0 != 0 table[1].Double(&table[0]) table[2].Set(&table[1]).AddAssign(&table[0]) table[4].Set(&table[3]).AddAssign(&table[0]) @@ -616,7 +635,7 @@ func (p *G1Affine) ClearCofactor(a *G1Affine) *G1Affine { } // ClearCofactor maps a point in E(Fp) to E(Fp)[r] -func (p *G1Jac) ClearCofactor(a *G1Jac) *G1Jac { +func (p *G1Jac) ClearCofactor(q *G1Jac) *G1Jac { var uP, vP, wP, L0, L1, tmp G1Jac var v, one, uPlusOne, uMinusOne, d1, d2, ht big.Int @@ -628,20 +647,20 @@ func (p *G1Jac) ClearCofactor(a *G1Jac) *G1Jac { ht.SetInt64(7) v.Mul(&xGen, &xGen).Add(&v, &one).Mul(&v, &uPlusOne) - uP.ScalarMultiplication(a, &xGen).Neg(&uP) - vP.Set(a).SubAssign(&uP). + uP.ScalarMultiplication(q, &xGen).Neg(&uP) + vP.Set(q).SubAssign(&uP). ScalarMultiplication(&vP, &v) wP.ScalarMultiplication(&vP, &uMinusOne).Neg(&wP). AddAssign(&uP) L0.ScalarMultiplication(&wP, &d1) tmp.ScalarMultiplication(&vP, &ht) L0.AddAssign(&tmp) - tmp.Double(a) + tmp.Double(q) L0.AddAssign(&tmp) - L1.Set(&uP).AddAssign(a).ScalarMultiplication(&L1, &d1) + L1.Set(&uP).AddAssign(q).ScalarMultiplication(&L1, &d1) tmp.ScalarMultiplication(&vP, &d2) L1.AddAssign(&tmp) - tmp.ScalarMultiplication(a, &ht) + tmp.ScalarMultiplication(q, &ht) L1.AddAssign(&tmp) p.phi(&L1).AddAssign(&L0) @@ -650,8 +669,8 @@ func (p *G1Jac) ClearCofactor(a *G1Jac) *G1Jac { } -// JointScalarMultiplicationBase computes [s1]g+[s2]a using Straus-Shamir technique -// where g is the prime subgroup generator +// JointScalarMultiplicationBase computes [s1]g+[s2]a using Strauss-Shamir technique +// where g is the prime subgroup generator and a is an affine point. func (p *G1Jac) JointScalarMultiplicationBase(a *G1Affine, s1, s2 *big.Int) *G1Jac { var res, p1, p2 G1Jac @@ -722,15 +741,15 @@ func (p *G1Jac) JointScalarMultiplicationBase(a *G1Affine, s1, s2 *big.Int) *G1J } // ------------------------------------------------------------------------------------------------- -// Jacobian extended +// extended Jacobian coordinates -// Set sets p to the provided point -func (p *g1JacExtended) Set(a *g1JacExtended) *g1JacExtended { - p.X, p.Y, p.ZZ, p.ZZZ = a.X, a.Y, a.ZZ, a.ZZZ +// Set sets p to a in extended Jacobian coordinates. +func (p *g1JacExtended) Set(q *g1JacExtended) *g1JacExtended { + p.X, p.Y, p.ZZ, p.ZZZ = q.X, q.Y, q.ZZ, q.ZZZ return p } -// setInfinity sets p to O +// setInfinity sets p to the infinity point (1,1,0,0). func (p *g1JacExtended) setInfinity() *g1JacExtended { p.X.SetOne() p.Y.SetOne() @@ -739,43 +758,45 @@ func (p *g1JacExtended) setInfinity() *g1JacExtended { return p } -func (p *g1JacExtended) IsZero() bool { +// IsInfinity checks if the p is infinity, i.e. p.ZZ=0. +func (p *g1JacExtended) IsInfinity() bool { return p.ZZ.IsZero() } -// fromJacExtended sets Q in affine coordinates -func (p *G1Affine) fromJacExtended(Q *g1JacExtended) *G1Affine { - if Q.ZZ.IsZero() { +// fromJacExtended converts an extended Jacobian point to an affine point. +func (p *G1Affine) fromJacExtended(q *g1JacExtended) *G1Affine { + if q.ZZ.IsZero() { p.X = fp.Element{} p.Y = fp.Element{} return p } - p.X.Inverse(&Q.ZZ).Mul(&p.X, &Q.X) - p.Y.Inverse(&Q.ZZZ).Mul(&p.Y, &Q.Y) + p.X.Inverse(&q.ZZ).Mul(&p.X, &q.X) + p.Y.Inverse(&q.ZZZ).Mul(&p.Y, &q.Y) return p } -// fromJacExtended sets Q in Jacobian coordinates -func (p *G1Jac) fromJacExtended(Q *g1JacExtended) *G1Jac { - if Q.ZZ.IsZero() { +// fromJacExtended converts an extended Jacobian point to a Jacobian point. +func (p *G1Jac) fromJacExtended(q *g1JacExtended) *G1Jac { + if q.ZZ.IsZero() { p.Set(&g1Infinity) return p } - p.X.Mul(&Q.ZZ, &Q.X).Mul(&p.X, &Q.ZZ) - p.Y.Mul(&Q.ZZZ, &Q.Y).Mul(&p.Y, &Q.ZZZ) - p.Z.Set(&Q.ZZZ) + p.X.Mul(&q.ZZ, &q.X).Mul(&p.X, &q.ZZ) + p.Y.Mul(&q.ZZZ, &q.Y).Mul(&p.Y, &q.ZZZ) + p.Z.Set(&q.ZZZ) return p } -// unsafeFromJacExtended sets p in Jacobian coordinates, but don't check for infinity -func (p *G1Jac) unsafeFromJacExtended(Q *g1JacExtended) *G1Jac { - p.X.Square(&Q.ZZ).Mul(&p.X, &Q.X) - p.Y.Square(&Q.ZZZ).Mul(&p.Y, &Q.Y) - p.Z = Q.ZZZ +// unsafeFromJacExtended converts an extended Jacobian point, distinct from Infinity, to a Jacobian point. +func (p *G1Jac) unsafeFromJacExtended(q *g1JacExtended) *G1Jac { + p.X.Square(&q.ZZ).Mul(&p.X, &q.X) + p.Y.Square(&q.ZZZ).Mul(&p.Y, &q.Y) + p.Z = q.ZZZ return p } -// add point in Jacobian extended coordinates +// add sets p to p+q in extended Jacobian coordinates. +// // https://www.hyperelliptic.org/EFD/g1p/auto-shortw-xyzz.html#addition-add-2008-s func (p *g1JacExtended) add(q *g1JacExtended) *g1JacExtended { //if q is infinity return p @@ -831,10 +852,11 @@ func (p *g1JacExtended) add(q *g1JacExtended) *g1JacExtended { return p } -// double point in Jacobian extended coordinates +// double sets p to [2]q in Jacobian extended coordinates. +// // http://www.hyperelliptic.org/EFD/g1p/auto-shortw-xyzz.html#doubling-dbl-2008-s-1 -// since we consider any point on Z=0 as the point at infinity -// this doubling formula works for infinity points as well +// N.B.: since we consider any point on Z=0 as the point at infinity +// this doubling formula works for infinity points as well. func (p *g1JacExtended) double(q *g1JacExtended) *g1JacExtended { var U, V, W, S, XX, M fp.Element @@ -844,7 +866,7 @@ func (p *g1JacExtended) double(q *g1JacExtended) *g1JacExtended { S.Mul(&q.X, &V) XX.Square(&q.X) M.Double(&XX). - Add(&M, &XX) // -> + a, but a=0 here + Add(&M, &XX) // -> + A, but A=0 here U.Mul(&W, &q.Y) p.X.Square(&M). @@ -859,9 +881,10 @@ func (p *g1JacExtended) double(q *g1JacExtended) *g1JacExtended { return p } -// subMixed same as addMixed, but will negate a.Y +// addMixed sets p to p+q in extended Jacobian coordinates, where a.ZZ=1. +// // http://www.hyperelliptic.org/EFD/g1p/auto-shortw-xyzz.html#addition-madd-2008-s -func (p *g1JacExtended) subMixed(a *G1Affine) *g1JacExtended { +func (p *g1JacExtended) addMixed(a *G1Affine) *g1JacExtended { //if a is infinity return p if a.IsInfinity() { @@ -870,7 +893,7 @@ func (p *g1JacExtended) subMixed(a *G1Affine) *g1JacExtended { // p is infinity, return a if p.ZZ.IsZero() { p.X = a.X - p.Y.Neg(&a.Y) + p.Y = a.Y p.ZZ.SetOne() p.ZZZ.SetOne() return p @@ -883,12 +906,11 @@ func (p *g1JacExtended) subMixed(a *G1Affine) *g1JacExtended { P.Sub(&P, &p.X) R.Mul(&a.Y, &p.ZZZ) - R.Neg(&R) R.Sub(&R, &p.Y) if P.IsZero() { if R.IsZero() { - return p.doubleNegMixed(a) + return p.doubleMixed(a) } p.ZZ = fp.Element{} @@ -915,9 +937,10 @@ func (p *g1JacExtended) subMixed(a *G1Affine) *g1JacExtended { } -// addMixed +// subMixed works the same as addMixed, but negates a.Y. +// // http://www.hyperelliptic.org/EFD/g1p/auto-shortw-xyzz.html#addition-madd-2008-s -func (p *g1JacExtended) addMixed(a *G1Affine) *g1JacExtended { +func (p *g1JacExtended) subMixed(a *G1Affine) *g1JacExtended { //if a is infinity return p if a.IsInfinity() { @@ -926,7 +949,7 @@ func (p *g1JacExtended) addMixed(a *G1Affine) *g1JacExtended { // p is infinity, return a if p.ZZ.IsZero() { p.X = a.X - p.Y = a.Y + p.Y.Neg(&a.Y) p.ZZ.SetOne() p.ZZZ.SetOne() return p @@ -939,11 +962,12 @@ func (p *g1JacExtended) addMixed(a *G1Affine) *g1JacExtended { P.Sub(&P, &p.X) R.Mul(&a.Y, &p.ZZZ) + R.Neg(&R) R.Sub(&R, &p.Y) if P.IsZero() { if R.IsZero() { - return p.doubleMixed(a) + return p.doubleNegMixed(a) } p.ZZ = fp.Element{} @@ -970,21 +994,21 @@ func (p *g1JacExtended) addMixed(a *G1Affine) *g1JacExtended { } -// doubleNegMixed same as double, but will negate q.Y -func (p *g1JacExtended) doubleNegMixed(q *G1Affine) *g1JacExtended { +// doubleNegMixed works the same as double, but negates q.Y. +func (p *g1JacExtended) doubleNegMixed(a *G1Affine) *g1JacExtended { var U, V, W, S, XX, M, S2, L fp.Element - U.Double(&q.Y) + U.Double(&a.Y) U.Neg(&U) V.Square(&U) W.Mul(&U, &V) - S.Mul(&q.X, &V) - XX.Square(&q.X) + S.Mul(&a.X, &V) + XX.Square(&a.X) M.Double(&XX). - Add(&M, &XX) // -> + a, but a=0 here + Add(&M, &XX) // -> + A, but A=0 here S2.Double(&S) - L.Mul(&W, &q.Y) + L.Mul(&W, &a.Y) p.X.Square(&M). Sub(&p.X, &S2) @@ -997,21 +1021,22 @@ func (p *g1JacExtended) doubleNegMixed(q *G1Affine) *g1JacExtended { return p } -// doubleMixed point in Jacobian extended coordinates +// doubleMixed sets p to [2]a in Jacobian extended coordinates, where a.ZZ=1. +// // http://www.hyperelliptic.org/EFD/g1p/auto-shortw-xyzz.html#doubling-dbl-2008-s-1 -func (p *g1JacExtended) doubleMixed(q *G1Affine) *g1JacExtended { +func (p *g1JacExtended) doubleMixed(a *G1Affine) *g1JacExtended { var U, V, W, S, XX, M, S2, L fp.Element - U.Double(&q.Y) + U.Double(&a.Y) V.Square(&U) W.Mul(&U, &V) - S.Mul(&q.X, &V) - XX.Square(&q.X) + S.Mul(&a.X, &V) + XX.Square(&a.X) M.Double(&XX). - Add(&M, &XX) // -> + a, but a=0 here + Add(&M, &XX) // -> + A, but A=0 here S2.Double(&S) - L.Mul(&W, &q.Y) + L.Mul(&W, &a.Y) p.X.Square(&M). Sub(&p.X, &S2) @@ -1025,7 +1050,7 @@ func (p *g1JacExtended) doubleMixed(q *G1Affine) *g1JacExtended { } // BatchJacobianToAffineG1 converts points in Jacobian coordinates to Affine coordinates -// performing a single field inversion (Montgomery batch inversion trick). +// performing a single field inversion using the Montgomery batch inversion trick. func BatchJacobianToAffineG1(points []G1Jac) []G1Affine { result := make([]G1Affine, len(points)) zeroes := make([]bool, len(points)) @@ -1075,7 +1100,7 @@ func BatchJacobianToAffineG1(points []G1Jac) []G1Affine { // BatchScalarMultiplicationG1 multiplies the same base by all scalars // and return resulting points in affine coordinates -// uses a simple windowed-NAF like exponentiation algorithm +// uses a simple windowed-NAF-like multiplication algorithm. func BatchScalarMultiplicationG1(base *G1Affine, scalars []fr.Element) []G1Affine { // approximate cost in group ops is // cost = 2^{c-1} + n(scalar.nbBits+nbChunks) @@ -1157,9 +1182,8 @@ func BatchScalarMultiplicationG1(base *G1Affine, scalars []fr.Element) []G1Affin return toReturnAff } -// batch add affine coordinates -// using batch inversion -// special cases (doubling, infinity) must be filtered out before this call +// batchAddG1Affine adds affine points using the Montgomery batch inversion trick. +// Special cases (doubling, infinity) must be filtered out before this call. func batchAddG1Affine[TP pG1Affine, TPP ppG1Affine, TC cG1Affine](R *TPP, P *TP, batchSize int) { var lambda, lambdain TC diff --git a/ecc/bw6-633/g2.go b/ecc/bw6-633/g2.go index 51a1f55c4..8dcc1ca7f 100644 --- a/ecc/bw6-633/g2.go +++ b/ecc/bw6-633/g2.go @@ -25,17 +25,17 @@ import ( "runtime" ) -// G2Affine point in affine coordinates +// G2Affine is a point in affine coordinates (x,y) type G2Affine struct { X, Y fp.Element } -// G2Jac is a point with fp.Element coordinates +// G2Jac is a point in Jacobian coordinates (x=X/Z², y=Y/Z³) type G2Jac struct { X, Y, Z fp.Element } -// g2JacExtended parameterized Jacobian coordinates (x=X/ZZ, y=Y/ZZZ, ZZ³=ZZZ²) +// g2JacExtended is a point in extended Jacobian coordinates (x=X/ZZ, y=Y/ZZZ, ZZ³=ZZZ²) type g2JacExtended struct { X, Y, ZZ, ZZZ fp.Element } @@ -46,22 +46,24 @@ type g2Proj struct { } // ------------------------------------------------------------------------------------------------- -// Affine +// Affine coordinates -// Set sets p to the provided point +// Set sets p to a in affine coordinates. func (p *G2Affine) Set(a *G2Affine) *G2Affine { p.X, p.Y = a.X, a.Y return p } -// setInfinity sets p to O +// setInfinity sets p to the infinity point, which is encoded as (0,0). +// N.B.: (0,0) is never on the curve for j=0 curves (Y²=X³+B). func (p *G2Affine) setInfinity() *G2Affine { p.X.SetZero() p.Y.SetZero() return p } -// ScalarMultiplication computes and returns p = a ⋅ s +// ScalarMultiplication computes and returns p = [s]a +// where p and a are affine points. func (p *G2Affine) ScalarMultiplication(a *G2Affine, s *big.Int) *G2Affine { var _p G2Jac _p.FromAffine(a) @@ -70,7 +72,8 @@ func (p *G2Affine) ScalarMultiplication(a *G2Affine, s *big.Int) *G2Affine { return p } -// ScalarMultiplicationBase computes and returns p = g ⋅ s where g is the prime subgroup generator +// ScalarMultiplicationBase computes and returns p = [s]g +// where g is the affine point generating the prime subgroup. func (p *G2Affine) ScalarMultiplicationBase(s *big.Int) *G2Affine { var _p G2Jac _p.mulGLV(&g2Gen, s) @@ -78,8 +81,9 @@ func (p *G2Affine) ScalarMultiplicationBase(s *big.Int) *G2Affine { return p } -// Add adds two point in affine coordinates. -// Jacobian addition with Z1=Z2=1 +// Add adds two points in affine coordinates. +// It uses the Jacobian addition with a.Z=b.Z=1 and converts the result to affine coordinates. +// // https://www.hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html#addition-mmadd-2007-bl func (p *G2Affine) Add(a, b *G2Affine) *G2Affine { var q G2Jac @@ -125,6 +129,10 @@ func (p *G2Affine) Add(a, b *G2Affine) *G2Affine { } // Double doubles a point in affine coordinates. +// It converts the point to Jacobian coordinates, doubles it using Jacobian +// addition with a.Z=1, and converts it back to affine coordinates. +// +// http://www.hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html#doubling-mdbl-2007-bl func (p *G2Affine) Double(a *G2Affine) *G2Affine { var q G2Jac q.FromAffine(a) @@ -133,7 +141,8 @@ func (p *G2Affine) Double(a *G2Affine) *G2Affine { return p } -// Sub subs two point in affine coordinates. +// Sub subtracts two points in affine coordinates. +// It uses a similar approach to Add, but negates the second point before adding. func (p *G2Affine) Sub(a, b *G2Affine) *G2Affine { var bneg G2Affine bneg.Neg(b) @@ -141,19 +150,19 @@ func (p *G2Affine) Sub(a, b *G2Affine) *G2Affine { return p } -// Equal tests if two points (in Affine coordinates) are equal +// Equal tests if two points in affine coordinates are equal. func (p *G2Affine) Equal(a *G2Affine) bool { return p.X.Equal(&a.X) && p.Y.Equal(&a.Y) } -// Neg computes -G +// Neg sets p to the affine negative point -a = (a.X, -a.Y). func (p *G2Affine) Neg(a *G2Affine) *G2Affine { p.X = a.X p.Y.Neg(&a.Y) return p } -// FromJacobian rescales a point in Jacobian coord in z=1 plane +// FromJacobian converts a point p1 from Jacobian to affine coordinates. func (p *G2Affine) FromJacobian(p1 *G2Jac) *G2Affine { var a, b fp.Element @@ -172,7 +181,7 @@ func (p *G2Affine) FromJacobian(p1 *G2Jac) *G2Affine { return p } -// String returns the string representation of the point or "O" if it is infinity +// String returns the string representation E(x,y) of the affine point p or "O" if it is infinity. func (p *G2Affine) String() string { if p.IsInfinity() { return "O" @@ -180,21 +189,20 @@ func (p *G2Affine) String() string { return "E([" + p.X.String() + "," + p.Y.String() + "])" } -// IsInfinity checks if the point is infinity -// in affine, it's encoded as (0,0) -// (0,0) is never on the curve for j=0 curves +// IsInfinity checks if the affine point p is infinity, which is encoded as (0,0). +// N.B.: (0,0) is never on the curve for j=0 curves (Y²=X³+B). func (p *G2Affine) IsInfinity() bool { return p.X.IsZero() && p.Y.IsZero() } -// IsOnCurve returns true if p in on the curve +// IsOnCurve returns true if the affine point p in on the curve. func (p *G2Affine) IsOnCurve() bool { var point G2Jac point.FromAffine(p) return point.IsOnCurve() // call this function to handle infinity point } -// IsInSubGroup returns true if p is in the correct subgroup, false otherwise +// IsInSubGroup returns true if the affine point p is in the correct subgroup, false otherwise. func (p *G2Affine) IsInSubGroup() bool { var _p G2Jac _p.FromAffine(p) @@ -202,84 +210,76 @@ func (p *G2Affine) IsInSubGroup() bool { } // ------------------------------------------------------------------------------------------------- -// Jacobian +// Jacobian coordinates -// Set sets p to the provided point -func (p *G2Jac) Set(a *G2Jac) *G2Jac { - p.X, p.Y, p.Z = a.X, a.Y, a.Z +// Set sets p to a in Jacobian coordinates. +func (p *G2Jac) Set(q *G2Jac) *G2Jac { + p.X, p.Y, p.Z = q.X, q.Y, q.Z return p } -// Equal tests if two points (in Jacobian coordinates) are equal -func (p *G2Jac) Equal(a *G2Jac) bool { +// Equal tests if two points in Jacobian coordinates are equal. +func (p *G2Jac) Equal(q *G2Jac) bool { // If one point is infinity, the other must also be infinity. if p.Z.IsZero() { - return a.Z.IsZero() + return q.Z.IsZero() } // If the other point is infinity, return false since we can't // the following checks would be incorrect. - if a.Z.IsZero() { + if q.Z.IsZero() { return false } var pZSquare, aZSquare fp.Element pZSquare.Square(&p.Z) - aZSquare.Square(&a.Z) + aZSquare.Square(&q.Z) var lhs, rhs fp.Element lhs.Mul(&p.X, &aZSquare) - rhs.Mul(&a.X, &pZSquare) + rhs.Mul(&q.X, &pZSquare) if !lhs.Equal(&rhs) { return false } - lhs.Mul(&p.Y, &aZSquare).Mul(&lhs, &a.Z) - rhs.Mul(&a.Y, &pZSquare).Mul(&rhs, &p.Z) + lhs.Mul(&p.Y, &aZSquare).Mul(&lhs, &q.Z) + rhs.Mul(&q.Y, &pZSquare).Mul(&rhs, &p.Z) return lhs.Equal(&rhs) } -// Neg computes -G -func (p *G2Jac) Neg(a *G2Jac) *G2Jac { - *p = *a - p.Y.Neg(&a.Y) +// Neg sets p to the Jacobian negative point -q = (q.X, -q.Y, q.Z). +func (p *G2Jac) Neg(q *G2Jac) *G2Jac { + *p = *q + p.Y.Neg(&q.Y) return p } -// SubAssign subtracts two points on the curve -func (p *G2Jac) SubAssign(a *G2Jac) *G2Jac { - var tmp G2Jac - tmp.Set(a) - tmp.Y.Neg(&tmp.Y) - p.AddAssign(&tmp) - return p -} - -// AddAssign point addition in montgomery form +// AddAssign sets p to p+a in Jacobian coordinates. +// // https://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-3.html#addition-add-2007-bl -func (p *G2Jac) AddAssign(a *G2Jac) *G2Jac { +func (p *G2Jac) AddAssign(q *G2Jac) *G2Jac { - // p is infinity, return a + // p is infinity, return q if p.Z.IsZero() { - p.Set(a) + p.Set(q) return p } - // a is infinity, return p - if a.Z.IsZero() { + // q is infinity, return p + if q.Z.IsZero() { return p } var Z1Z1, Z2Z2, U1, U2, S1, S2, H, I, J, r, V fp.Element - Z1Z1.Square(&a.Z) + Z1Z1.Square(&q.Z) Z2Z2.Square(&p.Z) - U1.Mul(&a.X, &Z2Z2) + U1.Mul(&q.X, &Z2Z2) U2.Mul(&p.X, &Z1Z1) - S1.Mul(&a.Y, &p.Z). + S1.Mul(&q.Y, &p.Z). Mul(&S1, &Z2Z2) - S2.Mul(&p.Y, &a.Z). + S2.Mul(&p.Y, &q.Z). Mul(&S2, &Z1Z1) - // if p == a, we double instead + // if p == q, we double instead if U1.Equal(&U2) && S1.Equal(&S2) { return p.DoubleAssign() } @@ -298,7 +298,7 @@ func (p *G2Jac) AddAssign(a *G2Jac) *G2Jac { Mul(&p.Y, &r) S1.Mul(&S1, &J).Double(&S1) p.Y.Sub(&p.Y, &S1) - p.Z.Add(&p.Z, &a.Z) + p.Z.Add(&p.Z, &q.Z) p.Z.Square(&p.Z). Sub(&p.Z, &Z1Z1). Sub(&p.Z, &Z2Z2). @@ -307,8 +307,19 @@ func (p *G2Jac) AddAssign(a *G2Jac) *G2Jac { return p } -// DoubleMixed point addition -// http://www.hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html#doubling-mdbl-2007-bl +// SubAssign sets p to p-a in Jacobian coordinates. +// It uses a similar approach to AddAssign, but negates the point a before adding. +func (p *G2Jac) SubAssign(q *G2Jac) *G2Jac { + var tmp G2Jac + tmp.Set(q) + tmp.Y.Neg(&tmp.Y) + p.AddAssign(&tmp) + return p +} + +// Double sets p to [2]q in Jacobian coordinates. +// +// https://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-3.html#doubling-dbl-2007-bl func (p *G2Jac) DoubleMixed(a *G2Affine) *G2Jac { var XX, YY, YYYY, S, M, T fp.Element XX.Square(&a.X) @@ -320,7 +331,7 @@ func (p *G2Jac) DoubleMixed(a *G2Affine) *G2Jac { Sub(&S, &YYYY). Double(&S) M.Double(&XX). - Add(&M, &XX) // -> + a, but a=0 here + Add(&M, &XX) // -> + A, but A=0 here T.Square(&M). Sub(&T, &S). Sub(&T, &S) @@ -336,7 +347,8 @@ func (p *G2Jac) DoubleMixed(a *G2Affine) *G2Jac { return p } -// AddMixed point addition +// AddMixed sets p to p+a in Jacobian coordinates, where a.Z = 1. +// // http://www.hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html#addition-madd-2007-bl func (p *G2Jac) AddMixed(a *G2Affine) *G2Jac { @@ -385,7 +397,8 @@ func (p *G2Jac) AddMixed(a *G2Affine) *G2Jac { return p } -// Double doubles a point in Jacobian coordinates +// Double sets p to [2]q in Jacobian coordinates. +// // https://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-3.html#doubling-dbl-2007-bl func (p *G2Jac) Double(q *G2Jac) *G2Jac { p.Set(q) @@ -393,7 +406,8 @@ func (p *G2Jac) Double(q *G2Jac) *G2Jac { return p } -// DoubleAssign doubles a point in Jacobian coordinates +// DoubleAssign doubles p in Jacobian coordinates. +// // https://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-3.html#doubling-dbl-2007-bl func (p *G2Jac) DoubleAssign() *G2Jac { @@ -425,34 +439,36 @@ func (p *G2Jac) DoubleAssign() *G2Jac { return p } -// ScalarMultiplication computes and returns p = a ⋅ s +// ScalarMultiplication computes and returns p = [s]a +// where p and a are Jacobian points. +// using the GLV technique. // see https://www.iacr.org/archive/crypto2001/21390189.pdf -func (p *G2Jac) ScalarMultiplication(a *G2Jac, s *big.Int) *G2Jac { - return p.mulGLV(a, s) +func (p *G2Jac) ScalarMultiplication(q *G2Jac, s *big.Int) *G2Jac { + return p.mulGLV(q, s) } -// String returns canonical representation of the point in affine coordinates +// String converts p to affine coordinates and returns its string representation E(x,y) or "O" if it is infinity. func (p *G2Jac) String() string { _p := G2Affine{} _p.FromJacobian(p) return _p.String() } -// FromAffine sets p = Q, p in Jacobian, Q in affine -func (p *G2Jac) FromAffine(Q *G2Affine) *G2Jac { - if Q.IsInfinity() { +// FromAffine converts a point a from affine to Jacobian coordinates. +func (p *G2Jac) FromAffine(a *G2Affine) *G2Jac { + if a.IsInfinity() { p.Z.SetZero() p.X.SetOne() p.Y.SetOne() return p } p.Z.SetOne() - p.X.Set(&Q.X) - p.Y.Set(&Q.Y) + p.X.Set(&a.X) + p.Y.Set(&a.Y) return p } -// IsOnCurve returns true if p in on the curve +// IsOnCurve returns true if the Jacobian point p in on the curve. func (p *G2Jac) IsOnCurve() bool { var left, right, tmp, ZZ fp.Element left.Square(&p.Y) @@ -484,13 +500,14 @@ func (p *G2Jac) IsInSubGroup() bool { return r.IsOnCurve() && r.Z.IsZero() } -// mulWindowed computes a 2-bits windowed scalar multiplication -func (p *G2Jac) mulWindowed(a *G2Jac, s *big.Int) *G2Jac { +// mulWindowed computes the 2-bits windowed double-and-add scalar +// multiplication p=[s]q in Jacobian coordinates. +func (p *G2Jac) mulWindowed(q *G2Jac, s *big.Int) *G2Jac { var res G2Jac var ops [3]G2Jac - ops[0].Set(a) + ops[0].Set(q) if s.Sign() == -1 { ops[0].Neg(&ops[0]) } @@ -517,17 +534,18 @@ func (p *G2Jac) mulWindowed(a *G2Jac, s *big.Int) *G2Jac { } -// ϕ assigns p to ϕ(a) where ϕ: (x,y) → (w x,y), and returns p -// where w is a third root of unity in 𝔽p -func (p *G2Jac) phi(a *G2Jac) *G2Jac { - p.Set(a) +// phi sets p to ϕ(a) where ϕ: (x,y) → (w x,y), +// where w is a third root of unity. +func (p *G2Jac) phi(q *G2Jac) *G2Jac { + p.Set(q) p.X.Mul(&p.X, &thirdRootOneG2) return p } // mulGLV computes the scalar multiplication using a windowed-GLV method +// // see https://www.iacr.org/archive/crypto2001/21390189.pdf -func (p *G2Jac) mulGLV(a *G2Jac, s *big.Int) *G2Jac { +func (p *G2Jac) mulGLV(q *G2Jac, s *big.Int) *G2Jac { var table [15]G2Jac var res G2Jac @@ -535,11 +553,11 @@ func (p *G2Jac) mulGLV(a *G2Jac, s *big.Int) *G2Jac { res.Set(&g2Infinity) - // table[b3b2b1b0-1] = b3b2 ⋅ ϕ(a) + b1b0*a - table[0].Set(a) - table[3].phi(a) + // table[b3b2b1b0-1] = b3b2 ⋅ ϕ(q) + b1b0*q + table[0].Set(q) + table[3].phi(q) - // split the scalar, modifies ±a, ϕ(a) accordingly + // split the scalar, modifies ±q, ϕ(q) accordingly k := ecc.SplitScalar(s, &glvBasis) if k[0].Sign() == -1 { @@ -552,7 +570,7 @@ func (p *G2Jac) mulGLV(a *G2Jac, s *big.Int) *G2Jac { } // precompute table (2 bits sliding window) - // table[b3b2b1b0-1] = b3b2 ⋅ ϕ(a) + b1b0 ⋅ a if b3b2b1b0 != 0 + // table[b3b2b1b0-1] = b3b2 ⋅ ϕ(q) + b1b0 ⋅ q if b3b2b1b0 != 0 table[1].Double(&table[0]) table[2].Set(&table[1]).AddAssign(&table[0]) table[4].Set(&table[3]).AddAssign(&table[0]) @@ -608,14 +626,14 @@ func (p *G2Affine) ClearCofactor(a *G2Affine) *G2Affine { } // ClearCofactor maps a point in curve to r-torsion -func (p *G2Jac) ClearCofactor(a *G2Jac) *G2Jac { +func (p *G2Jac) ClearCofactor(q *G2Jac) *G2Jac { var uP, u2P, u3P, u4P, u5P, xP, vP, wP, L0, L1, tmp G2Jac var ht, d1, d3 big.Int ht.SetInt64(7) // negative d1.SetInt64(13) d3.SetInt64(5) // negative - uP.ScalarMultiplication(a, &xGen) // negative + uP.ScalarMultiplication(q, &xGen) // negative u2P.ScalarMultiplication(&uP, &xGen) u3P.ScalarMultiplication(&u2P, &xGen) // negative u4P.ScalarMultiplication(&u3P, &xGen) @@ -624,18 +642,18 @@ func (p *G2Jac) ClearCofactor(a *G2Jac) *G2Jac { AddAssign(&u3P). Double(&vP). AddAssign(&u4P). - AddAssign(a) + AddAssign(q) wP.Set(&uP).SubAssign(&u4P).SubAssign(&u5P) - xP.Set(a).AddAssign(&vP) - L0.Set(&uP).SubAssign(a).ScalarMultiplication(&L0, &d1) + xP.Set(q).AddAssign(&vP) + L0.Set(&uP).SubAssign(q).ScalarMultiplication(&L0, &d1) tmp.ScalarMultiplication(&xP, &d3) L0.AddAssign(&tmp) - tmp.ScalarMultiplication(a, &ht) // negative + tmp.ScalarMultiplication(q, &ht) // negative L0.SubAssign(&tmp) L1.ScalarMultiplication(&wP, &d1) tmp.ScalarMultiplication(&vP, &ht) L1.AddAssign(&tmp) - tmp.ScalarMultiplication(a, &d3) + tmp.ScalarMultiplication(q, &d3) L1.AddAssign(&tmp) p.phi(&L1).AddAssign(&L0) @@ -645,15 +663,15 @@ func (p *G2Jac) ClearCofactor(a *G2Jac) *G2Jac { } // ------------------------------------------------------------------------------------------------- -// Jacobian extended +// extended Jacobian coordinates -// Set sets p to the provided point -func (p *g2JacExtended) Set(a *g2JacExtended) *g2JacExtended { - p.X, p.Y, p.ZZ, p.ZZZ = a.X, a.Y, a.ZZ, a.ZZZ +// Set sets p to a in extended Jacobian coordinates. +func (p *g2JacExtended) Set(q *g2JacExtended) *g2JacExtended { + p.X, p.Y, p.ZZ, p.ZZZ = q.X, q.Y, q.ZZ, q.ZZZ return p } -// setInfinity sets p to O +// setInfinity sets p to the infinity point (1,1,0,0). func (p *g2JacExtended) setInfinity() *g2JacExtended { p.X.SetOne() p.Y.SetOne() @@ -662,43 +680,45 @@ func (p *g2JacExtended) setInfinity() *g2JacExtended { return p } -func (p *g2JacExtended) IsZero() bool { +// IsInfinity checks if the p is infinity, i.e. p.ZZ=0. +func (p *g2JacExtended) IsInfinity() bool { return p.ZZ.IsZero() } -// fromJacExtended sets Q in affine coordinates -func (p *G2Affine) fromJacExtended(Q *g2JacExtended) *G2Affine { - if Q.ZZ.IsZero() { +// fromJacExtended converts an extended Jacobian point to an affine point. +func (p *G2Affine) fromJacExtended(q *g2JacExtended) *G2Affine { + if q.ZZ.IsZero() { p.X = fp.Element{} p.Y = fp.Element{} return p } - p.X.Inverse(&Q.ZZ).Mul(&p.X, &Q.X) - p.Y.Inverse(&Q.ZZZ).Mul(&p.Y, &Q.Y) + p.X.Inverse(&q.ZZ).Mul(&p.X, &q.X) + p.Y.Inverse(&q.ZZZ).Mul(&p.Y, &q.Y) return p } -// fromJacExtended sets Q in Jacobian coordinates -func (p *G2Jac) fromJacExtended(Q *g2JacExtended) *G2Jac { - if Q.ZZ.IsZero() { +// fromJacExtended converts an extended Jacobian point to a Jacobian point. +func (p *G2Jac) fromJacExtended(q *g2JacExtended) *G2Jac { + if q.ZZ.IsZero() { p.Set(&g2Infinity) return p } - p.X.Mul(&Q.ZZ, &Q.X).Mul(&p.X, &Q.ZZ) - p.Y.Mul(&Q.ZZZ, &Q.Y).Mul(&p.Y, &Q.ZZZ) - p.Z.Set(&Q.ZZZ) + p.X.Mul(&q.ZZ, &q.X).Mul(&p.X, &q.ZZ) + p.Y.Mul(&q.ZZZ, &q.Y).Mul(&p.Y, &q.ZZZ) + p.Z.Set(&q.ZZZ) return p } -// unsafeFromJacExtended sets p in Jacobian coordinates, but don't check for infinity -func (p *G2Jac) unsafeFromJacExtended(Q *g2JacExtended) *G2Jac { - p.X.Square(&Q.ZZ).Mul(&p.X, &Q.X) - p.Y.Square(&Q.ZZZ).Mul(&p.Y, &Q.Y) - p.Z = Q.ZZZ +// unsafeFromJacExtended converts an extended Jacobian point, distinct from Infinity, to a Jacobian point. +func (p *G2Jac) unsafeFromJacExtended(q *g2JacExtended) *G2Jac { + p.X.Square(&q.ZZ).Mul(&p.X, &q.X) + p.Y.Square(&q.ZZZ).Mul(&p.Y, &q.Y) + p.Z = q.ZZZ return p } -// add point in Jacobian extended coordinates +// add sets p to p+q in extended Jacobian coordinates. +// // https://www.hyperelliptic.org/EFD/g1p/auto-shortw-xyzz.html#addition-add-2008-s func (p *g2JacExtended) add(q *g2JacExtended) *g2JacExtended { //if q is infinity return p @@ -754,10 +774,11 @@ func (p *g2JacExtended) add(q *g2JacExtended) *g2JacExtended { return p } -// double point in Jacobian extended coordinates +// double sets p to [2]q in Jacobian extended coordinates. +// // http://www.hyperelliptic.org/EFD/g1p/auto-shortw-xyzz.html#doubling-dbl-2008-s-1 -// since we consider any point on Z=0 as the point at infinity -// this doubling formula works for infinity points as well +// N.B.: since we consider any point on Z=0 as the point at infinity +// this doubling formula works for infinity points as well. func (p *g2JacExtended) double(q *g2JacExtended) *g2JacExtended { var U, V, W, S, XX, M fp.Element @@ -767,7 +788,7 @@ func (p *g2JacExtended) double(q *g2JacExtended) *g2JacExtended { S.Mul(&q.X, &V) XX.Square(&q.X) M.Double(&XX). - Add(&M, &XX) // -> + a, but a=0 here + Add(&M, &XX) // -> + A, but A=0 here U.Mul(&W, &q.Y) p.X.Square(&M). @@ -782,9 +803,10 @@ func (p *g2JacExtended) double(q *g2JacExtended) *g2JacExtended { return p } -// subMixed same as addMixed, but will negate a.Y +// addMixed sets p to p+q in extended Jacobian coordinates, where a.ZZ=1. +// // http://www.hyperelliptic.org/EFD/g1p/auto-shortw-xyzz.html#addition-madd-2008-s -func (p *g2JacExtended) subMixed(a *G2Affine) *g2JacExtended { +func (p *g2JacExtended) addMixed(a *G2Affine) *g2JacExtended { //if a is infinity return p if a.IsInfinity() { @@ -793,7 +815,7 @@ func (p *g2JacExtended) subMixed(a *G2Affine) *g2JacExtended { // p is infinity, return a if p.ZZ.IsZero() { p.X = a.X - p.Y.Neg(&a.Y) + p.Y = a.Y p.ZZ.SetOne() p.ZZZ.SetOne() return p @@ -806,12 +828,11 @@ func (p *g2JacExtended) subMixed(a *G2Affine) *g2JacExtended { P.Sub(&P, &p.X) R.Mul(&a.Y, &p.ZZZ) - R.Neg(&R) R.Sub(&R, &p.Y) if P.IsZero() { if R.IsZero() { - return p.doubleNegMixed(a) + return p.doubleMixed(a) } p.ZZ = fp.Element{} @@ -838,9 +859,10 @@ func (p *g2JacExtended) subMixed(a *G2Affine) *g2JacExtended { } -// addMixed +// subMixed works the same as addMixed, but negates a.Y. +// // http://www.hyperelliptic.org/EFD/g1p/auto-shortw-xyzz.html#addition-madd-2008-s -func (p *g2JacExtended) addMixed(a *G2Affine) *g2JacExtended { +func (p *g2JacExtended) subMixed(a *G2Affine) *g2JacExtended { //if a is infinity return p if a.IsInfinity() { @@ -849,7 +871,7 @@ func (p *g2JacExtended) addMixed(a *G2Affine) *g2JacExtended { // p is infinity, return a if p.ZZ.IsZero() { p.X = a.X - p.Y = a.Y + p.Y.Neg(&a.Y) p.ZZ.SetOne() p.ZZZ.SetOne() return p @@ -862,11 +884,12 @@ func (p *g2JacExtended) addMixed(a *G2Affine) *g2JacExtended { P.Sub(&P, &p.X) R.Mul(&a.Y, &p.ZZZ) + R.Neg(&R) R.Sub(&R, &p.Y) if P.IsZero() { if R.IsZero() { - return p.doubleMixed(a) + return p.doubleNegMixed(a) } p.ZZ = fp.Element{} @@ -893,21 +916,21 @@ func (p *g2JacExtended) addMixed(a *G2Affine) *g2JacExtended { } -// doubleNegMixed same as double, but will negate q.Y -func (p *g2JacExtended) doubleNegMixed(q *G2Affine) *g2JacExtended { +// doubleNegMixed works the same as double, but negates q.Y. +func (p *g2JacExtended) doubleNegMixed(a *G2Affine) *g2JacExtended { var U, V, W, S, XX, M, S2, L fp.Element - U.Double(&q.Y) + U.Double(&a.Y) U.Neg(&U) V.Square(&U) W.Mul(&U, &V) - S.Mul(&q.X, &V) - XX.Square(&q.X) + S.Mul(&a.X, &V) + XX.Square(&a.X) M.Double(&XX). - Add(&M, &XX) // -> + a, but a=0 here + Add(&M, &XX) // -> + A, but A=0 here S2.Double(&S) - L.Mul(&W, &q.Y) + L.Mul(&W, &a.Y) p.X.Square(&M). Sub(&p.X, &S2) @@ -920,21 +943,22 @@ func (p *g2JacExtended) doubleNegMixed(q *G2Affine) *g2JacExtended { return p } -// doubleMixed point in Jacobian extended coordinates +// doubleMixed sets p to [2]a in Jacobian extended coordinates, where a.ZZ=1. +// // http://www.hyperelliptic.org/EFD/g1p/auto-shortw-xyzz.html#doubling-dbl-2008-s-1 -func (p *g2JacExtended) doubleMixed(q *G2Affine) *g2JacExtended { +func (p *g2JacExtended) doubleMixed(a *G2Affine) *g2JacExtended { var U, V, W, S, XX, M, S2, L fp.Element - U.Double(&q.Y) + U.Double(&a.Y) V.Square(&U) W.Mul(&U, &V) - S.Mul(&q.X, &V) - XX.Square(&q.X) + S.Mul(&a.X, &V) + XX.Square(&a.X) M.Double(&XX). - Add(&M, &XX) // -> + a, but a=0 here + Add(&M, &XX) // -> + A, but A=0 here S2.Double(&S) - L.Mul(&W, &q.Y) + L.Mul(&W, &a.Y) p.X.Square(&M). Sub(&p.X, &S2) @@ -948,38 +972,38 @@ func (p *g2JacExtended) doubleMixed(q *G2Affine) *g2JacExtended { } // ------------------------------------------------------------------------------------------------- -// Homogenous projective +// Homogenous projective coordinates -// Set sets p to the provided point -func (p *g2Proj) Set(a *g2Proj) *g2Proj { - p.x, p.y, p.z = a.x, a.y, a.z +// Set sets p to a in projective coordinates. +func (p *g2Proj) Set(q *g2Proj) *g2Proj { + p.x, p.y, p.z = q.x, q.y, q.z return p } -// Neg computes -G -func (p *g2Proj) Neg(a *g2Proj) *g2Proj { - *p = *a - p.y.Neg(&a.y) +// Neg sets p to the projective negative point -q = (q.X, -q.Y). +func (p *g2Proj) Neg(q *g2Proj) *g2Proj { + *p = *q + p.y.Neg(&q.y) return p } -// FromAffine sets p = Q, p in homogenous projective, Q in affine -func (p *g2Proj) FromAffine(Q *G2Affine) *g2Proj { - if Q.X.IsZero() && Q.Y.IsZero() { +// FromAffine converts q in affine to p in projective coordinates. +func (p *g2Proj) FromAffine(a *G2Affine) *g2Proj { + if a.X.IsZero() && a.Y.IsZero() { p.z.SetZero() p.x.SetOne() p.y.SetOne() return p } p.z.SetOne() - p.x.Set(&Q.X) - p.y.Set(&Q.Y) + p.x.Set(&a.X) + p.y.Set(&a.Y) return p } // BatchScalarMultiplicationG2 multiplies the same base by all scalars // and return resulting points in affine coordinates -// uses a simple windowed-NAF like exponentiation algorithm +// uses a simple windowed-NAF-like multiplication algorithm. func BatchScalarMultiplicationG2(base *G2Affine, scalars []fr.Element) []G2Affine { // approximate cost in group ops is // cost = 2^{c-1} + n(scalar.nbBits+nbChunks) @@ -1058,9 +1082,8 @@ func BatchScalarMultiplicationG2(base *G2Affine, scalars []fr.Element) []G2Affin return toReturn } -// batch add affine coordinates -// using batch inversion -// special cases (doubling, infinity) must be filtered out before this call +// batchAddG1Affine adds affine points using the Montgomery batch inversion trick. +// Special cases (doubling, infinity) must be filtered out before this call. func batchAddG2Affine[TP pG2Affine, TPP ppG2Affine, TC cG2Affine](R *TPP, P *TP, batchSize int) { var lambda, lambdain TC diff --git a/ecc/bw6-633/multiexp_affine.go b/ecc/bw6-633/multiexp_affine.go index 97342412c..459d7cdc7 100644 --- a/ecc/bw6-633/multiexp_affine.go +++ b/ecc/bw6-633/multiexp_affine.go @@ -225,7 +225,7 @@ func processChunkG1BatchAffine[BJE ibg1JacExtended, B ibG1Affine, BS bitSet, TP total.setInfinity() for k := len(buckets) - 1; k >= 0; k-- { runningSum.addMixed(&buckets[k]) - if !bucketsJE[k].IsZero() { + if !bucketsJE[k].IsInfinity() { runningSum.add(&bucketsJE[k]) } total.add(&runningSum) @@ -493,7 +493,7 @@ func processChunkG2BatchAffine[BJE ibg2JacExtended, B ibG2Affine, BS bitSet, TP total.setInfinity() for k := len(buckets) - 1; k >= 0; k-- { runningSum.addMixed(&buckets[k]) - if !bucketsJE[k].IsZero() { + if !bucketsJE[k].IsInfinity() { runningSum.add(&bucketsJE[k]) } total.add(&runningSum) diff --git a/ecc/bw6-633/multiexp_jacobian.go b/ecc/bw6-633/multiexp_jacobian.go index 5f2e6906d..ffd7d0a5c 100644 --- a/ecc/bw6-633/multiexp_jacobian.go +++ b/ecc/bw6-633/multiexp_jacobian.go @@ -56,7 +56,7 @@ func processChunkG1Jacobian[B ibg1JacExtended](chunk uint64, runningSum.setInfinity() total.setInfinity() for k := len(buckets) - 1; k >= 0; k-- { - if !buckets[k].IsZero() { + if !buckets[k].IsInfinity() { runningSum.add(&buckets[k]) } total.add(&runningSum) @@ -129,7 +129,7 @@ func processChunkG2Jacobian[B ibg2JacExtended](chunk uint64, runningSum.setInfinity() total.setInfinity() for k := len(buckets) - 1; k >= 0; k-- { - if !buckets[k].IsZero() { + if !buckets[k].IsInfinity() { runningSum.add(&buckets[k]) } total.add(&runningSum) diff --git a/ecc/bw6-756/g1.go b/ecc/bw6-756/g1.go index 066285b9d..34e6d933d 100644 --- a/ecc/bw6-756/g1.go +++ b/ecc/bw6-756/g1.go @@ -25,38 +25,40 @@ import ( "runtime" ) -// G1Affine point in affine coordinates +// G1Affine is a point in affine coordinates (x,y) type G1Affine struct { X, Y fp.Element } -// G1Jac is a point with fp.Element coordinates +// G1Jac is a point in Jacobian coordinates (x=X/Z², y=Y/Z³) type G1Jac struct { X, Y, Z fp.Element } -// g1JacExtended parameterized Jacobian coordinates (x=X/ZZ, y=Y/ZZZ, ZZ³=ZZZ²) +// g1JacExtended is a point in extended Jacobian coordinates (x=X/ZZ, y=Y/ZZZ, ZZ³=ZZZ²) type g1JacExtended struct { X, Y, ZZ, ZZZ fp.Element } // ------------------------------------------------------------------------------------------------- -// Affine +// Affine coordinates -// Set sets p to the provided point +// Set sets p to a in affine coordinates. func (p *G1Affine) Set(a *G1Affine) *G1Affine { p.X, p.Y = a.X, a.Y return p } -// setInfinity sets p to O +// setInfinity sets p to the infinity point, which is encoded as (0,0). +// N.B.: (0,0) is never on the curve for j=0 curves (Y²=X³+B). func (p *G1Affine) setInfinity() *G1Affine { p.X.SetZero() p.Y.SetZero() return p } -// ScalarMultiplication computes and returns p = a ⋅ s +// ScalarMultiplication computes and returns p = [s]a +// where p and a are affine points. func (p *G1Affine) ScalarMultiplication(a *G1Affine, s *big.Int) *G1Affine { var _p G1Jac _p.FromAffine(a) @@ -65,20 +67,22 @@ func (p *G1Affine) ScalarMultiplication(a *G1Affine, s *big.Int) *G1Affine { return p } -// ScalarMultiplicationAffine computes and returns p = a ⋅ s -// Takes an affine point and returns a Jacobian point (useful for KZG) +// ScalarMultiplicationAffine computes and returns p = [s]a +// where a is an affine point and p a Jacobian point (useful for KZG). func (p *G1Jac) ScalarMultiplicationAffine(a *G1Affine, s *big.Int) *G1Jac { p.FromAffine(a) p.mulGLV(p, s) return p } -// ScalarMultiplicationBase computes and returns p = g ⋅ s where g is the prime subgroup generator +// ScalarMultiplicationBase computes and returns p = [s]g +// where g is the Jacobian point generating the prime subgroup. func (p *G1Jac) ScalarMultiplicationBase(s *big.Int) *G1Jac { return p.mulGLV(&g1Gen, s) } -// ScalarMultiplicationBase computes and returns p = g ⋅ s where g is the prime subgroup generator +// ScalarMultiplicationBase computes and returns p = [s]g +// where g is the affine point generating the prime subgroup. func (p *G1Affine) ScalarMultiplicationBase(s *big.Int) *G1Affine { var _p G1Jac _p.mulGLV(&g1Gen, s) @@ -86,8 +90,9 @@ func (p *G1Affine) ScalarMultiplicationBase(s *big.Int) *G1Affine { return p } -// Add adds two point in affine coordinates. -// Jacobian addition with Z1=Z2=1 +// Add adds two points in affine coordinates. +// It uses the Jacobian addition with a.Z=b.Z=1 and converts the result to affine coordinates. +// // https://www.hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html#addition-mmadd-2007-bl func (p *G1Affine) Add(a, b *G1Affine) *G1Affine { var q G1Jac @@ -133,6 +138,10 @@ func (p *G1Affine) Add(a, b *G1Affine) *G1Affine { } // Double doubles a point in affine coordinates. +// It converts the point to Jacobian coordinates, doubles it using Jacobian +// addition with a.Z=1, and converts it back to affine coordinates. +// +// http://www.hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html#doubling-mdbl-2007-bl func (p *G1Affine) Double(a *G1Affine) *G1Affine { var q G1Jac q.FromAffine(a) @@ -141,7 +150,8 @@ func (p *G1Affine) Double(a *G1Affine) *G1Affine { return p } -// Sub subs two point in affine coordinates. +// Sub subtracts two points in affine coordinates. +// It uses a similar approach to Add, but negates the second point before adding. func (p *G1Affine) Sub(a, b *G1Affine) *G1Affine { var bneg G1Affine bneg.Neg(b) @@ -149,19 +159,19 @@ func (p *G1Affine) Sub(a, b *G1Affine) *G1Affine { return p } -// Equal tests if two points (in Affine coordinates) are equal +// Equal tests if two points in affine coordinates are equal. func (p *G1Affine) Equal(a *G1Affine) bool { return p.X.Equal(&a.X) && p.Y.Equal(&a.Y) } -// Neg computes -G +// Neg sets p to the affine negative point -a = (a.X, -a.Y). func (p *G1Affine) Neg(a *G1Affine) *G1Affine { p.X = a.X p.Y.Neg(&a.Y) return p } -// FromJacobian rescales a point in Jacobian coord in z=1 plane +// FromJacobian converts a point p1 from Jacobian to affine coordinates. func (p *G1Affine) FromJacobian(p1 *G1Jac) *G1Affine { var a, b fp.Element @@ -180,7 +190,7 @@ func (p *G1Affine) FromJacobian(p1 *G1Jac) *G1Affine { return p } -// String returns the string representation of the point or "O" if it is infinity +// String returns the string representation E(x,y) of the affine point p or "O" if it is infinity. func (p *G1Affine) String() string { if p.IsInfinity() { return "O" @@ -188,21 +198,20 @@ func (p *G1Affine) String() string { return "E([" + p.X.String() + "," + p.Y.String() + "])" } -// IsInfinity checks if the point is infinity -// in affine, it's encoded as (0,0) -// (0,0) is never on the curve for j=0 curves +// IsInfinity checks if the affine point p is infinity, which is encoded as (0,0). +// N.B.: (0,0) is never on the curve for j=0 curves (Y²=X³+B). func (p *G1Affine) IsInfinity() bool { return p.X.IsZero() && p.Y.IsZero() } -// IsOnCurve returns true if p in on the curve +// IsOnCurve returns true if the affine point p in on the curve. func (p *G1Affine) IsOnCurve() bool { var point G1Jac point.FromAffine(p) return point.IsOnCurve() // call this function to handle infinity point } -// IsInSubGroup returns true if p is in the correct subgroup, false otherwise +// IsInSubGroup returns true if the affine point p is in the correct subgroup, false otherwise. func (p *G1Affine) IsInSubGroup() bool { var _p G1Jac _p.FromAffine(p) @@ -210,84 +219,76 @@ func (p *G1Affine) IsInSubGroup() bool { } // ------------------------------------------------------------------------------------------------- -// Jacobian +// Jacobian coordinates -// Set sets p to the provided point -func (p *G1Jac) Set(a *G1Jac) *G1Jac { - p.X, p.Y, p.Z = a.X, a.Y, a.Z +// Set sets p to a in Jacobian coordinates. +func (p *G1Jac) Set(q *G1Jac) *G1Jac { + p.X, p.Y, p.Z = q.X, q.Y, q.Z return p } -// Equal tests if two points (in Jacobian coordinates) are equal -func (p *G1Jac) Equal(a *G1Jac) bool { +// Equal tests if two points in Jacobian coordinates are equal. +func (p *G1Jac) Equal(q *G1Jac) bool { // If one point is infinity, the other must also be infinity. if p.Z.IsZero() { - return a.Z.IsZero() + return q.Z.IsZero() } // If the other point is infinity, return false since we can't // the following checks would be incorrect. - if a.Z.IsZero() { + if q.Z.IsZero() { return false } var pZSquare, aZSquare fp.Element pZSquare.Square(&p.Z) - aZSquare.Square(&a.Z) + aZSquare.Square(&q.Z) var lhs, rhs fp.Element lhs.Mul(&p.X, &aZSquare) - rhs.Mul(&a.X, &pZSquare) + rhs.Mul(&q.X, &pZSquare) if !lhs.Equal(&rhs) { return false } - lhs.Mul(&p.Y, &aZSquare).Mul(&lhs, &a.Z) - rhs.Mul(&a.Y, &pZSquare).Mul(&rhs, &p.Z) + lhs.Mul(&p.Y, &aZSquare).Mul(&lhs, &q.Z) + rhs.Mul(&q.Y, &pZSquare).Mul(&rhs, &p.Z) return lhs.Equal(&rhs) } -// Neg computes -G -func (p *G1Jac) Neg(a *G1Jac) *G1Jac { - *p = *a - p.Y.Neg(&a.Y) +// Neg sets p to the Jacobian negative point -q = (q.X, -q.Y, q.Z). +func (p *G1Jac) Neg(q *G1Jac) *G1Jac { + *p = *q + p.Y.Neg(&q.Y) return p } -// SubAssign subtracts two points on the curve -func (p *G1Jac) SubAssign(a *G1Jac) *G1Jac { - var tmp G1Jac - tmp.Set(a) - tmp.Y.Neg(&tmp.Y) - p.AddAssign(&tmp) - return p -} - -// AddAssign point addition in montgomery form +// AddAssign sets p to p+a in Jacobian coordinates. +// // https://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-3.html#addition-add-2007-bl -func (p *G1Jac) AddAssign(a *G1Jac) *G1Jac { +func (p *G1Jac) AddAssign(q *G1Jac) *G1Jac { - // p is infinity, return a + // p is infinity, return q if p.Z.IsZero() { - p.Set(a) + p.Set(q) return p } - // a is infinity, return p - if a.Z.IsZero() { + // q is infinity, return p + if q.Z.IsZero() { return p } var Z1Z1, Z2Z2, U1, U2, S1, S2, H, I, J, r, V fp.Element - Z1Z1.Square(&a.Z) + Z1Z1.Square(&q.Z) Z2Z2.Square(&p.Z) - U1.Mul(&a.X, &Z2Z2) + U1.Mul(&q.X, &Z2Z2) U2.Mul(&p.X, &Z1Z1) - S1.Mul(&a.Y, &p.Z). + S1.Mul(&q.Y, &p.Z). Mul(&S1, &Z2Z2) - S2.Mul(&p.Y, &a.Z). + S2.Mul(&p.Y, &q.Z). Mul(&S2, &Z1Z1) - // if p == a, we double instead + // if p == q, we double instead if U1.Equal(&U2) && S1.Equal(&S2) { return p.DoubleAssign() } @@ -306,7 +307,7 @@ func (p *G1Jac) AddAssign(a *G1Jac) *G1Jac { Mul(&p.Y, &r) S1.Mul(&S1, &J).Double(&S1) p.Y.Sub(&p.Y, &S1) - p.Z.Add(&p.Z, &a.Z) + p.Z.Add(&p.Z, &q.Z) p.Z.Square(&p.Z). Sub(&p.Z, &Z1Z1). Sub(&p.Z, &Z2Z2). @@ -315,8 +316,19 @@ func (p *G1Jac) AddAssign(a *G1Jac) *G1Jac { return p } -// DoubleMixed point addition -// http://www.hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html#doubling-mdbl-2007-bl +// SubAssign sets p to p-a in Jacobian coordinates. +// It uses a similar approach to AddAssign, but negates the point a before adding. +func (p *G1Jac) SubAssign(q *G1Jac) *G1Jac { + var tmp G1Jac + tmp.Set(q) + tmp.Y.Neg(&tmp.Y) + p.AddAssign(&tmp) + return p +} + +// Double sets p to [2]q in Jacobian coordinates. +// +// https://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-3.html#doubling-dbl-2007-bl func (p *G1Jac) DoubleMixed(a *G1Affine) *G1Jac { var XX, YY, YYYY, S, M, T fp.Element XX.Square(&a.X) @@ -328,7 +340,7 @@ func (p *G1Jac) DoubleMixed(a *G1Affine) *G1Jac { Sub(&S, &YYYY). Double(&S) M.Double(&XX). - Add(&M, &XX) // -> + a, but a=0 here + Add(&M, &XX) // -> + A, but A=0 here T.Square(&M). Sub(&T, &S). Sub(&T, &S) @@ -344,7 +356,8 @@ func (p *G1Jac) DoubleMixed(a *G1Affine) *G1Jac { return p } -// AddMixed point addition +// AddMixed sets p to p+a in Jacobian coordinates, where a.Z = 1. +// // http://www.hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html#addition-madd-2007-bl func (p *G1Jac) AddMixed(a *G1Affine) *G1Jac { @@ -393,7 +406,8 @@ func (p *G1Jac) AddMixed(a *G1Affine) *G1Jac { return p } -// Double doubles a point in Jacobian coordinates +// Double sets p to [2]q in Jacobian coordinates. +// // https://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-3.html#doubling-dbl-2007-bl func (p *G1Jac) Double(q *G1Jac) *G1Jac { p.Set(q) @@ -401,7 +415,8 @@ func (p *G1Jac) Double(q *G1Jac) *G1Jac { return p } -// DoubleAssign doubles a point in Jacobian coordinates +// DoubleAssign doubles p in Jacobian coordinates. +// // https://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-3.html#doubling-dbl-2007-bl func (p *G1Jac) DoubleAssign() *G1Jac { @@ -433,34 +448,36 @@ func (p *G1Jac) DoubleAssign() *G1Jac { return p } -// ScalarMultiplication computes and returns p = a ⋅ s +// ScalarMultiplication computes and returns p = [s]a +// where p and a are Jacobian points. +// using the GLV technique. // see https://www.iacr.org/archive/crypto2001/21390189.pdf -func (p *G1Jac) ScalarMultiplication(a *G1Jac, s *big.Int) *G1Jac { - return p.mulGLV(a, s) +func (p *G1Jac) ScalarMultiplication(q *G1Jac, s *big.Int) *G1Jac { + return p.mulGLV(q, s) } -// String returns canonical representation of the point in affine coordinates +// String converts p to affine coordinates and returns its string representation E(x,y) or "O" if it is infinity. func (p *G1Jac) String() string { _p := G1Affine{} _p.FromJacobian(p) return _p.String() } -// FromAffine sets p = Q, p in Jacobian, Q in affine -func (p *G1Jac) FromAffine(Q *G1Affine) *G1Jac { - if Q.IsInfinity() { +// FromAffine converts a point a from affine to Jacobian coordinates. +func (p *G1Jac) FromAffine(a *G1Affine) *G1Jac { + if a.IsInfinity() { p.Z.SetZero() p.X.SetOne() p.Y.SetOne() return p } p.Z.SetOne() - p.X.Set(&Q.X) - p.Y.Set(&Q.Y) + p.X.Set(&a.X) + p.Y.Set(&a.Y) return p } -// IsOnCurve returns true if p in on the curve +// IsOnCurve returns true if the Jacobian point p in on the curve. func (p *G1Jac) IsOnCurve() bool { var left, right, tmp, ZZ fp.Element left.Square(&p.Y) @@ -495,13 +512,14 @@ func (p *G1Jac) IsInSubGroup() bool { } -// mulWindowed computes a 2-bits windowed scalar multiplication -func (p *G1Jac) mulWindowed(a *G1Jac, s *big.Int) *G1Jac { +// mulWindowed computes the 2-bits windowed double-and-add scalar +// multiplication p=[s]q in Jacobian coordinates. +func (p *G1Jac) mulWindowed(q *G1Jac, s *big.Int) *G1Jac { var res G1Jac var ops [3]G1Jac - ops[0].Set(a) + ops[0].Set(q) if s.Sign() == -1 { ops[0].Neg(&ops[0]) } @@ -528,17 +546,18 @@ func (p *G1Jac) mulWindowed(a *G1Jac, s *big.Int) *G1Jac { } -// ϕ assigns p to ϕ(a) where ϕ: (x,y) → (w x,y), and returns p -// where w is a third root of unity in 𝔽p -func (p *G1Jac) phi(a *G1Jac) *G1Jac { - p.Set(a) +// phi sets p to ϕ(a) where ϕ: (x,y) → (w x,y), +// where w is a third root of unity. +func (p *G1Jac) phi(q *G1Jac) *G1Jac { + p.Set(q) p.X.Mul(&p.X, &thirdRootOneG1) return p } // mulGLV computes the scalar multiplication using a windowed-GLV method +// // see https://www.iacr.org/archive/crypto2001/21390189.pdf -func (p *G1Jac) mulGLV(a *G1Jac, s *big.Int) *G1Jac { +func (p *G1Jac) mulGLV(q *G1Jac, s *big.Int) *G1Jac { var table [15]G1Jac var res G1Jac @@ -546,11 +565,11 @@ func (p *G1Jac) mulGLV(a *G1Jac, s *big.Int) *G1Jac { res.Set(&g1Infinity) - // table[b3b2b1b0-1] = b3b2 ⋅ ϕ(a) + b1b0*a - table[0].Set(a) - table[3].phi(a) + // table[b3b2b1b0-1] = b3b2 ⋅ ϕ(q) + b1b0*q + table[0].Set(q) + table[3].phi(q) - // split the scalar, modifies ±a, ϕ(a) accordingly + // split the scalar, modifies ±q, ϕ(q) accordingly k := ecc.SplitScalar(s, &glvBasis) if k[0].Sign() == -1 { @@ -563,7 +582,7 @@ func (p *G1Jac) mulGLV(a *G1Jac, s *big.Int) *G1Jac { } // precompute table (2 bits sliding window) - // table[b3b2b1b0-1] = b3b2 ⋅ ϕ(a) + b1b0 ⋅ a if b3b2b1b0 != 0 + // table[b3b2b1b0-1] = b3b2 ⋅ ϕ(q) + b1b0 ⋅ q if b3b2b1b0 != 0 table[1].Double(&table[0]) table[2].Set(&table[1]).AddAssign(&table[0]) table[4].Set(&table[3]).AddAssign(&table[0]) @@ -619,29 +638,29 @@ func (p *G1Affine) ClearCofactor(a *G1Affine) *G1Affine { } // ClearCofactor maps a point in E(Fp) to E(Fp)[r] -func (p *G1Jac) ClearCofactor(a *G1Jac) *G1Jac { +func (p *G1Jac) ClearCofactor(q *G1Jac) *G1Jac { var L0, L1, uP, u2P, u3P, tmp G1Jac - uP.ScalarMultiplication(a, &xGen) + uP.ScalarMultiplication(q, &xGen) u2P.ScalarMultiplication(&uP, &xGen) u3P.ScalarMultiplication(&u2P, &xGen) - L0.Set(a).AddAssign(&u3P). + L0.Set(q).AddAssign(&u3P). SubAssign(&u2P) - tmp.Set(a).AddAssign(&u2P). + tmp.Set(q).AddAssign(&u2P). SubAssign(&uP). SubAssign(&uP). Double(&tmp) L0.SubAssign(&tmp). - SubAssign(a) + SubAssign(q) - L1.Set(a).AddAssign(&uP) - tmp.Set(&uP).SubAssign(a). + L1.Set(q).AddAssign(&uP) + tmp.Set(&uP).SubAssign(q). Double(&tmp). SubAssign(&u2P) L1.AddAssign(&tmp). - SubAssign(a) + SubAssign(q) p.phi(&L1). AddAssign(&L0) @@ -649,8 +668,8 @@ func (p *G1Jac) ClearCofactor(a *G1Jac) *G1Jac { return p } -// JointScalarMultiplicationBase computes [s1]g+[s2]a using Straus-Shamir technique -// where g is the prime subgroup generator +// JointScalarMultiplicationBase computes [s1]g+[s2]a using Strauss-Shamir technique +// where g is the prime subgroup generator and a is an affine point. func (p *G1Jac) JointScalarMultiplicationBase(a *G1Affine, s1, s2 *big.Int) *G1Jac { var res, p1, p2 G1Jac @@ -721,15 +740,15 @@ func (p *G1Jac) JointScalarMultiplicationBase(a *G1Affine, s1, s2 *big.Int) *G1J } // ------------------------------------------------------------------------------------------------- -// Jacobian extended +// extended Jacobian coordinates -// Set sets p to the provided point -func (p *g1JacExtended) Set(a *g1JacExtended) *g1JacExtended { - p.X, p.Y, p.ZZ, p.ZZZ = a.X, a.Y, a.ZZ, a.ZZZ +// Set sets p to a in extended Jacobian coordinates. +func (p *g1JacExtended) Set(q *g1JacExtended) *g1JacExtended { + p.X, p.Y, p.ZZ, p.ZZZ = q.X, q.Y, q.ZZ, q.ZZZ return p } -// setInfinity sets p to O +// setInfinity sets p to the infinity point (1,1,0,0). func (p *g1JacExtended) setInfinity() *g1JacExtended { p.X.SetOne() p.Y.SetOne() @@ -738,43 +757,45 @@ func (p *g1JacExtended) setInfinity() *g1JacExtended { return p } -func (p *g1JacExtended) IsZero() bool { +// IsInfinity checks if the p is infinity, i.e. p.ZZ=0. +func (p *g1JacExtended) IsInfinity() bool { return p.ZZ.IsZero() } -// fromJacExtended sets Q in affine coordinates -func (p *G1Affine) fromJacExtended(Q *g1JacExtended) *G1Affine { - if Q.ZZ.IsZero() { +// fromJacExtended converts an extended Jacobian point to an affine point. +func (p *G1Affine) fromJacExtended(q *g1JacExtended) *G1Affine { + if q.ZZ.IsZero() { p.X = fp.Element{} p.Y = fp.Element{} return p } - p.X.Inverse(&Q.ZZ).Mul(&p.X, &Q.X) - p.Y.Inverse(&Q.ZZZ).Mul(&p.Y, &Q.Y) + p.X.Inverse(&q.ZZ).Mul(&p.X, &q.X) + p.Y.Inverse(&q.ZZZ).Mul(&p.Y, &q.Y) return p } -// fromJacExtended sets Q in Jacobian coordinates -func (p *G1Jac) fromJacExtended(Q *g1JacExtended) *G1Jac { - if Q.ZZ.IsZero() { +// fromJacExtended converts an extended Jacobian point to a Jacobian point. +func (p *G1Jac) fromJacExtended(q *g1JacExtended) *G1Jac { + if q.ZZ.IsZero() { p.Set(&g1Infinity) return p } - p.X.Mul(&Q.ZZ, &Q.X).Mul(&p.X, &Q.ZZ) - p.Y.Mul(&Q.ZZZ, &Q.Y).Mul(&p.Y, &Q.ZZZ) - p.Z.Set(&Q.ZZZ) + p.X.Mul(&q.ZZ, &q.X).Mul(&p.X, &q.ZZ) + p.Y.Mul(&q.ZZZ, &q.Y).Mul(&p.Y, &q.ZZZ) + p.Z.Set(&q.ZZZ) return p } -// unsafeFromJacExtended sets p in Jacobian coordinates, but don't check for infinity -func (p *G1Jac) unsafeFromJacExtended(Q *g1JacExtended) *G1Jac { - p.X.Square(&Q.ZZ).Mul(&p.X, &Q.X) - p.Y.Square(&Q.ZZZ).Mul(&p.Y, &Q.Y) - p.Z = Q.ZZZ +// unsafeFromJacExtended converts an extended Jacobian point, distinct from Infinity, to a Jacobian point. +func (p *G1Jac) unsafeFromJacExtended(q *g1JacExtended) *G1Jac { + p.X.Square(&q.ZZ).Mul(&p.X, &q.X) + p.Y.Square(&q.ZZZ).Mul(&p.Y, &q.Y) + p.Z = q.ZZZ return p } -// add point in Jacobian extended coordinates +// add sets p to p+q in extended Jacobian coordinates. +// // https://www.hyperelliptic.org/EFD/g1p/auto-shortw-xyzz.html#addition-add-2008-s func (p *g1JacExtended) add(q *g1JacExtended) *g1JacExtended { //if q is infinity return p @@ -830,10 +851,11 @@ func (p *g1JacExtended) add(q *g1JacExtended) *g1JacExtended { return p } -// double point in Jacobian extended coordinates +// double sets p to [2]q in Jacobian extended coordinates. +// // http://www.hyperelliptic.org/EFD/g1p/auto-shortw-xyzz.html#doubling-dbl-2008-s-1 -// since we consider any point on Z=0 as the point at infinity -// this doubling formula works for infinity points as well +// N.B.: since we consider any point on Z=0 as the point at infinity +// this doubling formula works for infinity points as well. func (p *g1JacExtended) double(q *g1JacExtended) *g1JacExtended { var U, V, W, S, XX, M fp.Element @@ -843,7 +865,7 @@ func (p *g1JacExtended) double(q *g1JacExtended) *g1JacExtended { S.Mul(&q.X, &V) XX.Square(&q.X) M.Double(&XX). - Add(&M, &XX) // -> + a, but a=0 here + Add(&M, &XX) // -> + A, but A=0 here U.Mul(&W, &q.Y) p.X.Square(&M). @@ -858,9 +880,10 @@ func (p *g1JacExtended) double(q *g1JacExtended) *g1JacExtended { return p } -// subMixed same as addMixed, but will negate a.Y +// addMixed sets p to p+q in extended Jacobian coordinates, where a.ZZ=1. +// // http://www.hyperelliptic.org/EFD/g1p/auto-shortw-xyzz.html#addition-madd-2008-s -func (p *g1JacExtended) subMixed(a *G1Affine) *g1JacExtended { +func (p *g1JacExtended) addMixed(a *G1Affine) *g1JacExtended { //if a is infinity return p if a.IsInfinity() { @@ -869,7 +892,7 @@ func (p *g1JacExtended) subMixed(a *G1Affine) *g1JacExtended { // p is infinity, return a if p.ZZ.IsZero() { p.X = a.X - p.Y.Neg(&a.Y) + p.Y = a.Y p.ZZ.SetOne() p.ZZZ.SetOne() return p @@ -882,12 +905,11 @@ func (p *g1JacExtended) subMixed(a *G1Affine) *g1JacExtended { P.Sub(&P, &p.X) R.Mul(&a.Y, &p.ZZZ) - R.Neg(&R) R.Sub(&R, &p.Y) if P.IsZero() { if R.IsZero() { - return p.doubleNegMixed(a) + return p.doubleMixed(a) } p.ZZ = fp.Element{} @@ -914,9 +936,10 @@ func (p *g1JacExtended) subMixed(a *G1Affine) *g1JacExtended { } -// addMixed +// subMixed works the same as addMixed, but negates a.Y. +// // http://www.hyperelliptic.org/EFD/g1p/auto-shortw-xyzz.html#addition-madd-2008-s -func (p *g1JacExtended) addMixed(a *G1Affine) *g1JacExtended { +func (p *g1JacExtended) subMixed(a *G1Affine) *g1JacExtended { //if a is infinity return p if a.IsInfinity() { @@ -925,7 +948,7 @@ func (p *g1JacExtended) addMixed(a *G1Affine) *g1JacExtended { // p is infinity, return a if p.ZZ.IsZero() { p.X = a.X - p.Y = a.Y + p.Y.Neg(&a.Y) p.ZZ.SetOne() p.ZZZ.SetOne() return p @@ -938,11 +961,12 @@ func (p *g1JacExtended) addMixed(a *G1Affine) *g1JacExtended { P.Sub(&P, &p.X) R.Mul(&a.Y, &p.ZZZ) + R.Neg(&R) R.Sub(&R, &p.Y) if P.IsZero() { if R.IsZero() { - return p.doubleMixed(a) + return p.doubleNegMixed(a) } p.ZZ = fp.Element{} @@ -969,21 +993,21 @@ func (p *g1JacExtended) addMixed(a *G1Affine) *g1JacExtended { } -// doubleNegMixed same as double, but will negate q.Y -func (p *g1JacExtended) doubleNegMixed(q *G1Affine) *g1JacExtended { +// doubleNegMixed works the same as double, but negates q.Y. +func (p *g1JacExtended) doubleNegMixed(a *G1Affine) *g1JacExtended { var U, V, W, S, XX, M, S2, L fp.Element - U.Double(&q.Y) + U.Double(&a.Y) U.Neg(&U) V.Square(&U) W.Mul(&U, &V) - S.Mul(&q.X, &V) - XX.Square(&q.X) + S.Mul(&a.X, &V) + XX.Square(&a.X) M.Double(&XX). - Add(&M, &XX) // -> + a, but a=0 here + Add(&M, &XX) // -> + A, but A=0 here S2.Double(&S) - L.Mul(&W, &q.Y) + L.Mul(&W, &a.Y) p.X.Square(&M). Sub(&p.X, &S2) @@ -996,21 +1020,22 @@ func (p *g1JacExtended) doubleNegMixed(q *G1Affine) *g1JacExtended { return p } -// doubleMixed point in Jacobian extended coordinates +// doubleMixed sets p to [2]a in Jacobian extended coordinates, where a.ZZ=1. +// // http://www.hyperelliptic.org/EFD/g1p/auto-shortw-xyzz.html#doubling-dbl-2008-s-1 -func (p *g1JacExtended) doubleMixed(q *G1Affine) *g1JacExtended { +func (p *g1JacExtended) doubleMixed(a *G1Affine) *g1JacExtended { var U, V, W, S, XX, M, S2, L fp.Element - U.Double(&q.Y) + U.Double(&a.Y) V.Square(&U) W.Mul(&U, &V) - S.Mul(&q.X, &V) - XX.Square(&q.X) + S.Mul(&a.X, &V) + XX.Square(&a.X) M.Double(&XX). - Add(&M, &XX) // -> + a, but a=0 here + Add(&M, &XX) // -> + A, but A=0 here S2.Double(&S) - L.Mul(&W, &q.Y) + L.Mul(&W, &a.Y) p.X.Square(&M). Sub(&p.X, &S2) @@ -1024,7 +1049,7 @@ func (p *g1JacExtended) doubleMixed(q *G1Affine) *g1JacExtended { } // BatchJacobianToAffineG1 converts points in Jacobian coordinates to Affine coordinates -// performing a single field inversion (Montgomery batch inversion trick). +// performing a single field inversion using the Montgomery batch inversion trick. func BatchJacobianToAffineG1(points []G1Jac) []G1Affine { result := make([]G1Affine, len(points)) zeroes := make([]bool, len(points)) @@ -1074,7 +1099,7 @@ func BatchJacobianToAffineG1(points []G1Jac) []G1Affine { // BatchScalarMultiplicationG1 multiplies the same base by all scalars // and return resulting points in affine coordinates -// uses a simple windowed-NAF like exponentiation algorithm +// uses a simple windowed-NAF-like multiplication algorithm. func BatchScalarMultiplicationG1(base *G1Affine, scalars []fr.Element) []G1Affine { // approximate cost in group ops is // cost = 2^{c-1} + n(scalar.nbBits+nbChunks) @@ -1156,9 +1181,8 @@ func BatchScalarMultiplicationG1(base *G1Affine, scalars []fr.Element) []G1Affin return toReturnAff } -// batch add affine coordinates -// using batch inversion -// special cases (doubling, infinity) must be filtered out before this call +// batchAddG1Affine adds affine points using the Montgomery batch inversion trick. +// Special cases (doubling, infinity) must be filtered out before this call. func batchAddG1Affine[TP pG1Affine, TPP ppG1Affine, TC cG1Affine](R *TPP, P *TP, batchSize int) { var lambda, lambdain TC diff --git a/ecc/bw6-756/g2.go b/ecc/bw6-756/g2.go index 86821c022..0c6e4fe7f 100644 --- a/ecc/bw6-756/g2.go +++ b/ecc/bw6-756/g2.go @@ -25,17 +25,17 @@ import ( "runtime" ) -// G2Affine point in affine coordinates +// G2Affine is a point in affine coordinates (x,y) type G2Affine struct { X, Y fp.Element } -// G2Jac is a point with fp.Element coordinates +// G2Jac is a point in Jacobian coordinates (x=X/Z², y=Y/Z³) type G2Jac struct { X, Y, Z fp.Element } -// g2JacExtended parameterized Jacobian coordinates (x=X/ZZ, y=Y/ZZZ, ZZ³=ZZZ²) +// g2JacExtended is a point in extended Jacobian coordinates (x=X/ZZ, y=Y/ZZZ, ZZ³=ZZZ²) type g2JacExtended struct { X, Y, ZZ, ZZZ fp.Element } @@ -46,22 +46,24 @@ type g2Proj struct { } // ------------------------------------------------------------------------------------------------- -// Affine +// Affine coordinates -// Set sets p to the provided point +// Set sets p to a in affine coordinates. func (p *G2Affine) Set(a *G2Affine) *G2Affine { p.X, p.Y = a.X, a.Y return p } -// setInfinity sets p to O +// setInfinity sets p to the infinity point, which is encoded as (0,0). +// N.B.: (0,0) is never on the curve for j=0 curves (Y²=X³+B). func (p *G2Affine) setInfinity() *G2Affine { p.X.SetZero() p.Y.SetZero() return p } -// ScalarMultiplication computes and returns p = a ⋅ s +// ScalarMultiplication computes and returns p = [s]a +// where p and a are affine points. func (p *G2Affine) ScalarMultiplication(a *G2Affine, s *big.Int) *G2Affine { var _p G2Jac _p.FromAffine(a) @@ -70,7 +72,8 @@ func (p *G2Affine) ScalarMultiplication(a *G2Affine, s *big.Int) *G2Affine { return p } -// ScalarMultiplicationBase computes and returns p = g ⋅ s where g is the prime subgroup generator +// ScalarMultiplicationBase computes and returns p = [s]g +// where g is the affine point generating the prime subgroup. func (p *G2Affine) ScalarMultiplicationBase(s *big.Int) *G2Affine { var _p G2Jac _p.mulGLV(&g2Gen, s) @@ -78,8 +81,9 @@ func (p *G2Affine) ScalarMultiplicationBase(s *big.Int) *G2Affine { return p } -// Add adds two point in affine coordinates. -// Jacobian addition with Z1=Z2=1 +// Add adds two points in affine coordinates. +// It uses the Jacobian addition with a.Z=b.Z=1 and converts the result to affine coordinates. +// // https://www.hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html#addition-mmadd-2007-bl func (p *G2Affine) Add(a, b *G2Affine) *G2Affine { var q G2Jac @@ -125,6 +129,10 @@ func (p *G2Affine) Add(a, b *G2Affine) *G2Affine { } // Double doubles a point in affine coordinates. +// It converts the point to Jacobian coordinates, doubles it using Jacobian +// addition with a.Z=1, and converts it back to affine coordinates. +// +// http://www.hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html#doubling-mdbl-2007-bl func (p *G2Affine) Double(a *G2Affine) *G2Affine { var q G2Jac q.FromAffine(a) @@ -133,7 +141,8 @@ func (p *G2Affine) Double(a *G2Affine) *G2Affine { return p } -// Sub subs two point in affine coordinates. +// Sub subtracts two points in affine coordinates. +// It uses a similar approach to Add, but negates the second point before adding. func (p *G2Affine) Sub(a, b *G2Affine) *G2Affine { var bneg G2Affine bneg.Neg(b) @@ -141,19 +150,19 @@ func (p *G2Affine) Sub(a, b *G2Affine) *G2Affine { return p } -// Equal tests if two points (in Affine coordinates) are equal +// Equal tests if two points in affine coordinates are equal. func (p *G2Affine) Equal(a *G2Affine) bool { return p.X.Equal(&a.X) && p.Y.Equal(&a.Y) } -// Neg computes -G +// Neg sets p to the affine negative point -a = (a.X, -a.Y). func (p *G2Affine) Neg(a *G2Affine) *G2Affine { p.X = a.X p.Y.Neg(&a.Y) return p } -// FromJacobian rescales a point in Jacobian coord in z=1 plane +// FromJacobian converts a point p1 from Jacobian to affine coordinates. func (p *G2Affine) FromJacobian(p1 *G2Jac) *G2Affine { var a, b fp.Element @@ -172,7 +181,7 @@ func (p *G2Affine) FromJacobian(p1 *G2Jac) *G2Affine { return p } -// String returns the string representation of the point or "O" if it is infinity +// String returns the string representation E(x,y) of the affine point p or "O" if it is infinity. func (p *G2Affine) String() string { if p.IsInfinity() { return "O" @@ -180,21 +189,20 @@ func (p *G2Affine) String() string { return "E([" + p.X.String() + "," + p.Y.String() + "])" } -// IsInfinity checks if the point is infinity -// in affine, it's encoded as (0,0) -// (0,0) is never on the curve for j=0 curves +// IsInfinity checks if the affine point p is infinity, which is encoded as (0,0). +// N.B.: (0,0) is never on the curve for j=0 curves (Y²=X³+B). func (p *G2Affine) IsInfinity() bool { return p.X.IsZero() && p.Y.IsZero() } -// IsOnCurve returns true if p in on the curve +// IsOnCurve returns true if the affine point p in on the curve. func (p *G2Affine) IsOnCurve() bool { var point G2Jac point.FromAffine(p) return point.IsOnCurve() // call this function to handle infinity point } -// IsInSubGroup returns true if p is in the correct subgroup, false otherwise +// IsInSubGroup returns true if the affine point p is in the correct subgroup, false otherwise. func (p *G2Affine) IsInSubGroup() bool { var _p G2Jac _p.FromAffine(p) @@ -202,84 +210,76 @@ func (p *G2Affine) IsInSubGroup() bool { } // ------------------------------------------------------------------------------------------------- -// Jacobian +// Jacobian coordinates -// Set sets p to the provided point -func (p *G2Jac) Set(a *G2Jac) *G2Jac { - p.X, p.Y, p.Z = a.X, a.Y, a.Z +// Set sets p to a in Jacobian coordinates. +func (p *G2Jac) Set(q *G2Jac) *G2Jac { + p.X, p.Y, p.Z = q.X, q.Y, q.Z return p } -// Equal tests if two points (in Jacobian coordinates) are equal -func (p *G2Jac) Equal(a *G2Jac) bool { +// Equal tests if two points in Jacobian coordinates are equal. +func (p *G2Jac) Equal(q *G2Jac) bool { // If one point is infinity, the other must also be infinity. if p.Z.IsZero() { - return a.Z.IsZero() + return q.Z.IsZero() } // If the other point is infinity, return false since we can't // the following checks would be incorrect. - if a.Z.IsZero() { + if q.Z.IsZero() { return false } var pZSquare, aZSquare fp.Element pZSquare.Square(&p.Z) - aZSquare.Square(&a.Z) + aZSquare.Square(&q.Z) var lhs, rhs fp.Element lhs.Mul(&p.X, &aZSquare) - rhs.Mul(&a.X, &pZSquare) + rhs.Mul(&q.X, &pZSquare) if !lhs.Equal(&rhs) { return false } - lhs.Mul(&p.Y, &aZSquare).Mul(&lhs, &a.Z) - rhs.Mul(&a.Y, &pZSquare).Mul(&rhs, &p.Z) + lhs.Mul(&p.Y, &aZSquare).Mul(&lhs, &q.Z) + rhs.Mul(&q.Y, &pZSquare).Mul(&rhs, &p.Z) return lhs.Equal(&rhs) } -// Neg computes -G -func (p *G2Jac) Neg(a *G2Jac) *G2Jac { - *p = *a - p.Y.Neg(&a.Y) +// Neg sets p to the Jacobian negative point -q = (q.X, -q.Y, q.Z). +func (p *G2Jac) Neg(q *G2Jac) *G2Jac { + *p = *q + p.Y.Neg(&q.Y) return p } -// SubAssign subtracts two points on the curve -func (p *G2Jac) SubAssign(a *G2Jac) *G2Jac { - var tmp G2Jac - tmp.Set(a) - tmp.Y.Neg(&tmp.Y) - p.AddAssign(&tmp) - return p -} - -// AddAssign point addition in montgomery form +// AddAssign sets p to p+a in Jacobian coordinates. +// // https://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-3.html#addition-add-2007-bl -func (p *G2Jac) AddAssign(a *G2Jac) *G2Jac { +func (p *G2Jac) AddAssign(q *G2Jac) *G2Jac { - // p is infinity, return a + // p is infinity, return q if p.Z.IsZero() { - p.Set(a) + p.Set(q) return p } - // a is infinity, return p - if a.Z.IsZero() { + // q is infinity, return p + if q.Z.IsZero() { return p } var Z1Z1, Z2Z2, U1, U2, S1, S2, H, I, J, r, V fp.Element - Z1Z1.Square(&a.Z) + Z1Z1.Square(&q.Z) Z2Z2.Square(&p.Z) - U1.Mul(&a.X, &Z2Z2) + U1.Mul(&q.X, &Z2Z2) U2.Mul(&p.X, &Z1Z1) - S1.Mul(&a.Y, &p.Z). + S1.Mul(&q.Y, &p.Z). Mul(&S1, &Z2Z2) - S2.Mul(&p.Y, &a.Z). + S2.Mul(&p.Y, &q.Z). Mul(&S2, &Z1Z1) - // if p == a, we double instead + // if p == q, we double instead if U1.Equal(&U2) && S1.Equal(&S2) { return p.DoubleAssign() } @@ -298,7 +298,7 @@ func (p *G2Jac) AddAssign(a *G2Jac) *G2Jac { Mul(&p.Y, &r) S1.Mul(&S1, &J).Double(&S1) p.Y.Sub(&p.Y, &S1) - p.Z.Add(&p.Z, &a.Z) + p.Z.Add(&p.Z, &q.Z) p.Z.Square(&p.Z). Sub(&p.Z, &Z1Z1). Sub(&p.Z, &Z2Z2). @@ -307,8 +307,19 @@ func (p *G2Jac) AddAssign(a *G2Jac) *G2Jac { return p } -// DoubleMixed point addition -// http://www.hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html#doubling-mdbl-2007-bl +// SubAssign sets p to p-a in Jacobian coordinates. +// It uses a similar approach to AddAssign, but negates the point a before adding. +func (p *G2Jac) SubAssign(q *G2Jac) *G2Jac { + var tmp G2Jac + tmp.Set(q) + tmp.Y.Neg(&tmp.Y) + p.AddAssign(&tmp) + return p +} + +// Double sets p to [2]q in Jacobian coordinates. +// +// https://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-3.html#doubling-dbl-2007-bl func (p *G2Jac) DoubleMixed(a *G2Affine) *G2Jac { var XX, YY, YYYY, S, M, T fp.Element XX.Square(&a.X) @@ -320,7 +331,7 @@ func (p *G2Jac) DoubleMixed(a *G2Affine) *G2Jac { Sub(&S, &YYYY). Double(&S) M.Double(&XX). - Add(&M, &XX) // -> + a, but a=0 here + Add(&M, &XX) // -> + A, but A=0 here T.Square(&M). Sub(&T, &S). Sub(&T, &S) @@ -336,7 +347,8 @@ func (p *G2Jac) DoubleMixed(a *G2Affine) *G2Jac { return p } -// AddMixed point addition +// AddMixed sets p to p+a in Jacobian coordinates, where a.Z = 1. +// // http://www.hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html#addition-madd-2007-bl func (p *G2Jac) AddMixed(a *G2Affine) *G2Jac { @@ -385,7 +397,8 @@ func (p *G2Jac) AddMixed(a *G2Affine) *G2Jac { return p } -// Double doubles a point in Jacobian coordinates +// Double sets p to [2]q in Jacobian coordinates. +// // https://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-3.html#doubling-dbl-2007-bl func (p *G2Jac) Double(q *G2Jac) *G2Jac { p.Set(q) @@ -393,7 +406,8 @@ func (p *G2Jac) Double(q *G2Jac) *G2Jac { return p } -// DoubleAssign doubles a point in Jacobian coordinates +// DoubleAssign doubles p in Jacobian coordinates. +// // https://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-3.html#doubling-dbl-2007-bl func (p *G2Jac) DoubleAssign() *G2Jac { @@ -425,34 +439,36 @@ func (p *G2Jac) DoubleAssign() *G2Jac { return p } -// ScalarMultiplication computes and returns p = a ⋅ s +// ScalarMultiplication computes and returns p = [s]a +// where p and a are Jacobian points. +// using the GLV technique. // see https://www.iacr.org/archive/crypto2001/21390189.pdf -func (p *G2Jac) ScalarMultiplication(a *G2Jac, s *big.Int) *G2Jac { - return p.mulGLV(a, s) +func (p *G2Jac) ScalarMultiplication(q *G2Jac, s *big.Int) *G2Jac { + return p.mulGLV(q, s) } -// String returns canonical representation of the point in affine coordinates +// String converts p to affine coordinates and returns its string representation E(x,y) or "O" if it is infinity. func (p *G2Jac) String() string { _p := G2Affine{} _p.FromJacobian(p) return _p.String() } -// FromAffine sets p = Q, p in Jacobian, Q in affine -func (p *G2Jac) FromAffine(Q *G2Affine) *G2Jac { - if Q.IsInfinity() { +// FromAffine converts a point a from affine to Jacobian coordinates. +func (p *G2Jac) FromAffine(a *G2Affine) *G2Jac { + if a.IsInfinity() { p.Z.SetZero() p.X.SetOne() p.Y.SetOne() return p } p.Z.SetOne() - p.X.Set(&Q.X) - p.Y.Set(&Q.Y) + p.X.Set(&a.X) + p.Y.Set(&a.Y) return p } -// IsOnCurve returns true if p in on the curve +// IsOnCurve returns true if the Jacobian point p in on the curve. func (p *G2Jac) IsOnCurve() bool { var left, right, tmp, ZZ fp.Element left.Square(&p.Y) @@ -487,13 +503,14 @@ func (p *G2Jac) IsInSubGroup() bool { } -// mulWindowed computes a 2-bits windowed scalar multiplication -func (p *G2Jac) mulWindowed(a *G2Jac, s *big.Int) *G2Jac { +// mulWindowed computes the 2-bits windowed double-and-add scalar +// multiplication p=[s]q in Jacobian coordinates. +func (p *G2Jac) mulWindowed(q *G2Jac, s *big.Int) *G2Jac { var res G2Jac var ops [3]G2Jac - ops[0].Set(a) + ops[0].Set(q) if s.Sign() == -1 { ops[0].Neg(&ops[0]) } @@ -520,17 +537,18 @@ func (p *G2Jac) mulWindowed(a *G2Jac, s *big.Int) *G2Jac { } -// ϕ assigns p to ϕ(a) where ϕ: (x,y) → (w x,y), and returns p -// where w is a third root of unity in 𝔽p -func (p *G2Jac) phi(a *G2Jac) *G2Jac { - p.Set(a) +// phi sets p to ϕ(a) where ϕ: (x,y) → (w x,y), +// where w is a third root of unity. +func (p *G2Jac) phi(q *G2Jac) *G2Jac { + p.Set(q) p.X.Mul(&p.X, &thirdRootOneG2) return p } // mulGLV computes the scalar multiplication using a windowed-GLV method +// // see https://www.iacr.org/archive/crypto2001/21390189.pdf -func (p *G2Jac) mulGLV(a *G2Jac, s *big.Int) *G2Jac { +func (p *G2Jac) mulGLV(q *G2Jac, s *big.Int) *G2Jac { var table [15]G2Jac var res G2Jac @@ -538,11 +556,11 @@ func (p *G2Jac) mulGLV(a *G2Jac, s *big.Int) *G2Jac { res.Set(&g2Infinity) - // table[b3b2b1b0-1] = b3b2 ⋅ ϕ(a) + b1b0*a - table[0].Set(a) - table[3].phi(a) + // table[b3b2b1b0-1] = b3b2 ⋅ ϕ(q) + b1b0*q + table[0].Set(q) + table[3].phi(q) - // split the scalar, modifies ±a, ϕ(a) accordingly + // split the scalar, modifies ±q, ϕ(q) accordingly k := ecc.SplitScalar(s, &glvBasis) if k[0].Sign() == -1 { @@ -555,7 +573,7 @@ func (p *G2Jac) mulGLV(a *G2Jac, s *big.Int) *G2Jac { } // precompute table (2 bits sliding window) - // table[b3b2b1b0-1] = b3b2 ⋅ ϕ(a) + b1b0 ⋅ a if b3b2b1b0 != 0 + // table[b3b2b1b0-1] = b3b2 ⋅ ϕ(q) + b1b0 ⋅ q if b3b2b1b0 != 0 table[1].Double(&table[0]) table[2].Set(&table[1]).AddAssign(&table[0]) table[4].Set(&table[3]).AddAssign(&table[0]) @@ -611,20 +629,20 @@ func (p *G2Affine) ClearCofactor(a *G2Affine) *G2Affine { } // ClearCofactor maps a point in curve to r-torsion -func (p *G2Jac) ClearCofactor(a *G2Jac) *G2Jac { +func (p *G2Jac) ClearCofactor(q *G2Jac) *G2Jac { var L0, L1, uP, u2P, u3P, tmp G2Jac - uP.ScalarMultiplication(a, &xGen) + uP.ScalarMultiplication(q, &xGen) u2P.ScalarMultiplication(&uP, &xGen) u3P.ScalarMultiplication(&u2P, &xGen) // ht=-2, hy=0 // d1=1, d2=-1, d3=-1 - L0.Set(a). + L0.Set(q). AddAssign(&u2P). SubAssign(&uP) tmp.Set(&u2P). - AddAssign(a). + AddAssign(q). SubAssign(&uP). Double(&tmp) L1.Set(&u3P). @@ -637,15 +655,15 @@ func (p *G2Jac) ClearCofactor(a *G2Jac) *G2Jac { } // ------------------------------------------------------------------------------------------------- -// Jacobian extended +// extended Jacobian coordinates -// Set sets p to the provided point -func (p *g2JacExtended) Set(a *g2JacExtended) *g2JacExtended { - p.X, p.Y, p.ZZ, p.ZZZ = a.X, a.Y, a.ZZ, a.ZZZ +// Set sets p to a in extended Jacobian coordinates. +func (p *g2JacExtended) Set(q *g2JacExtended) *g2JacExtended { + p.X, p.Y, p.ZZ, p.ZZZ = q.X, q.Y, q.ZZ, q.ZZZ return p } -// setInfinity sets p to O +// setInfinity sets p to the infinity point (1,1,0,0). func (p *g2JacExtended) setInfinity() *g2JacExtended { p.X.SetOne() p.Y.SetOne() @@ -654,43 +672,45 @@ func (p *g2JacExtended) setInfinity() *g2JacExtended { return p } -func (p *g2JacExtended) IsZero() bool { +// IsInfinity checks if the p is infinity, i.e. p.ZZ=0. +func (p *g2JacExtended) IsInfinity() bool { return p.ZZ.IsZero() } -// fromJacExtended sets Q in affine coordinates -func (p *G2Affine) fromJacExtended(Q *g2JacExtended) *G2Affine { - if Q.ZZ.IsZero() { +// fromJacExtended converts an extended Jacobian point to an affine point. +func (p *G2Affine) fromJacExtended(q *g2JacExtended) *G2Affine { + if q.ZZ.IsZero() { p.X = fp.Element{} p.Y = fp.Element{} return p } - p.X.Inverse(&Q.ZZ).Mul(&p.X, &Q.X) - p.Y.Inverse(&Q.ZZZ).Mul(&p.Y, &Q.Y) + p.X.Inverse(&q.ZZ).Mul(&p.X, &q.X) + p.Y.Inverse(&q.ZZZ).Mul(&p.Y, &q.Y) return p } -// fromJacExtended sets Q in Jacobian coordinates -func (p *G2Jac) fromJacExtended(Q *g2JacExtended) *G2Jac { - if Q.ZZ.IsZero() { +// fromJacExtended converts an extended Jacobian point to a Jacobian point. +func (p *G2Jac) fromJacExtended(q *g2JacExtended) *G2Jac { + if q.ZZ.IsZero() { p.Set(&g2Infinity) return p } - p.X.Mul(&Q.ZZ, &Q.X).Mul(&p.X, &Q.ZZ) - p.Y.Mul(&Q.ZZZ, &Q.Y).Mul(&p.Y, &Q.ZZZ) - p.Z.Set(&Q.ZZZ) + p.X.Mul(&q.ZZ, &q.X).Mul(&p.X, &q.ZZ) + p.Y.Mul(&q.ZZZ, &q.Y).Mul(&p.Y, &q.ZZZ) + p.Z.Set(&q.ZZZ) return p } -// unsafeFromJacExtended sets p in Jacobian coordinates, but don't check for infinity -func (p *G2Jac) unsafeFromJacExtended(Q *g2JacExtended) *G2Jac { - p.X.Square(&Q.ZZ).Mul(&p.X, &Q.X) - p.Y.Square(&Q.ZZZ).Mul(&p.Y, &Q.Y) - p.Z = Q.ZZZ +// unsafeFromJacExtended converts an extended Jacobian point, distinct from Infinity, to a Jacobian point. +func (p *G2Jac) unsafeFromJacExtended(q *g2JacExtended) *G2Jac { + p.X.Square(&q.ZZ).Mul(&p.X, &q.X) + p.Y.Square(&q.ZZZ).Mul(&p.Y, &q.Y) + p.Z = q.ZZZ return p } -// add point in Jacobian extended coordinates +// add sets p to p+q in extended Jacobian coordinates. +// // https://www.hyperelliptic.org/EFD/g1p/auto-shortw-xyzz.html#addition-add-2008-s func (p *g2JacExtended) add(q *g2JacExtended) *g2JacExtended { //if q is infinity return p @@ -746,10 +766,11 @@ func (p *g2JacExtended) add(q *g2JacExtended) *g2JacExtended { return p } -// double point in Jacobian extended coordinates +// double sets p to [2]q in Jacobian extended coordinates. +// // http://www.hyperelliptic.org/EFD/g1p/auto-shortw-xyzz.html#doubling-dbl-2008-s-1 -// since we consider any point on Z=0 as the point at infinity -// this doubling formula works for infinity points as well +// N.B.: since we consider any point on Z=0 as the point at infinity +// this doubling formula works for infinity points as well. func (p *g2JacExtended) double(q *g2JacExtended) *g2JacExtended { var U, V, W, S, XX, M fp.Element @@ -759,7 +780,7 @@ func (p *g2JacExtended) double(q *g2JacExtended) *g2JacExtended { S.Mul(&q.X, &V) XX.Square(&q.X) M.Double(&XX). - Add(&M, &XX) // -> + a, but a=0 here + Add(&M, &XX) // -> + A, but A=0 here U.Mul(&W, &q.Y) p.X.Square(&M). @@ -774,9 +795,10 @@ func (p *g2JacExtended) double(q *g2JacExtended) *g2JacExtended { return p } -// subMixed same as addMixed, but will negate a.Y +// addMixed sets p to p+q in extended Jacobian coordinates, where a.ZZ=1. +// // http://www.hyperelliptic.org/EFD/g1p/auto-shortw-xyzz.html#addition-madd-2008-s -func (p *g2JacExtended) subMixed(a *G2Affine) *g2JacExtended { +func (p *g2JacExtended) addMixed(a *G2Affine) *g2JacExtended { //if a is infinity return p if a.IsInfinity() { @@ -785,7 +807,7 @@ func (p *g2JacExtended) subMixed(a *G2Affine) *g2JacExtended { // p is infinity, return a if p.ZZ.IsZero() { p.X = a.X - p.Y.Neg(&a.Y) + p.Y = a.Y p.ZZ.SetOne() p.ZZZ.SetOne() return p @@ -798,12 +820,11 @@ func (p *g2JacExtended) subMixed(a *G2Affine) *g2JacExtended { P.Sub(&P, &p.X) R.Mul(&a.Y, &p.ZZZ) - R.Neg(&R) R.Sub(&R, &p.Y) if P.IsZero() { if R.IsZero() { - return p.doubleNegMixed(a) + return p.doubleMixed(a) } p.ZZ = fp.Element{} @@ -830,9 +851,10 @@ func (p *g2JacExtended) subMixed(a *G2Affine) *g2JacExtended { } -// addMixed +// subMixed works the same as addMixed, but negates a.Y. +// // http://www.hyperelliptic.org/EFD/g1p/auto-shortw-xyzz.html#addition-madd-2008-s -func (p *g2JacExtended) addMixed(a *G2Affine) *g2JacExtended { +func (p *g2JacExtended) subMixed(a *G2Affine) *g2JacExtended { //if a is infinity return p if a.IsInfinity() { @@ -841,7 +863,7 @@ func (p *g2JacExtended) addMixed(a *G2Affine) *g2JacExtended { // p is infinity, return a if p.ZZ.IsZero() { p.X = a.X - p.Y = a.Y + p.Y.Neg(&a.Y) p.ZZ.SetOne() p.ZZZ.SetOne() return p @@ -854,11 +876,12 @@ func (p *g2JacExtended) addMixed(a *G2Affine) *g2JacExtended { P.Sub(&P, &p.X) R.Mul(&a.Y, &p.ZZZ) + R.Neg(&R) R.Sub(&R, &p.Y) if P.IsZero() { if R.IsZero() { - return p.doubleMixed(a) + return p.doubleNegMixed(a) } p.ZZ = fp.Element{} @@ -885,21 +908,21 @@ func (p *g2JacExtended) addMixed(a *G2Affine) *g2JacExtended { } -// doubleNegMixed same as double, but will negate q.Y -func (p *g2JacExtended) doubleNegMixed(q *G2Affine) *g2JacExtended { +// doubleNegMixed works the same as double, but negates q.Y. +func (p *g2JacExtended) doubleNegMixed(a *G2Affine) *g2JacExtended { var U, V, W, S, XX, M, S2, L fp.Element - U.Double(&q.Y) + U.Double(&a.Y) U.Neg(&U) V.Square(&U) W.Mul(&U, &V) - S.Mul(&q.X, &V) - XX.Square(&q.X) + S.Mul(&a.X, &V) + XX.Square(&a.X) M.Double(&XX). - Add(&M, &XX) // -> + a, but a=0 here + Add(&M, &XX) // -> + A, but A=0 here S2.Double(&S) - L.Mul(&W, &q.Y) + L.Mul(&W, &a.Y) p.X.Square(&M). Sub(&p.X, &S2) @@ -912,21 +935,22 @@ func (p *g2JacExtended) doubleNegMixed(q *G2Affine) *g2JacExtended { return p } -// doubleMixed point in Jacobian extended coordinates +// doubleMixed sets p to [2]a in Jacobian extended coordinates, where a.ZZ=1. +// // http://www.hyperelliptic.org/EFD/g1p/auto-shortw-xyzz.html#doubling-dbl-2008-s-1 -func (p *g2JacExtended) doubleMixed(q *G2Affine) *g2JacExtended { +func (p *g2JacExtended) doubleMixed(a *G2Affine) *g2JacExtended { var U, V, W, S, XX, M, S2, L fp.Element - U.Double(&q.Y) + U.Double(&a.Y) V.Square(&U) W.Mul(&U, &V) - S.Mul(&q.X, &V) - XX.Square(&q.X) + S.Mul(&a.X, &V) + XX.Square(&a.X) M.Double(&XX). - Add(&M, &XX) // -> + a, but a=0 here + Add(&M, &XX) // -> + A, but A=0 here S2.Double(&S) - L.Mul(&W, &q.Y) + L.Mul(&W, &a.Y) p.X.Square(&M). Sub(&p.X, &S2) @@ -940,38 +964,38 @@ func (p *g2JacExtended) doubleMixed(q *G2Affine) *g2JacExtended { } // ------------------------------------------------------------------------------------------------- -// Homogenous projective +// Homogenous projective coordinates -// Set sets p to the provided point -func (p *g2Proj) Set(a *g2Proj) *g2Proj { - p.x, p.y, p.z = a.x, a.y, a.z +// Set sets p to a in projective coordinates. +func (p *g2Proj) Set(q *g2Proj) *g2Proj { + p.x, p.y, p.z = q.x, q.y, q.z return p } -// Neg computes -G -func (p *g2Proj) Neg(a *g2Proj) *g2Proj { - *p = *a - p.y.Neg(&a.y) +// Neg sets p to the projective negative point -q = (q.X, -q.Y). +func (p *g2Proj) Neg(q *g2Proj) *g2Proj { + *p = *q + p.y.Neg(&q.y) return p } -// FromAffine sets p = Q, p in homogenous projective, Q in affine -func (p *g2Proj) FromAffine(Q *G2Affine) *g2Proj { - if Q.X.IsZero() && Q.Y.IsZero() { +// FromAffine converts q in affine to p in projective coordinates. +func (p *g2Proj) FromAffine(a *G2Affine) *g2Proj { + if a.X.IsZero() && a.Y.IsZero() { p.z.SetZero() p.x.SetOne() p.y.SetOne() return p } p.z.SetOne() - p.x.Set(&Q.X) - p.y.Set(&Q.Y) + p.x.Set(&a.X) + p.y.Set(&a.Y) return p } // BatchScalarMultiplicationG2 multiplies the same base by all scalars // and return resulting points in affine coordinates -// uses a simple windowed-NAF like exponentiation algorithm +// uses a simple windowed-NAF-like multiplication algorithm. func BatchScalarMultiplicationG2(base *G2Affine, scalars []fr.Element) []G2Affine { // approximate cost in group ops is // cost = 2^{c-1} + n(scalar.nbBits+nbChunks) @@ -1050,9 +1074,8 @@ func BatchScalarMultiplicationG2(base *G2Affine, scalars []fr.Element) []G2Affin return toReturn } -// batch add affine coordinates -// using batch inversion -// special cases (doubling, infinity) must be filtered out before this call +// batchAddG1Affine adds affine points using the Montgomery batch inversion trick. +// Special cases (doubling, infinity) must be filtered out before this call. func batchAddG2Affine[TP pG2Affine, TPP ppG2Affine, TC cG2Affine](R *TPP, P *TP, batchSize int) { var lambda, lambdain TC diff --git a/ecc/bw6-756/multiexp_affine.go b/ecc/bw6-756/multiexp_affine.go index f2ab30472..a3dcf88cb 100644 --- a/ecc/bw6-756/multiexp_affine.go +++ b/ecc/bw6-756/multiexp_affine.go @@ -225,7 +225,7 @@ func processChunkG1BatchAffine[BJE ibg1JacExtended, B ibG1Affine, BS bitSet, TP total.setInfinity() for k := len(buckets) - 1; k >= 0; k-- { runningSum.addMixed(&buckets[k]) - if !bucketsJE[k].IsZero() { + if !bucketsJE[k].IsInfinity() { runningSum.add(&bucketsJE[k]) } total.add(&runningSum) @@ -493,7 +493,7 @@ func processChunkG2BatchAffine[BJE ibg2JacExtended, B ibG2Affine, BS bitSet, TP total.setInfinity() for k := len(buckets) - 1; k >= 0; k-- { runningSum.addMixed(&buckets[k]) - if !bucketsJE[k].IsZero() { + if !bucketsJE[k].IsInfinity() { runningSum.add(&bucketsJE[k]) } total.add(&runningSum) diff --git a/ecc/bw6-756/multiexp_jacobian.go b/ecc/bw6-756/multiexp_jacobian.go index 13c370337..5dc50140f 100644 --- a/ecc/bw6-756/multiexp_jacobian.go +++ b/ecc/bw6-756/multiexp_jacobian.go @@ -56,7 +56,7 @@ func processChunkG1Jacobian[B ibg1JacExtended](chunk uint64, runningSum.setInfinity() total.setInfinity() for k := len(buckets) - 1; k >= 0; k-- { - if !buckets[k].IsZero() { + if !buckets[k].IsInfinity() { runningSum.add(&buckets[k]) } total.add(&runningSum) @@ -129,7 +129,7 @@ func processChunkG2Jacobian[B ibg2JacExtended](chunk uint64, runningSum.setInfinity() total.setInfinity() for k := len(buckets) - 1; k >= 0; k-- { - if !buckets[k].IsZero() { + if !buckets[k].IsInfinity() { runningSum.add(&buckets[k]) } total.add(&runningSum) diff --git a/ecc/bw6-761/g1.go b/ecc/bw6-761/g1.go index 0b6198fe6..365139218 100644 --- a/ecc/bw6-761/g1.go +++ b/ecc/bw6-761/g1.go @@ -25,38 +25,40 @@ import ( "runtime" ) -// G1Affine point in affine coordinates +// G1Affine is a point in affine coordinates (x,y) type G1Affine struct { X, Y fp.Element } -// G1Jac is a point with fp.Element coordinates +// G1Jac is a point in Jacobian coordinates (x=X/Z², y=Y/Z³) type G1Jac struct { X, Y, Z fp.Element } -// g1JacExtended parameterized Jacobian coordinates (x=X/ZZ, y=Y/ZZZ, ZZ³=ZZZ²) +// g1JacExtended is a point in extended Jacobian coordinates (x=X/ZZ, y=Y/ZZZ, ZZ³=ZZZ²) type g1JacExtended struct { X, Y, ZZ, ZZZ fp.Element } // ------------------------------------------------------------------------------------------------- -// Affine +// Affine coordinates -// Set sets p to the provided point +// Set sets p to a in affine coordinates. func (p *G1Affine) Set(a *G1Affine) *G1Affine { p.X, p.Y = a.X, a.Y return p } -// setInfinity sets p to O +// setInfinity sets p to the infinity point, which is encoded as (0,0). +// N.B.: (0,0) is never on the curve for j=0 curves (Y²=X³+B). func (p *G1Affine) setInfinity() *G1Affine { p.X.SetZero() p.Y.SetZero() return p } -// ScalarMultiplication computes and returns p = a ⋅ s +// ScalarMultiplication computes and returns p = [s]a +// where p and a are affine points. func (p *G1Affine) ScalarMultiplication(a *G1Affine, s *big.Int) *G1Affine { var _p G1Jac _p.FromAffine(a) @@ -65,20 +67,22 @@ func (p *G1Affine) ScalarMultiplication(a *G1Affine, s *big.Int) *G1Affine { return p } -// ScalarMultiplicationAffine computes and returns p = a ⋅ s -// Takes an affine point and returns a Jacobian point (useful for KZG) +// ScalarMultiplicationAffine computes and returns p = [s]a +// where a is an affine point and p a Jacobian point (useful for KZG). func (p *G1Jac) ScalarMultiplicationAffine(a *G1Affine, s *big.Int) *G1Jac { p.FromAffine(a) p.mulGLV(p, s) return p } -// ScalarMultiplicationBase computes and returns p = g ⋅ s where g is the prime subgroup generator +// ScalarMultiplicationBase computes and returns p = [s]g +// where g is the Jacobian point generating the prime subgroup. func (p *G1Jac) ScalarMultiplicationBase(s *big.Int) *G1Jac { return p.mulGLV(&g1Gen, s) } -// ScalarMultiplicationBase computes and returns p = g ⋅ s where g is the prime subgroup generator +// ScalarMultiplicationBase computes and returns p = [s]g +// where g is the affine point generating the prime subgroup. func (p *G1Affine) ScalarMultiplicationBase(s *big.Int) *G1Affine { var _p G1Jac _p.mulGLV(&g1Gen, s) @@ -86,8 +90,9 @@ func (p *G1Affine) ScalarMultiplicationBase(s *big.Int) *G1Affine { return p } -// Add adds two point in affine coordinates. -// Jacobian addition with Z1=Z2=1 +// Add adds two points in affine coordinates. +// It uses the Jacobian addition with a.Z=b.Z=1 and converts the result to affine coordinates. +// // https://www.hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html#addition-mmadd-2007-bl func (p *G1Affine) Add(a, b *G1Affine) *G1Affine { var q G1Jac @@ -133,6 +138,10 @@ func (p *G1Affine) Add(a, b *G1Affine) *G1Affine { } // Double doubles a point in affine coordinates. +// It converts the point to Jacobian coordinates, doubles it using Jacobian +// addition with a.Z=1, and converts it back to affine coordinates. +// +// http://www.hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html#doubling-mdbl-2007-bl func (p *G1Affine) Double(a *G1Affine) *G1Affine { var q G1Jac q.FromAffine(a) @@ -141,7 +150,8 @@ func (p *G1Affine) Double(a *G1Affine) *G1Affine { return p } -// Sub subs two point in affine coordinates. +// Sub subtracts two points in affine coordinates. +// It uses a similar approach to Add, but negates the second point before adding. func (p *G1Affine) Sub(a, b *G1Affine) *G1Affine { var bneg G1Affine bneg.Neg(b) @@ -149,19 +159,19 @@ func (p *G1Affine) Sub(a, b *G1Affine) *G1Affine { return p } -// Equal tests if two points (in Affine coordinates) are equal +// Equal tests if two points in affine coordinates are equal. func (p *G1Affine) Equal(a *G1Affine) bool { return p.X.Equal(&a.X) && p.Y.Equal(&a.Y) } -// Neg computes -G +// Neg sets p to the affine negative point -a = (a.X, -a.Y). func (p *G1Affine) Neg(a *G1Affine) *G1Affine { p.X = a.X p.Y.Neg(&a.Y) return p } -// FromJacobian rescales a point in Jacobian coord in z=1 plane +// FromJacobian converts a point p1 from Jacobian to affine coordinates. func (p *G1Affine) FromJacobian(p1 *G1Jac) *G1Affine { var a, b fp.Element @@ -180,7 +190,7 @@ func (p *G1Affine) FromJacobian(p1 *G1Jac) *G1Affine { return p } -// String returns the string representation of the point or "O" if it is infinity +// String returns the string representation E(x,y) of the affine point p or "O" if it is infinity. func (p *G1Affine) String() string { if p.IsInfinity() { return "O" @@ -188,21 +198,20 @@ func (p *G1Affine) String() string { return "E([" + p.X.String() + "," + p.Y.String() + "])" } -// IsInfinity checks if the point is infinity -// in affine, it's encoded as (0,0) -// (0,0) is never on the curve for j=0 curves +// IsInfinity checks if the affine point p is infinity, which is encoded as (0,0). +// N.B.: (0,0) is never on the curve for j=0 curves (Y²=X³+B). func (p *G1Affine) IsInfinity() bool { return p.X.IsZero() && p.Y.IsZero() } -// IsOnCurve returns true if p in on the curve +// IsOnCurve returns true if the affine point p in on the curve. func (p *G1Affine) IsOnCurve() bool { var point G1Jac point.FromAffine(p) return point.IsOnCurve() // call this function to handle infinity point } -// IsInSubGroup returns true if p is in the correct subgroup, false otherwise +// IsInSubGroup returns true if the affine point p is in the correct subgroup, false otherwise. func (p *G1Affine) IsInSubGroup() bool { var _p G1Jac _p.FromAffine(p) @@ -210,84 +219,76 @@ func (p *G1Affine) IsInSubGroup() bool { } // ------------------------------------------------------------------------------------------------- -// Jacobian +// Jacobian coordinates -// Set sets p to the provided point -func (p *G1Jac) Set(a *G1Jac) *G1Jac { - p.X, p.Y, p.Z = a.X, a.Y, a.Z +// Set sets p to a in Jacobian coordinates. +func (p *G1Jac) Set(q *G1Jac) *G1Jac { + p.X, p.Y, p.Z = q.X, q.Y, q.Z return p } -// Equal tests if two points (in Jacobian coordinates) are equal -func (p *G1Jac) Equal(a *G1Jac) bool { +// Equal tests if two points in Jacobian coordinates are equal. +func (p *G1Jac) Equal(q *G1Jac) bool { // If one point is infinity, the other must also be infinity. if p.Z.IsZero() { - return a.Z.IsZero() + return q.Z.IsZero() } // If the other point is infinity, return false since we can't // the following checks would be incorrect. - if a.Z.IsZero() { + if q.Z.IsZero() { return false } var pZSquare, aZSquare fp.Element pZSquare.Square(&p.Z) - aZSquare.Square(&a.Z) + aZSquare.Square(&q.Z) var lhs, rhs fp.Element lhs.Mul(&p.X, &aZSquare) - rhs.Mul(&a.X, &pZSquare) + rhs.Mul(&q.X, &pZSquare) if !lhs.Equal(&rhs) { return false } - lhs.Mul(&p.Y, &aZSquare).Mul(&lhs, &a.Z) - rhs.Mul(&a.Y, &pZSquare).Mul(&rhs, &p.Z) + lhs.Mul(&p.Y, &aZSquare).Mul(&lhs, &q.Z) + rhs.Mul(&q.Y, &pZSquare).Mul(&rhs, &p.Z) return lhs.Equal(&rhs) } -// Neg computes -G -func (p *G1Jac) Neg(a *G1Jac) *G1Jac { - *p = *a - p.Y.Neg(&a.Y) +// Neg sets p to the Jacobian negative point -q = (q.X, -q.Y, q.Z). +func (p *G1Jac) Neg(q *G1Jac) *G1Jac { + *p = *q + p.Y.Neg(&q.Y) return p } -// SubAssign subtracts two points on the curve -func (p *G1Jac) SubAssign(a *G1Jac) *G1Jac { - var tmp G1Jac - tmp.Set(a) - tmp.Y.Neg(&tmp.Y) - p.AddAssign(&tmp) - return p -} - -// AddAssign point addition in montgomery form +// AddAssign sets p to p+a in Jacobian coordinates. +// // https://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-3.html#addition-add-2007-bl -func (p *G1Jac) AddAssign(a *G1Jac) *G1Jac { +func (p *G1Jac) AddAssign(q *G1Jac) *G1Jac { - // p is infinity, return a + // p is infinity, return q if p.Z.IsZero() { - p.Set(a) + p.Set(q) return p } - // a is infinity, return p - if a.Z.IsZero() { + // q is infinity, return p + if q.Z.IsZero() { return p } var Z1Z1, Z2Z2, U1, U2, S1, S2, H, I, J, r, V fp.Element - Z1Z1.Square(&a.Z) + Z1Z1.Square(&q.Z) Z2Z2.Square(&p.Z) - U1.Mul(&a.X, &Z2Z2) + U1.Mul(&q.X, &Z2Z2) U2.Mul(&p.X, &Z1Z1) - S1.Mul(&a.Y, &p.Z). + S1.Mul(&q.Y, &p.Z). Mul(&S1, &Z2Z2) - S2.Mul(&p.Y, &a.Z). + S2.Mul(&p.Y, &q.Z). Mul(&S2, &Z1Z1) - // if p == a, we double instead + // if p == q, we double instead if U1.Equal(&U2) && S1.Equal(&S2) { return p.DoubleAssign() } @@ -306,7 +307,7 @@ func (p *G1Jac) AddAssign(a *G1Jac) *G1Jac { Mul(&p.Y, &r) S1.Mul(&S1, &J).Double(&S1) p.Y.Sub(&p.Y, &S1) - p.Z.Add(&p.Z, &a.Z) + p.Z.Add(&p.Z, &q.Z) p.Z.Square(&p.Z). Sub(&p.Z, &Z1Z1). Sub(&p.Z, &Z2Z2). @@ -315,8 +316,19 @@ func (p *G1Jac) AddAssign(a *G1Jac) *G1Jac { return p } -// DoubleMixed point addition -// http://www.hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html#doubling-mdbl-2007-bl +// SubAssign sets p to p-a in Jacobian coordinates. +// It uses a similar approach to AddAssign, but negates the point a before adding. +func (p *G1Jac) SubAssign(q *G1Jac) *G1Jac { + var tmp G1Jac + tmp.Set(q) + tmp.Y.Neg(&tmp.Y) + p.AddAssign(&tmp) + return p +} + +// Double sets p to [2]q in Jacobian coordinates. +// +// https://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-3.html#doubling-dbl-2007-bl func (p *G1Jac) DoubleMixed(a *G1Affine) *G1Jac { var XX, YY, YYYY, S, M, T fp.Element XX.Square(&a.X) @@ -328,7 +340,7 @@ func (p *G1Jac) DoubleMixed(a *G1Affine) *G1Jac { Sub(&S, &YYYY). Double(&S) M.Double(&XX). - Add(&M, &XX) // -> + a, but a=0 here + Add(&M, &XX) // -> + A, but A=0 here T.Square(&M). Sub(&T, &S). Sub(&T, &S) @@ -344,7 +356,8 @@ func (p *G1Jac) DoubleMixed(a *G1Affine) *G1Jac { return p } -// AddMixed point addition +// AddMixed sets p to p+a in Jacobian coordinates, where a.Z = 1. +// // http://www.hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html#addition-madd-2007-bl func (p *G1Jac) AddMixed(a *G1Affine) *G1Jac { @@ -393,7 +406,8 @@ func (p *G1Jac) AddMixed(a *G1Affine) *G1Jac { return p } -// Double doubles a point in Jacobian coordinates +// Double sets p to [2]q in Jacobian coordinates. +// // https://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-3.html#doubling-dbl-2007-bl func (p *G1Jac) Double(q *G1Jac) *G1Jac { p.Set(q) @@ -401,7 +415,8 @@ func (p *G1Jac) Double(q *G1Jac) *G1Jac { return p } -// DoubleAssign doubles a point in Jacobian coordinates +// DoubleAssign doubles p in Jacobian coordinates. +// // https://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-3.html#doubling-dbl-2007-bl func (p *G1Jac) DoubleAssign() *G1Jac { @@ -433,34 +448,36 @@ func (p *G1Jac) DoubleAssign() *G1Jac { return p } -// ScalarMultiplication computes and returns p = a ⋅ s +// ScalarMultiplication computes and returns p = [s]a +// where p and a are Jacobian points. +// using the GLV technique. // see https://www.iacr.org/archive/crypto2001/21390189.pdf -func (p *G1Jac) ScalarMultiplication(a *G1Jac, s *big.Int) *G1Jac { - return p.mulGLV(a, s) +func (p *G1Jac) ScalarMultiplication(q *G1Jac, s *big.Int) *G1Jac { + return p.mulGLV(q, s) } -// String returns canonical representation of the point in affine coordinates +// String converts p to affine coordinates and returns its string representation E(x,y) or "O" if it is infinity. func (p *G1Jac) String() string { _p := G1Affine{} _p.FromJacobian(p) return _p.String() } -// FromAffine sets p = Q, p in Jacobian, Q in affine -func (p *G1Jac) FromAffine(Q *G1Affine) *G1Jac { - if Q.IsInfinity() { +// FromAffine converts a point a from affine to Jacobian coordinates. +func (p *G1Jac) FromAffine(a *G1Affine) *G1Jac { + if a.IsInfinity() { p.Z.SetZero() p.X.SetOne() p.Y.SetOne() return p } p.Z.SetOne() - p.X.Set(&Q.X) - p.Y.Set(&Q.Y) + p.X.Set(&a.X) + p.Y.Set(&a.Y) return p } -// IsOnCurve returns true if p in on the curve +// IsOnCurve returns true if the Jacobian point p in on the curve. func (p *G1Jac) IsOnCurve() bool { var left, right, tmp, ZZ fp.Element left.Square(&p.Y) @@ -496,13 +513,14 @@ func (p *G1Jac) IsInSubGroup() bool { } -// mulWindowed computes a 2-bits windowed scalar multiplication -func (p *G1Jac) mulWindowed(a *G1Jac, s *big.Int) *G1Jac { +// mulWindowed computes the 2-bits windowed double-and-add scalar +// multiplication p=[s]q in Jacobian coordinates. +func (p *G1Jac) mulWindowed(q *G1Jac, s *big.Int) *G1Jac { var res G1Jac var ops [3]G1Jac - ops[0].Set(a) + ops[0].Set(q) if s.Sign() == -1 { ops[0].Neg(&ops[0]) } @@ -529,17 +547,18 @@ func (p *G1Jac) mulWindowed(a *G1Jac, s *big.Int) *G1Jac { } -// ϕ assigns p to ϕ(a) where ϕ: (x,y) → (w x,y), and returns p -// where w is a third root of unity in 𝔽p -func (p *G1Jac) phi(a *G1Jac) *G1Jac { - p.Set(a) +// phi sets p to ϕ(a) where ϕ: (x,y) → (w x,y), +// where w is a third root of unity. +func (p *G1Jac) phi(q *G1Jac) *G1Jac { + p.Set(q) p.X.Mul(&p.X, &thirdRootOneG1) return p } // mulGLV computes the scalar multiplication using a windowed-GLV method +// // see https://www.iacr.org/archive/crypto2001/21390189.pdf -func (p *G1Jac) mulGLV(a *G1Jac, s *big.Int) *G1Jac { +func (p *G1Jac) mulGLV(q *G1Jac, s *big.Int) *G1Jac { var table [15]G1Jac var res G1Jac @@ -547,11 +566,11 @@ func (p *G1Jac) mulGLV(a *G1Jac, s *big.Int) *G1Jac { res.Set(&g1Infinity) - // table[b3b2b1b0-1] = b3b2 ⋅ ϕ(a) + b1b0*a - table[0].Set(a) - table[3].phi(a) + // table[b3b2b1b0-1] = b3b2 ⋅ ϕ(q) + b1b0*q + table[0].Set(q) + table[3].phi(q) - // split the scalar, modifies ±a, ϕ(a) accordingly + // split the scalar, modifies ±q, ϕ(q) accordingly k := ecc.SplitScalar(s, &glvBasis) if k[0].Sign() == -1 { @@ -564,7 +583,7 @@ func (p *G1Jac) mulGLV(a *G1Jac, s *big.Int) *G1Jac { } // precompute table (2 bits sliding window) - // table[b3b2b1b0-1] = b3b2 ⋅ ϕ(a) + b1b0 ⋅ a if b3b2b1b0 != 0 + // table[b3b2b1b0-1] = b3b2 ⋅ ϕ(q) + b1b0 ⋅ q if b3b2b1b0 != 0 table[1].Double(&table[0]) table[2].Set(&table[1]).AddAssign(&table[0]) table[4].Set(&table[3]).AddAssign(&table[0]) @@ -620,12 +639,12 @@ func (p *G1Affine) ClearCofactor(a *G1Affine) *G1Affine { } // ClearCofactor maps a point in E(Fp) to E(Fp)[r] -func (p *G1Jac) ClearCofactor(a *G1Jac) *G1Jac { +func (p *G1Jac) ClearCofactor(q *G1Jac) *G1Jac { // https://eprint.iacr.org/2020/351.pdf var points [4]G1Jac - points[0].Set(a) - points[1].ScalarMultiplication(a, &xGen) + points[0].Set(q) + points[1].ScalarMultiplication(q, &xGen) points[2].ScalarMultiplication(&points[1], &xGen) points[3].ScalarMultiplication(&points[2], &xGen) @@ -661,8 +680,8 @@ func (p *G1Jac) ClearCofactor(a *G1Jac) *G1Jac { } -// JointScalarMultiplicationBase computes [s1]g+[s2]a using Straus-Shamir technique -// where g is the prime subgroup generator +// JointScalarMultiplicationBase computes [s1]g+[s2]a using Strauss-Shamir technique +// where g is the prime subgroup generator and a is an affine point. func (p *G1Jac) JointScalarMultiplicationBase(a *G1Affine, s1, s2 *big.Int) *G1Jac { var res, p1, p2 G1Jac @@ -733,15 +752,15 @@ func (p *G1Jac) JointScalarMultiplicationBase(a *G1Affine, s1, s2 *big.Int) *G1J } // ------------------------------------------------------------------------------------------------- -// Jacobian extended +// extended Jacobian coordinates -// Set sets p to the provided point -func (p *g1JacExtended) Set(a *g1JacExtended) *g1JacExtended { - p.X, p.Y, p.ZZ, p.ZZZ = a.X, a.Y, a.ZZ, a.ZZZ +// Set sets p to a in extended Jacobian coordinates. +func (p *g1JacExtended) Set(q *g1JacExtended) *g1JacExtended { + p.X, p.Y, p.ZZ, p.ZZZ = q.X, q.Y, q.ZZ, q.ZZZ return p } -// setInfinity sets p to O +// setInfinity sets p to the infinity point (1,1,0,0). func (p *g1JacExtended) setInfinity() *g1JacExtended { p.X.SetOne() p.Y.SetOne() @@ -750,43 +769,45 @@ func (p *g1JacExtended) setInfinity() *g1JacExtended { return p } -func (p *g1JacExtended) IsZero() bool { +// IsInfinity checks if the p is infinity, i.e. p.ZZ=0. +func (p *g1JacExtended) IsInfinity() bool { return p.ZZ.IsZero() } -// fromJacExtended sets Q in affine coordinates -func (p *G1Affine) fromJacExtended(Q *g1JacExtended) *G1Affine { - if Q.ZZ.IsZero() { +// fromJacExtended converts an extended Jacobian point to an affine point. +func (p *G1Affine) fromJacExtended(q *g1JacExtended) *G1Affine { + if q.ZZ.IsZero() { p.X = fp.Element{} p.Y = fp.Element{} return p } - p.X.Inverse(&Q.ZZ).Mul(&p.X, &Q.X) - p.Y.Inverse(&Q.ZZZ).Mul(&p.Y, &Q.Y) + p.X.Inverse(&q.ZZ).Mul(&p.X, &q.X) + p.Y.Inverse(&q.ZZZ).Mul(&p.Y, &q.Y) return p } -// fromJacExtended sets Q in Jacobian coordinates -func (p *G1Jac) fromJacExtended(Q *g1JacExtended) *G1Jac { - if Q.ZZ.IsZero() { +// fromJacExtended converts an extended Jacobian point to a Jacobian point. +func (p *G1Jac) fromJacExtended(q *g1JacExtended) *G1Jac { + if q.ZZ.IsZero() { p.Set(&g1Infinity) return p } - p.X.Mul(&Q.ZZ, &Q.X).Mul(&p.X, &Q.ZZ) - p.Y.Mul(&Q.ZZZ, &Q.Y).Mul(&p.Y, &Q.ZZZ) - p.Z.Set(&Q.ZZZ) + p.X.Mul(&q.ZZ, &q.X).Mul(&p.X, &q.ZZ) + p.Y.Mul(&q.ZZZ, &q.Y).Mul(&p.Y, &q.ZZZ) + p.Z.Set(&q.ZZZ) return p } -// unsafeFromJacExtended sets p in Jacobian coordinates, but don't check for infinity -func (p *G1Jac) unsafeFromJacExtended(Q *g1JacExtended) *G1Jac { - p.X.Square(&Q.ZZ).Mul(&p.X, &Q.X) - p.Y.Square(&Q.ZZZ).Mul(&p.Y, &Q.Y) - p.Z = Q.ZZZ +// unsafeFromJacExtended converts an extended Jacobian point, distinct from Infinity, to a Jacobian point. +func (p *G1Jac) unsafeFromJacExtended(q *g1JacExtended) *G1Jac { + p.X.Square(&q.ZZ).Mul(&p.X, &q.X) + p.Y.Square(&q.ZZZ).Mul(&p.Y, &q.Y) + p.Z = q.ZZZ return p } -// add point in Jacobian extended coordinates +// add sets p to p+q in extended Jacobian coordinates. +// // https://www.hyperelliptic.org/EFD/g1p/auto-shortw-xyzz.html#addition-add-2008-s func (p *g1JacExtended) add(q *g1JacExtended) *g1JacExtended { //if q is infinity return p @@ -842,10 +863,11 @@ func (p *g1JacExtended) add(q *g1JacExtended) *g1JacExtended { return p } -// double point in Jacobian extended coordinates +// double sets p to [2]q in Jacobian extended coordinates. +// // http://www.hyperelliptic.org/EFD/g1p/auto-shortw-xyzz.html#doubling-dbl-2008-s-1 -// since we consider any point on Z=0 as the point at infinity -// this doubling formula works for infinity points as well +// N.B.: since we consider any point on Z=0 as the point at infinity +// this doubling formula works for infinity points as well. func (p *g1JacExtended) double(q *g1JacExtended) *g1JacExtended { var U, V, W, S, XX, M fp.Element @@ -855,7 +877,7 @@ func (p *g1JacExtended) double(q *g1JacExtended) *g1JacExtended { S.Mul(&q.X, &V) XX.Square(&q.X) M.Double(&XX). - Add(&M, &XX) // -> + a, but a=0 here + Add(&M, &XX) // -> + A, but A=0 here U.Mul(&W, &q.Y) p.X.Square(&M). @@ -870,9 +892,10 @@ func (p *g1JacExtended) double(q *g1JacExtended) *g1JacExtended { return p } -// subMixed same as addMixed, but will negate a.Y +// addMixed sets p to p+q in extended Jacobian coordinates, where a.ZZ=1. +// // http://www.hyperelliptic.org/EFD/g1p/auto-shortw-xyzz.html#addition-madd-2008-s -func (p *g1JacExtended) subMixed(a *G1Affine) *g1JacExtended { +func (p *g1JacExtended) addMixed(a *G1Affine) *g1JacExtended { //if a is infinity return p if a.IsInfinity() { @@ -881,7 +904,7 @@ func (p *g1JacExtended) subMixed(a *G1Affine) *g1JacExtended { // p is infinity, return a if p.ZZ.IsZero() { p.X = a.X - p.Y.Neg(&a.Y) + p.Y = a.Y p.ZZ.SetOne() p.ZZZ.SetOne() return p @@ -894,12 +917,11 @@ func (p *g1JacExtended) subMixed(a *G1Affine) *g1JacExtended { P.Sub(&P, &p.X) R.Mul(&a.Y, &p.ZZZ) - R.Neg(&R) R.Sub(&R, &p.Y) if P.IsZero() { if R.IsZero() { - return p.doubleNegMixed(a) + return p.doubleMixed(a) } p.ZZ = fp.Element{} @@ -926,9 +948,10 @@ func (p *g1JacExtended) subMixed(a *G1Affine) *g1JacExtended { } -// addMixed +// subMixed works the same as addMixed, but negates a.Y. +// // http://www.hyperelliptic.org/EFD/g1p/auto-shortw-xyzz.html#addition-madd-2008-s -func (p *g1JacExtended) addMixed(a *G1Affine) *g1JacExtended { +func (p *g1JacExtended) subMixed(a *G1Affine) *g1JacExtended { //if a is infinity return p if a.IsInfinity() { @@ -937,7 +960,7 @@ func (p *g1JacExtended) addMixed(a *G1Affine) *g1JacExtended { // p is infinity, return a if p.ZZ.IsZero() { p.X = a.X - p.Y = a.Y + p.Y.Neg(&a.Y) p.ZZ.SetOne() p.ZZZ.SetOne() return p @@ -950,11 +973,12 @@ func (p *g1JacExtended) addMixed(a *G1Affine) *g1JacExtended { P.Sub(&P, &p.X) R.Mul(&a.Y, &p.ZZZ) + R.Neg(&R) R.Sub(&R, &p.Y) if P.IsZero() { if R.IsZero() { - return p.doubleMixed(a) + return p.doubleNegMixed(a) } p.ZZ = fp.Element{} @@ -981,21 +1005,21 @@ func (p *g1JacExtended) addMixed(a *G1Affine) *g1JacExtended { } -// doubleNegMixed same as double, but will negate q.Y -func (p *g1JacExtended) doubleNegMixed(q *G1Affine) *g1JacExtended { +// doubleNegMixed works the same as double, but negates q.Y. +func (p *g1JacExtended) doubleNegMixed(a *G1Affine) *g1JacExtended { var U, V, W, S, XX, M, S2, L fp.Element - U.Double(&q.Y) + U.Double(&a.Y) U.Neg(&U) V.Square(&U) W.Mul(&U, &V) - S.Mul(&q.X, &V) - XX.Square(&q.X) + S.Mul(&a.X, &V) + XX.Square(&a.X) M.Double(&XX). - Add(&M, &XX) // -> + a, but a=0 here + Add(&M, &XX) // -> + A, but A=0 here S2.Double(&S) - L.Mul(&W, &q.Y) + L.Mul(&W, &a.Y) p.X.Square(&M). Sub(&p.X, &S2) @@ -1008,21 +1032,22 @@ func (p *g1JacExtended) doubleNegMixed(q *G1Affine) *g1JacExtended { return p } -// doubleMixed point in Jacobian extended coordinates +// doubleMixed sets p to [2]a in Jacobian extended coordinates, where a.ZZ=1. +// // http://www.hyperelliptic.org/EFD/g1p/auto-shortw-xyzz.html#doubling-dbl-2008-s-1 -func (p *g1JacExtended) doubleMixed(q *G1Affine) *g1JacExtended { +func (p *g1JacExtended) doubleMixed(a *G1Affine) *g1JacExtended { var U, V, W, S, XX, M, S2, L fp.Element - U.Double(&q.Y) + U.Double(&a.Y) V.Square(&U) W.Mul(&U, &V) - S.Mul(&q.X, &V) - XX.Square(&q.X) + S.Mul(&a.X, &V) + XX.Square(&a.X) M.Double(&XX). - Add(&M, &XX) // -> + a, but a=0 here + Add(&M, &XX) // -> + A, but A=0 here S2.Double(&S) - L.Mul(&W, &q.Y) + L.Mul(&W, &a.Y) p.X.Square(&M). Sub(&p.X, &S2) @@ -1036,7 +1061,7 @@ func (p *g1JacExtended) doubleMixed(q *G1Affine) *g1JacExtended { } // BatchJacobianToAffineG1 converts points in Jacobian coordinates to Affine coordinates -// performing a single field inversion (Montgomery batch inversion trick). +// performing a single field inversion using the Montgomery batch inversion trick. func BatchJacobianToAffineG1(points []G1Jac) []G1Affine { result := make([]G1Affine, len(points)) zeroes := make([]bool, len(points)) @@ -1086,7 +1111,7 @@ func BatchJacobianToAffineG1(points []G1Jac) []G1Affine { // BatchScalarMultiplicationG1 multiplies the same base by all scalars // and return resulting points in affine coordinates -// uses a simple windowed-NAF like exponentiation algorithm +// uses a simple windowed-NAF-like multiplication algorithm. func BatchScalarMultiplicationG1(base *G1Affine, scalars []fr.Element) []G1Affine { // approximate cost in group ops is // cost = 2^{c-1} + n(scalar.nbBits+nbChunks) @@ -1168,9 +1193,8 @@ func BatchScalarMultiplicationG1(base *G1Affine, scalars []fr.Element) []G1Affin return toReturnAff } -// batch add affine coordinates -// using batch inversion -// special cases (doubling, infinity) must be filtered out before this call +// batchAddG1Affine adds affine points using the Montgomery batch inversion trick. +// Special cases (doubling, infinity) must be filtered out before this call. func batchAddG1Affine[TP pG1Affine, TPP ppG1Affine, TC cG1Affine](R *TPP, P *TP, batchSize int) { var lambda, lambdain TC diff --git a/ecc/bw6-761/g2.go b/ecc/bw6-761/g2.go index 3c01f4b3f..215073177 100644 --- a/ecc/bw6-761/g2.go +++ b/ecc/bw6-761/g2.go @@ -25,17 +25,17 @@ import ( "runtime" ) -// G2Affine point in affine coordinates +// G2Affine is a point in affine coordinates (x,y) type G2Affine struct { X, Y fp.Element } -// G2Jac is a point with fp.Element coordinates +// G2Jac is a point in Jacobian coordinates (x=X/Z², y=Y/Z³) type G2Jac struct { X, Y, Z fp.Element } -// g2JacExtended parameterized Jacobian coordinates (x=X/ZZ, y=Y/ZZZ, ZZ³=ZZZ²) +// g2JacExtended is a point in extended Jacobian coordinates (x=X/ZZ, y=Y/ZZZ, ZZ³=ZZZ²) type g2JacExtended struct { X, Y, ZZ, ZZZ fp.Element } @@ -46,22 +46,24 @@ type g2Proj struct { } // ------------------------------------------------------------------------------------------------- -// Affine +// Affine coordinates -// Set sets p to the provided point +// Set sets p to a in affine coordinates. func (p *G2Affine) Set(a *G2Affine) *G2Affine { p.X, p.Y = a.X, a.Y return p } -// setInfinity sets p to O +// setInfinity sets p to the infinity point, which is encoded as (0,0). +// N.B.: (0,0) is never on the curve for j=0 curves (Y²=X³+B). func (p *G2Affine) setInfinity() *G2Affine { p.X.SetZero() p.Y.SetZero() return p } -// ScalarMultiplication computes and returns p = a ⋅ s +// ScalarMultiplication computes and returns p = [s]a +// where p and a are affine points. func (p *G2Affine) ScalarMultiplication(a *G2Affine, s *big.Int) *G2Affine { var _p G2Jac _p.FromAffine(a) @@ -70,7 +72,8 @@ func (p *G2Affine) ScalarMultiplication(a *G2Affine, s *big.Int) *G2Affine { return p } -// ScalarMultiplicationBase computes and returns p = g ⋅ s where g is the prime subgroup generator +// ScalarMultiplicationBase computes and returns p = [s]g +// where g is the affine point generating the prime subgroup. func (p *G2Affine) ScalarMultiplicationBase(s *big.Int) *G2Affine { var _p G2Jac _p.mulGLV(&g2Gen, s) @@ -78,8 +81,9 @@ func (p *G2Affine) ScalarMultiplicationBase(s *big.Int) *G2Affine { return p } -// Add adds two point in affine coordinates. -// Jacobian addition with Z1=Z2=1 +// Add adds two points in affine coordinates. +// It uses the Jacobian addition with a.Z=b.Z=1 and converts the result to affine coordinates. +// // https://www.hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html#addition-mmadd-2007-bl func (p *G2Affine) Add(a, b *G2Affine) *G2Affine { var q G2Jac @@ -125,6 +129,10 @@ func (p *G2Affine) Add(a, b *G2Affine) *G2Affine { } // Double doubles a point in affine coordinates. +// It converts the point to Jacobian coordinates, doubles it using Jacobian +// addition with a.Z=1, and converts it back to affine coordinates. +// +// http://www.hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html#doubling-mdbl-2007-bl func (p *G2Affine) Double(a *G2Affine) *G2Affine { var q G2Jac q.FromAffine(a) @@ -133,7 +141,8 @@ func (p *G2Affine) Double(a *G2Affine) *G2Affine { return p } -// Sub subs two point in affine coordinates. +// Sub subtracts two points in affine coordinates. +// It uses a similar approach to Add, but negates the second point before adding. func (p *G2Affine) Sub(a, b *G2Affine) *G2Affine { var bneg G2Affine bneg.Neg(b) @@ -141,19 +150,19 @@ func (p *G2Affine) Sub(a, b *G2Affine) *G2Affine { return p } -// Equal tests if two points (in Affine coordinates) are equal +// Equal tests if two points in affine coordinates are equal. func (p *G2Affine) Equal(a *G2Affine) bool { return p.X.Equal(&a.X) && p.Y.Equal(&a.Y) } -// Neg computes -G +// Neg sets p to the affine negative point -a = (a.X, -a.Y). func (p *G2Affine) Neg(a *G2Affine) *G2Affine { p.X = a.X p.Y.Neg(&a.Y) return p } -// FromJacobian rescales a point in Jacobian coord in z=1 plane +// FromJacobian converts a point p1 from Jacobian to affine coordinates. func (p *G2Affine) FromJacobian(p1 *G2Jac) *G2Affine { var a, b fp.Element @@ -172,7 +181,7 @@ func (p *G2Affine) FromJacobian(p1 *G2Jac) *G2Affine { return p } -// String returns the string representation of the point or "O" if it is infinity +// String returns the string representation E(x,y) of the affine point p or "O" if it is infinity. func (p *G2Affine) String() string { if p.IsInfinity() { return "O" @@ -180,21 +189,20 @@ func (p *G2Affine) String() string { return "E([" + p.X.String() + "," + p.Y.String() + "])" } -// IsInfinity checks if the point is infinity -// in affine, it's encoded as (0,0) -// (0,0) is never on the curve for j=0 curves +// IsInfinity checks if the affine point p is infinity, which is encoded as (0,0). +// N.B.: (0,0) is never on the curve for j=0 curves (Y²=X³+B). func (p *G2Affine) IsInfinity() bool { return p.X.IsZero() && p.Y.IsZero() } -// IsOnCurve returns true if p in on the curve +// IsOnCurve returns true if the affine point p in on the curve. func (p *G2Affine) IsOnCurve() bool { var point G2Jac point.FromAffine(p) return point.IsOnCurve() // call this function to handle infinity point } -// IsInSubGroup returns true if p is in the correct subgroup, false otherwise +// IsInSubGroup returns true if the affine point p is in the correct subgroup, false otherwise. func (p *G2Affine) IsInSubGroup() bool { var _p G2Jac _p.FromAffine(p) @@ -202,84 +210,76 @@ func (p *G2Affine) IsInSubGroup() bool { } // ------------------------------------------------------------------------------------------------- -// Jacobian +// Jacobian coordinates -// Set sets p to the provided point -func (p *G2Jac) Set(a *G2Jac) *G2Jac { - p.X, p.Y, p.Z = a.X, a.Y, a.Z +// Set sets p to a in Jacobian coordinates. +func (p *G2Jac) Set(q *G2Jac) *G2Jac { + p.X, p.Y, p.Z = q.X, q.Y, q.Z return p } -// Equal tests if two points (in Jacobian coordinates) are equal -func (p *G2Jac) Equal(a *G2Jac) bool { +// Equal tests if two points in Jacobian coordinates are equal. +func (p *G2Jac) Equal(q *G2Jac) bool { // If one point is infinity, the other must also be infinity. if p.Z.IsZero() { - return a.Z.IsZero() + return q.Z.IsZero() } // If the other point is infinity, return false since we can't // the following checks would be incorrect. - if a.Z.IsZero() { + if q.Z.IsZero() { return false } var pZSquare, aZSquare fp.Element pZSquare.Square(&p.Z) - aZSquare.Square(&a.Z) + aZSquare.Square(&q.Z) var lhs, rhs fp.Element lhs.Mul(&p.X, &aZSquare) - rhs.Mul(&a.X, &pZSquare) + rhs.Mul(&q.X, &pZSquare) if !lhs.Equal(&rhs) { return false } - lhs.Mul(&p.Y, &aZSquare).Mul(&lhs, &a.Z) - rhs.Mul(&a.Y, &pZSquare).Mul(&rhs, &p.Z) + lhs.Mul(&p.Y, &aZSquare).Mul(&lhs, &q.Z) + rhs.Mul(&q.Y, &pZSquare).Mul(&rhs, &p.Z) return lhs.Equal(&rhs) } -// Neg computes -G -func (p *G2Jac) Neg(a *G2Jac) *G2Jac { - *p = *a - p.Y.Neg(&a.Y) +// Neg sets p to the Jacobian negative point -q = (q.X, -q.Y, q.Z). +func (p *G2Jac) Neg(q *G2Jac) *G2Jac { + *p = *q + p.Y.Neg(&q.Y) return p } -// SubAssign subtracts two points on the curve -func (p *G2Jac) SubAssign(a *G2Jac) *G2Jac { - var tmp G2Jac - tmp.Set(a) - tmp.Y.Neg(&tmp.Y) - p.AddAssign(&tmp) - return p -} - -// AddAssign point addition in montgomery form +// AddAssign sets p to p+a in Jacobian coordinates. +// // https://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-3.html#addition-add-2007-bl -func (p *G2Jac) AddAssign(a *G2Jac) *G2Jac { +func (p *G2Jac) AddAssign(q *G2Jac) *G2Jac { - // p is infinity, return a + // p is infinity, return q if p.Z.IsZero() { - p.Set(a) + p.Set(q) return p } - // a is infinity, return p - if a.Z.IsZero() { + // q is infinity, return p + if q.Z.IsZero() { return p } var Z1Z1, Z2Z2, U1, U2, S1, S2, H, I, J, r, V fp.Element - Z1Z1.Square(&a.Z) + Z1Z1.Square(&q.Z) Z2Z2.Square(&p.Z) - U1.Mul(&a.X, &Z2Z2) + U1.Mul(&q.X, &Z2Z2) U2.Mul(&p.X, &Z1Z1) - S1.Mul(&a.Y, &p.Z). + S1.Mul(&q.Y, &p.Z). Mul(&S1, &Z2Z2) - S2.Mul(&p.Y, &a.Z). + S2.Mul(&p.Y, &q.Z). Mul(&S2, &Z1Z1) - // if p == a, we double instead + // if p == q, we double instead if U1.Equal(&U2) && S1.Equal(&S2) { return p.DoubleAssign() } @@ -298,7 +298,7 @@ func (p *G2Jac) AddAssign(a *G2Jac) *G2Jac { Mul(&p.Y, &r) S1.Mul(&S1, &J).Double(&S1) p.Y.Sub(&p.Y, &S1) - p.Z.Add(&p.Z, &a.Z) + p.Z.Add(&p.Z, &q.Z) p.Z.Square(&p.Z). Sub(&p.Z, &Z1Z1). Sub(&p.Z, &Z2Z2). @@ -307,8 +307,19 @@ func (p *G2Jac) AddAssign(a *G2Jac) *G2Jac { return p } -// DoubleMixed point addition -// http://www.hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html#doubling-mdbl-2007-bl +// SubAssign sets p to p-a in Jacobian coordinates. +// It uses a similar approach to AddAssign, but negates the point a before adding. +func (p *G2Jac) SubAssign(q *G2Jac) *G2Jac { + var tmp G2Jac + tmp.Set(q) + tmp.Y.Neg(&tmp.Y) + p.AddAssign(&tmp) + return p +} + +// Double sets p to [2]q in Jacobian coordinates. +// +// https://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-3.html#doubling-dbl-2007-bl func (p *G2Jac) DoubleMixed(a *G2Affine) *G2Jac { var XX, YY, YYYY, S, M, T fp.Element XX.Square(&a.X) @@ -320,7 +331,7 @@ func (p *G2Jac) DoubleMixed(a *G2Affine) *G2Jac { Sub(&S, &YYYY). Double(&S) M.Double(&XX). - Add(&M, &XX) // -> + a, but a=0 here + Add(&M, &XX) // -> + A, but A=0 here T.Square(&M). Sub(&T, &S). Sub(&T, &S) @@ -336,7 +347,8 @@ func (p *G2Jac) DoubleMixed(a *G2Affine) *G2Jac { return p } -// AddMixed point addition +// AddMixed sets p to p+a in Jacobian coordinates, where a.Z = 1. +// // http://www.hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html#addition-madd-2007-bl func (p *G2Jac) AddMixed(a *G2Affine) *G2Jac { @@ -385,7 +397,8 @@ func (p *G2Jac) AddMixed(a *G2Affine) *G2Jac { return p } -// Double doubles a point in Jacobian coordinates +// Double sets p to [2]q in Jacobian coordinates. +// // https://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-3.html#doubling-dbl-2007-bl func (p *G2Jac) Double(q *G2Jac) *G2Jac { p.Set(q) @@ -393,7 +406,8 @@ func (p *G2Jac) Double(q *G2Jac) *G2Jac { return p } -// DoubleAssign doubles a point in Jacobian coordinates +// DoubleAssign doubles p in Jacobian coordinates. +// // https://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-3.html#doubling-dbl-2007-bl func (p *G2Jac) DoubleAssign() *G2Jac { @@ -425,34 +439,36 @@ func (p *G2Jac) DoubleAssign() *G2Jac { return p } -// ScalarMultiplication computes and returns p = a ⋅ s +// ScalarMultiplication computes and returns p = [s]a +// where p and a are Jacobian points. +// using the GLV technique. // see https://www.iacr.org/archive/crypto2001/21390189.pdf -func (p *G2Jac) ScalarMultiplication(a *G2Jac, s *big.Int) *G2Jac { - return p.mulGLV(a, s) +func (p *G2Jac) ScalarMultiplication(q *G2Jac, s *big.Int) *G2Jac { + return p.mulGLV(q, s) } -// String returns canonical representation of the point in affine coordinates +// String converts p to affine coordinates and returns its string representation E(x,y) or "O" if it is infinity. func (p *G2Jac) String() string { _p := G2Affine{} _p.FromJacobian(p) return _p.String() } -// FromAffine sets p = Q, p in Jacobian, Q in affine -func (p *G2Jac) FromAffine(Q *G2Affine) *G2Jac { - if Q.IsInfinity() { +// FromAffine converts a point a from affine to Jacobian coordinates. +func (p *G2Jac) FromAffine(a *G2Affine) *G2Jac { + if a.IsInfinity() { p.Z.SetZero() p.X.SetOne() p.Y.SetOne() return p } p.Z.SetOne() - p.X.Set(&Q.X) - p.Y.Set(&Q.Y) + p.X.Set(&a.X) + p.Y.Set(&a.Y) return p } -// IsOnCurve returns true if p in on the curve +// IsOnCurve returns true if the Jacobian point p in on the curve. func (p *G2Jac) IsOnCurve() bool { var left, right, tmp, ZZ fp.Element left.Square(&p.Y) @@ -488,13 +504,14 @@ func (p *G2Jac) IsInSubGroup() bool { } -// mulWindowed computes a 2-bits windowed scalar multiplication -func (p *G2Jac) mulWindowed(a *G2Jac, s *big.Int) *G2Jac { +// mulWindowed computes the 2-bits windowed double-and-add scalar +// multiplication p=[s]q in Jacobian coordinates. +func (p *G2Jac) mulWindowed(q *G2Jac, s *big.Int) *G2Jac { var res G2Jac var ops [3]G2Jac - ops[0].Set(a) + ops[0].Set(q) if s.Sign() == -1 { ops[0].Neg(&ops[0]) } @@ -521,17 +538,18 @@ func (p *G2Jac) mulWindowed(a *G2Jac, s *big.Int) *G2Jac { } -// ϕ assigns p to ϕ(a) where ϕ: (x,y) → (w x,y), and returns p -// where w is a third root of unity in 𝔽p -func (p *G2Jac) phi(a *G2Jac) *G2Jac { - p.Set(a) +// phi sets p to ϕ(a) where ϕ: (x,y) → (w x,y), +// where w is a third root of unity. +func (p *G2Jac) phi(q *G2Jac) *G2Jac { + p.Set(q) p.X.Mul(&p.X, &thirdRootOneG2) return p } // mulGLV computes the scalar multiplication using a windowed-GLV method +// // see https://www.iacr.org/archive/crypto2001/21390189.pdf -func (p *G2Jac) mulGLV(a *G2Jac, s *big.Int) *G2Jac { +func (p *G2Jac) mulGLV(q *G2Jac, s *big.Int) *G2Jac { var table [15]G2Jac var res G2Jac @@ -539,11 +557,11 @@ func (p *G2Jac) mulGLV(a *G2Jac, s *big.Int) *G2Jac { res.Set(&g2Infinity) - // table[b3b2b1b0-1] = b3b2 ⋅ ϕ(a) + b1b0*a - table[0].Set(a) - table[3].phi(a) + // table[b3b2b1b0-1] = b3b2 ⋅ ϕ(q) + b1b0*q + table[0].Set(q) + table[3].phi(q) - // split the scalar, modifies ±a, ϕ(a) accordingly + // split the scalar, modifies ±q, ϕ(q) accordingly k := ecc.SplitScalar(s, &glvBasis) if k[0].Sign() == -1 { @@ -556,7 +574,7 @@ func (p *G2Jac) mulGLV(a *G2Jac, s *big.Int) *G2Jac { } // precompute table (2 bits sliding window) - // table[b3b2b1b0-1] = b3b2 ⋅ ϕ(a) + b1b0 ⋅ a if b3b2b1b0 != 0 + // table[b3b2b1b0-1] = b3b2 ⋅ ϕ(q) + b1b0 ⋅ q if b3b2b1b0 != 0 table[1].Double(&table[0]) table[2].Set(&table[1]).AddAssign(&table[0]) table[4].Set(&table[3]).AddAssign(&table[0]) @@ -612,10 +630,10 @@ func (p *G2Affine) ClearCofactor(a *G2Affine) *G2Affine { } // ClearCofactor maps a point in curve to r-torsion -func (p *G2Jac) ClearCofactor(a *G2Jac) *G2Jac { +func (p *G2Jac) ClearCofactor(q *G2Jac) *G2Jac { var points [4]G2Jac - points[0].Set(a) - points[1].ScalarMultiplication(a, &xGen) + points[0].Set(q) + points[1].ScalarMultiplication(q, &xGen) points[2].ScalarMultiplication(&points[1], &xGen) points[3].ScalarMultiplication(&points[2], &xGen) @@ -652,15 +670,15 @@ func (p *G2Jac) ClearCofactor(a *G2Jac) *G2Jac { } // ------------------------------------------------------------------------------------------------- -// Jacobian extended +// extended Jacobian coordinates -// Set sets p to the provided point -func (p *g2JacExtended) Set(a *g2JacExtended) *g2JacExtended { - p.X, p.Y, p.ZZ, p.ZZZ = a.X, a.Y, a.ZZ, a.ZZZ +// Set sets p to a in extended Jacobian coordinates. +func (p *g2JacExtended) Set(q *g2JacExtended) *g2JacExtended { + p.X, p.Y, p.ZZ, p.ZZZ = q.X, q.Y, q.ZZ, q.ZZZ return p } -// setInfinity sets p to O +// setInfinity sets p to the infinity point (1,1,0,0). func (p *g2JacExtended) setInfinity() *g2JacExtended { p.X.SetOne() p.Y.SetOne() @@ -669,43 +687,45 @@ func (p *g2JacExtended) setInfinity() *g2JacExtended { return p } -func (p *g2JacExtended) IsZero() bool { +// IsInfinity checks if the p is infinity, i.e. p.ZZ=0. +func (p *g2JacExtended) IsInfinity() bool { return p.ZZ.IsZero() } -// fromJacExtended sets Q in affine coordinates -func (p *G2Affine) fromJacExtended(Q *g2JacExtended) *G2Affine { - if Q.ZZ.IsZero() { +// fromJacExtended converts an extended Jacobian point to an affine point. +func (p *G2Affine) fromJacExtended(q *g2JacExtended) *G2Affine { + if q.ZZ.IsZero() { p.X = fp.Element{} p.Y = fp.Element{} return p } - p.X.Inverse(&Q.ZZ).Mul(&p.X, &Q.X) - p.Y.Inverse(&Q.ZZZ).Mul(&p.Y, &Q.Y) + p.X.Inverse(&q.ZZ).Mul(&p.X, &q.X) + p.Y.Inverse(&q.ZZZ).Mul(&p.Y, &q.Y) return p } -// fromJacExtended sets Q in Jacobian coordinates -func (p *G2Jac) fromJacExtended(Q *g2JacExtended) *G2Jac { - if Q.ZZ.IsZero() { +// fromJacExtended converts an extended Jacobian point to a Jacobian point. +func (p *G2Jac) fromJacExtended(q *g2JacExtended) *G2Jac { + if q.ZZ.IsZero() { p.Set(&g2Infinity) return p } - p.X.Mul(&Q.ZZ, &Q.X).Mul(&p.X, &Q.ZZ) - p.Y.Mul(&Q.ZZZ, &Q.Y).Mul(&p.Y, &Q.ZZZ) - p.Z.Set(&Q.ZZZ) + p.X.Mul(&q.ZZ, &q.X).Mul(&p.X, &q.ZZ) + p.Y.Mul(&q.ZZZ, &q.Y).Mul(&p.Y, &q.ZZZ) + p.Z.Set(&q.ZZZ) return p } -// unsafeFromJacExtended sets p in Jacobian coordinates, but don't check for infinity -func (p *G2Jac) unsafeFromJacExtended(Q *g2JacExtended) *G2Jac { - p.X.Square(&Q.ZZ).Mul(&p.X, &Q.X) - p.Y.Square(&Q.ZZZ).Mul(&p.Y, &Q.Y) - p.Z = Q.ZZZ +// unsafeFromJacExtended converts an extended Jacobian point, distinct from Infinity, to a Jacobian point. +func (p *G2Jac) unsafeFromJacExtended(q *g2JacExtended) *G2Jac { + p.X.Square(&q.ZZ).Mul(&p.X, &q.X) + p.Y.Square(&q.ZZZ).Mul(&p.Y, &q.Y) + p.Z = q.ZZZ return p } -// add point in Jacobian extended coordinates +// add sets p to p+q in extended Jacobian coordinates. +// // https://www.hyperelliptic.org/EFD/g1p/auto-shortw-xyzz.html#addition-add-2008-s func (p *g2JacExtended) add(q *g2JacExtended) *g2JacExtended { //if q is infinity return p @@ -761,10 +781,11 @@ func (p *g2JacExtended) add(q *g2JacExtended) *g2JacExtended { return p } -// double point in Jacobian extended coordinates +// double sets p to [2]q in Jacobian extended coordinates. +// // http://www.hyperelliptic.org/EFD/g1p/auto-shortw-xyzz.html#doubling-dbl-2008-s-1 -// since we consider any point on Z=0 as the point at infinity -// this doubling formula works for infinity points as well +// N.B.: since we consider any point on Z=0 as the point at infinity +// this doubling formula works for infinity points as well. func (p *g2JacExtended) double(q *g2JacExtended) *g2JacExtended { var U, V, W, S, XX, M fp.Element @@ -774,7 +795,7 @@ func (p *g2JacExtended) double(q *g2JacExtended) *g2JacExtended { S.Mul(&q.X, &V) XX.Square(&q.X) M.Double(&XX). - Add(&M, &XX) // -> + a, but a=0 here + Add(&M, &XX) // -> + A, but A=0 here U.Mul(&W, &q.Y) p.X.Square(&M). @@ -789,9 +810,10 @@ func (p *g2JacExtended) double(q *g2JacExtended) *g2JacExtended { return p } -// subMixed same as addMixed, but will negate a.Y +// addMixed sets p to p+q in extended Jacobian coordinates, where a.ZZ=1. +// // http://www.hyperelliptic.org/EFD/g1p/auto-shortw-xyzz.html#addition-madd-2008-s -func (p *g2JacExtended) subMixed(a *G2Affine) *g2JacExtended { +func (p *g2JacExtended) addMixed(a *G2Affine) *g2JacExtended { //if a is infinity return p if a.IsInfinity() { @@ -800,7 +822,7 @@ func (p *g2JacExtended) subMixed(a *G2Affine) *g2JacExtended { // p is infinity, return a if p.ZZ.IsZero() { p.X = a.X - p.Y.Neg(&a.Y) + p.Y = a.Y p.ZZ.SetOne() p.ZZZ.SetOne() return p @@ -813,12 +835,11 @@ func (p *g2JacExtended) subMixed(a *G2Affine) *g2JacExtended { P.Sub(&P, &p.X) R.Mul(&a.Y, &p.ZZZ) - R.Neg(&R) R.Sub(&R, &p.Y) if P.IsZero() { if R.IsZero() { - return p.doubleNegMixed(a) + return p.doubleMixed(a) } p.ZZ = fp.Element{} @@ -845,9 +866,10 @@ func (p *g2JacExtended) subMixed(a *G2Affine) *g2JacExtended { } -// addMixed +// subMixed works the same as addMixed, but negates a.Y. +// // http://www.hyperelliptic.org/EFD/g1p/auto-shortw-xyzz.html#addition-madd-2008-s -func (p *g2JacExtended) addMixed(a *G2Affine) *g2JacExtended { +func (p *g2JacExtended) subMixed(a *G2Affine) *g2JacExtended { //if a is infinity return p if a.IsInfinity() { @@ -856,7 +878,7 @@ func (p *g2JacExtended) addMixed(a *G2Affine) *g2JacExtended { // p is infinity, return a if p.ZZ.IsZero() { p.X = a.X - p.Y = a.Y + p.Y.Neg(&a.Y) p.ZZ.SetOne() p.ZZZ.SetOne() return p @@ -869,11 +891,12 @@ func (p *g2JacExtended) addMixed(a *G2Affine) *g2JacExtended { P.Sub(&P, &p.X) R.Mul(&a.Y, &p.ZZZ) + R.Neg(&R) R.Sub(&R, &p.Y) if P.IsZero() { if R.IsZero() { - return p.doubleMixed(a) + return p.doubleNegMixed(a) } p.ZZ = fp.Element{} @@ -900,21 +923,21 @@ func (p *g2JacExtended) addMixed(a *G2Affine) *g2JacExtended { } -// doubleNegMixed same as double, but will negate q.Y -func (p *g2JacExtended) doubleNegMixed(q *G2Affine) *g2JacExtended { +// doubleNegMixed works the same as double, but negates q.Y. +func (p *g2JacExtended) doubleNegMixed(a *G2Affine) *g2JacExtended { var U, V, W, S, XX, M, S2, L fp.Element - U.Double(&q.Y) + U.Double(&a.Y) U.Neg(&U) V.Square(&U) W.Mul(&U, &V) - S.Mul(&q.X, &V) - XX.Square(&q.X) + S.Mul(&a.X, &V) + XX.Square(&a.X) M.Double(&XX). - Add(&M, &XX) // -> + a, but a=0 here + Add(&M, &XX) // -> + A, but A=0 here S2.Double(&S) - L.Mul(&W, &q.Y) + L.Mul(&W, &a.Y) p.X.Square(&M). Sub(&p.X, &S2) @@ -927,21 +950,22 @@ func (p *g2JacExtended) doubleNegMixed(q *G2Affine) *g2JacExtended { return p } -// doubleMixed point in Jacobian extended coordinates +// doubleMixed sets p to [2]a in Jacobian extended coordinates, where a.ZZ=1. +// // http://www.hyperelliptic.org/EFD/g1p/auto-shortw-xyzz.html#doubling-dbl-2008-s-1 -func (p *g2JacExtended) doubleMixed(q *G2Affine) *g2JacExtended { +func (p *g2JacExtended) doubleMixed(a *G2Affine) *g2JacExtended { var U, V, W, S, XX, M, S2, L fp.Element - U.Double(&q.Y) + U.Double(&a.Y) V.Square(&U) W.Mul(&U, &V) - S.Mul(&q.X, &V) - XX.Square(&q.X) + S.Mul(&a.X, &V) + XX.Square(&a.X) M.Double(&XX). - Add(&M, &XX) // -> + a, but a=0 here + Add(&M, &XX) // -> + A, but A=0 here S2.Double(&S) - L.Mul(&W, &q.Y) + L.Mul(&W, &a.Y) p.X.Square(&M). Sub(&p.X, &S2) @@ -955,38 +979,38 @@ func (p *g2JacExtended) doubleMixed(q *G2Affine) *g2JacExtended { } // ------------------------------------------------------------------------------------------------- -// Homogenous projective +// Homogenous projective coordinates -// Set sets p to the provided point -func (p *g2Proj) Set(a *g2Proj) *g2Proj { - p.x, p.y, p.z = a.x, a.y, a.z +// Set sets p to a in projective coordinates. +func (p *g2Proj) Set(q *g2Proj) *g2Proj { + p.x, p.y, p.z = q.x, q.y, q.z return p } -// Neg computes -G -func (p *g2Proj) Neg(a *g2Proj) *g2Proj { - *p = *a - p.y.Neg(&a.y) +// Neg sets p to the projective negative point -q = (q.X, -q.Y). +func (p *g2Proj) Neg(q *g2Proj) *g2Proj { + *p = *q + p.y.Neg(&q.y) return p } -// FromAffine sets p = Q, p in homogenous projective, Q in affine -func (p *g2Proj) FromAffine(Q *G2Affine) *g2Proj { - if Q.X.IsZero() && Q.Y.IsZero() { +// FromAffine converts q in affine to p in projective coordinates. +func (p *g2Proj) FromAffine(a *G2Affine) *g2Proj { + if a.X.IsZero() && a.Y.IsZero() { p.z.SetZero() p.x.SetOne() p.y.SetOne() return p } p.z.SetOne() - p.x.Set(&Q.X) - p.y.Set(&Q.Y) + p.x.Set(&a.X) + p.y.Set(&a.Y) return p } // BatchScalarMultiplicationG2 multiplies the same base by all scalars // and return resulting points in affine coordinates -// uses a simple windowed-NAF like exponentiation algorithm +// uses a simple windowed-NAF-like multiplication algorithm. func BatchScalarMultiplicationG2(base *G2Affine, scalars []fr.Element) []G2Affine { // approximate cost in group ops is // cost = 2^{c-1} + n(scalar.nbBits+nbChunks) @@ -1065,9 +1089,8 @@ func BatchScalarMultiplicationG2(base *G2Affine, scalars []fr.Element) []G2Affin return toReturn } -// batch add affine coordinates -// using batch inversion -// special cases (doubling, infinity) must be filtered out before this call +// batchAddG1Affine adds affine points using the Montgomery batch inversion trick. +// Special cases (doubling, infinity) must be filtered out before this call. func batchAddG2Affine[TP pG2Affine, TPP ppG2Affine, TC cG2Affine](R *TPP, P *TP, batchSize int) { var lambda, lambdain TC diff --git a/ecc/bw6-761/multiexp_affine.go b/ecc/bw6-761/multiexp_affine.go index 8aee61aeb..09fe09a9d 100644 --- a/ecc/bw6-761/multiexp_affine.go +++ b/ecc/bw6-761/multiexp_affine.go @@ -225,7 +225,7 @@ func processChunkG1BatchAffine[BJE ibg1JacExtended, B ibG1Affine, BS bitSet, TP total.setInfinity() for k := len(buckets) - 1; k >= 0; k-- { runningSum.addMixed(&buckets[k]) - if !bucketsJE[k].IsZero() { + if !bucketsJE[k].IsInfinity() { runningSum.add(&bucketsJE[k]) } total.add(&runningSum) @@ -493,7 +493,7 @@ func processChunkG2BatchAffine[BJE ibg2JacExtended, B ibG2Affine, BS bitSet, TP total.setInfinity() for k := len(buckets) - 1; k >= 0; k-- { runningSum.addMixed(&buckets[k]) - if !bucketsJE[k].IsZero() { + if !bucketsJE[k].IsInfinity() { runningSum.add(&bucketsJE[k]) } total.add(&runningSum) diff --git a/ecc/bw6-761/multiexp_jacobian.go b/ecc/bw6-761/multiexp_jacobian.go index 21c669647..cb9b215db 100644 --- a/ecc/bw6-761/multiexp_jacobian.go +++ b/ecc/bw6-761/multiexp_jacobian.go @@ -56,7 +56,7 @@ func processChunkG1Jacobian[B ibg1JacExtended](chunk uint64, runningSum.setInfinity() total.setInfinity() for k := len(buckets) - 1; k >= 0; k-- { - if !buckets[k].IsZero() { + if !buckets[k].IsInfinity() { runningSum.add(&buckets[k]) } total.add(&runningSum) @@ -131,7 +131,7 @@ func processChunkG2Jacobian[B ibg2JacExtended](chunk uint64, runningSum.setInfinity() total.setInfinity() for k := len(buckets) - 1; k >= 0; k-- { - if !buckets[k].IsZero() { + if !buckets[k].IsInfinity() { runningSum.add(&buckets[k]) } total.add(&runningSum) diff --git a/ecc/secp256k1/g1.go b/ecc/secp256k1/g1.go index 1417e8b77..0a25344ea 100644 --- a/ecc/secp256k1/g1.go +++ b/ecc/secp256k1/g1.go @@ -25,38 +25,40 @@ import ( "runtime" ) -// G1Affine point in affine coordinates +// G1Affine is a point in affine coordinates (x,y) type G1Affine struct { X, Y fp.Element } -// G1Jac is a point with fp.Element coordinates +// G1Jac is a point in Jacobian coordinates (x=X/Z², y=Y/Z³) type G1Jac struct { X, Y, Z fp.Element } -// g1JacExtended parameterized Jacobian coordinates (x=X/ZZ, y=Y/ZZZ, ZZ³=ZZZ²) +// g1JacExtended is a point in extended Jacobian coordinates (x=X/ZZ, y=Y/ZZZ, ZZ³=ZZZ²) type g1JacExtended struct { X, Y, ZZ, ZZZ fp.Element } // ------------------------------------------------------------------------------------------------- -// Affine +// Affine coordinates -// Set sets p to the provided point +// Set sets p to a in affine coordinates. func (p *G1Affine) Set(a *G1Affine) *G1Affine { p.X, p.Y = a.X, a.Y return p } -// setInfinity sets p to O +// setInfinity sets p to the infinity point, which is encoded as (0,0). +// N.B.: (0,0) is never on the curve for j=0 curves (Y²=X³+B). func (p *G1Affine) setInfinity() *G1Affine { p.X.SetZero() p.Y.SetZero() return p } -// ScalarMultiplication computes and returns p = a ⋅ s +// ScalarMultiplication computes and returns p = [s]a +// where p and a are affine points. func (p *G1Affine) ScalarMultiplication(a *G1Affine, s *big.Int) *G1Affine { var _p G1Jac _p.FromAffine(a) @@ -65,20 +67,22 @@ func (p *G1Affine) ScalarMultiplication(a *G1Affine, s *big.Int) *G1Affine { return p } -// ScalarMultiplicationAffine computes and returns p = a ⋅ s -// Takes an affine point and returns a Jacobian point (useful for KZG) +// ScalarMultiplicationAffine computes and returns p = [s]a +// where a is an affine point and p a Jacobian point (useful for KZG). func (p *G1Jac) ScalarMultiplicationAffine(a *G1Affine, s *big.Int) *G1Jac { p.FromAffine(a) p.mulGLV(p, s) return p } -// ScalarMultiplicationBase computes and returns p = g ⋅ s where g is the prime subgroup generator +// ScalarMultiplicationBase computes and returns p = [s]g +// where g is the Jacobian point generating the prime subgroup. func (p *G1Jac) ScalarMultiplicationBase(s *big.Int) *G1Jac { return p.mulGLV(&g1Gen, s) } -// ScalarMultiplicationBase computes and returns p = g ⋅ s where g is the prime subgroup generator +// ScalarMultiplicationBase computes and returns p = [s]g +// where g is the affine point generating the prime subgroup. func (p *G1Affine) ScalarMultiplicationBase(s *big.Int) *G1Affine { var _p G1Jac _p.mulGLV(&g1Gen, s) @@ -86,8 +90,9 @@ func (p *G1Affine) ScalarMultiplicationBase(s *big.Int) *G1Affine { return p } -// Add adds two point in affine coordinates. -// Jacobian addition with Z1=Z2=1 +// Add adds two points in affine coordinates. +// It uses the Jacobian addition with a.Z=b.Z=1 and converts the result to affine coordinates. +// // https://www.hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html#addition-mmadd-2007-bl func (p *G1Affine) Add(a, b *G1Affine) *G1Affine { var q G1Jac @@ -133,6 +138,10 @@ func (p *G1Affine) Add(a, b *G1Affine) *G1Affine { } // Double doubles a point in affine coordinates. +// It converts the point to Jacobian coordinates, doubles it using Jacobian +// addition with a.Z=1, and converts it back to affine coordinates. +// +// http://www.hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html#doubling-mdbl-2007-bl func (p *G1Affine) Double(a *G1Affine) *G1Affine { var q G1Jac q.FromAffine(a) @@ -141,7 +150,8 @@ func (p *G1Affine) Double(a *G1Affine) *G1Affine { return p } -// Sub subs two point in affine coordinates. +// Sub subtracts two points in affine coordinates. +// It uses a similar approach to Add, but negates the second point before adding. func (p *G1Affine) Sub(a, b *G1Affine) *G1Affine { var bneg G1Affine bneg.Neg(b) @@ -149,19 +159,19 @@ func (p *G1Affine) Sub(a, b *G1Affine) *G1Affine { return p } -// Equal tests if two points (in Affine coordinates) are equal +// Equal tests if two points in affine coordinates are equal. func (p *G1Affine) Equal(a *G1Affine) bool { return p.X.Equal(&a.X) && p.Y.Equal(&a.Y) } -// Neg computes -G +// Neg sets p to the affine negative point -a = (a.X, -a.Y). func (p *G1Affine) Neg(a *G1Affine) *G1Affine { p.X = a.X p.Y.Neg(&a.Y) return p } -// FromJacobian rescales a point in Jacobian coord in z=1 plane +// FromJacobian converts a point p1 from Jacobian to affine coordinates. func (p *G1Affine) FromJacobian(p1 *G1Jac) *G1Affine { var a, b fp.Element @@ -180,7 +190,7 @@ func (p *G1Affine) FromJacobian(p1 *G1Jac) *G1Affine { return p } -// String returns the string representation of the point or "O" if it is infinity +// String returns the string representation E(x,y) of the affine point p or "O" if it is infinity. func (p *G1Affine) String() string { if p.IsInfinity() { return "O" @@ -188,21 +198,20 @@ func (p *G1Affine) String() string { return "E([" + p.X.String() + "," + p.Y.String() + "])" } -// IsInfinity checks if the point is infinity -// in affine, it's encoded as (0,0) -// (0,0) is never on the curve for j=0 curves +// IsInfinity checks if the affine point p is infinity, which is encoded as (0,0). +// N.B.: (0,0) is never on the curve for j=0 curves (Y²=X³+B). func (p *G1Affine) IsInfinity() bool { return p.X.IsZero() && p.Y.IsZero() } -// IsOnCurve returns true if p in on the curve +// IsOnCurve returns true if the affine point p in on the curve. func (p *G1Affine) IsOnCurve() bool { var point G1Jac point.FromAffine(p) return point.IsOnCurve() // call this function to handle infinity point } -// IsInSubGroup returns true if p is in the correct subgroup, false otherwise +// IsInSubGroup returns true if the affine point p is in the correct subgroup, false otherwise. func (p *G1Affine) IsInSubGroup() bool { var _p G1Jac _p.FromAffine(p) @@ -210,84 +219,76 @@ func (p *G1Affine) IsInSubGroup() bool { } // ------------------------------------------------------------------------------------------------- -// Jacobian +// Jacobian coordinates -// Set sets p to the provided point -func (p *G1Jac) Set(a *G1Jac) *G1Jac { - p.X, p.Y, p.Z = a.X, a.Y, a.Z +// Set sets p to a in Jacobian coordinates. +func (p *G1Jac) Set(q *G1Jac) *G1Jac { + p.X, p.Y, p.Z = q.X, q.Y, q.Z return p } -// Equal tests if two points (in Jacobian coordinates) are equal -func (p *G1Jac) Equal(a *G1Jac) bool { +// Equal tests if two points in Jacobian coordinates are equal. +func (p *G1Jac) Equal(q *G1Jac) bool { // If one point is infinity, the other must also be infinity. if p.Z.IsZero() { - return a.Z.IsZero() + return q.Z.IsZero() } // If the other point is infinity, return false since we can't // the following checks would be incorrect. - if a.Z.IsZero() { + if q.Z.IsZero() { return false } var pZSquare, aZSquare fp.Element pZSquare.Square(&p.Z) - aZSquare.Square(&a.Z) + aZSquare.Square(&q.Z) var lhs, rhs fp.Element lhs.Mul(&p.X, &aZSquare) - rhs.Mul(&a.X, &pZSquare) + rhs.Mul(&q.X, &pZSquare) if !lhs.Equal(&rhs) { return false } - lhs.Mul(&p.Y, &aZSquare).Mul(&lhs, &a.Z) - rhs.Mul(&a.Y, &pZSquare).Mul(&rhs, &p.Z) + lhs.Mul(&p.Y, &aZSquare).Mul(&lhs, &q.Z) + rhs.Mul(&q.Y, &pZSquare).Mul(&rhs, &p.Z) return lhs.Equal(&rhs) } -// Neg computes -G -func (p *G1Jac) Neg(a *G1Jac) *G1Jac { - *p = *a - p.Y.Neg(&a.Y) +// Neg sets p to the Jacobian negative point -q = (q.X, -q.Y, q.Z). +func (p *G1Jac) Neg(q *G1Jac) *G1Jac { + *p = *q + p.Y.Neg(&q.Y) return p } -// SubAssign subtracts two points on the curve -func (p *G1Jac) SubAssign(a *G1Jac) *G1Jac { - var tmp G1Jac - tmp.Set(a) - tmp.Y.Neg(&tmp.Y) - p.AddAssign(&tmp) - return p -} - -// AddAssign point addition in montgomery form +// AddAssign sets p to p+a in Jacobian coordinates. +// // https://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-3.html#addition-add-2007-bl -func (p *G1Jac) AddAssign(a *G1Jac) *G1Jac { +func (p *G1Jac) AddAssign(q *G1Jac) *G1Jac { - // p is infinity, return a + // p is infinity, return q if p.Z.IsZero() { - p.Set(a) + p.Set(q) return p } - // a is infinity, return p - if a.Z.IsZero() { + // q is infinity, return p + if q.Z.IsZero() { return p } var Z1Z1, Z2Z2, U1, U2, S1, S2, H, I, J, r, V fp.Element - Z1Z1.Square(&a.Z) + Z1Z1.Square(&q.Z) Z2Z2.Square(&p.Z) - U1.Mul(&a.X, &Z2Z2) + U1.Mul(&q.X, &Z2Z2) U2.Mul(&p.X, &Z1Z1) - S1.Mul(&a.Y, &p.Z). + S1.Mul(&q.Y, &p.Z). Mul(&S1, &Z2Z2) - S2.Mul(&p.Y, &a.Z). + S2.Mul(&p.Y, &q.Z). Mul(&S2, &Z1Z1) - // if p == a, we double instead + // if p == q, we double instead if U1.Equal(&U2) && S1.Equal(&S2) { return p.DoubleAssign() } @@ -306,7 +307,7 @@ func (p *G1Jac) AddAssign(a *G1Jac) *G1Jac { Mul(&p.Y, &r) S1.Mul(&S1, &J).Double(&S1) p.Y.Sub(&p.Y, &S1) - p.Z.Add(&p.Z, &a.Z) + p.Z.Add(&p.Z, &q.Z) p.Z.Square(&p.Z). Sub(&p.Z, &Z1Z1). Sub(&p.Z, &Z2Z2). @@ -315,8 +316,19 @@ func (p *G1Jac) AddAssign(a *G1Jac) *G1Jac { return p } -// DoubleMixed point addition -// http://www.hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html#doubling-mdbl-2007-bl +// SubAssign sets p to p-a in Jacobian coordinates. +// It uses a similar approach to AddAssign, but negates the point a before adding. +func (p *G1Jac) SubAssign(q *G1Jac) *G1Jac { + var tmp G1Jac + tmp.Set(q) + tmp.Y.Neg(&tmp.Y) + p.AddAssign(&tmp) + return p +} + +// Double sets p to [2]q in Jacobian coordinates. +// +// https://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-3.html#doubling-dbl-2007-bl func (p *G1Jac) DoubleMixed(a *G1Affine) *G1Jac { var XX, YY, YYYY, S, M, T fp.Element XX.Square(&a.X) @@ -328,7 +340,7 @@ func (p *G1Jac) DoubleMixed(a *G1Affine) *G1Jac { Sub(&S, &YYYY). Double(&S) M.Double(&XX). - Add(&M, &XX) // -> + a, but a=0 here + Add(&M, &XX) // -> + A, but A=0 here T.Square(&M). Sub(&T, &S). Sub(&T, &S) @@ -344,7 +356,8 @@ func (p *G1Jac) DoubleMixed(a *G1Affine) *G1Jac { return p } -// AddMixed point addition +// AddMixed sets p to p+a in Jacobian coordinates, where a.Z = 1. +// // http://www.hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html#addition-madd-2007-bl func (p *G1Jac) AddMixed(a *G1Affine) *G1Jac { @@ -393,7 +406,8 @@ func (p *G1Jac) AddMixed(a *G1Affine) *G1Jac { return p } -// Double doubles a point in Jacobian coordinates +// Double sets p to [2]q in Jacobian coordinates. +// // https://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-3.html#doubling-dbl-2007-bl func (p *G1Jac) Double(q *G1Jac) *G1Jac { p.Set(q) @@ -401,7 +415,8 @@ func (p *G1Jac) Double(q *G1Jac) *G1Jac { return p } -// DoubleAssign doubles a point in Jacobian coordinates +// DoubleAssign doubles p in Jacobian coordinates. +// // https://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-3.html#doubling-dbl-2007-bl func (p *G1Jac) DoubleAssign() *G1Jac { @@ -433,34 +448,36 @@ func (p *G1Jac) DoubleAssign() *G1Jac { return p } -// ScalarMultiplication computes and returns p = a ⋅ s +// ScalarMultiplication computes and returns p = [s]a +// where p and a are Jacobian points. +// using the GLV technique. // see https://www.iacr.org/archive/crypto2001/21390189.pdf -func (p *G1Jac) ScalarMultiplication(a *G1Jac, s *big.Int) *G1Jac { - return p.mulGLV(a, s) +func (p *G1Jac) ScalarMultiplication(q *G1Jac, s *big.Int) *G1Jac { + return p.mulGLV(q, s) } -// String returns canonical representation of the point in affine coordinates +// String converts p to affine coordinates and returns its string representation E(x,y) or "O" if it is infinity. func (p *G1Jac) String() string { _p := G1Affine{} _p.FromJacobian(p) return _p.String() } -// FromAffine sets p = Q, p in Jacobian, Q in affine -func (p *G1Jac) FromAffine(Q *G1Affine) *G1Jac { - if Q.IsInfinity() { +// FromAffine converts a point a from affine to Jacobian coordinates. +func (p *G1Jac) FromAffine(a *G1Affine) *G1Jac { + if a.IsInfinity() { p.Z.SetZero() p.X.SetOne() p.Y.SetOne() return p } p.Z.SetOne() - p.X.Set(&Q.X) - p.Y.Set(&Q.Y) + p.X.Set(&a.X) + p.Y.Set(&a.Y) return p } -// IsOnCurve returns true if p in on the curve +// IsOnCurve returns true if the Jacobian point p in on the curve. func (p *G1Jac) IsOnCurve() bool { var left, right, tmp, ZZ fp.Element left.Square(&p.Y) @@ -481,13 +498,14 @@ func (p *G1Jac) IsInSubGroup() bool { } -// mulWindowed computes a 2-bits windowed scalar multiplication -func (p *G1Jac) mulWindowed(a *G1Jac, s *big.Int) *G1Jac { +// mulWindowed computes the 2-bits windowed double-and-add scalar +// multiplication p=[s]q in Jacobian coordinates. +func (p *G1Jac) mulWindowed(q *G1Jac, s *big.Int) *G1Jac { var res G1Jac var ops [3]G1Jac - ops[0].Set(a) + ops[0].Set(q) if s.Sign() == -1 { ops[0].Neg(&ops[0]) } @@ -514,17 +532,18 @@ func (p *G1Jac) mulWindowed(a *G1Jac, s *big.Int) *G1Jac { } -// ϕ assigns p to ϕ(a) where ϕ: (x,y) → (w x,y), and returns p -// where w is a third root of unity in 𝔽p -func (p *G1Jac) phi(a *G1Jac) *G1Jac { - p.Set(a) +// phi sets p to ϕ(a) where ϕ: (x,y) → (w x,y), +// where w is a third root of unity. +func (p *G1Jac) phi(q *G1Jac) *G1Jac { + p.Set(q) p.X.Mul(&p.X, &thirdRootOneG1) return p } // mulGLV computes the scalar multiplication using a windowed-GLV method +// // see https://www.iacr.org/archive/crypto2001/21390189.pdf -func (p *G1Jac) mulGLV(a *G1Jac, s *big.Int) *G1Jac { +func (p *G1Jac) mulGLV(q *G1Jac, s *big.Int) *G1Jac { var table [15]G1Jac var res G1Jac @@ -532,11 +551,11 @@ func (p *G1Jac) mulGLV(a *G1Jac, s *big.Int) *G1Jac { res.Set(&g1Infinity) - // table[b3b2b1b0-1] = b3b2 ⋅ ϕ(a) + b1b0*a - table[0].Set(a) - table[3].phi(a) + // table[b3b2b1b0-1] = b3b2 ⋅ ϕ(q) + b1b0*q + table[0].Set(q) + table[3].phi(q) - // split the scalar, modifies ±a, ϕ(a) accordingly + // split the scalar, modifies ±q, ϕ(q) accordingly k := ecc.SplitScalar(s, &glvBasis) if k[0].Sign() == -1 { @@ -549,7 +568,7 @@ func (p *G1Jac) mulGLV(a *G1Jac, s *big.Int) *G1Jac { } // precompute table (2 bits sliding window) - // table[b3b2b1b0-1] = b3b2 ⋅ ϕ(a) + b1b0 ⋅ a if b3b2b1b0 != 0 + // table[b3b2b1b0-1] = b3b2 ⋅ ϕ(q) + b1b0 ⋅ q if b3b2b1b0 != 0 table[1].Double(&table[0]) table[2].Set(&table[1]).AddAssign(&table[0]) table[4].Set(&table[3]).AddAssign(&table[0]) @@ -595,8 +614,8 @@ func (p *G1Jac) mulGLV(a *G1Jac, s *big.Int) *G1Jac { return p } -// JointScalarMultiplicationBase computes [s1]g+[s2]a using Straus-Shamir technique -// where g is the prime subgroup generator +// JointScalarMultiplicationBase computes [s1]g+[s2]a using Strauss-Shamir technique +// where g is the prime subgroup generator and a is an affine point. func (p *G1Jac) JointScalarMultiplicationBase(a *G1Affine, s1, s2 *big.Int) *G1Jac { var res, p1, p2 G1Jac @@ -667,15 +686,15 @@ func (p *G1Jac) JointScalarMultiplicationBase(a *G1Affine, s1, s2 *big.Int) *G1J } // ------------------------------------------------------------------------------------------------- -// Jacobian extended +// extended Jacobian coordinates -// Set sets p to the provided point -func (p *g1JacExtended) Set(a *g1JacExtended) *g1JacExtended { - p.X, p.Y, p.ZZ, p.ZZZ = a.X, a.Y, a.ZZ, a.ZZZ +// Set sets p to a in extended Jacobian coordinates. +func (p *g1JacExtended) Set(q *g1JacExtended) *g1JacExtended { + p.X, p.Y, p.ZZ, p.ZZZ = q.X, q.Y, q.ZZ, q.ZZZ return p } -// setInfinity sets p to O +// setInfinity sets p to the infinity point (1,1,0,0). func (p *g1JacExtended) setInfinity() *g1JacExtended { p.X.SetOne() p.Y.SetOne() @@ -684,43 +703,45 @@ func (p *g1JacExtended) setInfinity() *g1JacExtended { return p } -func (p *g1JacExtended) IsZero() bool { +// IsInfinity checks if the p is infinity, i.e. p.ZZ=0. +func (p *g1JacExtended) IsInfinity() bool { return p.ZZ.IsZero() } -// fromJacExtended sets Q in affine coordinates -func (p *G1Affine) fromJacExtended(Q *g1JacExtended) *G1Affine { - if Q.ZZ.IsZero() { +// fromJacExtended converts an extended Jacobian point to an affine point. +func (p *G1Affine) fromJacExtended(q *g1JacExtended) *G1Affine { + if q.ZZ.IsZero() { p.X = fp.Element{} p.Y = fp.Element{} return p } - p.X.Inverse(&Q.ZZ).Mul(&p.X, &Q.X) - p.Y.Inverse(&Q.ZZZ).Mul(&p.Y, &Q.Y) + p.X.Inverse(&q.ZZ).Mul(&p.X, &q.X) + p.Y.Inverse(&q.ZZZ).Mul(&p.Y, &q.Y) return p } -// fromJacExtended sets Q in Jacobian coordinates -func (p *G1Jac) fromJacExtended(Q *g1JacExtended) *G1Jac { - if Q.ZZ.IsZero() { +// fromJacExtended converts an extended Jacobian point to a Jacobian point. +func (p *G1Jac) fromJacExtended(q *g1JacExtended) *G1Jac { + if q.ZZ.IsZero() { p.Set(&g1Infinity) return p } - p.X.Mul(&Q.ZZ, &Q.X).Mul(&p.X, &Q.ZZ) - p.Y.Mul(&Q.ZZZ, &Q.Y).Mul(&p.Y, &Q.ZZZ) - p.Z.Set(&Q.ZZZ) + p.X.Mul(&q.ZZ, &q.X).Mul(&p.X, &q.ZZ) + p.Y.Mul(&q.ZZZ, &q.Y).Mul(&p.Y, &q.ZZZ) + p.Z.Set(&q.ZZZ) return p } -// unsafeFromJacExtended sets p in Jacobian coordinates, but don't check for infinity -func (p *G1Jac) unsafeFromJacExtended(Q *g1JacExtended) *G1Jac { - p.X.Square(&Q.ZZ).Mul(&p.X, &Q.X) - p.Y.Square(&Q.ZZZ).Mul(&p.Y, &Q.Y) - p.Z = Q.ZZZ +// unsafeFromJacExtended converts an extended Jacobian point, distinct from Infinity, to a Jacobian point. +func (p *G1Jac) unsafeFromJacExtended(q *g1JacExtended) *G1Jac { + p.X.Square(&q.ZZ).Mul(&p.X, &q.X) + p.Y.Square(&q.ZZZ).Mul(&p.Y, &q.Y) + p.Z = q.ZZZ return p } -// add point in Jacobian extended coordinates +// add sets p to p+q in extended Jacobian coordinates. +// // https://www.hyperelliptic.org/EFD/g1p/auto-shortw-xyzz.html#addition-add-2008-s func (p *g1JacExtended) add(q *g1JacExtended) *g1JacExtended { //if q is infinity return p @@ -776,10 +797,11 @@ func (p *g1JacExtended) add(q *g1JacExtended) *g1JacExtended { return p } -// double point in Jacobian extended coordinates +// double sets p to [2]q in Jacobian extended coordinates. +// // http://www.hyperelliptic.org/EFD/g1p/auto-shortw-xyzz.html#doubling-dbl-2008-s-1 -// since we consider any point on Z=0 as the point at infinity -// this doubling formula works for infinity points as well +// N.B.: since we consider any point on Z=0 as the point at infinity +// this doubling formula works for infinity points as well. func (p *g1JacExtended) double(q *g1JacExtended) *g1JacExtended { var U, V, W, S, XX, M fp.Element @@ -789,7 +811,7 @@ func (p *g1JacExtended) double(q *g1JacExtended) *g1JacExtended { S.Mul(&q.X, &V) XX.Square(&q.X) M.Double(&XX). - Add(&M, &XX) // -> + a, but a=0 here + Add(&M, &XX) // -> + A, but A=0 here U.Mul(&W, &q.Y) p.X.Square(&M). @@ -804,9 +826,10 @@ func (p *g1JacExtended) double(q *g1JacExtended) *g1JacExtended { return p } -// subMixed same as addMixed, but will negate a.Y +// addMixed sets p to p+q in extended Jacobian coordinates, where a.ZZ=1. +// // http://www.hyperelliptic.org/EFD/g1p/auto-shortw-xyzz.html#addition-madd-2008-s -func (p *g1JacExtended) subMixed(a *G1Affine) *g1JacExtended { +func (p *g1JacExtended) addMixed(a *G1Affine) *g1JacExtended { //if a is infinity return p if a.IsInfinity() { @@ -815,7 +838,7 @@ func (p *g1JacExtended) subMixed(a *G1Affine) *g1JacExtended { // p is infinity, return a if p.ZZ.IsZero() { p.X = a.X - p.Y.Neg(&a.Y) + p.Y = a.Y p.ZZ.SetOne() p.ZZZ.SetOne() return p @@ -828,12 +851,11 @@ func (p *g1JacExtended) subMixed(a *G1Affine) *g1JacExtended { P.Sub(&P, &p.X) R.Mul(&a.Y, &p.ZZZ) - R.Neg(&R) R.Sub(&R, &p.Y) if P.IsZero() { if R.IsZero() { - return p.doubleNegMixed(a) + return p.doubleMixed(a) } p.ZZ = fp.Element{} @@ -860,9 +882,10 @@ func (p *g1JacExtended) subMixed(a *G1Affine) *g1JacExtended { } -// addMixed +// subMixed works the same as addMixed, but negates a.Y. +// // http://www.hyperelliptic.org/EFD/g1p/auto-shortw-xyzz.html#addition-madd-2008-s -func (p *g1JacExtended) addMixed(a *G1Affine) *g1JacExtended { +func (p *g1JacExtended) subMixed(a *G1Affine) *g1JacExtended { //if a is infinity return p if a.IsInfinity() { @@ -871,7 +894,7 @@ func (p *g1JacExtended) addMixed(a *G1Affine) *g1JacExtended { // p is infinity, return a if p.ZZ.IsZero() { p.X = a.X - p.Y = a.Y + p.Y.Neg(&a.Y) p.ZZ.SetOne() p.ZZZ.SetOne() return p @@ -884,11 +907,12 @@ func (p *g1JacExtended) addMixed(a *G1Affine) *g1JacExtended { P.Sub(&P, &p.X) R.Mul(&a.Y, &p.ZZZ) + R.Neg(&R) R.Sub(&R, &p.Y) if P.IsZero() { if R.IsZero() { - return p.doubleMixed(a) + return p.doubleNegMixed(a) } p.ZZ = fp.Element{} @@ -915,21 +939,21 @@ func (p *g1JacExtended) addMixed(a *G1Affine) *g1JacExtended { } -// doubleNegMixed same as double, but will negate q.Y -func (p *g1JacExtended) doubleNegMixed(q *G1Affine) *g1JacExtended { +// doubleNegMixed works the same as double, but negates q.Y. +func (p *g1JacExtended) doubleNegMixed(a *G1Affine) *g1JacExtended { var U, V, W, S, XX, M, S2, L fp.Element - U.Double(&q.Y) + U.Double(&a.Y) U.Neg(&U) V.Square(&U) W.Mul(&U, &V) - S.Mul(&q.X, &V) - XX.Square(&q.X) + S.Mul(&a.X, &V) + XX.Square(&a.X) M.Double(&XX). - Add(&M, &XX) // -> + a, but a=0 here + Add(&M, &XX) // -> + A, but A=0 here S2.Double(&S) - L.Mul(&W, &q.Y) + L.Mul(&W, &a.Y) p.X.Square(&M). Sub(&p.X, &S2) @@ -942,21 +966,22 @@ func (p *g1JacExtended) doubleNegMixed(q *G1Affine) *g1JacExtended { return p } -// doubleMixed point in Jacobian extended coordinates +// doubleMixed sets p to [2]a in Jacobian extended coordinates, where a.ZZ=1. +// // http://www.hyperelliptic.org/EFD/g1p/auto-shortw-xyzz.html#doubling-dbl-2008-s-1 -func (p *g1JacExtended) doubleMixed(q *G1Affine) *g1JacExtended { +func (p *g1JacExtended) doubleMixed(a *G1Affine) *g1JacExtended { var U, V, W, S, XX, M, S2, L fp.Element - U.Double(&q.Y) + U.Double(&a.Y) V.Square(&U) W.Mul(&U, &V) - S.Mul(&q.X, &V) - XX.Square(&q.X) + S.Mul(&a.X, &V) + XX.Square(&a.X) M.Double(&XX). - Add(&M, &XX) // -> + a, but a=0 here + Add(&M, &XX) // -> + A, but A=0 here S2.Double(&S) - L.Mul(&W, &q.Y) + L.Mul(&W, &a.Y) p.X.Square(&M). Sub(&p.X, &S2) @@ -970,7 +995,7 @@ func (p *g1JacExtended) doubleMixed(q *G1Affine) *g1JacExtended { } // BatchJacobianToAffineG1 converts points in Jacobian coordinates to Affine coordinates -// performing a single field inversion (Montgomery batch inversion trick). +// performing a single field inversion using the Montgomery batch inversion trick. func BatchJacobianToAffineG1(points []G1Jac) []G1Affine { result := make([]G1Affine, len(points)) zeroes := make([]bool, len(points)) @@ -1020,7 +1045,7 @@ func BatchJacobianToAffineG1(points []G1Jac) []G1Affine { // BatchScalarMultiplicationG1 multiplies the same base by all scalars // and return resulting points in affine coordinates -// uses a simple windowed-NAF like exponentiation algorithm +// uses a simple windowed-NAF-like multiplication algorithm. func BatchScalarMultiplicationG1(base *G1Affine, scalars []fr.Element) []G1Affine { // approximate cost in group ops is // cost = 2^{c-1} + n(scalar.nbBits+nbChunks) @@ -1102,9 +1127,8 @@ func BatchScalarMultiplicationG1(base *G1Affine, scalars []fr.Element) []G1Affin return toReturnAff } -// batch add affine coordinates -// using batch inversion -// special cases (doubling, infinity) must be filtered out before this call +// batchAddG1Affine adds affine points using the Montgomery batch inversion trick. +// Special cases (doubling, infinity) must be filtered out before this call. func batchAddG1Affine[TP pG1Affine, TPP ppG1Affine, TC cG1Affine](R *TPP, P *TP, batchSize int) { var lambda, lambdain TC diff --git a/ecc/secp256k1/multiexp_affine.go b/ecc/secp256k1/multiexp_affine.go index b7bcb9330..83da182a0 100644 --- a/ecc/secp256k1/multiexp_affine.go +++ b/ecc/secp256k1/multiexp_affine.go @@ -225,7 +225,7 @@ func processChunkG1BatchAffine[BJE ibg1JacExtended, B ibG1Affine, BS bitSet, TP total.setInfinity() for k := len(buckets) - 1; k >= 0; k-- { runningSum.addMixed(&buckets[k]) - if !bucketsJE[k].IsZero() { + if !bucketsJE[k].IsInfinity() { runningSum.add(&bucketsJE[k]) } total.add(&runningSum) diff --git a/ecc/secp256k1/multiexp_jacobian.go b/ecc/secp256k1/multiexp_jacobian.go index a63c09e41..bbbc17b0d 100644 --- a/ecc/secp256k1/multiexp_jacobian.go +++ b/ecc/secp256k1/multiexp_jacobian.go @@ -56,7 +56,7 @@ func processChunkG1Jacobian[B ibg1JacExtended](chunk uint64, runningSum.setInfinity() total.setInfinity() for k := len(buckets) - 1; k >= 0; k-- { - if !buckets[k].IsZero() { + if !buckets[k].IsInfinity() { runningSum.add(&buckets[k]) } total.add(&runningSum) diff --git a/ecc/stark-curve/g1.go b/ecc/stark-curve/g1.go index 11b50ba23..9062618a0 100644 --- a/ecc/stark-curve/g1.go +++ b/ecc/stark-curve/g1.go @@ -24,38 +24,40 @@ import ( "github.com/consensys/gnark-crypto/internal/parallel" ) -// G1Affine point in affine coordinates +// G1Affine is a point in affine coordinates (x,y) type G1Affine struct { X, Y fp.Element } -// G1Jac is a point with fp.Element coordinates +// G1Jac is a point in Jacobian coordinates (x=X/Z², y=Y/Z³) type G1Jac struct { X, Y, Z fp.Element } -// g1JacExtended parameterized Jacobian coordinates (x=X/ZZ, y=Y/ZZZ, ZZ³=ZZZ²) +// g1JacExtended is a point in extended Jacobian coordinates (x=X/ZZ, y=Y/ZZZ, ZZ³=ZZZ²) type g1JacExtended struct { X, Y, ZZ, ZZZ fp.Element } // ------------------------------------------------------------------------------------------------- -// Affine +// Affine coordinates -// Set sets p to the provided point +// Set sets p to a in affine coordinates. func (p *G1Affine) Set(a *G1Affine) *G1Affine { p.X, p.Y = a.X, a.Y return p } -// setInfinity sets p to O +// setInfinity sets p to the infinity point, which is encoded as (0,0). +// N.B.: (0,0) is not on the STARK curve (Y²=X³+X+B). func (p *G1Affine) setInfinity() *G1Affine { p.X.SetZero() p.Y.SetZero() return p } -// ScalarMultiplication computes and returns p = a ⋅ s +// ScalarMultiplication computes and returns p = [s]a +// where p and a are affine points. func (p *G1Affine) ScalarMultiplication(a *G1Affine, s *big.Int) *G1Affine { var _p G1Jac _p.FromAffine(a) @@ -64,15 +66,8 @@ func (p *G1Affine) ScalarMultiplication(a *G1Affine, s *big.Int) *G1Affine { return p } -// ScalarMultiplicationAffine computes and returns p = a ⋅ s -// Takes an affine point and returns a Jacobian point (useful for KZG) -func (p *G1Jac) ScalarMultiplicationAffine(a *G1Affine, s *big.Int) *G1Jac { - p.FromAffine(a) - p.mulWindowed(p, s) - return p -} - -// ScalarMultiplication computes and returns p = g ⋅ s where g is the prime subgroup generator +// ScalarMultiplicationBase computes and returns p = [s]g +// where g is the affine point generating the prime subgroup. func (p *G1Affine) ScalarMultiplicationBase(s *big.Int) *G1Affine { var _p G1Jac _p.mulWindowed(&g1Gen, s) @@ -80,8 +75,10 @@ func (p *G1Affine) ScalarMultiplicationBase(s *big.Int) *G1Affine { return p } -// Add adds two point in affine coordinates. -// This should rarely be used as it is very inefficient compared to Jacobian +// Add adds two points in affine coordinates. +// It uses the Jacobian addition with a.Z=b.Z=1 and converts the result to affine coordinates. +// +// https://www.hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html#addition-mmadd-2007-bl func (p *G1Affine) Add(a, b *G1Affine) *G1Affine { var p1, p2 G1Jac p1.FromAffine(a) @@ -91,8 +88,8 @@ func (p *G1Affine) Add(a, b *G1Affine) *G1Affine { return p } -// Sub subs two point in affine coordinates. -// This should rarely be used as it is very inefficient compared to Jacobian +// Sub subtracts two points in affine coordinates. +// It uses a similar approach to Add, but negates the second point before adding. func (p *G1Affine) Sub(a, b *G1Affine) *G1Affine { var p1, p2 G1Jac p1.FromAffine(a) @@ -102,19 +99,19 @@ func (p *G1Affine) Sub(a, b *G1Affine) *G1Affine { return p } -// Equal tests if two points (in Affine coordinates) are equal +// Equal tests if two points in affine coordinates are equal. func (p *G1Affine) Equal(a *G1Affine) bool { return p.X.Equal(&a.X) && p.Y.Equal(&a.Y) } -// Neg computes -G +// Neg sets p to the affine negative point -a = (a.X, -a.Y). func (p *G1Affine) Neg(a *G1Affine) *G1Affine { p.X = a.X p.Y.Neg(&a.Y) return p } -// FromJacobian rescales a point in Jacobian coord in z=1 plane +// FromJacobian converts a point p1 from Jacobian to affine coordinates. func (p *G1Affine) FromJacobian(p1 *G1Jac) *G1Affine { var a, b fp.Element @@ -133,7 +130,7 @@ func (p *G1Affine) FromJacobian(p1 *G1Jac) *G1Affine { return p } -// String returns the string representation of the point or "O" if it is infinity +// String returns the string representation E(x,y) of the affine point p or "O" if it is infinity. func (p *G1Affine) String() string { if p.IsInfinity() { return "O" @@ -141,21 +138,20 @@ func (p *G1Affine) String() string { return "E([" + p.X.String() + "," + p.Y.String() + "])" } -// IsInfinity checks if the point is infinity -// in affine, it's encoded as (0,0) -// (0,0) is never on the curve for j=0 curves +// IsInfinity checks if the affine point p is infinity, which is encoded as (0,0). +// N.B.: (0,0) is not on the STARK curve (Y²=X³+X+B). func (p *G1Affine) IsInfinity() bool { return p.X.IsZero() && p.Y.IsZero() } -// IsOnCurve returns true if p in on the curve +// IsOnCurve returns true if the affine point p in on the curve. func (p *G1Affine) IsOnCurve() bool { var point G1Jac point.FromAffine(p) return point.IsOnCurve() // call this function to handle infinity point } -// IsInSubGroup returns true if p is in the correct subgroup, false otherwise +// IsInSubGroup returns true if the affine point p is in the correct subgroup, false otherwise. func (p *G1Affine) IsInSubGroup() bool { var _p G1Jac _p.FromAffine(p) @@ -163,15 +159,15 @@ func (p *G1Affine) IsInSubGroup() bool { } // ------------------------------------------------------------------------------------------------- -// Jacobian +// Jacobian coordinates -// Set sets p to the provided point -func (p *G1Jac) Set(a *G1Jac) *G1Jac { - p.X, p.Y, p.Z = a.X, a.Y, a.Z +// Set sets p to a in Jacobian coordinates. +func (p *G1Jac) Set(q *G1Jac) *G1Jac { + p.X, p.Y, p.Z = q.X, q.Y, q.Z return p } -// Equal tests if two points (in Jacobian coordinates) are equal +// Equal tests if two points in Jacobian coordinates are equal. func (p *G1Jac) Equal(a *G1Jac) bool { if p.Z.IsZero() && a.Z.IsZero() { @@ -186,14 +182,15 @@ func (p *G1Jac) Equal(a *G1Jac) bool { return _p.X.Equal(&_a.X) && _p.Y.Equal(&_a.Y) } -// Neg computes -G -func (p *G1Jac) Neg(a *G1Jac) *G1Jac { - *p = *a - p.Y.Neg(&a.Y) +// Neg sets p to the Jacobian negative point -q = (q.X, -q.Y, q.Z). +func (p *G1Jac) Neg(q *G1Jac) *G1Jac { + *p = *q + p.Y.Neg(&q.Y) return p } -// SubAssign subtracts two points on the curve +// SubAssign sets p to p-a in Jacobian coordinates. +// It uses a similar approach to AddAssign, but negates the point a before adding. func (p *G1Jac) SubAssign(a *G1Jac) *G1Jac { var tmp G1Jac tmp.Set(a) @@ -202,7 +199,8 @@ func (p *G1Jac) SubAssign(a *G1Jac) *G1Jac { return p } -// AddAssign point addition in montgomery form +// AddAssign sets p to p+a in Jacobian coordinates. +// // https://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-3.html#addition-add-2007-bl func (p *G1Jac) AddAssign(a *G1Jac) *G1Jac { @@ -255,7 +253,8 @@ func (p *G1Jac) AddAssign(a *G1Jac) *G1Jac { return p } -// AddMixed point addition +// AddMixed sets p to p+a in Jacobian coordinates, where a.Z = 1. +// // http://www.hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html#addition-madd-2007-bl func (p *G1Jac) AddMixed(a *G1Affine) *G1Jac { @@ -304,7 +303,8 @@ func (p *G1Jac) AddMixed(a *G1Affine) *G1Jac { return p } -// Double doubles a point in Jacobian coordinates +// Double sets p to [2]q in Jacobian coordinates. +// // https://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-3.html#doubling-dbl-2007-bl func (p *G1Jac) Double(q *G1Jac) *G1Jac { p.Set(q) @@ -312,7 +312,8 @@ func (p *G1Jac) Double(q *G1Jac) *G1Jac { return p } -// DoubleAssign doubles a point in Jacobian coordinates +// DoubleAssign doubles p in Jacobian coordinates. +// // https://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-3.html#doubling-dbl-2007-bl func (p *G1Jac) DoubleAssign() *G1Jac { @@ -346,20 +347,20 @@ func (p *G1Jac) DoubleAssign() *G1Jac { return p } -// ScalarMultiplication computes and returns p = a ⋅ s -// using 2-bits windowed exponentiation +// ScalarMultiplication computes and returns p = [s]a +// using a 2-bits windowed double-and-add method. func (p *G1Jac) ScalarMultiplication(a *G1Jac, s *big.Int) *G1Jac { return p.mulWindowed(a, s) } -// String returns canonical representation of the point in affine coordinates +// String converts p to affine coordinates and returns its string representation E(x,y) or "O" if it is infinity. func (p *G1Jac) String() string { _p := G1Affine{} _p.FromJacobian(p) return _p.String() } -// FromAffine sets p = Q, p in Jacobian, Q in affine +// FromAffine converts a point a from affine to Jacobian coordinates. func (p *G1Jac) FromAffine(Q *G1Affine) *G1Jac { if Q.IsInfinity() { p.Z.SetZero() @@ -391,13 +392,16 @@ func (p *G1Jac) IsOnCurve() bool { } // IsInSubGroup returns true if p is on the r-torsion, false otherwise. +// the curve is of prime order i.e. E(𝔽p) is the full group +// so we just check that the point is on the curve. func (p *G1Jac) IsInSubGroup() bool { return p.IsOnCurve() } -// mulWindowed computes a 2-bits windowed scalar multiplication +// mulWindowed computes the 2-bits windowed double-and-add scalar +// multiplication p=[s]q in Jacobian coordinates. func (p *G1Jac) mulWindowed(a *G1Jac, s *big.Int) *G1Jac { var res G1Jac @@ -568,15 +572,15 @@ func (p *G1Jac) JointScalarMultiplication(p1, p2 *G1Jac, s1, s2 *big.Int) *G1Jac } // ------------------------------------------------------------------------------------------------- -// Jacobian extended +// extended Jacobian coordinates -// Set sets p to the provided point +// Set sets p to a in extended Jacobian coordinates. func (p *g1JacExtended) Set(a *g1JacExtended) *g1JacExtended { p.X, p.Y, p.ZZ, p.ZZZ = a.X, a.Y, a.ZZ, a.ZZZ return p } -// setInfinity sets p to O +// setInfinity sets p to the infinity point (1,1,0,0). func (p *g1JacExtended) setInfinity() *g1JacExtended { p.X.SetOne() p.Y.SetOne() @@ -585,7 +589,7 @@ func (p *g1JacExtended) setInfinity() *g1JacExtended { return p } -// fromJacExtended sets Q in affine coordinates +// fromJacExtended converts an extended Jacobian point to an affine point. func (p *G1Affine) fromJacExtended(Q *g1JacExtended) *G1Affine { if Q.ZZ.IsZero() { p.X = fp.Element{} @@ -597,7 +601,7 @@ func (p *G1Affine) fromJacExtended(Q *g1JacExtended) *G1Affine { return p } -// fromJacExtended sets Q in Jacobian coordinates +// fromJacExtended converts an extended Jacobian point to a Jacobian point. func (p *G1Jac) fromJacExtended(Q *g1JacExtended) *G1Jac { if Q.ZZ.IsZero() { p.Set(&g1Infinity) @@ -609,7 +613,7 @@ func (p *G1Jac) fromJacExtended(Q *g1JacExtended) *G1Jac { return p } -// unsafeFromJacExtended sets p in Jacobian coordinates, but don't check for infinity +// unsafeFromJacExtended converts an extended Jacobian point, distinct from Infinity, to a Jacobian point. func (p *G1Jac) unsafeFromJacExtended(Q *g1JacExtended) *G1Jac { p.X.Square(&Q.ZZ).Mul(&p.X, &Q.X) p.Y.Square(&Q.ZZZ).Mul(&p.Y, &Q.Y) @@ -617,7 +621,8 @@ func (p *G1Jac) unsafeFromJacExtended(Q *g1JacExtended) *G1Jac { return p } -// add point in Jacobian extended coordinates +// add sets p to p+q in extended Jacobian coordinates. +// // https://www.hyperelliptic.org/EFD/g1p/auto-shortw-xyzz.html#addition-add-2008-s func (p *g1JacExtended) add(q *g1JacExtended) *g1JacExtended { //if q is infinity return p @@ -673,10 +678,11 @@ func (p *g1JacExtended) add(q *g1JacExtended) *g1JacExtended { return p } -// double point in Jacobian extended coordinates +// double sets p to [2]q in Jacobian extended coordinates. +// // http://www.hyperelliptic.org/EFD/g1p/auto-shortw-xyzz.html#doubling-dbl-2008-s-1 -// since we consider any point on Z=0 as the point at infinity -// this doubling formula works for infinity points as well +// N.B.: since we consider any point on Z=0 as the point at infinity +// this doubling formula works for infinity points as well. func (p *g1JacExtended) double(q *g1JacExtended) *g1JacExtended { var Z, U, V, W, S, XX, M fp.Element @@ -703,7 +709,8 @@ func (p *g1JacExtended) double(q *g1JacExtended) *g1JacExtended { return p } -// subMixed same as addMixed, but will negate a.Y +// subMixed is the same as addMixed, but negates a.Y. +// // http://www.hyperelliptic.org/EFD/g1p/auto-shortw-xyzz.html#addition-madd-2008-s func (p *g1JacExtended) subMixed(a *G1Affine) *g1JacExtended { @@ -759,7 +766,8 @@ func (p *g1JacExtended) subMixed(a *G1Affine) *g1JacExtended { } -// addMixed +// addMixed sets p to p+q in extended Jacobian coordinates, where a.ZZ=1. +// // http://www.hyperelliptic.org/EFD/g1p/auto-shortw-xyzz.html#addition-madd-2008-s func (p *g1JacExtended) addMixed(a *G1Affine) *g1JacExtended { @@ -814,7 +822,7 @@ func (p *g1JacExtended) addMixed(a *G1Affine) *g1JacExtended { } -// doubleNegMixed same as double, but will negate q.Y +// doubleNegMixed works the same as double, but negates q.Y. func (p *g1JacExtended) doubleNegMixed(q *G1Affine) *g1JacExtended { var Z, U, V, W, S, XX, M, S2, L fp.Element @@ -843,7 +851,8 @@ func (p *g1JacExtended) doubleNegMixed(q *G1Affine) *g1JacExtended { return p } -// doubleMixed point in Jacobian extended coordinates +// doubleMixed sets p to [2]a in Jacobian extended coordinates, where a.ZZ=1. +// // http://www.hyperelliptic.org/EFD/g1p/auto-shortw-xyzz.html#doubling-dbl-2008-s-1 func (p *g1JacExtended) doubleMixed(q *G1Affine) *g1JacExtended { @@ -873,7 +882,7 @@ func (p *g1JacExtended) doubleMixed(q *G1Affine) *g1JacExtended { } // BatchJacobianToAffineG1 converts points in Jacobian coordinates to Affine coordinates -// performing a single field inversion (Montgomery batch inversion trick). +// performing a single field inversion using the Montgomery batch inversion trick. func BatchJacobianToAffineG1(points []G1Jac) []G1Affine { result := make([]G1Affine, len(points)) zeroes := make([]bool, len(points)) diff --git a/internal/generator/ecc/template/multiexp_affine.go.tmpl b/internal/generator/ecc/template/multiexp_affine.go.tmpl index 5ba73557f..07aada388 100644 --- a/internal/generator/ecc/template/multiexp_affine.go.tmpl +++ b/internal/generator/ecc/template/multiexp_affine.go.tmpl @@ -230,7 +230,7 @@ func processChunk{{ $.UPointName }}BatchAffine[BJE ib{{ $.TJacobianExtended }},B total.setInfinity() for k := len(buckets) - 1; k >= 0; k-- { runningSum.addMixed(&buckets[k]) - if !bucketsJE[k].IsZero() { + if !bucketsJE[k].IsInfinity() { runningSum.add(&bucketsJE[k]) } total.add(&runningSum) diff --git a/internal/generator/ecc/template/multiexp_jacobian.go.tmpl b/internal/generator/ecc/template/multiexp_jacobian.go.tmpl index 1dce6fc55..39a6b55c7 100644 --- a/internal/generator/ecc/template/multiexp_jacobian.go.tmpl +++ b/internal/generator/ecc/template/multiexp_jacobian.go.tmpl @@ -58,7 +58,7 @@ func processChunk{{ $.UPointName }}Jacobian[B ib{{ $.TJacobianExtended }}](chunk runningSum.setInfinity() total.setInfinity() for k := len(buckets) - 1; k >= 0; k-- { - if !buckets[k].IsZero() { + if !buckets[k].IsInfinity() { runningSum.add(&buckets[k]) } total.add(&runningSum) diff --git a/internal/generator/ecc/template/point.go.tmpl b/internal/generator/ecc/template/point.go.tmpl index c173459c1..f28a4a695 100644 --- a/internal/generator/ecc/template/point.go.tmpl +++ b/internal/generator/ecc/template/point.go.tmpl @@ -22,17 +22,17 @@ import ( ) -// {{ $TAffine }} point in affine coordinates +// {{ $TAffine }} is a point in affine coordinates (x,y) type {{ $TAffine }} struct { X, Y {{.CoordType}} } -// {{ $TJacobian }} is a point with {{.CoordType}} coordinates +// {{ $TJacobian }} is a point in Jacobian coordinates (x=X/Z², y=Y/Z³) type {{ $TJacobian }} struct { X, Y, Z {{.CoordType}} } -// {{ $TJacobianExtended }} parameterized Jacobian coordinates (x=X/ZZ, y=Y/ZZZ, ZZ³=ZZZ²) +// {{ $TJacobianExtended }} is a point in extended Jacobian coordinates (x=X/ZZ, y=Y/ZZZ, ZZ³=ZZZ²) type {{ $TJacobianExtended }} struct { X, Y, ZZ, ZZZ {{.CoordType}} } @@ -47,22 +47,24 @@ type {{ $TProjective }} struct { // ------------------------------------------------------------------------------------------------- -// Affine +// Affine coordinates -// Set sets p to the provided point +// Set sets p to a in affine coordinates. func (p *{{ $TAffine }}) Set(a *{{ $TAffine }}) *{{ $TAffine }} { p.X, p.Y = a.X, a.Y return p } -// setInfinity sets p to O +// setInfinity sets p to the infinity point, which is encoded as (0,0). +// N.B.: (0,0) is never on the curve for j=0 curves (Y²=X³+B). func (p *{{ $TAffine }}) setInfinity() *{{ $TAffine }} { p.X.SetZero() p.Y.SetZero() return p } -// ScalarMultiplication computes and returns p = a ⋅ s +// ScalarMultiplication computes and returns p = [s]a +// where p and a are affine points. func (p *{{ $TAffine }}) ScalarMultiplication(a *{{ $TAffine }}, s *big.Int) *{{ $TAffine }} { var _p {{ $TJacobian }} _p.FromAffine(a) @@ -76,8 +78,8 @@ func (p *{{ $TAffine }}) ScalarMultiplication(a *{{ $TAffine }}, s *big.Int) *{{ } {{- if eq .PointName "g1"}} -// ScalarMultiplicationAffine computes and returns p = a ⋅ s -// Takes an affine point and returns a Jacobian point (useful for KZG) +// ScalarMultiplicationAffine computes and returns p = [s]a +// where a is an affine point and p a Jacobian point (useful for KZG). func (p *{{ $TJacobian }}) ScalarMultiplicationAffine(a *{{ $TAffine }}, s *big.Int) *{{ $TJacobian }} { p.FromAffine(a) {{- if .GLV}} @@ -88,13 +90,15 @@ func (p *{{ $TJacobian }}) ScalarMultiplicationAffine(a *{{ $TAffine }}, s *big. return p } -// ScalarMultiplicationBase computes and returns p = g ⋅ s where g is the prime subgroup generator +// ScalarMultiplicationBase computes and returns p = [s]g +// where g is the Jacobian point generating the prime subgroup. func (p *{{ $TJacobian }}) ScalarMultiplicationBase(s *big.Int) *{{ $TJacobian }} { return p.mulGLV(&g1Gen, s) } {{- end}} -// ScalarMultiplicationBase computes and returns p = g ⋅ s where g is the prime subgroup generator +// ScalarMultiplicationBase computes and returns p = [s]g +// where g is the affine point generating the prime subgroup. func (p *{{ $TAffine }}) ScalarMultiplicationBase(s *big.Int) *{{ $TAffine }} { var _p {{ $TJacobian }} _p.mulGLV(&{{ toLower .PointName}}Gen, s) @@ -103,8 +107,9 @@ func (p *{{ $TAffine }}) ScalarMultiplicationBase(s *big.Int) *{{ $TAffine }} { } -// Add adds two point in affine coordinates. -// Jacobian addition with Z1=Z2=1 +// Add adds two points in affine coordinates. +// It uses the Jacobian addition with a.Z=b.Z=1 and converts the result to affine coordinates. +// // https://www.hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html#addition-mmadd-2007-bl func (p *{{ $TAffine }}) Add(a, b *{{ $TAffine }}) *{{ $TAffine }} { var q {{ $TJacobian }} @@ -150,6 +155,10 @@ func (p *{{ $TAffine }}) Add(a, b *{{ $TAffine }}) *{{ $TAffine }} { } // Double doubles a point in affine coordinates. +// It converts the point to Jacobian coordinates, doubles it using Jacobian +// addition with a.Z=1, and converts it back to affine coordinates. +// +// http://www.hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html#doubling-mdbl-2007-bl func (p *{{ $TAffine }}) Double(a *{{ $TAffine }}) *{{ $TAffine }} { var q {{ $TJacobian }} q.FromAffine(a) @@ -158,7 +167,8 @@ func (p *{{ $TAffine }}) Double(a *{{ $TAffine }}) *{{ $TAffine }} { return p } -// Sub subs two point in affine coordinates. +// Sub subtracts two points in affine coordinates. +// It uses a similar approach to Add, but negates the second point before adding. func (p *{{ $TAffine }}) Sub(a, b *{{ $TAffine }}) *{{ $TAffine }} { var bneg {{ $TAffine }} bneg.Neg(b) @@ -166,23 +176,20 @@ func (p *{{ $TAffine }}) Sub(a, b *{{ $TAffine }}) *{{ $TAffine }} { return p } -// Equal tests if two points (in Affine coordinates) are equal +// Equal tests if two points in affine coordinates are equal. func (p *{{ $TAffine }}) Equal(a *{{ $TAffine }}) bool { return p.X.Equal(&a.X) && p.Y.Equal(&a.Y) } -// Neg computes -G +// Neg sets p to the affine negative point -a = (a.X, -a.Y). func (p *{{ $TAffine }}) Neg(a *{{ $TAffine }}) *{{ $TAffine }} { p.X = a.X p.Y.Neg(&a.Y) return p } - - - -// FromJacobian rescales a point in Jacobian coord in z=1 plane +// FromJacobian converts a point p1 from Jacobian to affine coordinates. func (p *{{ $TAffine }}) FromJacobian(p1 *{{ $TJacobian }}) *{{ $TAffine }} { var a, b {{.CoordType}} @@ -201,8 +208,7 @@ func (p *{{ $TAffine }}) FromJacobian(p1 *{{ $TJacobian }}) *{{ $TAffine }} { return p } - -// String returns the string representation of the point or "O" if it is infinity +// String returns the string representation E(x,y) of the affine point p or "O" if it is infinity. func (p *{{ $TAffine }}) String() string { if p.IsInfinity() { return "O" @@ -210,21 +216,20 @@ func (p *{{ $TAffine }}) String() string { return "E([" + p.X.String() + "," + p.Y.String() + "])" } -// IsInfinity checks if the point is infinity -// in affine, it's encoded as (0,0) -// (0,0) is never on the curve for j=0 curves +// IsInfinity checks if the affine point p is infinity, which is encoded as (0,0). +// N.B.: (0,0) is never on the curve for j=0 curves (Y²=X³+B). func (p *{{ $TAffine }}) IsInfinity() bool { return p.X.IsZero() && p.Y.IsZero() } -// IsOnCurve returns true if p in on the curve +// IsOnCurve returns true if the affine point p in on the curve. func (p *{{ $TAffine }}) IsOnCurve() bool { var point {{ $TJacobian }} point.FromAffine(p) return point.IsOnCurve() // call this function to handle infinity point } -// IsInSubGroup returns true if p is in the correct subgroup, false otherwise +// IsInSubGroup returns true if the affine point p is in the correct subgroup, false otherwise. func (p *{{ $TAffine }}) IsInSubGroup() bool { var _p {{ $TJacobian }} _p.FromAffine(p) @@ -233,86 +238,76 @@ func (p *{{ $TAffine }}) IsInSubGroup() bool { // ------------------------------------------------------------------------------------------------- -// Jacobian +// Jacobian coordinates -// Set sets p to the provided point -func (p *{{ $TJacobian }}) Set(a *{{ $TJacobian }}) *{{ $TJacobian }} { - p.X, p.Y, p.Z = a.X, a.Y, a.Z +// Set sets p to a in Jacobian coordinates. +func (p *{{ $TJacobian }}) Set(q *{{ $TJacobian }}) *{{ $TJacobian }} { + p.X, p.Y, p.Z = q.X, q.Y, q.Z return p } -// Equal tests if two points (in Jacobian coordinates) are equal -func (p *{{ $TJacobian }}) Equal(a *{{ $TJacobian }}) bool { +// Equal tests if two points in Jacobian coordinates are equal. +func (p *{{ $TJacobian }}) Equal(q *{{ $TJacobian }}) bool { // If one point is infinity, the other must also be infinity. if p.Z.IsZero() { - return a.Z.IsZero() + return q.Z.IsZero() } // If the other point is infinity, return false since we can't // the following checks would be incorrect. - if a.Z.IsZero() { + if q.Z.IsZero() { return false } var pZSquare, aZSquare {{.CoordType}} pZSquare.Square(&p.Z) - aZSquare.Square(&a.Z) + aZSquare.Square(&q.Z) var lhs, rhs {{.CoordType}} lhs.Mul(&p.X, &aZSquare) - rhs.Mul(&a.X, &pZSquare) + rhs.Mul(&q.X, &pZSquare) if !lhs.Equal(&rhs) { return false } - lhs.Mul(&p.Y, &aZSquare).Mul(&lhs, &a.Z) - rhs.Mul(&a.Y, &pZSquare).Mul(&rhs, &p.Z) + lhs.Mul(&p.Y, &aZSquare).Mul(&lhs, &q.Z) + rhs.Mul(&q.Y, &pZSquare).Mul(&rhs, &p.Z) return lhs.Equal(&rhs) } -// Neg computes -G -func (p *{{ $TJacobian }}) Neg(a *{{ $TJacobian }}) *{{ $TJacobian }} { - *p = *a - p.Y.Neg(&a.Y) - return p -} - - -// SubAssign subtracts two points on the curve -func (p *{{ $TJacobian }}) SubAssign(a *{{ $TJacobian }}) *{{ $TJacobian }} { - var tmp {{ $TJacobian }} - tmp.Set(a) - tmp.Y.Neg(&tmp.Y) - p.AddAssign(&tmp) +// Neg sets p to the Jacobian negative point -q = (q.X, -q.Y, q.Z). +func (p *{{ $TJacobian }}) Neg(q *{{ $TJacobian }}) *{{ $TJacobian }} { + *p = *q + p.Y.Neg(&q.Y) return p } - -// AddAssign point addition in montgomery form +// AddAssign sets p to p+a in Jacobian coordinates. +// // https://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-3.html#addition-add-2007-bl -func (p *{{ $TJacobian }}) AddAssign(a *{{ $TJacobian }}) *{{ $TJacobian }} { +func (p *{{ $TJacobian }}) AddAssign(q *{{ $TJacobian }}) *{{ $TJacobian }} { - // p is infinity, return a + // p is infinity, return q if p.Z.IsZero() { - p.Set(a) + p.Set(q) return p } - // a is infinity, return p - if a.Z.IsZero() { + // q is infinity, return p + if q.Z.IsZero() { return p } var Z1Z1, Z2Z2, U1, U2, S1, S2, H, I, J, r, V {{.CoordType}} - Z1Z1.Square(&a.Z) + Z1Z1.Square(&q.Z) Z2Z2.Square(&p.Z) - U1.Mul(&a.X, &Z2Z2) + U1.Mul(&q.X, &Z2Z2) U2.Mul(&p.X, &Z1Z1) - S1.Mul(&a.Y, &p.Z). + S1.Mul(&q.Y, &p.Z). Mul(&S1, &Z2Z2) - S2.Mul(&p.Y, &a.Z). + S2.Mul(&p.Y, &q.Z). Mul(&S2, &Z1Z1) - // if p == a, we double instead + // if p == q, we double instead if U1.Equal(&U2) && S1.Equal(&S2) { return p.DoubleAssign() } @@ -331,7 +326,7 @@ func (p *{{ $TJacobian }}) AddAssign(a *{{ $TJacobian }}) *{{ $TJacobian }} { Mul(&p.Y, &r) S1.Mul(&S1, &J).Double(&S1) p.Y.Sub(&p.Y, &S1) - p.Z.Add(&p.Z, &a.Z) + p.Z.Add(&p.Z, &q.Z) p.Z.Square(&p.Z). Sub(&p.Z, &Z1Z1). Sub(&p.Z, &Z2Z2). @@ -340,8 +335,19 @@ func (p *{{ $TJacobian }}) AddAssign(a *{{ $TJacobian }}) *{{ $TJacobian }} { return p } -// DoubleMixed point addition -// http://www.hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html#doubling-mdbl-2007-bl +// SubAssign sets p to p-a in Jacobian coordinates. +// It uses a similar approach to AddAssign, but negates the point a before adding. +func (p *{{ $TJacobian }}) SubAssign(q *{{ $TJacobian }}) *{{ $TJacobian }} { + var tmp {{ $TJacobian }} + tmp.Set(q) + tmp.Y.Neg(&tmp.Y) + p.AddAssign(&tmp) + return p +} + +// Double sets p to [2]q in Jacobian coordinates. +// +// https://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-3.html#doubling-dbl-2007-bl func (p *{{ $TJacobian }}) DoubleMixed(a *{{ $TAffine }}) *{{ $TJacobian }} { var XX, YY, YYYY, S, M, T {{.CoordType}} XX.Square(&a.X) @@ -353,7 +359,7 @@ func (p *{{ $TJacobian }}) DoubleMixed(a *{{ $TAffine }}) *{{ $TJacobian }} { Sub(&S, &YYYY). Double(&S) M.Double(&XX). - Add(&M, &XX) // -> + a, but a=0 here + Add(&M, &XX) // -> + A, but A=0 here T.Square(&M). Sub(&T, &S). Sub(&T, &S) @@ -369,7 +375,8 @@ func (p *{{ $TJacobian }}) DoubleMixed(a *{{ $TAffine }}) *{{ $TJacobian }} { return p } -// AddMixed point addition +// AddMixed sets p to p+a in Jacobian coordinates, where a.Z = 1. +// // http://www.hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html#addition-madd-2007-bl func (p *{{ $TJacobian }}) AddMixed(a *{{ $TAffine }}) *{{ $TJacobian }} { @@ -418,7 +425,8 @@ func (p *{{ $TJacobian }}) AddMixed(a *{{ $TAffine }}) *{{ $TJacobian }} { return p } -// Double doubles a point in Jacobian coordinates +// Double sets p to [2]q in Jacobian coordinates. +// // https://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-3.html#doubling-dbl-2007-bl func (p *{{ $TJacobian }}) Double(q *{{ $TJacobian }}) *{{ $TJacobian }} { p.Set(q) @@ -426,7 +434,8 @@ func (p *{{ $TJacobian }}) Double(q *{{ $TJacobian }}) *{{ $TJacobian }} { return p } -// DoubleAssign doubles a point in Jacobian coordinates +// DoubleAssign doubles p in Jacobian coordinates. +// // https://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-3.html#doubling-dbl-2007-bl func (p *{{ $TJacobian }}) DoubleAssign() *{{ $TJacobian }} { @@ -458,40 +467,44 @@ func (p *{{ $TJacobian }}) DoubleAssign() *{{ $TJacobian }} { return p } - -// ScalarMultiplication computes and returns p = a ⋅ s -// {{- if .GLV}} see https://www.iacr.org/archive/crypto2001/21390189.pdf {{- else }} using 2-bits windowed exponentiation {{- end }} -func (p *{{ $TJacobian }}) ScalarMultiplication(a *{{ $TJacobian }}, s *big.Int) *{{ $TJacobian }} { +// ScalarMultiplication computes and returns p = [s]a +// where p and a are Jacobian points. +{{- if .GLV}} +// using the GLV technique. +// see https://www.iacr.org/archive/crypto2001/21390189.pdf +{{- else }} +// using a 2-bits windowed double-and-add method. +{{- end }} +func (p *{{ $TJacobian }}) ScalarMultiplication(q *{{ $TJacobian }}, s *big.Int) *{{ $TJacobian }} { {{- if .GLV}} - return p.mulGLV(a, s) + return p.mulGLV(q, s) {{- else }} - return p.mulWindowed(a, s) + return p.mulWindowed(q, s) {{- end }} } -// String returns canonical representation of the point in affine coordinates +// String converts p to affine coordinates and returns its string representation E(x,y) or "O" if it is infinity. func (p *{{ $TJacobian }}) String() string { _p := {{ $TAffine }}{} _p.FromJacobian(p) return _p.String() } -// FromAffine sets p = Q, p in Jacobian, Q in affine -func (p *{{ $TJacobian }}) FromAffine(Q *{{ $TAffine }}) *{{ $TJacobian }} { - if Q.IsInfinity() { +// FromAffine converts a point a from affine to Jacobian coordinates. +func (p *{{ $TJacobian }}) FromAffine(a *{{ $TAffine }}) *{{ $TJacobian }} { + if a.IsInfinity() { p.Z.SetZero() p.X.SetOne() p.Y.SetOne() return p } p.Z.SetOne() - p.X.Set(&Q.X) - p.Y.Set(&Q.Y) + p.X.Set(&a.X) + p.Y.Set(&a.Y) return p } - -// IsOnCurve returns true if p in on the curve +// IsOnCurve returns true if the Jacobian point p in on the curve. func (p *{{ $TJacobian }}) IsOnCurve() bool { var left, right, tmp, ZZ {{.CoordType}} left.Square(&p.Y) @@ -719,13 +732,14 @@ func (p *{{ $TJacobian }}) IsOnCurve() bool { {{- end}} -// mulWindowed computes a 2-bits windowed scalar multiplication -func (p *{{ $TJacobian }}) mulWindowed(a *{{ $TJacobian }}, s *big.Int) *{{ $TJacobian }} { +// mulWindowed computes the 2-bits windowed double-and-add scalar +// multiplication p=[s]q in Jacobian coordinates. +func (p *{{ $TJacobian }}) mulWindowed(q *{{ $TJacobian }}, s *big.Int) *{{ $TJacobian }} { var res {{ $TJacobian }} var ops [3]{{ $TJacobian }} - ops[0].Set(a) + ops[0].Set(q) if s.Sign() == -1 { ops[0].Neg(&ops[0]) } @@ -753,18 +767,18 @@ func (p *{{ $TJacobian }}) mulWindowed(a *{{ $TJacobian }}, s *big.Int) *{{ $TJa } {{ if eq .CoordType "fptower.E2" }} - // ψ(p) = u o π o u⁻¹ where u:E'→E iso from the twist to E - func (p *{{ $TJacobian }}) psi(a *{{ $TJacobian }}) *{{ $TJacobian }} { - p.Set(a) + // psi sets p to ψ(q) = u o π o u⁻¹ where u:E'→E is the isomorphism from the twist to the curve E and π is the Frobenius map. + func (p *{{ $TJacobian }}) psi(q *{{ $TJacobian }}) *{{ $TJacobian }} { + p.Set(q) p.X.Conjugate(&p.X).Mul(&p.X, &endo.u) p.Y.Conjugate(&p.Y).Mul(&p.Y, &endo.v) p.Z.Conjugate(&p.Z) return p } {{ else if eq .CoordType "fptower.E4"}} - // ψ(p) = u o π o u⁻¹ where u:E'→E iso from the twist to E - func (p *{{ $TJacobian }}) psi(a *{{ $TJacobian }}) *{{ $TJacobian }} { - p.Set(a) + // psi sets p to ψ(q) = u o π o u⁻¹ where u:E'→E is the isomorphism from the twist to the curve E and π is the Frobenius map. + func (p *{{ $TJacobian }}) psi(q *{{ $TJacobian }}) *{{ $TJacobian }} { + p.Set(q) p.X.Frobenius(&p.X).Mul(&p.X, &endo.u) p.Y.Frobenius(&p.Y).Mul(&p.Y, &endo.v) p.Z.Frobenius(&p.Z) @@ -774,10 +788,10 @@ func (p *{{ $TJacobian }}) mulWindowed(a *{{ $TJacobian }}, s *big.Int) *{{ $TJa {{ if .GLV}} -// ϕ assigns p to ϕ(a) where ϕ: (x,y) → (w x,y), and returns p -// where w is a third root of unity in 𝔽p -func (p *{{ $TJacobian }}) phi(a *{{ $TJacobian }}) *{{ $TJacobian }} { - p.Set(a) +// phi sets p to ϕ(a) where ϕ: (x,y) → (w x,y), +// where w is a third root of unity. +func (p *{{ $TJacobian }}) phi(q *{{ $TJacobian }}) *{{ $TJacobian }} { + p.Set(q) {{- if or (eq .CoordType "fptower.E2" ) (eq .CoordType "fptower.E4" )}} p.X.MulByElement(&p.X, &thirdRootOne{{toUpper .PointName}}) {{- else}} @@ -787,8 +801,9 @@ func (p *{{ $TJacobian }}) phi(a *{{ $TJacobian }}) *{{ $TJacobian }} { } // mulGLV computes the scalar multiplication using a windowed-GLV method +// // see https://www.iacr.org/archive/crypto2001/21390189.pdf -func (p *{{ $TJacobian }}) mulGLV(a *{{ $TJacobian }}, s *big.Int) *{{ $TJacobian }} { +func (p *{{ $TJacobian }}) mulGLV(q *{{ $TJacobian }}, s *big.Int) *{{ $TJacobian }} { var table [15]{{ $TJacobian }} var res {{ $TJacobian }} @@ -796,11 +811,11 @@ func (p *{{ $TJacobian }}) mulGLV(a *{{ $TJacobian }}, s *big.Int) *{{ $TJacobia res.Set(&{{ toLower .PointName}}Infinity) - // table[b3b2b1b0-1] = b3b2 ⋅ ϕ(a) + b1b0*a - table[0].Set(a) - table[3].phi(a) + // table[b3b2b1b0-1] = b3b2 ⋅ ϕ(q) + b1b0*q + table[0].Set(q) + table[3].phi(q) - // split the scalar, modifies ±a, ϕ(a) accordingly + // split the scalar, modifies ±q, ϕ(q) accordingly k := ecc.SplitScalar(s, &glvBasis) if k[0].Sign() == -1 { @@ -813,7 +828,7 @@ func (p *{{ $TJacobian }}) mulGLV(a *{{ $TJacobian }}, s *big.Int) *{{ $TJacobia } // precompute table (2 bits sliding window) - // table[b3b2b1b0-1] = b3b2 ⋅ ϕ(a) + b1b0 ⋅ a if b3b2b1b0 != 0 + // table[b3b2b1b0-1] = b3b2 ⋅ ϕ(q) + b1b0 ⋅ q if b3b2b1b0 != 0 table[1].Double(&table[0]) table[2].Set(&table[1]).AddAssign(&table[0]) table[4].Set(&table[3]).AddAssign(&table[0]) @@ -876,25 +891,25 @@ func (p *{{ $TAffine }}) ClearCofactor(a *{{ $TAffine }}) *{{ $TAffine }} { {{- if eq .PointName "g1"}} // ClearCofactor maps a point in E(Fp) to E(Fp)[r] -func (p *{{$TJacobian}}) ClearCofactor(a *{{$TJacobian}}) *{{$TJacobian}} { +func (p *{{$TJacobian}}) ClearCofactor(q *{{$TJacobian}}) *{{$TJacobian}} { {{- if or (eq .Name "bls12-381") (eq .Name "bls24-315")}} // cf https://eprint.iacr.org/2019/403.pdf, 5 var res {{$TJacobian}} - res.ScalarMultiplication(a, &xGen).AddAssign(a) + res.ScalarMultiplication(q, &xGen).AddAssign(q) p.Set(&res) return p {{else if or (eq .Name "bls12-377") (eq .Name "bls12-378") (eq .Name "bls24-317")}} // cf https://eprint.iacr.org/2019/403.pdf, 5 var res {{$TJacobian}} - res.ScalarMultiplication(a, &xGen).Neg(&res).AddAssign(a) + res.ScalarMultiplication(q, &xGen).Neg(&res).AddAssign(q) p.Set(&res) return p {{else if eq .Name "bw6-761"}} {{ if .GLV}} // https://eprint.iacr.org/2020/351.pdf var points [4]{{$TJacobian}} - points[0].Set(a) - points[1].ScalarMultiplication(a, &xGen) + points[0].Set(q) + points[1].ScalarMultiplication(q, &xGen) points[2].ScalarMultiplication(&points[1], &xGen) points[3].ScalarMultiplication(&points[2], &xGen) @@ -928,7 +943,7 @@ func (p *{{$TJacobian}}) ClearCofactor(a *{{$TJacobian}}) *{{$TJacobian}} { {{ else}} var c1 big.Int c1.SetString("26642435879335816683987677701488073867751118270052650655942102502312977592501693353047140953112195348280268661194876", 10) - p.ScalarMultiplication(a, &c1) + p.ScalarMultiplication(q, &c1) {{ end}} return p @@ -944,27 +959,27 @@ func (p *{{$TJacobian}}) ClearCofactor(a *{{$TJacobian}}) *{{$TJacobian}} { ht.SetInt64(7) v.Mul(&xGen, &xGen).Add(&v, &one).Mul(&v, &uPlusOne) - uP.ScalarMultiplication(a, &xGen).Neg(&uP) - vP.Set(a).SubAssign(&uP). + uP.ScalarMultiplication(q, &xGen).Neg(&uP) + vP.Set(q).SubAssign(&uP). ScalarMultiplication(&vP, &v) wP.ScalarMultiplication(&vP, &uMinusOne).Neg(&wP). AddAssign(&uP) L0.ScalarMultiplication(&wP, &d1) tmp.ScalarMultiplication(&vP, &ht) L0.AddAssign(&tmp) - tmp.Double(a) + tmp.Double(q) L0.AddAssign(&tmp) - L1.Set(&uP).AddAssign(a).ScalarMultiplication(&L1, &d1) + L1.Set(&uP).AddAssign(q).ScalarMultiplication(&L1, &d1) tmp.ScalarMultiplication(&vP, &d2) L1.AddAssign(&tmp) - tmp.ScalarMultiplication(a, &ht) + tmp.ScalarMultiplication(q, &ht) L1.AddAssign(&tmp) p.phi(&L1).AddAssign(&L0) {{ else}} var c1 big.Int c1.SetString("516166855112631370346774477030598579858367278343565509012644853411927535599366632765988905418773", 10) - p.ScalarMultiplication(a, &c1) + p.ScalarMultiplication(q, &c1) {{ end}} return p @@ -972,32 +987,32 @@ func (p *{{$TJacobian}}) ClearCofactor(a *{{$TJacobian}}) *{{$TJacobian}} { {{ if .GLV}} var L0, L1, uP, u2P, u3P, tmp G1Jac - uP.ScalarMultiplication(a, &xGen) + uP.ScalarMultiplication(q, &xGen) u2P.ScalarMultiplication(&uP, &xGen) u3P.ScalarMultiplication(&u2P, &xGen) - L0.Set(a).AddAssign(&u3P). + L0.Set(q).AddAssign(&u3P). SubAssign(&u2P) - tmp.Set(a).AddAssign(&u2P). + tmp.Set(q).AddAssign(&u2P). SubAssign(&uP). SubAssign(&uP). Double(&tmp) L0.SubAssign(&tmp). - SubAssign(a) + SubAssign(q) - L1.Set(a).AddAssign(&uP) - tmp.Set(&uP).SubAssign(a). + L1.Set(q).AddAssign(&uP) + tmp.Set(&uP).SubAssign(q). Double(&tmp). SubAssign(&u2P) L1.AddAssign(&tmp). - SubAssign(a) + SubAssign(q) p.phi(&L1). AddAssign(&L0) {{ else}} var c1 big.Int c1.SetString("605248206075306171568857128027361794400937215108643640003009340657451546212610770151705515081537938829431808196608", 10) - p.ScalarMultiplication(a, &c1) + p.ScalarMultiplication(q, &c1) {{ end}} return p @@ -1006,12 +1021,12 @@ func (p *{{$TJacobian}}) ClearCofactor(a *{{$TJacobian}}) *{{$TJacobian}} { {{ else }} // ClearCofactor maps a point in curve to r-torsion -func (p *{{$TJacobian}}) ClearCofactor(a *{{$TJacobian}}) *{{$TJacobian}} { +func (p *{{$TJacobian}}) ClearCofactor(q *{{$TJacobian}}) *{{$TJacobian}} { {{- if eq .Name "bn254"}} // cf http://cacr.uwaterloo.ca/techreports/2011/cacr2011-26.pdf, 6.1 var points [4]{{$TJacobian}} - points[0].ScalarMultiplication(a, &xGen) + points[0].ScalarMultiplication(q, &xGen) points[1].Double(&points[0]). AddAssign(&points[0]). @@ -1020,7 +1035,7 @@ func (p *{{$TJacobian}}) ClearCofactor(a *{{$TJacobian}}) *{{$TJacobian}} { points[2].psi(&points[0]). psi(&points[2]) - points[3].psi(a).psi(&points[3]).psi(&points[3]) + points[3].psi(q).psi(&points[3]).psi(&points[3]) var res {{$TJacobian}} res.Set(&g2Infinity) @@ -1032,20 +1047,20 @@ func (p *{{$TJacobian}}) ClearCofactor(a *{{$TJacobian}}) *{{$TJacobian}} { {{else if eq .Name "bls12-381"}} // https://eprint.iacr.org/2017/419.pdf, 4.1 var xg, xxg, res, t G2Jac - xg.ScalarMultiplication(a, &xGen).Neg(&xg) + xg.ScalarMultiplication(q, &xGen).Neg(&xg) xxg.ScalarMultiplication(&xg, &xGen).Neg(&xxg) res.Set(&xxg). SubAssign(&xg). - SubAssign(a) + SubAssign(q) t.Set(&xg). - SubAssign(a). + SubAssign(q). psi(&t) res.AddAssign(&t) - t.Double(a) + t.Double(q) t.X.MulByElement(&t.X, &thirdRootOneG1) res.SubAssign(&t) @@ -1057,20 +1072,20 @@ func (p *{{$TJacobian}}) ClearCofactor(a *{{$TJacobian}}) *{{$TJacobian}} { {{else if or (eq .Name "bls12-377") (eq .Name "bls12-378")}} // https://eprint.iacr.org/2017/419.pdf, 4.1 var xg, xxg, res, t G2Jac - xg.ScalarMultiplication(a, &xGen) + xg.ScalarMultiplication(q, &xGen) xxg.ScalarMultiplication(&xg, &xGen) res.Set(&xxg). SubAssign(&xg). - SubAssign(a) + SubAssign(q) t.Set(&xg). - SubAssign(a). + SubAssign(q). psi(&t) res.AddAssign(&t) - t.Double(a) + t.Double(q) t.X.MulByElement(&t.X, &thirdRootOneG1) res.SubAssign(&t) @@ -1084,20 +1099,20 @@ func (p *{{$TJacobian}}) ClearCofactor(a *{{$TJacobian}}) *{{$TJacobian}} { // multiply by (3x⁴-3)*cofacor {{ if eq .Name "bls24-315"}} var xg, xxg, xxxg, xxxxg, res, t G2Jac - xg.ScalarMultiplication(a, &xGen).Neg(&xg).SubAssign(a) + xg.ScalarMultiplication(q, &xGen).Neg(&xg).SubAssign(q) xxg.ScalarMultiplication(&xg, &xGen).Neg(&xxg) xxxg.ScalarMultiplication(&xxg, &xGen).Neg(&xxxg) xxxxg.ScalarMultiplication(&xxxg, &xGen).Neg(&xxxxg) {{ else }} var xg, xxg, xxxg, xxxxg, res, t G2Jac - xg.ScalarMultiplication(a, &xGen).SubAssign(a) + xg.ScalarMultiplication(q, &xGen).SubAssign(q) xxg.ScalarMultiplication(&xg, &xGen) xxxg.ScalarMultiplication(&xxg, &xGen) xxxxg.ScalarMultiplication(&xxxg, &xGen) {{ end }} res.Set(&xxxxg). - SubAssign(a) + SubAssign(q) t.Set(&xxxg). psi(&t). @@ -1114,7 +1129,7 @@ func (p *{{$TJacobian}}) ClearCofactor(a *{{$TJacobian}}) *{{$TJacobian}} { psi(&t). AddAssign(&res) - res.Double(a). + res.Double(q). psi(&res). psi(&res). psi(&res). @@ -1128,8 +1143,8 @@ func (p *{{$TJacobian}}) ClearCofactor(a *{{$TJacobian}}) *{{$TJacobian}} { {{- if .GLV}} var points [4]{{$TJacobian}} - points[0].Set(a) - points[1].ScalarMultiplication(a, &xGen) + points[0].Set(q) + points[1].ScalarMultiplication(q, &xGen) points[2].ScalarMultiplication(&points[1], &xGen) points[3].ScalarMultiplication(&points[2], &xGen) @@ -1163,7 +1178,7 @@ func (p *{{$TJacobian}}) ClearCofactor(a *{{$TJacobian}}) *{{$TJacobian}} { {{else}} var c2 big.Int c2.SetString("26642435879335816683987677701488073867751118270052650655942102502312977592501693353047140953112195348280268661194869", 10) - p.ScalarMultiplication(a, &c2) + p.ScalarMultiplication(q, &c2) {{end}} return p @@ -1175,7 +1190,7 @@ func (p *{{$TJacobian}}) ClearCofactor(a *{{$TJacobian}}) *{{$TJacobian}} { d1.SetInt64(13) d3.SetInt64(5) // negative - uP.ScalarMultiplication(a, &xGen) // negative + uP.ScalarMultiplication(q, &xGen) // negative u2P.ScalarMultiplication(&uP, &xGen) u3P.ScalarMultiplication(&u2P, &xGen) // negative u4P.ScalarMultiplication(&u3P, &xGen) @@ -1184,25 +1199,25 @@ func (p *{{$TJacobian}}) ClearCofactor(a *{{$TJacobian}}) *{{$TJacobian}} { AddAssign(&u3P). Double(&vP). AddAssign(&u4P). - AddAssign(a) + AddAssign(q) wP.Set(&uP).SubAssign(&u4P).SubAssign(&u5P) - xP.Set(a).AddAssign(&vP) - L0.Set(&uP).SubAssign(a).ScalarMultiplication(&L0, &d1) + xP.Set(q).AddAssign(&vP) + L0.Set(&uP).SubAssign(q).ScalarMultiplication(&L0, &d1) tmp.ScalarMultiplication(&xP, &d3) L0.AddAssign(&tmp) - tmp.ScalarMultiplication(a, &ht) // negative + tmp.ScalarMultiplication(q, &ht) // negative L0.SubAssign(&tmp) L1.ScalarMultiplication(&wP, &d1) tmp.ScalarMultiplication(&vP, &ht) L1.AddAssign(&tmp) - tmp.ScalarMultiplication(a, &d3) + tmp.ScalarMultiplication(q, &d3) L1.AddAssign(&tmp) p.phi(&L1).AddAssign(&L0) {{else}} var c2 big.Int c2.SetString("516166855112631370346774477030598579858367278343565509012644853411927535599366632765988905418768", 10) - p.ScalarMultiplication(a, &c2) + p.ScalarMultiplication(q, &c2) {{end}} return p @@ -1211,17 +1226,17 @@ func (p *{{$TJacobian}}) ClearCofactor(a *{{$TJacobian}}) *{{$TJacobian}} { {{- if .GLV}} var L0, L1, uP, u2P, u3P, tmp G2Jac - uP.ScalarMultiplication(a, &xGen) + uP.ScalarMultiplication(q, &xGen) u2P.ScalarMultiplication(&uP, &xGen) u3P.ScalarMultiplication(&u2P, &xGen) // ht=-2, hy=0 // d1=1, d2=-1, d3=-1 - L0.Set(a). + L0.Set(q). AddAssign(&u2P). SubAssign(&uP) tmp.Set(&u2P). - AddAssign(a). + AddAssign(q). SubAssign(&uP). Double(&tmp) L1.Set(&u3P). @@ -1232,7 +1247,7 @@ func (p *{{$TJacobian}}) ClearCofactor(a *{{$TJacobian}}) *{{$TJacobian}} { {{else}} var c2 big.Int c2.SetString("605248206075306171568857128027361794400937215108643640003009340657451546212610770151705515081537938829431808196609", 10) - p.ScalarMultiplication(a, &c2) + p.ScalarMultiplication(q, &c2) {{end}} return p @@ -1245,8 +1260,8 @@ func (p *{{$TJacobian}}) ClearCofactor(a *{{$TJacobian}}) *{{$TJacobian}} { {{ end }} {{ if eq .PointName "g1" }} -// JointScalarMultiplicationBase computes [s1]g+[s2]a using Straus-Shamir technique -// where g is the prime subgroup generator +// JointScalarMultiplicationBase computes [s1]g+[s2]a using Strauss-Shamir technique +// where g is the prime subgroup generator and a is an affine point. func (p *{{$TJacobian}}) JointScalarMultiplicationBase(a *G1Affine, s1, s2 *big.Int) *{{$TJacobian}} { var res, p1, p2 {{$TJacobian}} @@ -1319,15 +1334,15 @@ func (p *{{$TJacobian}}) JointScalarMultiplicationBase(a *G1Affine, s1, s2 *big. // ------------------------------------------------------------------------------------------------- -// Jacobian extended +// extended Jacobian coordinates -// Set sets p to the provided point -func (p *{{ $TJacobianExtended }}) Set(a *{{ $TJacobianExtended }}) *{{ $TJacobianExtended }} { - p.X, p.Y, p.ZZ, p.ZZZ = a.X, a.Y, a.ZZ, a.ZZZ +// Set sets p to a in extended Jacobian coordinates. +func (p *{{ $TJacobianExtended }}) Set(q *{{ $TJacobianExtended }}) *{{ $TJacobianExtended }} { + p.X, p.Y, p.ZZ, p.ZZZ = q.X, q.Y, q.ZZ, q.ZZZ return p } -// setInfinity sets p to O +// setInfinity sets p to the infinity point (1,1,0,0). func (p *{{ $TJacobianExtended }}) setInfinity() *{{ $TJacobianExtended }} { p.X.SetOne() p.Y.SetOne() @@ -1336,43 +1351,45 @@ func (p *{{ $TJacobianExtended }}) setInfinity() *{{ $TJacobianExtended }} { return p } -func (p *{{ $TJacobianExtended }}) IsZero() bool { +// IsInfinity checks if the p is infinity, i.e. p.ZZ=0. +func (p *{{ $TJacobianExtended }}) IsInfinity() bool { return p.ZZ.IsZero() } -// fromJacExtended sets Q in affine coordinates -func (p *{{ $TAffine }}) fromJacExtended (Q *{{ $TJacobianExtended }}) *{{ $TAffine }} { - if Q.ZZ.IsZero() { +// fromJacExtended converts an extended Jacobian point to an affine point. +func (p *{{ $TAffine }}) fromJacExtended (q *{{ $TJacobianExtended }}) *{{ $TAffine }} { + if q.ZZ.IsZero() { p.X = {{.CoordType}}{} p.Y = {{.CoordType}}{} return p } - p.X.Inverse(&Q.ZZ).Mul(&p.X, &Q.X) - p.Y.Inverse(&Q.ZZZ).Mul(&p.Y, &Q.Y) + p.X.Inverse(&q.ZZ).Mul(&p.X, &q.X) + p.Y.Inverse(&q.ZZZ).Mul(&p.Y, &q.Y) return p } -// fromJacExtended sets Q in Jacobian coordinates -func (p *{{ $TJacobian }}) fromJacExtended(Q *{{ $TJacobianExtended }}) *{{ $TJacobian }} { - if Q.ZZ.IsZero() { +// fromJacExtended converts an extended Jacobian point to a Jacobian point. +func (p *{{ $TJacobian }}) fromJacExtended(q *{{ $TJacobianExtended }}) *{{ $TJacobian }} { + if q.ZZ.IsZero() { p.Set(&{{ toLower .PointName }}Infinity) return p } - p.X.Mul(&Q.ZZ, &Q.X).Mul(&p.X, &Q.ZZ) - p.Y.Mul(&Q.ZZZ, &Q.Y).Mul(&p.Y, &Q.ZZZ) - p.Z.Set(&Q.ZZZ) + p.X.Mul(&q.ZZ, &q.X).Mul(&p.X, &q.ZZ) + p.Y.Mul(&q.ZZZ, &q.Y).Mul(&p.Y, &q.ZZZ) + p.Z.Set(&q.ZZZ) return p } -// unsafeFromJacExtended sets p in Jacobian coordinates, but don't check for infinity -func (p *{{ $TJacobian }}) unsafeFromJacExtended(Q *{{ $TJacobianExtended }}) *{{ $TJacobian }} { - p.X.Square(&Q.ZZ).Mul(&p.X, &Q.X) - p.Y.Square(&Q.ZZZ).Mul(&p.Y, &Q.Y) - p.Z = Q.ZZZ +// unsafeFromJacExtended converts an extended Jacobian point, distinct from Infinity, to a Jacobian point. +func (p *{{ $TJacobian }}) unsafeFromJacExtended(q *{{ $TJacobianExtended }}) *{{ $TJacobian }} { + p.X.Square(&q.ZZ).Mul(&p.X, &q.X) + p.Y.Square(&q.ZZZ).Mul(&p.Y, &q.Y) + p.Z = q.ZZZ return p } -// add point in Jacobian extended coordinates +// add sets p to p+q in extended Jacobian coordinates. +// // https://www.hyperelliptic.org/EFD/g1p/auto-shortw-xyzz.html#addition-add-2008-s func (p *{{ $TJacobianExtended }}) add(q *{{ $TJacobianExtended }}) *{{ $TJacobianExtended }} { //if q is infinity return p @@ -1429,10 +1446,11 @@ func (p *{{ $TJacobianExtended }}) add(q *{{ $TJacobianExtended }}) *{{ $TJacobi return p } -// double point in Jacobian extended coordinates +// double sets p to [2]q in Jacobian extended coordinates. +// // http://www.hyperelliptic.org/EFD/g1p/auto-shortw-xyzz.html#doubling-dbl-2008-s-1 -// since we consider any point on Z=0 as the point at infinity -// this doubling formula works for infinity points as well +// N.B.: since we consider any point on Z=0 as the point at infinity +// this doubling formula works for infinity points as well. func (p *{{ $TJacobianExtended }}) double(q *{{ $TJacobianExtended }}) *{{ $TJacobianExtended }} { var U, V, W, S, XX, M {{.CoordType}} @@ -1442,7 +1460,7 @@ func (p *{{ $TJacobianExtended }}) double(q *{{ $TJacobianExtended }}) *{{ $TJac S.Mul(&q.X, &V) XX.Square(&q.X) M.Double(&XX). - Add(&M, &XX) // -> + a, but a=0 here + Add(&M, &XX) // -> + A, but A=0 here U.Mul(&W, &q.Y) p.X.Square(&M). @@ -1457,44 +1475,47 @@ func (p *{{ $TJacobianExtended }}) double(q *{{ $TJacobianExtended }}) *{{ $TJac return p } -// subMixed same as addMixed, but will negate a.Y +// addMixed sets p to p+q in extended Jacobian coordinates, where a.ZZ=1. +// // http://www.hyperelliptic.org/EFD/g1p/auto-shortw-xyzz.html#addition-madd-2008-s -func (p *{{ $TJacobianExtended }}) subMixed(a *{{ $TAffine }}) *{{ $TJacobianExtended }} { - {{ template "mAdd" dict "all" . "negate" true}} +func (p *{{ $TJacobianExtended }}) addMixed(a *{{ $TAffine }}) *{{ $TJacobianExtended }} { + {{ template "mAdd" dict "all" . "negate" false}} } -// addMixed +// subMixed works the same as addMixed, but negates a.Y. +// // http://www.hyperelliptic.org/EFD/g1p/auto-shortw-xyzz.html#addition-madd-2008-s -func (p *{{ $TJacobianExtended }}) addMixed(a *{{ $TAffine }}) *{{ $TJacobianExtended }} { - {{ template "mAdd" dict "all" . "negate" false}} +func (p *{{ $TJacobianExtended }}) subMixed(a *{{ $TAffine }}) *{{ $TJacobianExtended }} { + {{ template "mAdd" dict "all" . "negate" true}} } -// doubleNegMixed same as double, but will negate q.Y -func (p *{{ $TJacobianExtended }}) doubleNegMixed(q *{{ $TAffine }}) *{{ $TJacobianExtended }} { +// doubleNegMixed works the same as double, but negates q.Y. +func (p *{{ $TJacobianExtended }}) doubleNegMixed(a *{{ $TAffine }}) *{{ $TJacobianExtended }} { {{ template "mDouble" dict "all" . "negate" true}} } -// doubleMixed point in Jacobian extended coordinates +// doubleMixed sets p to [2]a in Jacobian extended coordinates, where a.ZZ=1. +// // http://www.hyperelliptic.org/EFD/g1p/auto-shortw-xyzz.html#doubling-dbl-2008-s-1 -func (p *{{ $TJacobianExtended }}) doubleMixed(q *{{ $TAffine }}) *{{ $TJacobianExtended }} { +func (p *{{ $TJacobianExtended }}) doubleMixed(a *{{ $TAffine }}) *{{ $TJacobianExtended }} { {{ template "mDouble" dict "all" . "negate" false}} } {{define "mDouble" }} var U, V, W, S, XX, M, S2, L {{.all.CoordType}} - U.Double(&q.Y) + U.Double(&a.Y) {{- if .negate}} U.Neg(&U) {{- end}} V.Square(&U) W.Mul(&U, &V) - S.Mul(&q.X, &V) - XX.Square(&q.X) + S.Mul(&a.X, &V) + XX.Square(&a.X) M.Double(&XX). - Add(&M, &XX) // -> + a, but a=0 here + Add(&M, &XX) // -> + A, but A=0 here S2.Double(&S) - L.Mul(&W, &q.Y) + L.Mul(&W, &a.Y) p.X.Square(&M). Sub(&p.X, &S2) @@ -1577,32 +1598,32 @@ func (p *{{ $TJacobianExtended }}) doubleMixed(q *{{ $TAffine }}) *{{ $TJacobian {{- if .Projective }} // ------------------------------------------------------------------------------------------------- -// Homogenous projective +// Homogenous projective coordinates -// Set sets p to the provided point -func (p *{{ $TProjective }}) Set(a *{{ $TProjective }}) *{{ $TProjective }} { - p.x, p.y, p.z = a.x, a.y, a.z +// Set sets p to a in projective coordinates. +func (p *{{ $TProjective }}) Set(q *{{ $TProjective }}) *{{ $TProjective }} { + p.x, p.y, p.z = q.x, q.y, q.z return p } -// Neg computes -G -func (p *{{ $TProjective }}) Neg(a *{{ $TProjective }}) *{{ $TProjective }} { - *p = *a - p.y.Neg(&a.y) +// Neg sets p to the projective negative point -q = (q.X, -q.Y). +func (p *{{ $TProjective }}) Neg(q *{{ $TProjective }}) *{{ $TProjective }} { + *p = *q + p.y.Neg(&q.y) return p } -// FromAffine sets p = Q, p in homogenous projective, Q in affine -func (p *{{ $TProjective }}) FromAffine(Q *{{ $TAffine }}) *{{ $TProjective }} { - if Q.X.IsZero() && Q.Y.IsZero() { +// FromAffine converts q in affine to p in projective coordinates. +func (p *{{ $TProjective }}) FromAffine(a *{{ $TAffine }}) *{{ $TProjective }} { + if a.X.IsZero() && a.Y.IsZero() { p.z.SetZero() p.x.SetOne() p.y.SetOne() return p } p.z.SetOne() - p.x.Set(&Q.X) - p.y.Set(&Q.Y) + p.x.Set(&a.X) + p.y.Set(&a.Y) return p } @@ -1613,7 +1634,7 @@ func (p *{{ $TProjective }}) FromAffine(Q *{{ $TAffine }}) *{{ $TProjective }} { {{- if eq .PointName "g1"}} // BatchJacobianToAffine{{ toUpper .PointName }} converts points in Jacobian coordinates to Affine coordinates -// performing a single field inversion (Montgomery batch inversion trick). +// performing a single field inversion using the Montgomery batch inversion trick. func BatchJacobianToAffine{{ toUpper .PointName }}(points []{{ $TJacobian }}) []{{ $TAffine }} { result := make([]{{ $TAffine }}, len(points)) zeroes := make([]bool, len(points)) @@ -1665,7 +1686,7 @@ func BatchJacobianToAffine{{ toUpper .PointName }}(points []{{ $TJacobian }}) [] // BatchScalarMultiplication{{ toUpper .PointName }} multiplies the same base by all scalars // and return resulting points in affine coordinates -// uses a simple windowed-NAF like exponentiation algorithm +// uses a simple windowed-NAF-like multiplication algorithm. func BatchScalarMultiplication{{ toUpper .PointName }}(base *{{ $TAffine }}, scalars []fr.Element) []{{ $TAffine }} { // approximate cost in group ops is // cost = 2^{c-1} + n(scalar.nbBits+nbChunks) @@ -1771,11 +1792,8 @@ func BatchScalarMultiplication{{ toUpper .PointName }}(base *{{ $TAffine }}, sca {{- end}} } - - -// batch add affine coordinates -// using batch inversion -// special cases (doubling, infinity) must be filtered out before this call +// batchAddG1Affine adds affine points using the Montgomery batch inversion trick. +// Special cases (doubling, infinity) must be filtered out before this call. func batchAdd{{ $TAffine }}[TP p{{ $TAffine }}, TPP pp{{ $TAffine }}, TC c{{ $TAffine }}](R *TPP,P *TP, batchSize int) { var lambda, lambdain TC From 968b76fa4fe59c92b40e4b947e81fc6a1ee6ad2f Mon Sep 17 00:00:00 2001 From: Youssef El Housni Date: Tue, 2 Jul 2024 15:38:33 +0100 Subject: [PATCH 6/6] fix: resolve conflict around kzg --- ecc/bls12-377/g1.go | 38 ++++++------- ecc/bls12-377/g2.go | 7 +++ ecc/bls12-378/g1.go | 38 ++++++------- ecc/bls12-378/g2.go | 7 +++ ecc/bls12-381/g1.go | 38 ++++++------- ecc/bls12-381/g2.go | 7 +++ ecc/bls24-315/g1.go | 38 ++++++------- ecc/bls24-315/g2.go | 7 +++ ecc/bls24-317/g1.go | 38 ++++++------- ecc/bls24-317/g2.go | 7 +++ ecc/bn254/g1.go | 38 ++++++------- ecc/bn254/g2.go | 7 +++ ecc/bw6-633/g1.go | 38 ++++++------- ecc/bw6-633/g2.go | 7 +++ ecc/bw6-756/g1.go | 38 ++++++------- ecc/bw6-756/g2.go | 7 +++ ecc/bw6-761/g1.go | 38 ++++++------- ecc/bw6-761/g2.go | 7 +++ ecc/secp256k1/g1.go | 38 ++++++------- internal/generator/ecc/template/point.go.tmpl | 53 ++++++++++--------- 20 files changed, 281 insertions(+), 215 deletions(-) diff --git a/ecc/bls12-377/g1.go b/ecc/bls12-377/g1.go index 4df42849b..b0c8bcb52 100644 --- a/ecc/bls12-377/g1.go +++ b/ecc/bls12-377/g1.go @@ -67,20 +67,6 @@ func (p *G1Affine) ScalarMultiplication(a *G1Affine, s *big.Int) *G1Affine { return p } -// ScalarMultiplicationAffine computes and returns p = [s]a -// where a is an affine point and p a Jacobian point (useful for KZG). -func (p *G1Jac) ScalarMultiplicationAffine(a *G1Affine, s *big.Int) *G1Jac { - p.FromAffine(a) - p.mulGLV(p, s) - return p -} - -// ScalarMultiplicationBase computes and returns p = [s]g -// where g is the Jacobian point generating the prime subgroup. -func (p *G1Jac) ScalarMultiplicationBase(s *big.Int) *G1Jac { - return p.mulGLV(&g1Gen, s) -} - // ScalarMultiplicationBase computes and returns p = [s]g // where g is the affine point generating the prime subgroup. func (p *G1Affine) ScalarMultiplicationBase(s *big.Int) *G1Affine { @@ -456,6 +442,13 @@ func (p *G1Jac) ScalarMultiplication(q *G1Jac, s *big.Int) *G1Jac { return p.mulGLV(q, s) } +// ScalarMultiplicationBase computes and returns p = [s]g +// where g is the prime subgroup generator. +func (p *G1Jac) ScalarMultiplicationBase(s *big.Int) *G1Jac { + return p.mulGLV(&g1Gen, s) + +} + // String converts p to affine coordinates and returns its string representation E(x,y) or "O" if it is infinity. func (p *G1Jac) String() string { _p := G1Affine{} @@ -643,14 +636,14 @@ func (p *G1Jac) ClearCofactor(q *G1Jac) *G1Jac { } -// JointScalarMultiplicationBase computes [s1]g+[s2]a using Strauss-Shamir technique -// where g is the prime subgroup generator and a is an affine point. -func (p *G1Jac) JointScalarMultiplicationBase(a *G1Affine, s1, s2 *big.Int) *G1Jac { +// JointScalarMultiplication computes [s1]a1+[s2]a2 using Strauss-Shamir technique +// where a1 and a2 are affine points. +func (p *G1Jac) JointScalarMultiplication(a1, a2 *G1Affine, s1, s2 *big.Int) *G1Jac { var res, p1, p2 G1Jac res.Set(&g1Infinity) - p1.Set(&g1Gen) - p2.FromAffine(a) + p1.FromAffine(a1) + p2.FromAffine(a2) var table [15]G1Jac @@ -714,6 +707,13 @@ func (p *G1Jac) JointScalarMultiplicationBase(a *G1Affine, s1, s2 *big.Int) *G1J } +// JointScalarMultiplicationBase computes [s1]g+[s2]a using Straus-Shamir technique +// where g is the prime subgroup generator. +func (p *G1Jac) JointScalarMultiplicationBase(a *G1Affine, s1, s2 *big.Int) *G1Jac { + return p.JointScalarMultiplication(&g1GenAff, a, s1, s2) + +} + // ------------------------------------------------------------------------------------------------- // extended Jacobian coordinates diff --git a/ecc/bls12-377/g2.go b/ecc/bls12-377/g2.go index 03c8037fa..cb01cf6b3 100644 --- a/ecc/bls12-377/g2.go +++ b/ecc/bls12-377/g2.go @@ -447,6 +447,13 @@ func (p *G2Jac) ScalarMultiplication(q *G2Jac, s *big.Int) *G2Jac { return p.mulGLV(q, s) } +// ScalarMultiplicationBase computes and returns p = [s]g +// where g is the prime subgroup generator. +func (p *G2Jac) ScalarMultiplicationBase(s *big.Int) *G2Jac { + return p.mulGLV(&g2Gen, s) + +} + // String converts p to affine coordinates and returns its string representation E(x,y) or "O" if it is infinity. func (p *G2Jac) String() string { _p := G2Affine{} diff --git a/ecc/bls12-378/g1.go b/ecc/bls12-378/g1.go index 690aba6a1..c484bfa14 100644 --- a/ecc/bls12-378/g1.go +++ b/ecc/bls12-378/g1.go @@ -67,20 +67,6 @@ func (p *G1Affine) ScalarMultiplication(a *G1Affine, s *big.Int) *G1Affine { return p } -// ScalarMultiplicationAffine computes and returns p = [s]a -// where a is an affine point and p a Jacobian point (useful for KZG). -func (p *G1Jac) ScalarMultiplicationAffine(a *G1Affine, s *big.Int) *G1Jac { - p.FromAffine(a) - p.mulGLV(p, s) - return p -} - -// ScalarMultiplicationBase computes and returns p = [s]g -// where g is the Jacobian point generating the prime subgroup. -func (p *G1Jac) ScalarMultiplicationBase(s *big.Int) *G1Jac { - return p.mulGLV(&g1Gen, s) -} - // ScalarMultiplicationBase computes and returns p = [s]g // where g is the affine point generating the prime subgroup. func (p *G1Affine) ScalarMultiplicationBase(s *big.Int) *G1Affine { @@ -456,6 +442,13 @@ func (p *G1Jac) ScalarMultiplication(q *G1Jac, s *big.Int) *G1Jac { return p.mulGLV(q, s) } +// ScalarMultiplicationBase computes and returns p = [s]g +// where g is the prime subgroup generator. +func (p *G1Jac) ScalarMultiplicationBase(s *big.Int) *G1Jac { + return p.mulGLV(&g1Gen, s) + +} + // String converts p to affine coordinates and returns its string representation E(x,y) or "O" if it is infinity. func (p *G1Jac) String() string { _p := G1Affine{} @@ -643,14 +636,14 @@ func (p *G1Jac) ClearCofactor(q *G1Jac) *G1Jac { } -// JointScalarMultiplicationBase computes [s1]g+[s2]a using Strauss-Shamir technique -// where g is the prime subgroup generator and a is an affine point. -func (p *G1Jac) JointScalarMultiplicationBase(a *G1Affine, s1, s2 *big.Int) *G1Jac { +// JointScalarMultiplication computes [s1]a1+[s2]a2 using Strauss-Shamir technique +// where a1 and a2 are affine points. +func (p *G1Jac) JointScalarMultiplication(a1, a2 *G1Affine, s1, s2 *big.Int) *G1Jac { var res, p1, p2 G1Jac res.Set(&g1Infinity) - p1.Set(&g1Gen) - p2.FromAffine(a) + p1.FromAffine(a1) + p2.FromAffine(a2) var table [15]G1Jac @@ -714,6 +707,13 @@ func (p *G1Jac) JointScalarMultiplicationBase(a *G1Affine, s1, s2 *big.Int) *G1J } +// JointScalarMultiplicationBase computes [s1]g+[s2]a using Straus-Shamir technique +// where g is the prime subgroup generator. +func (p *G1Jac) JointScalarMultiplicationBase(a *G1Affine, s1, s2 *big.Int) *G1Jac { + return p.JointScalarMultiplication(&g1GenAff, a, s1, s2) + +} + // ------------------------------------------------------------------------------------------------- // extended Jacobian coordinates diff --git a/ecc/bls12-378/g2.go b/ecc/bls12-378/g2.go index b3a47afee..7e1eecbc9 100644 --- a/ecc/bls12-378/g2.go +++ b/ecc/bls12-378/g2.go @@ -447,6 +447,13 @@ func (p *G2Jac) ScalarMultiplication(q *G2Jac, s *big.Int) *G2Jac { return p.mulGLV(q, s) } +// ScalarMultiplicationBase computes and returns p = [s]g +// where g is the prime subgroup generator. +func (p *G2Jac) ScalarMultiplicationBase(s *big.Int) *G2Jac { + return p.mulGLV(&g2Gen, s) + +} + // String converts p to affine coordinates and returns its string representation E(x,y) or "O" if it is infinity. func (p *G2Jac) String() string { _p := G2Affine{} diff --git a/ecc/bls12-381/g1.go b/ecc/bls12-381/g1.go index 356f5de99..50ab4713e 100644 --- a/ecc/bls12-381/g1.go +++ b/ecc/bls12-381/g1.go @@ -67,20 +67,6 @@ func (p *G1Affine) ScalarMultiplication(a *G1Affine, s *big.Int) *G1Affine { return p } -// ScalarMultiplicationAffine computes and returns p = [s]a -// where a is an affine point and p a Jacobian point (useful for KZG). -func (p *G1Jac) ScalarMultiplicationAffine(a *G1Affine, s *big.Int) *G1Jac { - p.FromAffine(a) - p.mulGLV(p, s) - return p -} - -// ScalarMultiplicationBase computes and returns p = [s]g -// where g is the Jacobian point generating the prime subgroup. -func (p *G1Jac) ScalarMultiplicationBase(s *big.Int) *G1Jac { - return p.mulGLV(&g1Gen, s) -} - // ScalarMultiplicationBase computes and returns p = [s]g // where g is the affine point generating the prime subgroup. func (p *G1Affine) ScalarMultiplicationBase(s *big.Int) *G1Affine { @@ -456,6 +442,13 @@ func (p *G1Jac) ScalarMultiplication(q *G1Jac, s *big.Int) *G1Jac { return p.mulGLV(q, s) } +// ScalarMultiplicationBase computes and returns p = [s]g +// where g is the prime subgroup generator. +func (p *G1Jac) ScalarMultiplicationBase(s *big.Int) *G1Jac { + return p.mulGLV(&g1Gen, s) + +} + // String converts p to affine coordinates and returns its string representation E(x,y) or "O" if it is infinity. func (p *G1Jac) String() string { _p := G1Affine{} @@ -644,14 +637,14 @@ func (p *G1Jac) ClearCofactor(q *G1Jac) *G1Jac { } -// JointScalarMultiplicationBase computes [s1]g+[s2]a using Strauss-Shamir technique -// where g is the prime subgroup generator and a is an affine point. -func (p *G1Jac) JointScalarMultiplicationBase(a *G1Affine, s1, s2 *big.Int) *G1Jac { +// JointScalarMultiplication computes [s1]a1+[s2]a2 using Strauss-Shamir technique +// where a1 and a2 are affine points. +func (p *G1Jac) JointScalarMultiplication(a1, a2 *G1Affine, s1, s2 *big.Int) *G1Jac { var res, p1, p2 G1Jac res.Set(&g1Infinity) - p1.Set(&g1Gen) - p2.FromAffine(a) + p1.FromAffine(a1) + p2.FromAffine(a2) var table [15]G1Jac @@ -715,6 +708,13 @@ func (p *G1Jac) JointScalarMultiplicationBase(a *G1Affine, s1, s2 *big.Int) *G1J } +// JointScalarMultiplicationBase computes [s1]g+[s2]a using Straus-Shamir technique +// where g is the prime subgroup generator. +func (p *G1Jac) JointScalarMultiplicationBase(a *G1Affine, s1, s2 *big.Int) *G1Jac { + return p.JointScalarMultiplication(&g1GenAff, a, s1, s2) + +} + // ------------------------------------------------------------------------------------------------- // extended Jacobian coordinates diff --git a/ecc/bls12-381/g2.go b/ecc/bls12-381/g2.go index 795667e63..827566d08 100644 --- a/ecc/bls12-381/g2.go +++ b/ecc/bls12-381/g2.go @@ -447,6 +447,13 @@ func (p *G2Jac) ScalarMultiplication(q *G2Jac, s *big.Int) *G2Jac { return p.mulGLV(q, s) } +// ScalarMultiplicationBase computes and returns p = [s]g +// where g is the prime subgroup generator. +func (p *G2Jac) ScalarMultiplicationBase(s *big.Int) *G2Jac { + return p.mulGLV(&g2Gen, s) + +} + // String converts p to affine coordinates and returns its string representation E(x,y) or "O" if it is infinity. func (p *G2Jac) String() string { _p := G2Affine{} diff --git a/ecc/bls24-315/g1.go b/ecc/bls24-315/g1.go index e5b4897cd..52de0e1d6 100644 --- a/ecc/bls24-315/g1.go +++ b/ecc/bls24-315/g1.go @@ -67,20 +67,6 @@ func (p *G1Affine) ScalarMultiplication(a *G1Affine, s *big.Int) *G1Affine { return p } -// ScalarMultiplicationAffine computes and returns p = [s]a -// where a is an affine point and p a Jacobian point (useful for KZG). -func (p *G1Jac) ScalarMultiplicationAffine(a *G1Affine, s *big.Int) *G1Jac { - p.FromAffine(a) - p.mulGLV(p, s) - return p -} - -// ScalarMultiplicationBase computes and returns p = [s]g -// where g is the Jacobian point generating the prime subgroup. -func (p *G1Jac) ScalarMultiplicationBase(s *big.Int) *G1Jac { - return p.mulGLV(&g1Gen, s) -} - // ScalarMultiplicationBase computes and returns p = [s]g // where g is the affine point generating the prime subgroup. func (p *G1Affine) ScalarMultiplicationBase(s *big.Int) *G1Affine { @@ -456,6 +442,13 @@ func (p *G1Jac) ScalarMultiplication(q *G1Jac, s *big.Int) *G1Jac { return p.mulGLV(q, s) } +// ScalarMultiplicationBase computes and returns p = [s]g +// where g is the prime subgroup generator. +func (p *G1Jac) ScalarMultiplicationBase(s *big.Int) *G1Jac { + return p.mulGLV(&g1Gen, s) + +} + // String converts p to affine coordinates and returns its string representation E(x,y) or "O" if it is infinity. func (p *G1Jac) String() string { _p := G1Affine{} @@ -645,14 +638,14 @@ func (p *G1Jac) ClearCofactor(q *G1Jac) *G1Jac { } -// JointScalarMultiplicationBase computes [s1]g+[s2]a using Strauss-Shamir technique -// where g is the prime subgroup generator and a is an affine point. -func (p *G1Jac) JointScalarMultiplicationBase(a *G1Affine, s1, s2 *big.Int) *G1Jac { +// JointScalarMultiplication computes [s1]a1+[s2]a2 using Strauss-Shamir technique +// where a1 and a2 are affine points. +func (p *G1Jac) JointScalarMultiplication(a1, a2 *G1Affine, s1, s2 *big.Int) *G1Jac { var res, p1, p2 G1Jac res.Set(&g1Infinity) - p1.Set(&g1Gen) - p2.FromAffine(a) + p1.FromAffine(a1) + p2.FromAffine(a2) var table [15]G1Jac @@ -716,6 +709,13 @@ func (p *G1Jac) JointScalarMultiplicationBase(a *G1Affine, s1, s2 *big.Int) *G1J } +// JointScalarMultiplicationBase computes [s1]g+[s2]a using Straus-Shamir technique +// where g is the prime subgroup generator. +func (p *G1Jac) JointScalarMultiplicationBase(a *G1Affine, s1, s2 *big.Int) *G1Jac { + return p.JointScalarMultiplication(&g1GenAff, a, s1, s2) + +} + // ------------------------------------------------------------------------------------------------- // extended Jacobian coordinates diff --git a/ecc/bls24-315/g2.go b/ecc/bls24-315/g2.go index 8dea01a97..a4483774f 100644 --- a/ecc/bls24-315/g2.go +++ b/ecc/bls24-315/g2.go @@ -447,6 +447,13 @@ func (p *G2Jac) ScalarMultiplication(q *G2Jac, s *big.Int) *G2Jac { return p.mulGLV(q, s) } +// ScalarMultiplicationBase computes and returns p = [s]g +// where g is the prime subgroup generator. +func (p *G2Jac) ScalarMultiplicationBase(s *big.Int) *G2Jac { + return p.mulGLV(&g2Gen, s) + +} + // String converts p to affine coordinates and returns its string representation E(x,y) or "O" if it is infinity. func (p *G2Jac) String() string { _p := G2Affine{} diff --git a/ecc/bls24-317/g1.go b/ecc/bls24-317/g1.go index 014baae64..18585821f 100644 --- a/ecc/bls24-317/g1.go +++ b/ecc/bls24-317/g1.go @@ -67,20 +67,6 @@ func (p *G1Affine) ScalarMultiplication(a *G1Affine, s *big.Int) *G1Affine { return p } -// ScalarMultiplicationAffine computes and returns p = [s]a -// where a is an affine point and p a Jacobian point (useful for KZG). -func (p *G1Jac) ScalarMultiplicationAffine(a *G1Affine, s *big.Int) *G1Jac { - p.FromAffine(a) - p.mulGLV(p, s) - return p -} - -// ScalarMultiplicationBase computes and returns p = [s]g -// where g is the Jacobian point generating the prime subgroup. -func (p *G1Jac) ScalarMultiplicationBase(s *big.Int) *G1Jac { - return p.mulGLV(&g1Gen, s) -} - // ScalarMultiplicationBase computes and returns p = [s]g // where g is the affine point generating the prime subgroup. func (p *G1Affine) ScalarMultiplicationBase(s *big.Int) *G1Affine { @@ -456,6 +442,13 @@ func (p *G1Jac) ScalarMultiplication(q *G1Jac, s *big.Int) *G1Jac { return p.mulGLV(q, s) } +// ScalarMultiplicationBase computes and returns p = [s]g +// where g is the prime subgroup generator. +func (p *G1Jac) ScalarMultiplicationBase(s *big.Int) *G1Jac { + return p.mulGLV(&g1Gen, s) + +} + // String converts p to affine coordinates and returns its string representation E(x,y) or "O" if it is infinity. func (p *G1Jac) String() string { _p := G1Affine{} @@ -646,14 +639,14 @@ func (p *G1Jac) ClearCofactor(q *G1Jac) *G1Jac { } -// JointScalarMultiplicationBase computes [s1]g+[s2]a using Strauss-Shamir technique -// where g is the prime subgroup generator and a is an affine point. -func (p *G1Jac) JointScalarMultiplicationBase(a *G1Affine, s1, s2 *big.Int) *G1Jac { +// JointScalarMultiplication computes [s1]a1+[s2]a2 using Strauss-Shamir technique +// where a1 and a2 are affine points. +func (p *G1Jac) JointScalarMultiplication(a1, a2 *G1Affine, s1, s2 *big.Int) *G1Jac { var res, p1, p2 G1Jac res.Set(&g1Infinity) - p1.Set(&g1Gen) - p2.FromAffine(a) + p1.FromAffine(a1) + p2.FromAffine(a2) var table [15]G1Jac @@ -717,6 +710,13 @@ func (p *G1Jac) JointScalarMultiplicationBase(a *G1Affine, s1, s2 *big.Int) *G1J } +// JointScalarMultiplicationBase computes [s1]g+[s2]a using Straus-Shamir technique +// where g is the prime subgroup generator. +func (p *G1Jac) JointScalarMultiplicationBase(a *G1Affine, s1, s2 *big.Int) *G1Jac { + return p.JointScalarMultiplication(&g1GenAff, a, s1, s2) + +} + // ------------------------------------------------------------------------------------------------- // extended Jacobian coordinates diff --git a/ecc/bls24-317/g2.go b/ecc/bls24-317/g2.go index c5c924a71..b87ad79f7 100644 --- a/ecc/bls24-317/g2.go +++ b/ecc/bls24-317/g2.go @@ -447,6 +447,13 @@ func (p *G2Jac) ScalarMultiplication(q *G2Jac, s *big.Int) *G2Jac { return p.mulGLV(q, s) } +// ScalarMultiplicationBase computes and returns p = [s]g +// where g is the prime subgroup generator. +func (p *G2Jac) ScalarMultiplicationBase(s *big.Int) *G2Jac { + return p.mulGLV(&g2Gen, s) + +} + // String converts p to affine coordinates and returns its string representation E(x,y) or "O" if it is infinity. func (p *G2Jac) String() string { _p := G2Affine{} diff --git a/ecc/bn254/g1.go b/ecc/bn254/g1.go index e4d573275..fc484aac9 100644 --- a/ecc/bn254/g1.go +++ b/ecc/bn254/g1.go @@ -67,20 +67,6 @@ func (p *G1Affine) ScalarMultiplication(a *G1Affine, s *big.Int) *G1Affine { return p } -// ScalarMultiplicationAffine computes and returns p = [s]a -// where a is an affine point and p a Jacobian point (useful for KZG). -func (p *G1Jac) ScalarMultiplicationAffine(a *G1Affine, s *big.Int) *G1Jac { - p.FromAffine(a) - p.mulGLV(p, s) - return p -} - -// ScalarMultiplicationBase computes and returns p = [s]g -// where g is the Jacobian point generating the prime subgroup. -func (p *G1Jac) ScalarMultiplicationBase(s *big.Int) *G1Jac { - return p.mulGLV(&g1Gen, s) -} - // ScalarMultiplicationBase computes and returns p = [s]g // where g is the affine point generating the prime subgroup. func (p *G1Affine) ScalarMultiplicationBase(s *big.Int) *G1Affine { @@ -456,6 +442,13 @@ func (p *G1Jac) ScalarMultiplication(q *G1Jac, s *big.Int) *G1Jac { return p.mulGLV(q, s) } +// ScalarMultiplicationBase computes and returns p = [s]g +// where g is the prime subgroup generator. +func (p *G1Jac) ScalarMultiplicationBase(s *big.Int) *G1Jac { + return p.mulGLV(&g1Gen, s) + +} + // String converts p to affine coordinates and returns its string representation E(x,y) or "O" if it is infinity. func (p *G1Jac) String() string { _p := G1Affine{} @@ -615,14 +608,14 @@ func (p *G1Jac) mulGLV(q *G1Jac, s *big.Int) *G1Jac { return p } -// JointScalarMultiplicationBase computes [s1]g+[s2]a using Strauss-Shamir technique -// where g is the prime subgroup generator and a is an affine point. -func (p *G1Jac) JointScalarMultiplicationBase(a *G1Affine, s1, s2 *big.Int) *G1Jac { +// JointScalarMultiplication computes [s1]a1+[s2]a2 using Strauss-Shamir technique +// where a1 and a2 are affine points. +func (p *G1Jac) JointScalarMultiplication(a1, a2 *G1Affine, s1, s2 *big.Int) *G1Jac { var res, p1, p2 G1Jac res.Set(&g1Infinity) - p1.Set(&g1Gen) - p2.FromAffine(a) + p1.FromAffine(a1) + p2.FromAffine(a2) var table [15]G1Jac @@ -686,6 +679,13 @@ func (p *G1Jac) JointScalarMultiplicationBase(a *G1Affine, s1, s2 *big.Int) *G1J } +// JointScalarMultiplicationBase computes [s1]g+[s2]a using Straus-Shamir technique +// where g is the prime subgroup generator. +func (p *G1Jac) JointScalarMultiplicationBase(a *G1Affine, s1, s2 *big.Int) *G1Jac { + return p.JointScalarMultiplication(&g1GenAff, a, s1, s2) + +} + // ------------------------------------------------------------------------------------------------- // extended Jacobian coordinates diff --git a/ecc/bn254/g2.go b/ecc/bn254/g2.go index bbdc9ca67..bab4bce83 100644 --- a/ecc/bn254/g2.go +++ b/ecc/bn254/g2.go @@ -447,6 +447,13 @@ func (p *G2Jac) ScalarMultiplication(q *G2Jac, s *big.Int) *G2Jac { return p.mulGLV(q, s) } +// ScalarMultiplicationBase computes and returns p = [s]g +// where g is the prime subgroup generator. +func (p *G2Jac) ScalarMultiplicationBase(s *big.Int) *G2Jac { + return p.mulGLV(&g2Gen, s) + +} + // String converts p to affine coordinates and returns its string representation E(x,y) or "O" if it is infinity. func (p *G2Jac) String() string { _p := G2Affine{} diff --git a/ecc/bw6-633/g1.go b/ecc/bw6-633/g1.go index 7394fc348..b1673bccd 100644 --- a/ecc/bw6-633/g1.go +++ b/ecc/bw6-633/g1.go @@ -67,20 +67,6 @@ func (p *G1Affine) ScalarMultiplication(a *G1Affine, s *big.Int) *G1Affine { return p } -// ScalarMultiplicationAffine computes and returns p = [s]a -// where a is an affine point and p a Jacobian point (useful for KZG). -func (p *G1Jac) ScalarMultiplicationAffine(a *G1Affine, s *big.Int) *G1Jac { - p.FromAffine(a) - p.mulGLV(p, s) - return p -} - -// ScalarMultiplicationBase computes and returns p = [s]g -// where g is the Jacobian point generating the prime subgroup. -func (p *G1Jac) ScalarMultiplicationBase(s *big.Int) *G1Jac { - return p.mulGLV(&g1Gen, s) -} - // ScalarMultiplicationBase computes and returns p = [s]g // where g is the affine point generating the prime subgroup. func (p *G1Affine) ScalarMultiplicationBase(s *big.Int) *G1Affine { @@ -456,6 +442,13 @@ func (p *G1Jac) ScalarMultiplication(q *G1Jac, s *big.Int) *G1Jac { return p.mulGLV(q, s) } +// ScalarMultiplicationBase computes and returns p = [s]g +// where g is the prime subgroup generator. +func (p *G1Jac) ScalarMultiplicationBase(s *big.Int) *G1Jac { + return p.mulGLV(&g1Gen, s) + +} + // String converts p to affine coordinates and returns its string representation E(x,y) or "O" if it is infinity. func (p *G1Jac) String() string { _p := G1Affine{} @@ -669,14 +662,14 @@ func (p *G1Jac) ClearCofactor(q *G1Jac) *G1Jac { } -// JointScalarMultiplicationBase computes [s1]g+[s2]a using Strauss-Shamir technique -// where g is the prime subgroup generator and a is an affine point. -func (p *G1Jac) JointScalarMultiplicationBase(a *G1Affine, s1, s2 *big.Int) *G1Jac { +// JointScalarMultiplication computes [s1]a1+[s2]a2 using Strauss-Shamir technique +// where a1 and a2 are affine points. +func (p *G1Jac) JointScalarMultiplication(a1, a2 *G1Affine, s1, s2 *big.Int) *G1Jac { var res, p1, p2 G1Jac res.Set(&g1Infinity) - p1.Set(&g1Gen) - p2.FromAffine(a) + p1.FromAffine(a1) + p2.FromAffine(a2) var table [15]G1Jac @@ -740,6 +733,13 @@ func (p *G1Jac) JointScalarMultiplicationBase(a *G1Affine, s1, s2 *big.Int) *G1J } +// JointScalarMultiplicationBase computes [s1]g+[s2]a using Straus-Shamir technique +// where g is the prime subgroup generator. +func (p *G1Jac) JointScalarMultiplicationBase(a *G1Affine, s1, s2 *big.Int) *G1Jac { + return p.JointScalarMultiplication(&g1GenAff, a, s1, s2) + +} + // ------------------------------------------------------------------------------------------------- // extended Jacobian coordinates diff --git a/ecc/bw6-633/g2.go b/ecc/bw6-633/g2.go index 8dcc1ca7f..c9e621189 100644 --- a/ecc/bw6-633/g2.go +++ b/ecc/bw6-633/g2.go @@ -447,6 +447,13 @@ func (p *G2Jac) ScalarMultiplication(q *G2Jac, s *big.Int) *G2Jac { return p.mulGLV(q, s) } +// ScalarMultiplicationBase computes and returns p = [s]g +// where g is the prime subgroup generator. +func (p *G2Jac) ScalarMultiplicationBase(s *big.Int) *G2Jac { + return p.mulGLV(&g2Gen, s) + +} + // String converts p to affine coordinates and returns its string representation E(x,y) or "O" if it is infinity. func (p *G2Jac) String() string { _p := G2Affine{} diff --git a/ecc/bw6-756/g1.go b/ecc/bw6-756/g1.go index 34e6d933d..ff42d69f4 100644 --- a/ecc/bw6-756/g1.go +++ b/ecc/bw6-756/g1.go @@ -67,20 +67,6 @@ func (p *G1Affine) ScalarMultiplication(a *G1Affine, s *big.Int) *G1Affine { return p } -// ScalarMultiplicationAffine computes and returns p = [s]a -// where a is an affine point and p a Jacobian point (useful for KZG). -func (p *G1Jac) ScalarMultiplicationAffine(a *G1Affine, s *big.Int) *G1Jac { - p.FromAffine(a) - p.mulGLV(p, s) - return p -} - -// ScalarMultiplicationBase computes and returns p = [s]g -// where g is the Jacobian point generating the prime subgroup. -func (p *G1Jac) ScalarMultiplicationBase(s *big.Int) *G1Jac { - return p.mulGLV(&g1Gen, s) -} - // ScalarMultiplicationBase computes and returns p = [s]g // where g is the affine point generating the prime subgroup. func (p *G1Affine) ScalarMultiplicationBase(s *big.Int) *G1Affine { @@ -456,6 +442,13 @@ func (p *G1Jac) ScalarMultiplication(q *G1Jac, s *big.Int) *G1Jac { return p.mulGLV(q, s) } +// ScalarMultiplicationBase computes and returns p = [s]g +// where g is the prime subgroup generator. +func (p *G1Jac) ScalarMultiplicationBase(s *big.Int) *G1Jac { + return p.mulGLV(&g1Gen, s) + +} + // String converts p to affine coordinates and returns its string representation E(x,y) or "O" if it is infinity. func (p *G1Jac) String() string { _p := G1Affine{} @@ -668,14 +661,14 @@ func (p *G1Jac) ClearCofactor(q *G1Jac) *G1Jac { return p } -// JointScalarMultiplicationBase computes [s1]g+[s2]a using Strauss-Shamir technique -// where g is the prime subgroup generator and a is an affine point. -func (p *G1Jac) JointScalarMultiplicationBase(a *G1Affine, s1, s2 *big.Int) *G1Jac { +// JointScalarMultiplication computes [s1]a1+[s2]a2 using Strauss-Shamir technique +// where a1 and a2 are affine points. +func (p *G1Jac) JointScalarMultiplication(a1, a2 *G1Affine, s1, s2 *big.Int) *G1Jac { var res, p1, p2 G1Jac res.Set(&g1Infinity) - p1.Set(&g1Gen) - p2.FromAffine(a) + p1.FromAffine(a1) + p2.FromAffine(a2) var table [15]G1Jac @@ -739,6 +732,13 @@ func (p *G1Jac) JointScalarMultiplicationBase(a *G1Affine, s1, s2 *big.Int) *G1J } +// JointScalarMultiplicationBase computes [s1]g+[s2]a using Straus-Shamir technique +// where g is the prime subgroup generator. +func (p *G1Jac) JointScalarMultiplicationBase(a *G1Affine, s1, s2 *big.Int) *G1Jac { + return p.JointScalarMultiplication(&g1GenAff, a, s1, s2) + +} + // ------------------------------------------------------------------------------------------------- // extended Jacobian coordinates diff --git a/ecc/bw6-756/g2.go b/ecc/bw6-756/g2.go index 0c6e4fe7f..823ac37cc 100644 --- a/ecc/bw6-756/g2.go +++ b/ecc/bw6-756/g2.go @@ -447,6 +447,13 @@ func (p *G2Jac) ScalarMultiplication(q *G2Jac, s *big.Int) *G2Jac { return p.mulGLV(q, s) } +// ScalarMultiplicationBase computes and returns p = [s]g +// where g is the prime subgroup generator. +func (p *G2Jac) ScalarMultiplicationBase(s *big.Int) *G2Jac { + return p.mulGLV(&g2Gen, s) + +} + // String converts p to affine coordinates and returns its string representation E(x,y) or "O" if it is infinity. func (p *G2Jac) String() string { _p := G2Affine{} diff --git a/ecc/bw6-761/g1.go b/ecc/bw6-761/g1.go index 365139218..d1939254c 100644 --- a/ecc/bw6-761/g1.go +++ b/ecc/bw6-761/g1.go @@ -67,20 +67,6 @@ func (p *G1Affine) ScalarMultiplication(a *G1Affine, s *big.Int) *G1Affine { return p } -// ScalarMultiplicationAffine computes and returns p = [s]a -// where a is an affine point and p a Jacobian point (useful for KZG). -func (p *G1Jac) ScalarMultiplicationAffine(a *G1Affine, s *big.Int) *G1Jac { - p.FromAffine(a) - p.mulGLV(p, s) - return p -} - -// ScalarMultiplicationBase computes and returns p = [s]g -// where g is the Jacobian point generating the prime subgroup. -func (p *G1Jac) ScalarMultiplicationBase(s *big.Int) *G1Jac { - return p.mulGLV(&g1Gen, s) -} - // ScalarMultiplicationBase computes and returns p = [s]g // where g is the affine point generating the prime subgroup. func (p *G1Affine) ScalarMultiplicationBase(s *big.Int) *G1Affine { @@ -456,6 +442,13 @@ func (p *G1Jac) ScalarMultiplication(q *G1Jac, s *big.Int) *G1Jac { return p.mulGLV(q, s) } +// ScalarMultiplicationBase computes and returns p = [s]g +// where g is the prime subgroup generator. +func (p *G1Jac) ScalarMultiplicationBase(s *big.Int) *G1Jac { + return p.mulGLV(&g1Gen, s) + +} + // String converts p to affine coordinates and returns its string representation E(x,y) or "O" if it is infinity. func (p *G1Jac) String() string { _p := G1Affine{} @@ -680,14 +673,14 @@ func (p *G1Jac) ClearCofactor(q *G1Jac) *G1Jac { } -// JointScalarMultiplicationBase computes [s1]g+[s2]a using Strauss-Shamir technique -// where g is the prime subgroup generator and a is an affine point. -func (p *G1Jac) JointScalarMultiplicationBase(a *G1Affine, s1, s2 *big.Int) *G1Jac { +// JointScalarMultiplication computes [s1]a1+[s2]a2 using Strauss-Shamir technique +// where a1 and a2 are affine points. +func (p *G1Jac) JointScalarMultiplication(a1, a2 *G1Affine, s1, s2 *big.Int) *G1Jac { var res, p1, p2 G1Jac res.Set(&g1Infinity) - p1.Set(&g1Gen) - p2.FromAffine(a) + p1.FromAffine(a1) + p2.FromAffine(a2) var table [15]G1Jac @@ -751,6 +744,13 @@ func (p *G1Jac) JointScalarMultiplicationBase(a *G1Affine, s1, s2 *big.Int) *G1J } +// JointScalarMultiplicationBase computes [s1]g+[s2]a using Straus-Shamir technique +// where g is the prime subgroup generator. +func (p *G1Jac) JointScalarMultiplicationBase(a *G1Affine, s1, s2 *big.Int) *G1Jac { + return p.JointScalarMultiplication(&g1GenAff, a, s1, s2) + +} + // ------------------------------------------------------------------------------------------------- // extended Jacobian coordinates diff --git a/ecc/bw6-761/g2.go b/ecc/bw6-761/g2.go index 215073177..513cc5f61 100644 --- a/ecc/bw6-761/g2.go +++ b/ecc/bw6-761/g2.go @@ -447,6 +447,13 @@ func (p *G2Jac) ScalarMultiplication(q *G2Jac, s *big.Int) *G2Jac { return p.mulGLV(q, s) } +// ScalarMultiplicationBase computes and returns p = [s]g +// where g is the prime subgroup generator. +func (p *G2Jac) ScalarMultiplicationBase(s *big.Int) *G2Jac { + return p.mulGLV(&g2Gen, s) + +} + // String converts p to affine coordinates and returns its string representation E(x,y) or "O" if it is infinity. func (p *G2Jac) String() string { _p := G2Affine{} diff --git a/ecc/secp256k1/g1.go b/ecc/secp256k1/g1.go index 0a25344ea..625e4f5f0 100644 --- a/ecc/secp256k1/g1.go +++ b/ecc/secp256k1/g1.go @@ -67,20 +67,6 @@ func (p *G1Affine) ScalarMultiplication(a *G1Affine, s *big.Int) *G1Affine { return p } -// ScalarMultiplicationAffine computes and returns p = [s]a -// where a is an affine point and p a Jacobian point (useful for KZG). -func (p *G1Jac) ScalarMultiplicationAffine(a *G1Affine, s *big.Int) *G1Jac { - p.FromAffine(a) - p.mulGLV(p, s) - return p -} - -// ScalarMultiplicationBase computes and returns p = [s]g -// where g is the Jacobian point generating the prime subgroup. -func (p *G1Jac) ScalarMultiplicationBase(s *big.Int) *G1Jac { - return p.mulGLV(&g1Gen, s) -} - // ScalarMultiplicationBase computes and returns p = [s]g // where g is the affine point generating the prime subgroup. func (p *G1Affine) ScalarMultiplicationBase(s *big.Int) *G1Affine { @@ -456,6 +442,13 @@ func (p *G1Jac) ScalarMultiplication(q *G1Jac, s *big.Int) *G1Jac { return p.mulGLV(q, s) } +// ScalarMultiplicationBase computes and returns p = [s]g +// where g is the prime subgroup generator. +func (p *G1Jac) ScalarMultiplicationBase(s *big.Int) *G1Jac { + return p.mulGLV(&g1Gen, s) + +} + // String converts p to affine coordinates and returns its string representation E(x,y) or "O" if it is infinity. func (p *G1Jac) String() string { _p := G1Affine{} @@ -614,14 +607,14 @@ func (p *G1Jac) mulGLV(q *G1Jac, s *big.Int) *G1Jac { return p } -// JointScalarMultiplicationBase computes [s1]g+[s2]a using Strauss-Shamir technique -// where g is the prime subgroup generator and a is an affine point. -func (p *G1Jac) JointScalarMultiplicationBase(a *G1Affine, s1, s2 *big.Int) *G1Jac { +// JointScalarMultiplication computes [s1]a1+[s2]a2 using Strauss-Shamir technique +// where a1 and a2 are affine points. +func (p *G1Jac) JointScalarMultiplication(a1, a2 *G1Affine, s1, s2 *big.Int) *G1Jac { var res, p1, p2 G1Jac res.Set(&g1Infinity) - p1.Set(&g1Gen) - p2.FromAffine(a) + p1.FromAffine(a1) + p2.FromAffine(a2) var table [15]G1Jac @@ -685,6 +678,13 @@ func (p *G1Jac) JointScalarMultiplicationBase(a *G1Affine, s1, s2 *big.Int) *G1J } +// JointScalarMultiplicationBase computes [s1]g+[s2]a using Straus-Shamir technique +// where g is the prime subgroup generator. +func (p *G1Jac) JointScalarMultiplicationBase(a *G1Affine, s1, s2 *big.Int) *G1Jac { + return p.JointScalarMultiplication(&g1GenAff, a, s1, s2) + +} + // ------------------------------------------------------------------------------------------------- // extended Jacobian coordinates diff --git a/internal/generator/ecc/template/point.go.tmpl b/internal/generator/ecc/template/point.go.tmpl index f28a4a695..c86a0eed9 100644 --- a/internal/generator/ecc/template/point.go.tmpl +++ b/internal/generator/ecc/template/point.go.tmpl @@ -77,31 +77,15 @@ func (p *{{ $TAffine }}) ScalarMultiplication(a *{{ $TAffine }}, s *big.Int) *{{ return p } -{{- if eq .PointName "g1"}} -// ScalarMultiplicationAffine computes and returns p = [s]a -// where a is an affine point and p a Jacobian point (useful for KZG). -func (p *{{ $TJacobian }}) ScalarMultiplicationAffine(a *{{ $TAffine }}, s *big.Int) *{{ $TJacobian }} { - p.FromAffine(a) - {{- if .GLV}} - p.mulGLV(p, s) - {{- else }} - p.mulWindowed(p, s) - {{- end }} - return p -} - -// ScalarMultiplicationBase computes and returns p = [s]g -// where g is the Jacobian point generating the prime subgroup. -func (p *{{ $TJacobian }}) ScalarMultiplicationBase(s *big.Int) *{{ $TJacobian }} { - return p.mulGLV(&g1Gen, s) -} -{{- end}} - // ScalarMultiplicationBase computes and returns p = [s]g // where g is the affine point generating the prime subgroup. func (p *{{ $TAffine }}) ScalarMultiplicationBase(s *big.Int) *{{ $TAffine }} { var _p {{ $TJacobian }} + {{- if .GLV}} _p.mulGLV(&{{ toLower .PointName}}Gen, s) + {{- else }} + _p.mulWindowed(&{{ toLower .PointName}}Gen, s) + {{- end }} p.FromJacobian(&_p) return p } @@ -483,6 +467,17 @@ func (p *{{ $TJacobian }}) ScalarMultiplication(q *{{ $TJacobian }}, s *big.Int) {{- end }} } +// ScalarMultiplicationBase computes and returns p = [s]g +// where g is the prime subgroup generator. +func (p *{{ $TJacobian }}) ScalarMultiplicationBase(s *big.Int) *{{ $TJacobian }} { + {{- if .GLV}} + return p.mulGLV(&{{ toLower .PointName }}Gen, s) + {{- else }} + _p.mulWindowed(&{{ toLower .PointName }}Gen, s) + {{- end }} + +} + // String converts p to affine coordinates and returns its string representation E(x,y) or "O" if it is infinity. func (p *{{ $TJacobian }}) String() string { _p := {{ $TAffine }}{} @@ -1260,14 +1255,14 @@ func (p *{{$TJacobian}}) ClearCofactor(q *{{$TJacobian}}) *{{$TJacobian}} { {{ end }} {{ if eq .PointName "g1" }} -// JointScalarMultiplicationBase computes [s1]g+[s2]a using Strauss-Shamir technique -// where g is the prime subgroup generator and a is an affine point. -func (p *{{$TJacobian}}) JointScalarMultiplicationBase(a *G1Affine, s1, s2 *big.Int) *{{$TJacobian}} { +// JointScalarMultiplication computes [s1]a1+[s2]a2 using Strauss-Shamir technique +// where a1 and a2 are affine points. +func (p *{{$TJacobian}}) JointScalarMultiplication(a1, a2 *G1Affine, s1, s2 *big.Int) *{{$TJacobian}} { var res, p1, p2 {{$TJacobian}} res.Set(&{{ toLower .PointName }}Infinity) - p1.Set(&g1Gen) - p2.FromAffine(a) + p1.FromAffine(a1) + p2.FromAffine(a2) var table [15]{{$TJacobian}} @@ -1330,6 +1325,14 @@ func (p *{{$TJacobian}}) JointScalarMultiplicationBase(a *G1Affine, s1, s2 *big. return p } + +// JointScalarMultiplicationBase computes [s1]g+[s2]a using Straus-Shamir technique +// where g is the prime subgroup generator. +func (p *{{$TJacobian}}) JointScalarMultiplicationBase(a *G1Affine, s1, s2 *big.Int) *{{$TJacobian}} { + return p.JointScalarMultiplication(&g1GenAff, a, s1, s2) + +} + {{ end }}