func (g *G1) AddMixed(r, p1, p2 *PointG1) *PointG1 {
	if g.IsZero(p1) {
		return r.Set(p2)
	}
	if g.IsZero(p2) {
		return r.Set(p1)
	}
	t := g.t
	square(t[7], &p1[2])     
	mul(t[1], &p2[0], t[7])  
	mul(t[2], &p1[2], t[7])  
	mul(t[0], &p2[1], t[2])  
	if p1[0].equal(t[1]) && p1[1].equal(t[0]) {
		return g.Double(r, p1)
	}
	sub(t[1], t[1], &p1[0])  
	square(t[2], t[1])       
	double(t[4], t[2])
	doubleAssign(t[4])       
	mul(t[5], t[1], t[4])    
	subAssign(t[0], &p1[1])  
	doubleAssign(t[0])       
	square(t[6], t[0])       
	subAssign(t[6], t[5])    
	mul(t[3], &p1[0], t[4])  
	double(t[4], t[3])       
	sub(&r[0], t[6], t[4])   
	sub(t[4], t[3], &r[0])   
	mul(t[6], &p1[1], t[5])  
	doubleAssign(t[6])       
	mul(t[0], t[0], t[4])    
	sub(&r[1], t[0], t[6])   
	add(t[0], &p1[2], t[1])  
	square(t[0], t[0])       
	subAssign(t[0], t[7])    
	sub(&r[2], t[0], t[2])   
	return r
}
Add adds two G1 points p1, p2 and assigns the result to point at first argument.
Expects the second point p2 in affine form.
package bls12381
import (
	"errors"
	"math"
	"math/big"
)
type PointG1 [3]fe
var wnafMulWindowG1 uint = 5
func (p *PointG1) Set(p2 *PointG1) *PointG1 {
	p[0].set(&p2[0])
	p[1].set(&p2[1])
	p[2].set(&p2[2])
	return p
}
func (p *PointG1) Zero() *PointG1 {
	p[0].zero()
	p[1].one()
	p[2].zero()
	return p
}
func (p *PointG1) IsAffine() bool {
	return p[2].isOne()
}
type tempG1 struct {
	t [9]*fe
}
type G1 struct {
	tempG1
}
func NewG1() *G1 {
	t := newTempG1()
	return &G1{t}
}
func newTempG1() tempG1 {
	t := [9]*fe{}
	for i := 0; i < 9; i++ {
		t[i] = &fe{}
	}
	return tempG1{t}
}
func (g *G1) Q() *big.Int {
	return new(big.Int).Set(qBig)
}
func (g *G1) FromUncompressed(uncompressed []byte) (*PointG1, error) {
	if len(uncompressed) != 2*fpByteSize {
		return nil, errors.New("input string length must be equal to 96 bytes")
	}
	var in [2 * fpByteSize]byte
	copy(in[:], uncompressed[:2*fpByteSize])
	if in[0]&(1<<7) != 0 {
		return nil, errors.New("compression flag must be zero")
	}
	if in[0]&(1<<5) != 0 {
		return nil, errors.New("sort flag must be zero")
	}
	if in[0]&(1<<6) != 0 {
		for i, v := range in {
			if (i == 0 && v != 0x40) || (i != 0 && v != 0x00) {
				return nil, errors.New("input string must be zero when infinity flag is set")
			}
		}
		return g.Zero(), nil
	}
	in[0] &= 0x1f
	x, err := fromBytes(in[:fpByteSize])
	if err != nil {
		return nil, err
	}
	y, err := fromBytes(in[fpByteSize:])
	if err != nil {
		return nil, err
	}
	z := new(fe).one()
	p := &PointG1{*x, *y, *z}
	if !g.IsOnCurve(p) {
		return nil, errors.New("point is not on curve")
	}
	if !g.InCorrectSubgroup(p) {
		return nil, errors.New("point is not on correct subgroup")
	}
	return p, nil
}
func (g *G1) ToUncompressed(p *PointG1) []byte {
	out := make([]byte, 2*fpByteSize)
	if g.IsZero(p) {
		out[0] |= 1 << 6
		return out
	}
	g.Affine(p)
	copy(out[:fpByteSize], toBytes(&p[0]))
	copy(out[fpByteSize:], toBytes(&p[1]))
	return out
}
func (g *G1) FromCompressed(compressed []byte) (*PointG1, error) {
	if len(compressed) != fpByteSize {
		return nil, errors.New("input string length must be equal to 48 bytes")
	}
	var in [fpByteSize]byte
	copy(in[:], compressed[:])
	if in[0]&(1<<7) == 0 {
		return nil, errors.New("compression flag must be set")
	}
	if in[0]&(1<<6) != 0 {
		for i, v := range in {
			if (i == 0 && v != 0xc0) || (i != 0 && v != 0x00) {
				return nil, errors.New("input string must be zero when infinity flag is set")
			}
		}
		return g.Zero(), nil
	}
	a := in[0]&(1<<5) != 0
	in[0] &= 0x1f
	x, err := fromBytes(in[:])
	if err != nil {
		return nil, err
	}
	y := &fe{}
	square(y, x)
	mul(y, y, x)
	add(y, y, b)
	if ok := sqrt(y, y); !ok {
		return nil, errors.New("point is not on curve")
	}
	if y.signBE() == a {
		neg(y, y)
	}
	z := new(fe).one()
	p := &PointG1{*x, *y, *z}
	if !g.InCorrectSubgroup(p) {
		return nil, errors.New("point is not on correct subgroup")
	}
	return p, nil
}
func (g *G1) ToCompressed(p *PointG1) []byte {
	out := make([]byte, fpByteSize)
	g.Affine(p)
	if g.IsZero(p) {
		out[0] |= 1 << 6
	} else {
		copy(out[:], toBytes(&p[0]))
		if !p[1].signBE() {
			out[0] |= 1 << 5
		}
	}
	out[0] |= 1 << 7
	return out
}
func (g *G1) fromBytesUnchecked(in []byte) (*PointG1, error) {
	p0, err := fromBytes(in[:fpByteSize])
	if err != nil {
		return nil, err
	}
	p1, err := fromBytes(in[fpByteSize:])
	if err != nil {
		return nil, err
	}
	p2 := new(fe).one()
	return &PointG1{*p0, *p1, *p2}, nil
}
func (g *G1) FromBytes(in []byte) (*PointG1, error) {
	if len(in) != 2*fpByteSize {
		return nil, errors.New("input string length must be equal to 96 bytes")
	}
	p0, err := fromBytes(in[:fpByteSize])
	if err != nil {
		return nil, err
	}
	p1, err := fromBytes(in[fpByteSize:])
	if err != nil {
		return nil, err
	}
	if p0.isZero() && p1.isZero() {
		return g.Zero(), nil
	}
	p2 := new(fe).one()
	p := &PointG1{*p0, *p1, *p2}
	if !g.IsOnCurve(p) {
		return nil, errors.New("point is not on curve")
	}
	return p, nil
}
func (g *G1) ToBytes(p *PointG1) []byte {
	out := make([]byte, 2*fpByteSize)
	if g.IsZero(p) {
		return out
	}
	g.Affine(p)
	copy(out[:fpByteSize], toBytes(&p[0]))
	copy(out[fpByteSize:], toBytes(&p[1]))
	return out
}
func (g *G1) New() *PointG1 {
	return g.Zero()
}
func (g *G1) Zero() *PointG1 {
	return new(PointG1).Zero()
}
func (g *G1) One() *PointG1 {
	p := &PointG1{}
	return p.Set(&g1One)
}
func (g *G1) IsZero(p *PointG1) bool {
	return p[2].isZero()
}
func (g *G1) Equal(p1, p2 *PointG1) bool {
	if g.IsZero(p1) {
		return g.IsZero(p2)
	}
	if g.IsZero(p2) {
		return g.IsZero(p1)
	}
	t := g.t
	square(t[0], &p1[2])
	square(t[1], &p2[2])
	mul(t[2], t[0], &p2[0])
	mul(t[3], t[1], &p1[0])
	mul(t[0], t[0], &p1[2])
	mul(t[1], t[1], &p2[2])
	mul(t[1], t[1], &p1[1])
	mul(t[0], t[0], &p2[1])
	return t[0].equal(t[1]) && t[2].equal(t[3])
}
func (g *G1) InCorrectSubgroup(p *PointG1) bool {
	mulZ := func(p *PointG1) {
		z := &Fr{0x0000000055555555, 0x396c8c005555e156}
		e := z.toWNAF(wnafMulWindowG1)
		g.wnafMul(p, p, e)
	}
	t0 := g.New().Set(p)
	g.glvEndomorphism(t0, t0)
	t1 := g.New().Set(t0)      
	g.glvEndomorphism(t0, t0)  
	g.Double(t1, t1)           
	g.Sub(t1, t1, p)           
	g.Sub(t1, t1, t0)          
	mulZ(t1)                   
	g.Sub(t1, t1, t0)          
	return g.IsZero(t1)
}
func (g *G1) IsOnCurve(p *PointG1) bool {
	if g.IsZero(p) {
		return true
	}
	t := g.t
	square(t[0], &p[1])     
	square(t[1], &p[0])     
	mul(t[1], t[1], &p[0])  
	if p.IsAffine() {
		addAssign(t[1], b)       
		return t[0].equal(t[1])  
	}
	square(t[2], &p[2])      
	square(t[3], t[2])       
	mul(t[2], t[2], t[3])    
	mul(t[2], b, t[2])       
	add(t[1], t[1], t[2])    
	return t[0].equal(t[1])  
}
func (g *G1) IsAffine(p *PointG1) bool {
	return p[2].isOne()
}
func (g *G1) Affine(p *PointG1) *PointG1 {
	return g.affine(p, p)
}
func (g *G1) affine(r, p *PointG1) *PointG1 {
	if g.IsZero(p) {
		return r.Zero()
	}
	if !g.IsAffine(p) {
		t := g.t
		inverse(t[0], &p[2])     
		square(t[1], t[0])       
		mul(&r[0], &p[0], t[1])  
		mul(t[0], t[0], t[1])    
		mul(&r[1], &p[1], t[0])  
		r[2].one()               
	} else {
		r.Set(p)
	}
	return r
}
func (g *G1) AffineBatch(p []*PointG1) {
	inverses := make([]fe, len(p))
	for i := 0; i < len(p); i++ {
		inverses[i].set(&p[i][2])
	}
	inverseBatch(inverses)
	t := g.t
	for i := 0; i < len(p); i++ {
		if !g.IsAffine(p[i]) && !g.IsZero(p[i]) {
			square(t[1], &inverses[i])
			mul(&p[i][0], &p[i][0], t[1])
			mul(t[0], &inverses[i], t[1])
			mul(&p[i][1], &p[i][1], t[0])
			p[i][2].one()
		}
	}
}
func (g *G1) Add(r, p1, p2 *PointG1) *PointG1 {
	if g.IsZero(p1) {
		return r.Set(p2)
	}
	if g.IsZero(p2) {
		return r.Set(p1)
	}
	if g.IsAffine(p2) {
		return g.AddMixed(r, p1, p2)
	}
	t := g.t
	square(t[7], &p1[2])     
	mul(t[1], &p2[0], t[7])  
	mul(t[2], &p1[2], t[7])  
	mul(t[0], &p2[1], t[2])  
	square(t[8], &p2[2])     
	mul(t[3], &p1[0], t[8])  
	mul(t[4], &p2[2], t[8])  
	mul(t[2], &p1[1], t[4])  
	if t[1].equal(t[3]) {
		if t[0].equal(t[2]) {
			return g.Double(r, p1)
		} else {
			return r.Zero()
		}
	}
	subAssign(t[1], t[3])      
	double(t[4], t[1])         
	square(t[4], t[4])         
	mul(t[5], t[1], t[4])      
	subAssign(t[0], t[2])      
	doubleAssign(t[0])         
	square(t[6], t[0])         
	subAssign(t[6], t[5])      
	mul(t[3], t[3], t[4])      
	double(t[4], t[3])         
	sub(&r[0], t[6], t[4])     
	sub(t[4], t[3], &r[0])     
	mul(t[6], t[2], t[5])      
	doubleAssign(t[6])         
	mul(t[0], t[0], t[4])      
	sub(&r[1], t[0], t[6])     
	add(t[0], &p1[2], &p2[2])  
	square(t[0], t[0])         
	subAssign(t[0], t[7])      
	subAssign(t[0], t[8])      
	mul(&r[2], t[0], t[1])     
	return r
}