github.com/cloudflare/circl@v1.5.0/dh/sidh/internal/p503/fp2.go (about) 1 // Code generated by go generate; DO NOT EDIT. 2 // This file was generated by robots. 3 4 package p503 5 6 import ( 7 "github.com/cloudflare/circl/dh/sidh/internal/common" 8 ) 9 10 // Montgomery multiplication. Input values must be already 11 // in Montgomery domain. 12 func mulP(dest, lhs, rhs *common.Fp) { 13 var ab common.FpX2 14 mulP503(&ab, lhs, rhs) // = a*b*R*R 15 rdcP503(dest, &ab) // = a*b*R mod p 16 } 17 18 // Set dest = x^((p-3)/4). If x is square, this is 1/sqrt(x). 19 // Uses variation of sliding-window algorithm from with window size 20 // of 5 and least to most significant bit sliding (left-to-right) 21 // See HAC 14.85 for general description. 22 // 23 // Allowed to overlap x with dest. 24 // All values in Montgomery domains 25 // Set dest = x^(2^k), for k >= 1, by repeated squarings. 26 func p34(dest, x *common.Fp) { 27 var lookup [16]common.Fp 28 29 // This performs sum(powStrategy) + 1 squarings and len(lookup) + len(mulStrategy) 30 // multiplications. 31 powStrategy := []uint8{12, 5, 5, 2, 7, 11, 3, 8, 4, 11, 4, 7, 5, 6, 3, 7, 5, 7, 2, 12, 5, 6, 4, 6, 8, 6, 4, 7, 5, 5, 8, 5, 8, 5, 5, 8, 9, 3, 6, 2, 10, 6, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 3} 32 mulStrategy := []uint8{12, 11, 10, 0, 1, 8, 3, 7, 1, 8, 3, 6, 7, 14, 2, 14, 14, 9, 0, 13, 9, 15, 5, 12, 7, 13, 7, 15, 6, 7, 9, 0, 5, 7, 6, 8, 8, 3, 7, 0, 10, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 3} 33 initialMul := uint8(0) 34 35 // Precompute lookup table of odd multiples of x for window 36 // size k=5. 37 var xx common.Fp 38 mulP(&xx, x, x) 39 lookup[0] = *x 40 for i := 1; i < 16; i++ { 41 mulP(&lookup[i], &lookup[i-1], &xx) 42 } 43 44 // Now lookup = {x, x^3, x^5, ... } 45 // so that lookup[i] = x^{2*i + 1} 46 // so that lookup[k/2] = x^k, for odd k 47 *dest = lookup[initialMul] 48 for i := uint8(0); i < uint8(len(powStrategy)); i++ { 49 mulP(dest, dest, dest) 50 for j := uint8(1); j < powStrategy[i]; j++ { 51 mulP(dest, dest, dest) 52 } 53 mulP(dest, dest, &lookup[mulStrategy[i]]) 54 } 55 } 56 57 func add(dest, lhs, rhs *common.Fp2) { 58 addP503(&dest.A, &lhs.A, &rhs.A) 59 addP503(&dest.B, &lhs.B, &rhs.B) 60 } 61 62 func sub(dest, lhs, rhs *common.Fp2) { 63 subP503(&dest.A, &lhs.A, &rhs.A) 64 subP503(&dest.B, &lhs.B, &rhs.B) 65 } 66 67 func mul(dest, lhs, rhs *common.Fp2) { 68 var bMinA, cMinD common.Fp 69 var ac, bd common.FpX2 70 var adPlusBc common.FpX2 71 var acMinBd common.FpX2 72 73 // Let (a,b,c,d) = (lhs.a,lhs.b,rhs.a,rhs.b). 74 // 75 // (a + bi)*(c + di) = (a*c - b*d) + (a*d + b*c)i 76 // 77 // Use Karatsuba's trick: note that 78 // 79 // (b - a)*(c - d) = (b*c + a*d) - a*c - b*d 80 // 81 // so (a*d + b*c) = (b-a)*(c-d) + a*c + b*d. 82 subP503(&bMinA, &lhs.B, &lhs.A) // = (b-a)*R 83 subP503(&cMinD, &rhs.A, &rhs.B) // = (c-d)*R 84 mulP503(&ac, &lhs.A, &rhs.A) // = a*c*R*R 85 mulP503(&bd, &lhs.B, &rhs.B) // = b*d*R*R 86 mulP503(&adPlusBc, &bMinA, &cMinD) // = (b-a)*(c-d)*R*R 87 adlP503(&adPlusBc, &adPlusBc, &ac) // = ((b-a)*(c-d) + a*c)*R*R 88 adlP503(&adPlusBc, &adPlusBc, &bd) // = ((b-a)*(c-d) + a*c + b*d)*R*R 89 rdcP503(&dest.B, &adPlusBc) // = (a*d + b*c)*R mod p 90 sulP503(&acMinBd, &ac, &bd) // = (a*c - b*d)*R*R 91 rdcP503(&dest.A, &acMinBd) // = (a*c - b*d)*R mod p 92 } 93 94 // Set dest = 1/x 95 // 96 // Allowed to overlap dest with x. 97 // 98 // Returns dest to allow chaining operations. 99 func inv(dest, x *common.Fp2) { 100 var e1, e2 common.FpX2 101 var f1, f2 common.Fp 102 103 // We want to compute 104 // 105 // 1 1 (a - bi) (a - bi) 106 // -------- = -------- -------- = ----------- 107 // (a + bi) (a + bi) (a - bi) (a^2 + b^2) 108 // 109 // Letting c = 1/(a^2 + b^2), this is 110 // 111 // 1/(a+bi) = a*c - b*ci. 112 113 mulP503(&e1, &x.A, &x.A) // = a*a*R*R 114 mulP503(&e2, &x.B, &x.B) // = b*b*R*R 115 adlP503(&e1, &e1, &e2) // = (a^2 + b^2)*R*R 116 rdcP503(&f1, &e1) // = (a^2 + b^2)*R mod p 117 // Now f1 = a^2 + b^2 118 119 mulP(&f2, &f1, &f1) 120 p34(&f2, &f2) 121 mulP(&f2, &f2, &f2) 122 mulP(&f2, &f2, &f1) 123 124 mulP503(&e1, &x.A, &f2) 125 rdcP503(&dest.A, &e1) 126 127 subP503(&f1, &common.Fp{}, &x.B) 128 mulP503(&e1, &f1, &f2) 129 rdcP503(&dest.B, &e1) 130 } 131 132 func sqr(dest, x *common.Fp2) { 133 var a2, aPlusB, aMinusB common.Fp 134 var a2MinB2, ab2 common.FpX2 135 136 a := &x.A 137 b := &x.B 138 139 // (a + bi)*(a + bi) = (a^2 - b^2) + 2abi. 140 addP503(&a2, a, a) // = a*R + a*R = 2*a*R 141 addP503(&aPlusB, a, b) // = a*R + b*R = (a+b)*R 142 subP503(&aMinusB, a, b) // = a*R - b*R = (a-b)*R 143 mulP503(&a2MinB2, &aPlusB, &aMinusB) // = (a+b)*(a-b)*R*R = (a^2 - b^2)*R*R 144 mulP503(&ab2, &a2, b) // = 2*a*b*R*R 145 rdcP503(&dest.A, &a2MinB2) // = (a^2 - b^2)*R mod p 146 rdcP503(&dest.B, &ab2) // = 2*a*b*R mod p 147 } 148 149 // In case choice == 1, performs following swap in constant time: 150 // 151 // xPx <-> xQx 152 // xPz <-> xQz 153 // 154 // Otherwise returns xPx, xPz, xQx, xQz unchanged 155 func cswap(xPx, xPz, xQx, xQz *common.Fp2, choice uint8) { 156 cswapP503(&xPx.A, &xQx.A, choice) 157 cswapP503(&xPx.B, &xQx.B, choice) 158 cswapP503(&xPz.A, &xQz.A, choice) 159 cswapP503(&xPz.B, &xQz.B, choice) 160 } 161 162 // In case choice == 1, performs following moves in constant time: 163 // 164 // xPx <- xQx 165 // xPz <- xQz 166 // 167 // Otherwise returns xPx, xPz, xQx, xQz unchanged 168 func cmov(xPx, xPz, xQx, xQz *common.Fp2, choice uint8) { 169 cmovP503(&xPx.A, &xQx.A, choice) 170 cmovP503(&xPx.B, &xQx.B, choice) 171 cmovP503(&xPz.A, &xQz.A, choice) 172 cmovP503(&xPz.B, &xQz.B, choice) 173 } 174 175 func isZero(x *common.Fp2) uint8 { 176 r64 := uint64(0) 177 for i := 0; i < FpWords; i++ { 178 r64 |= x.A[i] | x.B[i] 179 } 180 r := uint8(0) 181 for i := uint64(0); i < 64; i++ { 182 r |= uint8((r64 >> i) & 0x1) 183 } 184 return 1 - r 185 } 186 187 // Converts in.A and in.B to Montgomery domain and stores 188 // in 'out' 189 // out.A = in.A * R mod p 190 // out.B = in.B * R mod p 191 // Performs v = v*R^2*R^(-1) mod p, for both in.A and in.B 192 func ToMontgomery(out, in *common.Fp2) { 193 var aRR common.FpX2 194 195 // a*R*R 196 mulP503(&aRR, &in.A, &P503R2) 197 // a*R mod p 198 rdcP503(&out.A, &aRR) 199 mulP503(&aRR, &in.B, &P503R2) 200 rdcP503(&out.B, &aRR) 201 } 202 203 // Converts in.A and in.B from Montgomery domain and stores 204 // in 'out' 205 // out.A = in.A mod p 206 // out.B = in.B mod p 207 // 208 // After returning from the call 'in' is not modified. 209 func FromMontgomery(out, in *common.Fp2) { 210 var aR common.FpX2 211 212 // convert from montgomery domain 213 copy(aR[:], in.A[:]) 214 rdcP503(&out.A, &aR) // = a mod p in [0, 2p) 215 modP503(&out.A) // = a mod p in [0, p) 216 for i := range aR { 217 aR[i] = 0 218 } 219 copy(aR[:], in.B[:]) 220 rdcP503(&out.B, &aR) 221 modP503(&out.B) 222 }