github.com/consensys/gnark-crypto@v0.14.0/ecc/bls12-381/bandersnatch/endomorpism.go (about)

     1  package bandersnatch
     2  
     3  import (
     4  	"math/big"
     5  
     6  	"github.com/consensys/gnark-crypto/ecc"
     7  	"github.com/consensys/gnark-crypto/ecc/bls12-381/fr"
     8  )
     9  
    10  // phi endomorphism sqrt(-2) \in O(-8)
    11  // (x,y,z)->\lambda*(x,y,z) s.t. \lamba^2 = -2 mod Order
    12  func (p *PointProj) phi(p1 *PointProj) *PointProj {
    13  
    14  	initOnce.Do(initCurveParams)
    15  
    16  	var zz, yy, xy, f, g, h fr.Element
    17  	zz.Square(&p1.Z)
    18  	yy.Square(&p1.Y)
    19  	xy.Mul(&p1.X, &p1.Y)
    20  	f.Sub(&zz, &yy).Mul(&f, &curveParams.endo[1])
    21  	zz.Mul(&zz, &curveParams.endo[0])
    22  	g.Add(&yy, &zz).Mul(&g, &curveParams.endo[0])
    23  	h.Sub(&yy, &zz)
    24  
    25  	p.X.Mul(&f, &h)
    26  	p.Y.Mul(&g, &xy)
    27  	p.Z.Mul(&h, &xy)
    28  
    29  	return p
    30  }
    31  
    32  // scalarMulGLV is the GLV scalar multiplication of a point
    33  // p1 in projective coordinates with a scalar in big.Int
    34  func (p *PointProj) scalarMulGLV(p1 *PointProj, scalar *big.Int) *PointProj {
    35  
    36  	initOnce.Do(initCurveParams)
    37  
    38  	var table [15]PointProj
    39  	var res PointProj
    40  	var k1, k2 fr.Element
    41  
    42  	res.setInfinity()
    43  
    44  	// table[b3b2b1b0-1] = b3b2*phi(p1) + b1b0*p1
    45  	table[0].Set(p1)
    46  	table[3].phi(p1)
    47  
    48  	// split the scalar, modifies +-p1, phi(p1) accordingly
    49  	k := ecc.SplitScalar(scalar, &curveParams.glvBasis)
    50  
    51  	if k[0].Sign() == -1 {
    52  		k[0].Neg(&k[0])
    53  		table[0].Neg(&table[0])
    54  	}
    55  	if k[1].Sign() == -1 {
    56  		k[1].Neg(&k[1])
    57  		table[3].Neg(&table[3])
    58  	}
    59  
    60  	// precompute table (2 bits sliding window)
    61  	// table[b3b2b1b0-1] = b3b2*phi(p1) + b1b0*p1 if b3b2b1b0 != 0
    62  	table[1].Double(&table[0])
    63  	table[2].Add(&table[1], &table[0])
    64  	table[4].Add(&table[3], &table[0])
    65  	table[5].Add(&table[3], &table[1])
    66  	table[6].Add(&table[3], &table[2])
    67  	table[7].Double(&table[3])
    68  	table[8].Add(&table[7], &table[0])
    69  	table[9].Add(&table[7], &table[1])
    70  	table[10].Add(&table[7], &table[2])
    71  	table[11].Add(&table[7], &table[3])
    72  	table[12].Add(&table[11], &table[0])
    73  	table[13].Add(&table[11], &table[1])
    74  	table[14].Add(&table[11], &table[2])
    75  
    76  	// bounds on the lattice base vectors guarantee that k1, k2 are len(r)/2 or len(r)/2+1 bits long max
    77  	// this is because we use a probabilistic scalar decomposition that replaces a division by a right-shift
    78  	k1 = k1.SetBigInt(&k[0]).Bits()
    79  	k2 = k2.SetBigInt(&k[1]).Bits()
    80  
    81  	// we don't target constant-timeness so we check first if we increase the bounds or not
    82  	maxBit := k1.BitLen()
    83  	if k2.BitLen() > maxBit {
    84  		maxBit = k2.BitLen()
    85  	}
    86  	hiWordIndex := (maxBit - 1) / 64
    87  
    88  	// loop starts from len(k1)/2 or len(k1)/2+1 due to the bounds
    89  	for i := hiWordIndex; i >= 0; i-- {
    90  		mask := uint64(3) << 62
    91  		for j := 0; j < 32; j++ {
    92  			res.Double(&res).Double(&res)
    93  			b1 := (k1[i] & mask) >> (62 - 2*j)
    94  			b2 := (k2[i] & mask) >> (62 - 2*j)
    95  			if b1|b2 != 0 {
    96  				scalar := (b2<<2 | b1)
    97  				res.Add(&res, &table[scalar-1])
    98  			}
    99  			mask = mask >> 2
   100  		}
   101  	}
   102  
   103  	p.Set(&res)
   104  	return p
   105  }
   106  
   107  // phi endomorphism sqrt(-2) \in O(-8)
   108  // (x,y,z)->\lambda*(x,y,z) s.t. \lamba^2 = -2 mod Order
   109  func (p *PointExtended) phi(p1 *PointExtended) *PointExtended {
   110  	initOnce.Do(initCurveParams)
   111  
   112  	var zz, yy, xy, f, g, h fr.Element
   113  	zz.Square(&p1.Z)
   114  	yy.Square(&p1.Y)
   115  	xy.Mul(&p1.X, &p1.Y)
   116  	f.Sub(&zz, &yy).Mul(&f, &curveParams.endo[1])
   117  	zz.Mul(&zz, &curveParams.endo[0])
   118  	g.Add(&yy, &zz).Mul(&g, &curveParams.endo[0])
   119  	h.Sub(&yy, &zz)
   120  
   121  	p.X.Mul(&f, &h)
   122  	p.Y.Mul(&g, &xy)
   123  	p.Z.Mul(&h, &xy)
   124  	p.T.Mul(&f, &g)
   125  
   126  	return p
   127  }
   128  
   129  // scalarMulGLV is the GLV scalar multiplication of a point
   130  // p1 in projective coordinates with a scalar in big.Int
   131  func (p *PointExtended) scalarMulGLV(p1 *PointExtended, scalar *big.Int) *PointExtended {
   132  
   133  	initOnce.Do(initCurveParams)
   134  
   135  	var table [15]PointExtended
   136  	var res PointExtended
   137  	var k1, k2 fr.Element
   138  
   139  	res.setInfinity()
   140  
   141  	// table[b3b2b1b0-1] = b3b2*phi(p1) + b1b0*p1
   142  	table[0].Set(p1)
   143  	table[3].phi(p1)
   144  
   145  	// split the scalar, modifies +-p1, phi(p1) accordingly
   146  	k := ecc.SplitScalar(scalar, &curveParams.glvBasis)
   147  
   148  	if k[0].Sign() == -1 {
   149  		k[0].Neg(&k[0])
   150  		table[0].Neg(&table[0])
   151  	}
   152  	if k[1].Sign() == -1 {
   153  		k[1].Neg(&k[1])
   154  		table[3].Neg(&table[3])
   155  	}
   156  
   157  	// precompute table (2 bits sliding window)
   158  	// table[b3b2b1b0-1] = b3b2*phi(p1) + b1b0*p1 if b3b2b1b0 != 0
   159  	table[1].Double(&table[0])
   160  	table[2].Add(&table[1], &table[0])
   161  	table[4].Add(&table[3], &table[0])
   162  	table[5].Add(&table[3], &table[1])
   163  	table[6].Add(&table[3], &table[2])
   164  	table[7].Double(&table[3])
   165  	table[8].Add(&table[7], &table[0])
   166  	table[9].Add(&table[7], &table[1])
   167  	table[10].Add(&table[7], &table[2])
   168  	table[11].Add(&table[7], &table[3])
   169  	table[12].Add(&table[11], &table[0])
   170  	table[13].Add(&table[11], &table[1])
   171  	table[14].Add(&table[11], &table[2])
   172  
   173  	// bounds on the lattice base vectors guarantee that k1, k2 are len(r)/2 or len(r)/2+1 bits long max
   174  	// this is because we use a probabilistic scalar decomposition that replaces a division by a right-shift
   175  	k1 = k1.SetBigInt(&k[0]).Bits()
   176  	k2 = k2.SetBigInt(&k[1]).Bits()
   177  
   178  	// we don't target constant-timeness so we check first if we increase the bounds or not
   179  	maxBit := k1.BitLen()
   180  	if k2.BitLen() > maxBit {
   181  		maxBit = k2.BitLen()
   182  	}
   183  	hiWordIndex := (maxBit - 1) / 64
   184  
   185  	// loop starts from len(k1)/2 or len(k1)/2+1 due to the bounds
   186  	for i := hiWordIndex; i >= 0; i-- {
   187  		mask := uint64(3) << 62
   188  		for j := 0; j < 32; j++ {
   189  			res.Double(&res).Double(&res)
   190  			b1 := (k1[i] & mask) >> (62 - 2*j)
   191  			b2 := (k2[i] & mask) >> (62 - 2*j)
   192  			if b1|b2 != 0 {
   193  				scalar := (b2<<2 | b1)
   194  				res.Add(&res, &table[scalar-1])
   195  			}
   196  			mask = mask >> 2
   197  		}
   198  	}
   199  
   200  	p.Set(&res)
   201  	return p
   202  }