func (g *G2) MapToCurve(in []byte) (*PointG2, error) {
	fp2 := g.f
	u, err := fp2.fromBytes(in)
	if err != nil {
		return nil, err
	}
	x, y := swuMapG2(fp2, u)
	isogenyMapG2(fp2, x, y)
	z := new(fe2).one()
	q := &PointG2{*x, *y, *z}
	g.ClearCofactor(q)
	return g.Affine(q), nil
}
MapToCurve given a byte slice returns a valid G2 point.
This mapping function implements the Simplified Shallue-van de Woestijne-Ulas method.
https://tools.ietf.org/html/draft-irtf-cfrg-hash-to-curve-05#section-6.6.2
Input byte slice should be a valid field element, otherwise an error is returned.
package bls12381
import (
	"errors"
	"math"
	"math/big"
)
type PointG2 [3]fe2
var wnafMulWindowG2 uint = 6
func (p *PointG2) Set(p2 *PointG2) *PointG2 {
	p[0].set(&p2[0])
	p[1].set(&p2[1])
	p[2].set(&p2[2])
	return p
}
func (p *PointG2) Zero() *PointG2 {
	p[0].zero()
	p[1].one()
	p[2].zero()
	return p
}
func (p *PointG2) IsAffine() bool {
	return p[2].isOne()
}
type tempG2 struct {
	t [9]*fe2
}
type G2 struct {
	f *fp2
	tempG2
}
func NewG2() *G2 {
	return newG2(nil)
}
func newG2(f *fp2) *G2 {
	if f == nil {
		f = newFp2()
	}
	t := newTempG2()
	return &G2{f, t}
}
func newTempG2() tempG2 {
	t := [9]*fe2{}
	for i := 0; i < 9; i++ {
		t[i] = &fe2{}
	}
	return tempG2{t}
}
func (g *G2) Q() *big.Int {
	return new(big.Int).Set(qBig)
}
func (g *G2) FromUncompressed(uncompressed []byte) (*PointG2, error) {
	if len(uncompressed) != 4*fpByteSize {
		return nil, errors.New("input string length must be equal to 192 bytes")
	}
	var in [4 * fpByteSize]byte
	copy(in[:], uncompressed[:4*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 := g.f.fromBytes(in[:2*fpByteSize])
	if err != nil {
		return nil, err
	}
	y, err := g.f.fromBytes(in[2*fpByteSize:])
	if err != nil {
		return nil, err
	}
	z := new(fe2).one()
	p := &PointG2{*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 *G2) ToUncompressed(p *PointG2) []byte {
	out := make([]byte, 4*fpByteSize)
	g.Affine(p)
	if g.IsZero(p) {
		out[0] |= 1 << 6
		return out
	}
	copy(out[:2*fpByteSize], g.f.toBytes(&p[0]))
	copy(out[2*fpByteSize:], g.f.toBytes(&p[1]))
	return out
}
func (g *G2) FromCompressed(compressed []byte) (*PointG2, error) {
	if len(compressed) != 2*fpByteSize {
		return nil, errors.New("input string length must be equal to 96 bytes")
	}
	var in [2 * 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 := g.f.fromBytes(in[:])
	if err != nil {
		return nil, err
	}
	y := &fe2{}
	g.f.square(y, x)
	g.f.mul(y, y, x)
	fp2Add(y, y, b2)
	if ok := g.f.sqrt(y, y); !ok {
		return nil, errors.New("point is not on curve")
	}
	if y.signBE() == a {
		fp2Neg(y, y)
	}
	z := new(fe2).one()
	p := &PointG2{*x, *y, *z}
	if !g.InCorrectSubgroup(p) {
		return nil, errors.New("point is not on correct subgroup")
	}
	return p, nil
}
func (g *G2) ToCompressed(p *PointG2) []byte {
	out := make([]byte, 2*fpByteSize)
	g.Affine(p)
	if g.IsZero(p) {
		out[0] |= 1 << 6
	} else {
		copy(out[:], g.f.toBytes(&p[0]))
		if !p[1].signBE() {
			out[0] |= 1 << 5
		}
	}
	out[0] |= 1 << 7
	return out
}
func (g *G2) fromBytesUnchecked(in []byte) (*PointG2, error) {
	p0, err := g.f.fromBytes(in[:2*fpByteSize])
	if err != nil {
		return nil, err
	}
	p1, err := g.f.fromBytes(in[2*fpByteSize:])
	if err != nil {
		return nil, err
	}
	p2 := new(fe2).one()
	return &PointG2{*p0, *p1, *p2}, nil
}
func (g *G2) FromBytes(in []byte) (*PointG2, error) {
	if len(in) != 4*fpByteSize {
		return nil, errors.New("input string length must be equal to 192 bytes")
	}
	p0, err := g.f.fromBytes(in[:2*fpByteSize])
	if err != nil {
		return nil, err
	}
	p1, err := g.f.fromBytes(in[2*fpByteSize:])
	if err != nil {
		return nil, err
	}
	if p0.isZero() && p1.isZero() {
		return g.Zero(), nil
	}
	p2 := new(fe2).one()
	p := &PointG2{*p0, *p1, *p2}
	if !g.IsOnCurve(p) {
		return nil, errors.New("point is not on curve")
	}
	return p, nil
}
func (g *G2) ToBytes(p *PointG2) []byte {
	out := make([]byte, 4*fpByteSize)
	if g.IsZero(p) {
		return out
	}
	g.Affine(p)
	copy(out[:2*fpByteSize], g.f.toBytes(&p[0]))
	copy(out[2*fpByteSize:], g.f.toBytes(&p[1]))
	return out
}
func (g *G2) New() *PointG2 {
	return new(PointG2).Zero()
}
func (g *G2) Zero() *PointG2 {
	return new(PointG2).Zero()
}
func (g *G2) One() *PointG2 {
	p := &PointG2{}
	return p.Set(&g2One)
}
func (g *G2) IsZero(p *PointG2) bool {
	return p[2].isZero()
}
func (g *G2) Equal(p1, p2 *PointG2) bool {
	if g.IsZero(p1) {
		return g.IsZero(p2)
	}
	if g.IsZero(p2) {
		return g.IsZero(p1)
	}
	t := g.t
	g.f.square(t[0], &p1[2])
	g.f.square(t[1], &p2[2])
	g.f.mul(t[2], t[0], &p2[0])
	g.f.mul(t[3], t[1], &p1[0])
	g.f.mulAssign(t[0], &p1[2])
	g.f.mulAssign(t[1], &p2[2])
	g.f.mulAssign(t[1], &p1[1])
	g.f.mulAssign(t[0], &p2[1])
	return t[0].equal(t[1]) && t[2].equal(t[3])
}
func (g *G2) IsOnCurve(p *PointG2) bool {
	if g.IsZero(p) {
		return true
	}
	t := g.t
	g.f.square(t[0], &p[1])     
	g.f.square(t[1], &p[0])     
	g.f.mul(t[1], t[1], &p[0])  
	if p.IsAffine() {
		fp2Add(t[1], t[1], b2)   
		return t[0].equal(t[1])  
	}
	g.f.square(t[2], &p[2])    
	g.f.square(t[3], t[2])     
	g.f.mulAssign(t[2], t[3])  
	g.f.mulAssign(t[2], b2)    
	fp2AddAssign(t[1], t[2])   
	return t[0].equal(t[1])    
}
func (g *G2) IsAffine(p *PointG2) bool {
	return p[2].isOne()
}
func (g *G2) Affine(p *PointG2) *PointG2 {
	return g.affine(p, p)
}
func (g *G2) affine(r, p *PointG2) *PointG2 {
	if g.IsZero(p) {
		return r.Zero()
	}
	if !g.IsAffine(p) {
		t := g.t
		g.f.inverse(t[0], &p[2])    
		g.f.square(t[1], t[0])      
		g.f.mulAssign(&r[0], t[1])  
		g.f.mulAssign(t[0], t[1])   
		g.f.mulAssign(&r[1], t[0])  
		r[2].one()                  
	} else {
		r.Set(p)
	}
	return r
}
func (g *G2) AffineBatch(p []*PointG2) {
	inverses := make([]fe2, len(p))
	for i := 0; i < len(p); i++ {
		inverses[i].set(&p[i][2])
	}
	g.f.inverseBatch(inverses)
	t := g.t
	for i := 0; i < len(p); i++ {
		if !g.IsAffine(p[i]) && !g.IsZero(p[i]) {
			g.f.square(t[1], &inverses[i])
			g.f.mulAssign(&p[i][0], t[1])
			g.f.mul(t[0], &inverses[i], t[1])
			g.f.mulAssign(&p[i][1], t[0])
			p[i][2].one()
		}
	}
}
func (g *G2) Add(r, p1, p2 *PointG2) *PointG2 {
	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
	g.f.square(t[7], &p1[2])     
	g.f.mul(t[1], &p2[0], t[7])  
	g.f.mul(t[2], &p1[2], t[7])  
	g.f.mul(t[0], &p2[1], t[2])  
	g.f.square(t[8], &p2[2])     
	g.f.mul(t[3], &p1[0], t[8])  
	g.f.mul(t[4], &p2[2], t[8])  
	g.f.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()
		}
	}
	fp2SubAssign(t[1], t[3])      
	fp2Double(t[4], t[1])         
	g.f.squareAssign(t[4])        
	g.f.mul(t[5], t[1], t[4])     
	fp2SubAssign(t[0], t[2])      
	fp2DoubleAssign(t[0])         
	g.f.square(t[6], t[0])        
	fp2SubAssign(t[6], t[5])      
	g.f.mulAssign(t[3], t[4])     
	fp2Double(t[4], t[3])         
	fp2Sub(&r[0], t[6], t[4])     
	fp2Sub(t[4], t[3], &r[0])     
	g.f.mul(t[6], t[2], t[5])     
	fp2DoubleAssign(t[6])         
	g.f.mulAssign(t[0], t[4])     
	fp2Sub(&r[1], t[0], t[6])     
	fp2Add(t[0], &p1[2], &p2[2])  
	g.f.squareAssign(t[0])        
	fp2SubAssign(t[0], t[7])      
	fp2SubAssign(t[0], t[8])      
	g.f.mul(&r[2], t[0], t[1])    
	return r
}
func (g *G2) AddMixed(r, p1, p2 *PointG2) *PointG2 {
	if g.IsZero(p1) {
		return r.Set(p2)
	}
	if g.IsZero(p2) {
		return r.Set(p1)
	}
	t := g.t
	g.f.square(t[7], &p1[2])     
	g.f.mul(t[1], &p2[0], t[7])  
	g.f.mul(t[2], &p1[2], t[7])  
	g.f.mul(t[0], &p2[1], t[2])  
	if p1[0].equal(t[1]) && p1[1].equal(t[0]) {
		return g.Double(r, p1)
	}
	fp2SubAssign(t[1], &p1[0])  
	g.f.square(t[2], t[1])      
	fp2Double(t[4], t[2])
	fp2DoubleAssign(t[4])        
	g.f.mul(t[5], t[1], t[4])    
	fp2SubAssign(t[0], &p1[1])   
	fp2DoubleAssign(t[0])        
	g.f.square(t[6], t[0])       
	fp2SubAssign(t[6], t[5])     
	g.f.mul(t[3], &p1[0], t[4])  
	fp2Double(t[4], t[3])        
	fp2Sub(&r[0], t[6], t[4])    
	fp2Sub(t[4], t[3], &r[0])    
	g.f.mul(t[6], &p1[1], t[5])  
	fp2DoubleAssign(t[6])        
	g.f.mulAssign(t[0], t[4])    
	fp2Sub(&r[1], t[0], t[6])    
	fp2Add(t[0], &p1[2], t[1])   
	g.f.squareAssign(t[0])       
	fp2SubAssign(t[0], t[7])     
	fp2Sub(&r[2], t[0], t[2])    
	return r
}
func (g *G2) Double(r, p *PointG2) *PointG2 {
	if g.IsZero(p) {
		return r.Set(p)
	}
	t := g.t
	g.f.square(t[0], &p[0])      
	g.f.square(t[1], &p[1])      
	g.f.square(t[2], t[1])       
	fp2AddAssign(t[1], &p[0])    
	g.f.squareAssign(t[1])       
	fp2SubAssign(t[1], t[0])     
	fp2SubAssign(t[1], t[2])     
	fp2DoubleAssign(t[1])        
	fp2Double(t[3], t[0])        
	fp2AddAssign(t[0], t[3])     
	g.f.square(t[4], t[0])       
	fp2Double(t[3], t[1])        
	fp2Sub(&r[0], t[4], t[3])    
	fp2SubAssign(t[1], &r[0])    
	fp2DoubleAssign(t[2])        
	fp2DoubleAssign(t[2])        
	fp2DoubleAssign(t[2])        
	g.f.mulAssign(t[0], t[1])    
	fp2Sub(t[1], t[0], t[2])     
	g.f.mul(t[0], &p[1], &p[2])  
	r[1].set(t[1])               
	fp2Double(&r[2], t[0])       
	return r
}
func (g *G2) Neg(r, p *PointG2) *PointG2 {
	r[0].set(&p[0])
	fp2Neg(&r[1], &p[1])
	r[2].set(&p[2])
	return r
}
func (g *G2) Sub(c, a, b *PointG2) *PointG2 {
	d := &PointG2{}
	g.Neg(d, b)
	g.Add(c, a, d)
	return c
}
func (g *G2) MulScalar(r, p *PointG2, e *Fr) *PointG2 {
	return g.glvMulFr(r, p, e)
}
func (g *G2) MulScalarBig(r, p *PointG2, e *big.Int) *PointG2 {
	return g.glvMulBig(r, p, e)
}
func (g *G2) mulScalar(c, p *PointG2, e *Fr) *PointG2 {
	q, n := &PointG2{}, &PointG2{}
	n.Set(p)
	for i := 0; i < frBitSize; i++ {
		if e.Bit(i) {
			g.Add(q, q, n)
		}
		g.Double(n, n)
	}
	return c.Set(q)
}
func (g *G2) mulScalarBig(c, p *PointG2, e *big.Int) *PointG2 {
	q, n := &PointG2{}, &PointG2{}
	n.Set(p)
	l := e.BitLen()
	for i := 0; i < l; i++ {
		if e.Bit(i) == 1 {
			g.Add(q, q, n)
		}
		g.Double(n, n)
	}
	return c.Set(q)
}
func (g *G2) wnafMulFr(r, p *PointG2, e *Fr) *PointG2 {
	wnaf := e.toWNAF(wnafMulWindowG2)
	return g.wnafMul(r, p, wnaf)
}
func (g *G2) wnafMulBig(r, p *PointG2, e *big.Int) *PointG2 {
	wnaf := bigToWNAF(e, wnafMulWindowG2)
	return g.wnafMul(r, p, wnaf)
}
func (g *G2) wnafMul(c, p *PointG2, wnaf nafNumber) *PointG2 {
	l := (1 << (wnafMulWindowG2 - 1))
	twoP, acc := g.New(), new(PointG2).Set(p)
	g.Double(twoP, p)
	g.Affine(twoP)
	table := make([]*PointG2, l*2)
	table[0], table[l] = g.New(), g.New()
	table[0].Set(p)
	g.Neg(table[l], table[0])
	for i := 1; i < l; i++ {
		g.AddMixed(acc, acc, twoP)
		table[i], table[i+l] = g.New(), g.New()
		table[i].Set(acc)
		g.Neg(table[i+l], table[i])
	}
	q := g.Zero()
	for i := len(wnaf) - 1; i >= 0; i-- {
		if wnaf[i] > 0 {
			g.Add(q, q, table[wnaf[i]>>1])
		} else if wnaf[i] < 0 {
			g.Add(q, q, table[((-wnaf[i])>>1)+l])
		}
		if i != 0 {
			g.Double(q, q)
		}
	}
	return c.Set(q)
}
func (g *G2) glvMulFr(r, p *PointG2, e *Fr) *PointG2 {
	return g.glvMul(r, p, new(glvVectorFr).new(e))
}
func (g *G2) glvMulBig(r, p *PointG2, e *big.Int) *PointG2 {
	return g.glvMul(r, p, new(glvVectorBig).new(e))
}
func (g *G2) glvMul(r, p0 *PointG2, v glvVector) *PointG2 {
	w := glvMulWindowG2
	l := 1 << (w - 1)
	tableK1, tableK2 := make([]*PointG2, l), make([]*PointG2, l)
	double := g.New()
	g.Double(double, p0)
	g.affine(double, double)
	tableK1[0] = new(PointG2)
	tableK1[0].Set(p0)
	for i := 1; i < l; i++ {
		tableK1[i] = new(PointG2)
		g.AddMixed(tableK1[i], tableK1[i-1], double)
	}
	g.AffineBatch(tableK1)
	for i := 0; i < l; i++ {
		tableK2[i] = new(PointG2)
		g.glvEndomorphism(tableK2[i], tableK1[i])
	}
	naf1, naf2 := v.wnaf(w)
	lenNAF1, lenNAF2 := len(naf1), len(naf2)
	lenNAF := lenNAF1
	if lenNAF2 > lenNAF {
		lenNAF = lenNAF2
	}
	acc, p1 := g.New(), g.New()
	add := func(table []*PointG2, naf int) {
		if naf != 0 {
			nafAbs := naf
			if nafAbs < 0 {
				nafAbs = -nafAbs
			}
			p1.Set(table[nafAbs>>1])
			if naf < 0 {
				g.Neg(p1, p1)
			}
			g.AddMixed(acc, acc, p1)
		}
	}
	for i := lenNAF - 1; i >= 0; i-- {
		if i < lenNAF1 {
			add(tableK1, naf1[i])
		}
		if i < lenNAF2 {
			add(tableK2, naf2[i])
		}
		if i != 0 {
			g.Double(acc, acc)
		}
	}
	return r.Set(acc)
}
func (g *G2) MultiExpBig(r *PointG2, points []*PointG2, scalars []*big.Int) (*PointG2, error) {
	if len(points) != len(scalars) {
		return nil, errors.New("point and scalar vectors should be in same length")
	}
	c := 3
	if len(scalars) >= 32 {
		c = int(math.Ceil(math.Log(float64(len(scalars)))))
	}
	bucketSize := (1 << c) - 1
	windows := make([]PointG2, 255/c+1)
	bucket := make([]PointG2, bucketSize)
	for j := 0; j < len(windows); j++ {
		for i := 0; i < bucketSize; i++ {
			bucket[i].Zero()
		}
		for i := 0; i < len(scalars); i++ {
			index := bucketSize & int(new(big.Int).Rsh(scalars[i], uint(c*j)).Int64())
			if index != 0 {
				g.Add(&bucket[index-1], &bucket[index-1], points[i])
			}
		}
		acc, sum := g.New(), g.New()
		for i := bucketSize - 1; i >= 0; i-- {
			g.Add(sum, sum, &bucket[i])
			g.Add(acc, acc, sum)
		}
		windows[j].Set(acc)
	}
	acc := g.New()
	for i := len(windows) - 1; i >= 0; i-- {
		for j := 0; j < c; j++ {
			g.Double(acc, acc)
		}
		g.Add(acc, acc, &windows[i])
	}
	return r.Set(acc), nil
}
func (g *G2) MultiExp(r *PointG2, points []*PointG2, scalars []*Fr) (*PointG2, error) {
	if len(points) != len(scalars) {
		return nil, errors.New("point and scalar vectors should be in same length")
	}
	g.AffineBatch(points)
	c := 3
	if len(scalars) >= 32 {
		c = int(math.Ceil(math.Log(float64(len(scalars)))))
	}
	bucketSize := (1 << c) - 1
	windows := make([]*PointG2, 255/c+1)
	bucket := make([]PointG2, bucketSize)
	for j := 0; j < len(windows); j++ {
		for i := 0; i < bucketSize; i++ {
			bucket[i].Zero()
		}
		for i := 0; i < len(scalars); i++ {
			index := bucketSize & int(scalars[i].sliceUint64(c*j))
			if index != 0 {
				g.AddMixed(&bucket[index-1], &bucket[index-1], points[i])
			}
		}
		acc, sum := g.New(), g.New()
		for i := bucketSize - 1; i >= 0; i-- {
			g.Add(sum, sum, &bucket[i])
			g.Add(acc, acc, sum)
		}
		windows[j] = g.New().Set(acc)
	}
	g.AffineBatch(windows)
	acc := g.New()
	for i := len(windows) - 1; i >= 0; i-- {
		for j := 0; j < c; j++ {
			g.Double(acc, acc)
		}
		g.AddMixed(acc, acc, windows[i])
	}
	return r.Set(acc), nil
}
func (g *G2) InCorrectSubgroup(p *PointG2) bool {
	t0, t1 := g.New().Set(p), g.New()
	g.psi(t0)
	g.psi(t0)
	g.Neg(t1, t0)  
	g.psi(t0)      
	g.mulX(t0)     
	g.Neg(t0, t0)
	g.Add(t0, t0, t1)
	g.Add(t0, t0, p)
	return g.IsZero(t0)
}
func (g *G2) ClearCofactor(p *PointG2) *PointG2 {
	t0, t1, t2, t3 := g.New().Set(p), g.New().Set(p), g.New().Set(p), g.New()
	g.Double(t0, t0)
	g.psi(t0)
	g.psi(t0)   
	g.psi(t2)   
	g.mulX(t1)  
	g.Sub(t3, t1, t2)  
	g.mulX(t3)         
	g.Sub(t1, t1, p)   
	g.Add(t3, t3, t1)  
	g.Sub(t3, t3, t2)  
	g.Add(t3, t3, t0)  
	return p.Set(t3)
}
func (g *G2) psi(p *PointG2) {
	fp2Conjugate(&p[0], &p[0])
	fp2Conjugate(&p[1], &p[1])
	fp2Conjugate(&p[2], &p[2])
	g.f.mul(&p[0], &p[0], &psix)
	g.f.mul(&p[1], &p[1], &psiy)
}
func (g *G2) mulX(p *PointG2) {
	chain := func(p0 *PointG2, n int, p1 *PointG2) {
		g.Add(p0, p0, p1)
		for i := 0; i < n; i++ {
			g.Double(p0, p0)
		}
	}
	t := g.New().Set(p)
	g.Double(p, t)
	chain(p, 2, t)
	chain(p, 3, t)
	chain(p, 9, t)
	chain(p, 32, t)
	chain(p, 16, t)
}