github.com/cloudflare/circl@v1.5.0/dh/csidh/fp511.go (about) 1 package csidh 2 3 import ( 4 "math/bits" 5 ) 6 7 // Constant time select. 8 // if pick == 0xFF..FF (out = in1) 9 // if pick == 0 (out = in2) 10 // else out is undefined. 11 func ctPick64(which uint64, in1, in2 uint64) uint64 { 12 return (in1 & which) | (in2 & ^which) 13 } 14 15 // ctIsNonZero64 returns 0 in case i == 0, otherwise it returns 1. 16 // Constant-time. 17 func ctIsNonZero64(i uint64) int { 18 // In case i==0 then i-1 will set MSB. Only in such case (i OR ~(i-1)) 19 // will result in MSB being not set (logical implication: (i-1)=>i is 20 // false iff (i-1)==0 and i==non-zero). In every other case MSB is 21 // set and hence function returns 1. 22 return int((i | (^(i - 1))) >> 63) 23 } 24 25 // Returns result of x<y operation. 26 func isLess(x, y *fp) bool { 27 for i := numWords - 1; i >= 0; i-- { 28 v, c := bits.Sub64(y[i], x[i], 0) 29 if c != 0 { 30 return false 31 } 32 if v != 0 { 33 return true 34 } 35 } 36 // x == y 37 return false 38 } 39 40 // r = x + y mod p. 41 func addRdc(r, x, y *fp) { 42 var c uint64 43 var t fp 44 r[0], c = bits.Add64(x[0], y[0], 0) 45 r[1], c = bits.Add64(x[1], y[1], c) 46 r[2], c = bits.Add64(x[2], y[2], c) 47 r[3], c = bits.Add64(x[3], y[3], c) 48 r[4], c = bits.Add64(x[4], y[4], c) 49 r[5], c = bits.Add64(x[5], y[5], c) 50 r[6], c = bits.Add64(x[6], y[6], c) 51 r[7], _ = bits.Add64(x[7], y[7], c) 52 53 t[0], c = bits.Sub64(r[0], p[0], 0) 54 t[1], c = bits.Sub64(r[1], p[1], c) 55 t[2], c = bits.Sub64(r[2], p[2], c) 56 t[3], c = bits.Sub64(r[3], p[3], c) 57 t[4], c = bits.Sub64(r[4], p[4], c) 58 t[5], c = bits.Sub64(r[5], p[5], c) 59 t[6], c = bits.Sub64(r[6], p[6], c) 60 t[7], c = bits.Sub64(r[7], p[7], c) 61 62 w := 0 - c 63 r[0] = ctPick64(w, r[0], t[0]) 64 r[1] = ctPick64(w, r[1], t[1]) 65 r[2] = ctPick64(w, r[2], t[2]) 66 r[3] = ctPick64(w, r[3], t[3]) 67 r[4] = ctPick64(w, r[4], t[4]) 68 r[5] = ctPick64(w, r[5], t[5]) 69 r[6] = ctPick64(w, r[6], t[6]) 70 r[7] = ctPick64(w, r[7], t[7]) 71 } 72 73 // r = x - y. 74 func sub512(r, x, y *fp) uint64 { 75 var c uint64 76 r[0], c = bits.Sub64(x[0], y[0], 0) 77 r[1], c = bits.Sub64(x[1], y[1], c) 78 r[2], c = bits.Sub64(x[2], y[2], c) 79 r[3], c = bits.Sub64(x[3], y[3], c) 80 r[4], c = bits.Sub64(x[4], y[4], c) 81 r[5], c = bits.Sub64(x[5], y[5], c) 82 r[6], c = bits.Sub64(x[6], y[6], c) 83 r[7], c = bits.Sub64(x[7], y[7], c) 84 return c 85 } 86 87 // r = x - y mod p. 88 func subRdc(r, x, y *fp) { 89 var c uint64 90 91 // Same as sub512(r,x,y). Unfortunately 92 // compiler is not able to inline it. 93 r[0], c = bits.Sub64(x[0], y[0], 0) 94 r[1], c = bits.Sub64(x[1], y[1], c) 95 r[2], c = bits.Sub64(x[2], y[2], c) 96 r[3], c = bits.Sub64(x[3], y[3], c) 97 r[4], c = bits.Sub64(x[4], y[4], c) 98 r[5], c = bits.Sub64(x[5], y[5], c) 99 r[6], c = bits.Sub64(x[6], y[6], c) 100 r[7], c = bits.Sub64(x[7], y[7], c) 101 102 // if x<y => r=x-y+p 103 w := 0 - c 104 r[0], c = bits.Add64(r[0], ctPick64(w, p[0], 0), 0) 105 r[1], c = bits.Add64(r[1], ctPick64(w, p[1], 0), c) 106 r[2], c = bits.Add64(r[2], ctPick64(w, p[2], 0), c) 107 r[3], c = bits.Add64(r[3], ctPick64(w, p[3], 0), c) 108 r[4], c = bits.Add64(r[4], ctPick64(w, p[4], 0), c) 109 r[5], c = bits.Add64(r[5], ctPick64(w, p[5], 0), c) 110 r[6], c = bits.Add64(r[6], ctPick64(w, p[6], 0), c) 111 r[7], _ = bits.Add64(r[7], ctPick64(w, p[7], 0), c) 112 } 113 114 // Fixed-window mod exp for fpBitLen bit value with 4 bit window. Returned 115 // result is a number in montgomery domain. 116 // r = b ^ e (mod p). 117 // Constant time. 118 func modExpRdcCommon(r, b, e *fp, fpBitLen int) { 119 var precomp [16]fp 120 var t fp 121 var c uint64 122 123 // Precompute step, computes an array of small powers of 'b'. As this 124 // algorithm implements 4-bit window, we need 2^4=16 of such values. 125 // b^0 = 1, which is equal to R from REDC. 126 precomp[0] = one // b ^ 0 127 precomp[1] = *b // b ^ 1 128 for i := 2; i < 16; i = i + 2 { 129 // OPTIMIZE: implement fast squaring. Then interleaving fast squaring 130 // with multiplication should improve performance. 131 mulRdc(&precomp[i], &precomp[i/2], &precomp[i/2]) // sqr 132 mulRdc(&precomp[i+1], &precomp[i], b) 133 } 134 135 *r = one 136 for i := fpBitLen/4 - 1; i >= 0; i-- { 137 for j := 0; j < 4; j++ { 138 mulRdc(r, r, r) 139 } 140 // note: non resistant to cache SCA 141 idx := (e[i/16] >> uint((i%16)*4)) & 15 142 mulRdc(r, r, &precomp[idx]) 143 } 144 145 // if p <= r < 2p then r = r-p 146 t[0], c = bits.Sub64(r[0], p[0], 0) 147 t[1], c = bits.Sub64(r[1], p[1], c) 148 t[2], c = bits.Sub64(r[2], p[2], c) 149 t[3], c = bits.Sub64(r[3], p[3], c) 150 t[4], c = bits.Sub64(r[4], p[4], c) 151 t[5], c = bits.Sub64(r[5], p[5], c) 152 t[6], c = bits.Sub64(r[6], p[6], c) 153 t[7], c = bits.Sub64(r[7], p[7], c) 154 155 w := 0 - c 156 r[0] = ctPick64(w, r[0], t[0]) 157 r[1] = ctPick64(w, r[1], t[1]) 158 r[2] = ctPick64(w, r[2], t[2]) 159 r[3] = ctPick64(w, r[3], t[3]) 160 r[4] = ctPick64(w, r[4], t[4]) 161 r[5] = ctPick64(w, r[5], t[5]) 162 r[6] = ctPick64(w, r[6], t[6]) 163 r[7] = ctPick64(w, r[7], t[7]) 164 } 165 166 // modExpRdc does modular exponentiation of 512-bit number. 167 // Constant-time. 168 func modExpRdc512(r, b, e *fp) { 169 modExpRdcCommon(r, b, e, 512) 170 } 171 172 // modExpRdc does modular exponentiation of 64-bit number. 173 // Constant-time. 174 func modExpRdc64(r, b *fp, e uint64) { 175 modExpRdcCommon(r, b, &fp{e}, 64) 176 } 177 178 // isNonQuadRes checks whether value v is quadratic residue. 179 // Implementation uses Fermat's little theorem (or 180 // Euler's criterion) 181 // 182 // a^(p-1) == 1, hence 183 // (a^2) ((p-1)/2) == 1 184 // 185 // Which means v is a quadratic residue iff v^((p-1)/2) == 1. 186 // Caller provided v must be in montgomery domain. 187 // Returns 0 in case v is quadratic residue or 1 in case 188 // v is quadratic non-residue. 189 func (v *fp) isNonQuadRes() int { 190 var res fp 191 var b uint64 192 193 modExpRdc512(&res, v, &pMin1By2) 194 for i := range res { 195 b |= res[i] ^ one[i] 196 } 197 198 return ctIsNonZero64(b) 199 } 200 201 // isZero returns false in case v is equal to 0, otherwise 202 // true. Constant time. 203 func (v *fp) isZero() bool { 204 var r uint64 205 for i := 0; i < numWords; i++ { 206 r |= v[i] 207 } 208 return ctIsNonZero64(r) == 0 209 } 210 211 // equal checks if v is equal to in. Constant time. 212 func (v *fp) equal(in *fp) bool { 213 var r uint64 214 for i := range v { 215 r |= v[i] ^ in[i] 216 } 217 return ctIsNonZero64(r) == 0 218 }