Files
mev-beta/vendor/github.com/consensys/gnark-crypto/ecc/bls12-381/bandersnatch/point.go

721 lines
17 KiB
Go

// Copyright 2020-2025 Consensys Software Inc.
// Licensed under the Apache License, Version 2.0. See the LICENSE file for details.
// Code generated by consensys/gnark-crypto DO NOT EDIT
package bandersnatch
import (
"crypto/subtle"
"io"
"math/big"
"math/bits"
"github.com/consensys/gnark-crypto/ecc/bls12-381/fr"
)
// PointAffine point on a twisted Edwards curve
type PointAffine struct {
X, Y fr.Element
}
// PointProj point in projective coordinates
type PointProj struct {
X, Y, Z fr.Element
}
// PointExtended point in extended coordinates
type PointExtended struct {
X, Y, Z, T fr.Element
}
const (
//following https://tools.ietf.org/html/rfc8032#section-3.1,
// an fr element x is negative if its binary encoding is
// lexicographically larger than -x.
mCompressedNegative = 0x80
mCompressedPositive = 0x00
mUnmask = 0x7f
// size in byte of a compressed point (point.Y --> fr.Element)
sizePointCompressed = fr.Bytes
)
// Bytes returns the compressed point as a byte array
// Follows https://tools.ietf.org/html/rfc8032#section-3.1,
// as the twisted Edwards implementation is primarily used
// for eddsa.
func (p *PointAffine) Bytes() [sizePointCompressed]byte {
var res [sizePointCompressed]byte
var mask uint
y := p.Y.Bytes()
if p.X.LexicographicallyLargest() {
mask = mCompressedNegative
} else {
mask = mCompressedPositive
}
// p.Y must be in little endian
y[0] |= byte(mask) // msb of y
for i, j := 0, sizePointCompressed-1; i < j; i, j = i+1, j-1 {
y[i], y[j] = y[j], y[i]
}
subtle.ConstantTimeCopy(1, res[:], y[:])
return res
}
// Marshal converts p to a byte slice
func (p *PointAffine) Marshal() []byte {
b := p.Bytes()
return b[:]
}
func computeX(y *fr.Element) (x fr.Element) {
initOnce.Do(initCurveParams)
var one, num, den fr.Element
one.SetOne()
num.Square(y)
den.Mul(&num, &curveParams.D)
num.Sub(&one, &num)
den.Sub(&curveParams.A, &den)
x.Div(&num, &den)
x.Sqrt(&x)
return
}
// SetBytes sets p from buf
// len(buf) >= sizePointCompressed
// buf contains the Y coordinate masked with a parity bit to recompute the X coordinate
// from the curve equation. See Bytes() and https://tools.ietf.org/html/rfc8032#section-3.1
// Returns the number of read bytes and an error if the buffer is too short.
func (p *PointAffine) SetBytes(buf []byte) (int, error) {
if len(buf) < sizePointCompressed {
return 0, io.ErrShortBuffer
}
bufCopy := make([]byte, sizePointCompressed)
subtle.ConstantTimeCopy(1, bufCopy, buf[:sizePointCompressed])
for i, j := 0, sizePointCompressed-1; i < j; i, j = i+1, j-1 {
bufCopy[i], bufCopy[j] = bufCopy[j], bufCopy[i]
}
isLexicographicallyLargest := (mCompressedNegative&bufCopy[0])>>7 == 1
bufCopy[0] &= mUnmask
p.Y.SetBytes(bufCopy)
p.X = computeX(&p.Y)
if isLexicographicallyLargest {
if !p.X.LexicographicallyLargest() {
p.X.Neg(&p.X)
}
} else {
if p.X.LexicographicallyLargest() {
p.X.Neg(&p.X)
}
}
return sizePointCompressed, nil
}
// Unmarshal alias to SetBytes()
func (p *PointAffine) Unmarshal(b []byte) error {
_, err := p.SetBytes(b)
return err
}
// Set sets p to p1 and return it
func (p *PointAffine) Set(p1 *PointAffine) *PointAffine {
p.X.Set(&p1.X)
p.Y.Set(&p1.Y)
return p
}
// Equal returns true if p=p1 false otherwise
func (p *PointAffine) Equal(p1 *PointAffine) bool {
return p.X.Equal(&p1.X) && p.Y.Equal(&p1.Y)
}
// IsZero returns true if p=0 false otherwise
func (p *PointAffine) IsZero() bool {
var one fr.Element
one.SetOne()
return p.X.IsZero() && p.Y.Equal(&one)
}
// NewPointAffine creates a new instance of PointAffine
func NewPointAffine(x, y fr.Element) PointAffine {
return PointAffine{x, y}
}
// IsOnCurve checks if a point is on the twisted Edwards curve
func (p *PointAffine) IsOnCurve() bool {
initOnce.Do(initCurveParams)
var lhs, rhs, tmp fr.Element
tmp.Mul(&p.Y, &p.Y)
lhs.Mul(&p.X, &p.X)
mulByA(&lhs)
lhs.Add(&lhs, &tmp)
tmp.Mul(&p.X, &p.X).
Mul(&tmp, &p.Y).
Mul(&tmp, &p.Y).
Mul(&tmp, &curveParams.D)
rhs.SetOne().Add(&rhs, &tmp)
return lhs.Equal(&rhs)
}
// IsInSubGroup checks if a point is in the prime subgroup (and on the curve)
// based on https://eprint.iacr.org/2022/037.pdf by D. Koshelev.
func (p *PointAffine) IsInSubGroup() bool {
if !p.IsOnCurve() {
return false
}
if p.IsZero() {
return true
}
initOnce.Do(initCurveParams)
// Given (x_e, x_e) a point on the twisted Edwards curve Ed_{a,d},
// (x_w, y_w) is a point on the birationally equivalent short Weierstrass curve W,
// where:
// x_w = ((1+y_e)/(1-y_e) + A/3 ) / B and
// A = 2(a+d)/(a-d), B = 4/(a-d)
//
// N.B.: We only need x_w in the following formula.
//
// We need to check that the two tate pairings t_{2,P1}(P) and t_{2,P2}(P) are 1,
// where P1, P2 form a basis of W[2].
// The Miller functions are:
// f1 = f_{2,P1} = x_w - P1.X
// f2 = f_{2,P2} = x_w - P2.X
// and the final exponentiations to (r-1)/2 are replaced by Legendre symbols.
//
// To avoid inverses we use the fact that ((a/b) / r)_2 = (a * b / r)_2.
// So f_{2,P2} and f_{2,Q2} are simplified as:
// f1 = (t0 + t1 * y) * (3B * (1-y)) and
// f2 = (t2 + t3 * y) * (3B * (1-y))
// where:
// t0 = 3+A-3B*P1.X
// t1 = 3-A+3B*P1.X
// t2 = 3+A-3B*P2.X
// t3 = 3-A+3B*P2.X
//
// With
// P1=(0x5de00fbdcf0964d2188e44aec311d927af0f7e94e94fca97c891a87d84178ed1,0)
// and
// P2=(0x23e93c143a3aa62dfef158aabe40ed250530ac9369509c984891a87e04178ed3,0)
// on W: y^2 = x^3 + x*(3-A^2)/(3*B^2) + (2*A^3-9*A)/(27*B^3),
// it happens that t0=t1=3 and f1 = (1 + y) * (B * (1-y))
var tate1, tate2, temp fr.Element
temp.SetOne()
tate2.Sub(&temp, &p.Y).
Mul(&tate2, &curveParams.b)
tate1.Add(&temp, &p.Y).
Mul(&tate1, &tate2)
fr.MulBy3(&tate2)
temp.Mul(&curveParams.t1, &p.Y).
Add(&temp, &curveParams.t0)
tate2.Mul(&temp, &tate2)
return tate1.Legendre() == 1 && tate2.Legendre() == 1
}
// Neg sets p to -p1 and returns it
func (p *PointAffine) Neg(p1 *PointAffine) *PointAffine {
p.X.Neg(&p1.X)
p.Y = p1.Y
return p
}
// Add adds two points (x,y), (u,v) on a twisted Edwards curve with parameters a, d
// modifies p
func (p *PointAffine) Add(p1, p2 *PointAffine) *PointAffine {
initOnce.Do(initCurveParams)
var xu, yv, xv, yu, dxyuv, one, denx, deny fr.Element
pRes := new(PointAffine)
xv.Mul(&p1.X, &p2.Y)
yu.Mul(&p1.Y, &p2.X)
pRes.X.Add(&xv, &yu)
xu.Mul(&p1.X, &p2.X)
mulByA(&xu)
yv.Mul(&p1.Y, &p2.Y)
pRes.Y.Sub(&yv, &xu)
dxyuv.Mul(&xv, &yu).Mul(&dxyuv, &curveParams.D)
one.SetOne()
denx.Add(&one, &dxyuv)
deny.Sub(&one, &dxyuv)
p.X.Div(&pRes.X, &denx)
p.Y.Div(&pRes.Y, &deny)
return p
}
// Double doubles point (x,y) on a twisted Edwards curve with parameters a, d
// modifies p
func (p *PointAffine) Double(p1 *PointAffine) *PointAffine {
p.Set(p1)
var xx, yy, xy, denum, two fr.Element
xx.Square(&p.X)
yy.Square(&p.Y)
xy.Mul(&p.X, &p.Y)
mulByA(&xx)
denum.Add(&xx, &yy)
p.X.Double(&xy).Div(&p.X, &denum)
two.SetOne().Double(&two)
denum.Neg(&denum).Add(&denum, &two)
p.Y.Sub(&yy, &xx).Div(&p.Y, &denum)
return p
}
// FromProj sets p in affine from p in projective
func (p *PointAffine) FromProj(p1 *PointProj) *PointAffine {
var I fr.Element
I.Inverse(&p1.Z)
p.X.Mul(&p1.X, &I)
p.Y.Mul(&p1.Y, &I)
return p
}
// FromExtended sets p in affine from p in extended coordinates
func (p *PointAffine) FromExtended(p1 *PointExtended) *PointAffine {
var I fr.Element
I.Inverse(&p1.Z)
p.X.Mul(&p1.X, &I)
p.Y.Mul(&p1.Y, &I)
return p
}
// ScalarMultiplication scalar multiplication of a point
// p1 in affine coordinates with a scalar in big.Int
func (p *PointAffine) ScalarMultiplication(p1 *PointAffine, scalar *big.Int) *PointAffine {
var p1Extended, resExtended PointExtended
p1Extended.FromAffine(p1)
resExtended.ScalarMultiplication(&p1Extended, scalar)
p.FromExtended(&resExtended)
return p
}
// setInfinity sets p to O (0:1)
func (p *PointAffine) setInfinity() *PointAffine {
p.X.SetZero()
p.Y.SetOne()
return p
}
//-------- Projective coordinates
// Set sets p to p1 and return it
func (p *PointProj) Set(p1 *PointProj) *PointProj {
p.X.Set(&p1.X)
p.Y.Set(&p1.Y)
p.Z.Set(&p1.Z)
return p
}
// setInfinity sets p to O (0:1:1)
func (p *PointProj) setInfinity() *PointProj {
p.X.SetZero()
p.Y.SetOne()
p.Z.SetOne()
return p
}
// Equal returns true if p=p1 false otherwise
// If one point is on the affine chart Z=0 it returns false
func (p *PointProj) Equal(p1 *PointProj) bool {
// If one point is infinity, the other must also be infinity.
if p.Z.IsZero() {
return p1.Z.IsZero()
}
// If the other point is infinity, return false since we can't
// the following checks would be incorrect.
if p1.Z.IsZero() {
return false
}
var lhs, rhs fr.Element
lhs.Mul(&p.X, &p1.Z)
rhs.Mul(&p1.X, &p.Z)
if !lhs.Equal(&rhs) {
return false
}
lhs.Mul(&p.Y, &p1.Z)
rhs.Mul(&p1.Y, &p.Z)
return lhs.Equal(&rhs)
}
// IsZero returns true if p=0 false otherwise
func (p *PointProj) IsZero() bool {
return p.X.IsZero() && p.Y.Equal(&p.Z)
}
// Neg negates point (x,y) on a twisted Edwards curve with parameters a, d
// modifies p
func (p *PointProj) Neg(p1 *PointProj) *PointProj {
p.X.Neg(&p1.X)
p.Y = p1.Y
p.Z = p1.Z
return p
}
// FromAffine sets p in projective from p in affine
func (p *PointProj) FromAffine(p1 *PointAffine) *PointProj {
p.X.Set(&p1.X)
p.Y.Set(&p1.Y)
p.Z.SetOne()
return p
}
// MixedAdd adds a point in projective to a point in affine coordinates
// cf https://hyperelliptic.org/EFD/g1p/auto-twisted-projective.html#addition-madd-2008-bbjlp
func (p *PointProj) MixedAdd(p1 *PointProj, p2 *PointAffine) *PointProj {
initOnce.Do(initCurveParams)
var B, C, D, E, F, G, H, I fr.Element
B.Square(&p1.Z)
C.Mul(&p1.X, &p2.X)
D.Mul(&p1.Y, &p2.Y)
E.Mul(&curveParams.D, &C).Mul(&E, &D)
F.Sub(&B, &E)
G.Add(&B, &E)
H.Add(&p1.X, &p1.Y)
I.Add(&p2.X, &p2.Y)
p.X.Mul(&H, &I).
Sub(&p.X, &C).
Sub(&p.X, &D).
Mul(&p.X, &p1.Z).
Mul(&p.X, &F)
mulByA(&C)
p.Y.Sub(&D, &C).
Mul(&p.Y, &p1.Z).
Mul(&p.Y, &G)
p.Z.Mul(&F, &G)
return p
}
// Double adds points in projective coordinates
// cf https://hyperelliptic.org/EFD/g1p/auto-twisted-projective.html#doubling-dbl-2008-bbjlp
func (p *PointProj) Double(p1 *PointProj) *PointProj {
var B, C, D, E, F, H, J fr.Element
B.Add(&p1.X, &p1.Y).Square(&B)
C.Square(&p1.X)
D.Square(&p1.Y)
E.Set(&C)
mulByA(&E)
F.Add(&E, &D)
H.Square(&p1.Z)
J.Sub(&F, &H).Sub(&J, &H)
p.X.Sub(&B, &C).
Sub(&p.X, &D).
Mul(&p.X, &J)
p.Y.Sub(&E, &D).Mul(&p.Y, &F)
p.Z.Mul(&F, &J)
return p
}
// Add adds points in projective coordinates
// cf https://hyperelliptic.org/EFD/g1p/auto-twisted-projective.html#addition-add-2008-bbjlp
func (p *PointProj) Add(p1, p2 *PointProj) *PointProj {
initOnce.Do(initCurveParams)
var A, B, C, D, E, F, G, H, I fr.Element
A.Mul(&p1.Z, &p2.Z)
B.Square(&A)
C.Mul(&p1.X, &p2.X)
D.Mul(&p1.Y, &p2.Y)
E.Mul(&curveParams.D, &C).Mul(&E, &D)
F.Sub(&B, &E)
G.Add(&B, &E)
H.Add(&p1.X, &p1.Y)
I.Add(&p2.X, &p2.Y)
p.X.Mul(&H, &I).
Sub(&p.X, &C).
Sub(&p.X, &D).
Mul(&p.X, &A).
Mul(&p.X, &F)
mulByA(&C)
C.Neg(&C)
p.Y.Add(&D, &C).
Mul(&p.Y, &A).
Mul(&p.Y, &G)
p.Z.Mul(&F, &G)
return p
}
// scalarMulWindowed scalar multiplication of a point
// p1 in projective coordinates with a scalar in big.Int
// using the windowed double-and-add method.
func (p *PointProj) scalarMulWindowed(p1 *PointProj, scalar *big.Int) *PointProj {
var _scalar big.Int
_scalar.Set(scalar)
p.Set(p1)
if _scalar.Sign() == -1 {
_scalar.Neg(&_scalar)
p.Neg(p)
}
var resProj PointProj
resProj.setInfinity()
const wordSize = bits.UintSize
sWords := _scalar.Bits()
for i := len(sWords) - 1; i >= 0; i-- {
ithWord := sWords[i]
for k := 0; k < wordSize; k++ {
resProj.Double(&resProj)
kthBit := (ithWord >> (wordSize - 1 - k)) & 1
if kthBit == 1 {
resProj.Add(&resProj, p)
}
}
}
p.Set(&resProj)
return p
}
// ScalarMultiplication scalar multiplication of a point
// p1 in projective coordinates with a scalar in big.Int
func (p *PointProj) ScalarMultiplication(p1 *PointProj, scalar *big.Int) *PointProj {
return p.scalarMulGLV(p1, scalar)
}
// ------- Extended coordinates
// Set sets p to p1 and return it
func (p *PointExtended) Set(p1 *PointExtended) *PointExtended {
p.X.Set(&p1.X)
p.Y.Set(&p1.Y)
p.T.Set(&p1.T)
p.Z.Set(&p1.Z)
return p
}
// IsZero returns true if p=0 false otherwise
func (p *PointExtended) IsZero() bool {
return p.X.IsZero() && p.Y.Equal(&p.Z) && p.T.IsZero()
}
// Equal returns true if p=p1 false otherwise
// If one point is on the affine chart Z=0 it returns false
func (p *PointExtended) Equal(p1 *PointExtended) bool {
if p.Z.IsZero() || p1.Z.IsZero() {
return false
}
var pAffine, p1Affine PointAffine
pAffine.FromExtended(p)
p1Affine.FromExtended(p1)
return pAffine.Equal(&p1Affine)
}
// Neg negates point (x,y) on a twisted Edwards curve with parameters a, d
// modifies p
func (p *PointExtended) Neg(p1 *PointExtended) *PointExtended {
p.X.Neg(&p1.X)
p.Y = p1.Y
p.Z = p1.Z
p.T.Neg(&p1.T)
return p
}
// FromAffine sets p in projective from p in affine
func (p *PointExtended) FromAffine(p1 *PointAffine) *PointExtended {
p.X.Set(&p1.X)
p.Y.Set(&p1.Y)
p.Z.SetOne()
p.T.Mul(&p1.X, &p1.Y)
return p
}
// Add adds points in extended coordinates
// See https://hyperelliptic.org/EFD/g1p/auto-twisted-extended.html#addition-add-2008-hwcd
func (p *PointExtended) Add(p1, p2 *PointExtended) *PointExtended {
var A, B, C, D, E, F, G, H, tmp fr.Element
A.Mul(&p1.X, &p2.X)
B.Mul(&p1.Y, &p2.Y)
C.Mul(&p1.T, &p2.T).Mul(&C, &curveParams.D)
D.Mul(&p1.Z, &p2.Z)
tmp.Add(&p1.X, &p1.Y)
E.Add(&p2.X, &p2.Y).
Mul(&E, &tmp).
Sub(&E, &A).
Sub(&E, &B)
F.Sub(&D, &C)
G.Add(&D, &C)
H.Set(&A)
mulByA(&H)
H.Sub(&B, &H)
p.X.Mul(&E, &F)
p.Y.Mul(&G, &H)
p.T.Mul(&E, &H)
p.Z.Mul(&F, &G)
return p
}
// MixedAdd adds a point in extended coordinates to a point in affine coordinates
// See https://hyperelliptic.org/EFD/g1p/auto-twisted-extended.html#addition-madd-2008-hwcd-2
func (p *PointExtended) MixedAdd(p1 *PointExtended, p2 *PointAffine) *PointExtended {
var A, B, C, D, E, F, G, H, tmp fr.Element
A.Mul(&p2.X, &p1.Z)
B.Mul(&p2.Y, &p1.Z)
if p1.X.Equal(&A) && p1.Y.Equal(&B) {
p.MixedDouble(p1)
return p
}
A.Mul(&p1.X, &p2.X)
B.Mul(&p1.Y, &p2.Y)
C.Mul(&p1.Z, &p2.X).
Mul(&C, &p2.Y)
D.Set(&p1.T)
E.Add(&D, &C)
tmp.Sub(&p1.X, &p1.Y)
F.Add(&p2.X, &p2.Y).
Mul(&F, &tmp).
Add(&F, &B).
Sub(&F, &A)
G.Set(&A)
mulByA(&G)
G.Add(&G, &B)
H.Sub(&D, &C)
p.X.Mul(&E, &F)
p.Y.Mul(&G, &H)
p.T.Mul(&E, &H)
p.Z.Mul(&F, &G)
return p
}
// Double adds points in extended coordinates
// Dedicated doubling
// https://hyperelliptic.org/EFD/g1p/auto-twisted-extended-1.html#doubling-dbl-2008-hwcd
func (p *PointExtended) Double(p1 *PointExtended) *PointExtended {
var A, B, C, D, E, F, G, H fr.Element
A.Square(&p1.X)
B.Square(&p1.Y)
C.Square(&p1.Z).
Double(&C)
D.Set(&A)
mulByA(&D)
E.Add(&p1.X, &p1.Y).
Square(&E).
Sub(&E, &A).
Sub(&E, &B)
G.Add(&D, &B)
F.Sub(&G, &C)
H.Sub(&D, &B)
p.X.Mul(&E, &F)
p.Y.Mul(&G, &H)
p.T.Mul(&H, &E)
p.Z.Mul(&F, &G)
return p
}
// MixedDouble adds points in extended coordinates
// Dedicated mixed doubling
// https://hyperelliptic.org/EFD/g1p/auto-twisted-extended-1.html#doubling-mdbl-2008-hwcd
func (p *PointExtended) MixedDouble(p1 *PointExtended) *PointExtended {
var A, B, D, E, G, H, two fr.Element
two.SetUint64(2)
A.Square(&p1.X)
B.Square(&p1.Y)
D.Set(&A)
mulByA(&D)
E.Add(&p1.X, &p1.Y).
Square(&E).
Sub(&E, &A).
Sub(&E, &B)
G.Add(&D, &B)
H.Sub(&D, &B)
p.X.Sub(&G, &two).
Mul(&p.X, &E)
p.Y.Mul(&G, &H)
p.T.Mul(&H, &E)
p.Z.Square(&G).
Sub(&p.Z, &G).
Sub(&p.Z, &G)
return p
}
// setInfinity sets p to O (0:1:1:0)
func (p *PointExtended) setInfinity() *PointExtended {
p.X.SetZero()
p.Y.SetOne()
p.Z.SetOne()
p.T.SetZero()
return p
}
// scalarMulWindowed scalar multiplication of a point
// p1 in extended coordinates with a scalar in big.Int
// using the windowed double-and-add method.
func (p *PointExtended) scalarMulWindowed(p1 *PointExtended, scalar *big.Int) *PointExtended {
var _scalar big.Int
_scalar.Set(scalar)
p.Set(p1)
if _scalar.Sign() == -1 {
_scalar.Neg(&_scalar)
p.Neg(p)
}
var resExtended PointExtended
resExtended.setInfinity()
const wordSize = bits.UintSize
sWords := _scalar.Bits()
for i := len(sWords) - 1; i >= 0; i-- {
ithWord := sWords[i]
for k := 0; k < wordSize; k++ {
resExtended.Double(&resExtended)
kthBit := (ithWord >> (wordSize - 1 - k)) & 1
if kthBit == 1 {
resExtended.Add(&resExtended, p)
}
}
}
p.Set(&resExtended)
return p
}
// ScalarMultiplication scalar multiplication of a point
// p1 in extended coordinates with a scalar in big.Int
func (p *PointExtended) ScalarMultiplication(p1 *PointExtended, scalar *big.Int) *PointExtended {
return p.scalarMulGLV(p1, scalar)
}