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 }