// 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) }