github.com/onflow/flow-go/crypto@v0.24.8/bls12381_hashtocurve.c (about) 1 // +build relic 2 3 #include "bls12381_utils.h" 4 #include "bls_include.h" 5 6 extern prec_st* bls_prec; 7 8 #if (hashToPoint== LOCAL_SSWU) 9 10 // These constants are taken from https://github.com/kwantam/bls12-381_hash 11 // and converted to the Mongtomery domain. 12 // Copyright 2019 Riad S. Wahby 13 const uint64_t iso_Nx_data[ELLP_Nx_LEN][Fp_DIGITS] = { 14 {0x4d18b6f3af00131c, 0x19fa219793fee28c, 0x3f2885f1467f19ae, 15 0x23dcea34f2ffb304, 0xd15b58d2ffc00054, 0x0913be200a20bef4,}, 16 {0x898985385cdbbd8b, 0x3c79e43cc7d966aa, 0x1597e193f4cd233a, 17 0x8637ef1e4d6623ad, 0x11b22deed20d827b, 0x07097bc5998784ad,}, 18 {0xa542583a480b664b, 0xfc7169c026e568c6, 0x5ba2ef314ed8b5a6, 19 0x5b5491c05102f0e7, 0xdf6e99707d2a0079, 0x0784151ed7605524,}, 20 {0x494e212870f72741, 0xab9be52fbda43021, 0x26f5577994e34c3d, 21 0x049dfee82aefbd60, 0x65dadd7828505289, 0x0e93d431ea011aeb,}, 22 {0x90ee774bd6a74d45, 0x7ada1c8a41bfb185, 0x0f1a8953b325f464, 23 0x104c24211be4805c, 0x169139d319ea7a8f, 0x09f20ead8e532bf6,}, 24 {0x6ddd93e2f43626b7, 0xa5482c9aa1ccd7bd, 0x143245631883f4bd, 25 0x2e0a94ccf77ec0db, 0xb0282d480e56489f, 0x18f4bfcbb4368929,}, 26 {0x23c5f0c953402dfd, 0x7a43ff6958ce4fe9, 0x2c390d3d2da5df63, 27 0xd0df5c98e1f9d70f, 0xffd89869a572b297, 0x1277ffc72f25e8fe,}, 28 {0x79f4f0490f06a8a6, 0x85f894a88030fd81, 0x12da3054b18b6410, 29 0xe2a57f6505880d65, 0xbba074f260e400f1, 0x08b76279f621d028,}, 30 {0xe67245ba78d5b00b, 0x8456ba9a1f186475, 0x7888bff6e6b33bb4, 31 0xe21585b9a30f86cb, 0x05a69cdcef55feee, 0x09e699dd9adfa5ac,}, 32 {0x0de5c357bff57107, 0x0a0db4ae6b1a10b2, 0xe256bb67b3b3cd8d, 33 0x8ad456574e9db24f, 0x0443915f50fd4179, 0x098c4bf7de8b6375,}, 34 {0xe6b0617e7dd929c7, 0xfe6e37d442537375, 0x1dafdeda137a489e, 35 0xe4efd1ad3f767ceb, 0x4a51d8667f0fe1cf, 0x054fdf4bbf1d821c,}, 36 {0x72db2a50658d767b, 0x8abf91faa257b3d5, 0xe969d6833764ab47, 37 0x464170142a1009eb, 0xb14f01aadb30be2f, 0x18ae6a856f40715d,}, 38 }; 39 40 const uint64_t iso_Ny_data[ELLP_Ny_LEN][Fp_DIGITS] = { 41 {0x2b567ff3e2837267, 0x1d4d9e57b958a767, 0xce028fea04bd7373, 42 0xcc31a30a0b6cd3df, 0x7d7b18a682692693, 0x0d300744d42a0310,}, 43 {0x99c2555fa542493f, 0xfe7f53cc4874f878, 0x5df0608b8f97608a, 44 0x14e03832052b49c8, 0x706326a6957dd5a4, 0x0a8dadd9c2414555,}, 45 {0x13d942922a5cf63a, 0x357e33e36e261e7d, 0xcf05a27c8456088d, 46 0x0000bd1de7ba50f0, 0x83d0c7532f8c1fde, 0x13f70bf38bbf2905,}, 47 {0x5c57fd95bfafbdbb, 0x28a359a65e541707, 0x3983ceb4f6360b6d, 48 0xafe19ff6f97e6d53, 0xb3468f4550192bf7, 0x0bb6cde49d8ba257,}, 49 {0x590b62c7ff8a513f, 0x314b4ce372cacefd, 0x6bef32ce94b8a800, 50 0x6ddf84a095713d5f, 0x64eace4cb0982191, 0x0386213c651b888d,}, 51 {0xa5310a31111bbcdd, 0xa14ac0f5da148982, 0xf9ad9cc95423d2e9, 52 0xaa6ec095283ee4a7, 0xcf5b1f022e1c9107, 0x01fddf5aed881793,}, 53 {0x65a572b0d7a7d950, 0xe25c2d8183473a19, 0xc2fcebe7cb877dbd, 54 0x05b2d36c769a89b0, 0xba12961be86e9efb, 0x07eb1b29c1dfde1f,}, 55 {0x93e09572f7c4cd24, 0x364e929076795091, 0x8569467e68af51b5, 56 0xa47da89439f5340f, 0xf4fa918082e44d64, 0x0ad52ba3e6695a79,}, 57 {0x911429844e0d5f54, 0xd03f51a3516bb233, 0x3d587e5640536e66, 58 0xfa86d2a3a9a73482, 0xa90ed5adf1ed5537, 0x149c9c326a5e7393,}, 59 {0x462bbeb03c12921a, 0xdc9af5fa0a274a17, 0x9a558ebde836ebed, 60 0x649ef8f11a4fae46, 0x8100e1652b3cdc62, 0x1862bd62c291dacb,}, 61 {0x05c9b8ca89f12c26, 0x0194160fa9b9ac4f, 0x6a643d5a6879fa2c, 62 0x14665bdd8846e19d, 0xbb1d0d53af3ff6bf, 0x12c7e1c3b28962e5,}, 63 {0xb55ebf900b8a3e17, 0xfedc77ec1a9201c4, 0x1f07db10ea1a4df4, 64 0x0dfbd15dc41a594d, 0x389547f2334a5391, 0x02419f98165871a4,}, 65 {0xb416af000745fc20, 0x8e563e9d1ea6d0f5, 0x7c763e17763a0652, 66 0x01458ef0159ebbef, 0x8346fe421f96bb13, 0x0d2d7b829ce324d2,}, 67 {0x93096bb538d64615, 0x6f2a2619951d823a, 0x8f66b3ea59514fa4, 68 0xf563e63704f7092f, 0x724b136c4cf2d9fa, 0x046959cfcfd0bf49,}, 69 {0xea748d4b6e405346, 0x91e9079c2c02d58f, 0x41064965946d9b59, 70 0xa06731f1d2bbe1ee, 0x07f897e267a33f1b, 0x1017290919210e5f,}, 71 {0x872aa6c17d985097, 0xeecc53161264562a, 0x07afe37afff55002, 72 0x54759078e5be6838, 0xc4b92d15db8acca8, 0x106d87d1b51d13b9,}, 73 }; 74 75 // sqrt_ration optimized for p mod 4 = 3. 76 // Check if (U/V) is a square, return 1 if yes, 0 otherwise 77 // If 1 is returned, out contains sqrt(U/V), 78 // otherwise out is sqrt(z*U/V) 79 // out should not be the same as U, or V 80 static int sqrt_ratio_3mod4(fp_t out, const fp_t u, const fp_t v) { 81 fp_t t0, t1, t2; 82 83 fp_sqr(t1, v); // V^2 84 fp_mul(t2, u, v); // U*V 85 fp_mul(t1, t1, t2); // U*V^3 86 fp_exp(out, t1, &bls_prec->p_3div4); // (U*V^3)^((p-3)/4) 87 fp_mul(out, out, t2); // (U*V)*(U*V^3)^((p-3)/4) = U^((p+1)/4) * V^(3p-5)/4 88 89 fp_sqr(t0, out); // out^2 90 fp_mul(t0, t0, v); // out^2 * V 91 92 int res = 1; 93 if (fp_cmp(t0, u) != RLC_EQ) { // check whether U/V is a quadratic residue 94 fp_mul(out, out, bls_prec->sqrt_z); // sqrt(-z)*U*V(UV^3)^((p-3)/4) 95 res = 0; 96 } 97 98 return res; 99 } 100 101 // returns 1 if input is odd and 0 if input is even 102 static int sign_0(const fp_t in) { 103 #if FP_RDC == MONTY 104 bn_t tmp; 105 fp_prime_back(tmp, in); // TODO: entire reduction may not be needed to get the parity 106 return bn_is_even(tmp); 107 #endif 108 return in[0]&1; 109 } 110 111 // Maps the field element t to a point p in E1(Fp) where E1: y^2 = g(x) = x^3 + a1*x + b1 112 // using optimized non-constant-time Simplified SWU implementation (A.B = 0) 113 // Outout point p is in Jacobian coordinates to avoid extra inversions. 114 static inline void map_to_E1_osswu(ep_t p, const fp_t t) { 115 fp_t t0, t1, t2, t3, t4; 116 117 // get the isogeny map coefficients 118 ctx_t* ctx = core_get(); 119 fp_t *a1 = &ctx->ep_iso.a; 120 fp_t *b1 = &ctx->ep_iso.b; 121 fp_t *z = &ctx->ep_map_u; 122 123 // compute numerator and denominator of X0(t) = N / D 124 fp_sqr(t1, t); // t^2 125 fp_mul(t1, t1, *z); // z * t^2 126 fp_sqr(t2, t1); // z^2 * t^4 127 fp_add(t2, t2, t1); // z * t^2 + z^2 * t^4 128 fp_add(t3, t2, bls_prec->r); // z * t^2 + z^2 * t^4 + 1 129 fp_mul(t3, t3, *b1); // N = b * (z * t^2 + z^2 * t^4 + 1) 130 131 if (fp_is_zero(t2)) { 132 fp_copy(p->z, bls_prec->a1z); // D = a * z 133 } else { 134 fp_mul(p->z, t2, bls_prec->minus_a1); // D = - a * (z * t^2 + z^2 * t^4) 135 } 136 137 // compute numerator and denominator of g(X0(t)) = U / V 138 // U = N^3 + a1 * N * D^2 + b1 * D^3 139 // V = D^3 140 fp_sqr(t2, t3); // N^2 141 fp_sqr(t0, p->z); // D^2 142 fp_mul(t4, *a1, t0); // a * D^2 143 fp_add(t2, t4, t2); // N^2 + a * D^2 144 fp_mul(t2, t3, t2); // N^3 + a * N * D^2 145 fp_mul(t0, t0, p->z); // V = D^3 146 fp_mul(t4, *b1, t0); // b * V = b * D^3 147 fp_add(t2, t4, t2); // U = N^3 + a1 * N * D^2 + b1 * D^3 148 149 // compute sqrt(U/V) 150 int is_sqr = sqrt_ratio_3mod4(p->y, t2, t0); 151 if (is_sqr) { 152 fp_copy(p->x, t3); // x = N 153 } else { 154 fp_mul(p->x, t1, t3); // x = N * z * t^2 155 fp_mul(t1, t1, t); // z * t^3 156 fp_mul(p->y, p->y, t1); // y = z * t^3 * sqrt(r * U/V) where r is 1 or map coefficient z 157 } 158 159 // negate y to be the same sign of t 160 if (sign_0(t) != sign_0(p->y)) { 161 fp_neg(p->y, p->y); // -y 162 } 163 164 // convert (x/D, y) into Jacobian (X,Y,Z) where Z=D to avoid inversion. 165 // Z = D, X = x/D * D^2 = x*D , Y = y*D^3 166 fp_mul(p->x, p->x, p->z); // X = N*D 167 fp_mul(p->y, p->y, t0); // Y = y*D^3 168 // p->z is already equal to D 169 p->coord = JACOB; 170 } 171 172 // This code is taken from https://github.com/kwantam/bls12-381_hash 173 // and adapted to use Relic modular arithemtic. 174 // Copyright 2019 Riad S. Wahby 175 static inline void hornerPolynomial(fp_t accumulator, const fp_t x, const int start_val, const fp_t fp_tmp[]) { 176 for (int i = start_val; i >= 0; --i) { 177 fp_mul(accumulator, accumulator, x); // acc *= x 178 fp_add(accumulator, accumulator, fp_tmp[i]); // acc += next_val 179 } 180 } 181 182 // This code is taken from https://github.com/kwantam/bls12-381_hash 183 // and adapted to use Relic modular arithemtic. 184 // Copyright 2019 Riad S. Wahby 185 static inline void compute_map_zvals(fp_t out[], const fp_t inv[], const fp_t zv[], const unsigned len) { 186 for (unsigned i = 0; i < len; ++i) { 187 fp_mul(out[i], inv[i], zv[i]); 188 } 189 } 190 191 // 11-isogeny map 192 // computes the mapping of p and stores the result in r 193 // 194 // This code is taken from https://github.com/kwantam/bls12-381_hash 195 // and adapted to use Relic modular arithemtic. The constant tables 196 // iso_D and iso_N were converted to the Montgomery domain. 197 // 198 // Copyright 2019 Riad S. Wahby 199 // Licensed under the Apache License, Version 2.0 (the "License"); 200 // you may not use this file except in compliance with the License. 201 // You may obtain a copy of the License at 202 203 // http://www.apache.org/licenses/LICENSE-2.0 204 205 // Unless required by applicable law or agreed to in writing, software 206 // distributed under the License is distributed on an "AS IS" BASIS, 207 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 208 // See the License for the specific language governing permissions and 209 // limitations under the License. 210 static inline void eval_iso11(ep_t r, const ep_t p) { 211 fp_t fp_tmp[32]; 212 213 // precompute even powers of Z up to Z^30 in fp_tmp[31]..fp_tmp[17] 214 fp_sqr(fp_tmp[31], p->z); // Z^2 215 fp_sqr(fp_tmp[30], fp_tmp[31]); // Z^4 216 fp_mul(fp_tmp[29], fp_tmp[30], fp_tmp[31]); // Z^6 217 fp_sqr(fp_tmp[28], fp_tmp[30]); // Z^8 218 fp_mul(fp_tmp[27], fp_tmp[28], fp_tmp[31]); // Z^10 219 fp_sqr(fp_tmp[26], fp_tmp[29]); // Z^12 220 fp_mul(fp_tmp[25], fp_tmp[26], fp_tmp[31]); // Z^14 221 fp_sqr(fp_tmp[24], fp_tmp[28]); // Z^16 222 fp_mul(fp_tmp[23], fp_tmp[24], fp_tmp[31]); // Z^18 223 fp_sqr(fp_tmp[22], fp_tmp[27]); // Z^20 224 fp_mul(fp_tmp[21], fp_tmp[22], fp_tmp[31]); // Z^22 225 fp_sqr(fp_tmp[20], fp_tmp[26]); // Z^24 226 fp_mul(fp_tmp[19], fp_tmp[20], fp_tmp[31]); // Z^26 227 fp_sqr(fp_tmp[18], fp_tmp[25]); // Z^28 228 fp_mul(fp_tmp[17], fp_tmp[18], fp_tmp[31]); // Z^30 229 230 // get isogeny map coefficients 231 iso_t iso = ep_curve_get_iso(); 232 // hardcode the constant to avoid warnings of gcc -Wstringop-overread 233 const int deg_dy = 15; // also equal to iso->deg_yd; 234 const int deg_dx = 10; // also equal to iso->deg_xd; 235 // TODO: get N coefficient from Relic and update N computations 236 237 // y = Ny/Dy 238 // compute Dy 239 compute_map_zvals(fp_tmp, iso->yd, fp_tmp + 17, deg_dy); // k_(15-i) Z^(2i) 240 fp_add(fp_tmp[16], p->x, fp_tmp[deg_dy - 1]); // X + k_14 Z^2 241 hornerPolynomial(fp_tmp[16], p->x, deg_dy - 2, fp_tmp); // Horner for the rest 242 fp_mul(fp_tmp[15], fp_tmp[16], fp_tmp[31]); // Dy * Z^2 243 fp_mul(fp_tmp[15], fp_tmp[15], p->z); // Dy * Z^3 244 245 // compute Ny 246 compute_map_zvals(fp_tmp, bls_prec->iso_Ny, fp_tmp + 17, ELLP_Ny_LEN - 1); // k_(15-i) Z^(2i) 247 fp_mul(fp_tmp[16], p->x, bls_prec->iso_Ny[ELLP_Ny_LEN - 1]); // k_15 * X 248 fp_add(fp_tmp[16], fp_tmp[16], fp_tmp[ELLP_Ny_LEN - 2]); // k_15 * X + k_14 Z^2 249 hornerPolynomial(fp_tmp[16], p->x, ELLP_Ny_LEN - 3, fp_tmp); // Horner for the rest 250 fp_mul(fp_tmp[16], fp_tmp[16], p->y); // Ny * Y 251 252 // x = Nx/Dx 253 // compute Dx 254 compute_map_zvals(fp_tmp, iso->xd, fp_tmp + 22, deg_dx); // k_(10-i) Z^(2i) 255 fp_add(fp_tmp[14], p->x, fp_tmp[deg_dx - 1]); // X + k_9 Z^2 256 hornerPolynomial(fp_tmp[14], p->x, deg_dx - 2, fp_tmp); // Horner for the rest 257 fp_mul(fp_tmp[14], fp_tmp[14], fp_tmp[31]); // Dx * Z^2 258 259 // compute Nx 260 compute_map_zvals(fp_tmp, bls_prec->iso_Nx, fp_tmp + 21, ELLP_Nx_LEN - 1); // k_(11-i) Z^(2i) 261 fp_mul(fp_tmp[13], p->x, bls_prec->iso_Nx[ELLP_Nx_LEN - 1]); // k_11 * X 262 fp_add(fp_tmp[13], fp_tmp[13], fp_tmp[ELLP_Nx_LEN - 2]); // k_11 * X + k_10 * Z^2 263 hornerPolynomial(fp_tmp[13], p->x, ELLP_Nx_LEN - 3, fp_tmp); // Dy: Horner for the rest 264 265 // compute the resulting point (Xo,Yo,Zo) 266 fp_mul(r->z, fp_tmp[14], fp_tmp[15]); // Zo = Dx Dy 267 fp_mul(r->x, fp_tmp[13], fp_tmp[15]); // Nx Dy 268 fp_mul(r->x, r->x, r->z); // Xo = Nx Dy Z 269 fp_sqr(fp_tmp[12], r->z); // Zo^2 270 fp_mul(r->y, fp_tmp[16], fp_tmp[14]); // Ny Dx 271 fp_mul(r->y, r->y, fp_tmp[12]); // Yo = Ny Dx Zo^2 272 r->coord = JACOB; 273 } 274 275 // map an input point in E to a point in G1 by clearing the cofactor of G1 276 static void clear_cofactor(ep_t out, const ep_t in) { 277 bn_t z; 278 bn_new(z); 279 fp_prime_get_par(z); 280 // compute 1-z 281 bn_neg(z, z); 282 bn_add_dig(z, z, 1); 283 ep_mul_dig(out, in, z->dp[0]); // z fits in 64 bits 284 bn_free(z); 285 } 286 287 // construction 2 section 5 in in https://eprint.iacr.org/2019/403.pdf 288 // evaluate the optimized SSWU map twice, add resulting points, apply isogeny map, clear cofactor 289 // the result is stored in p 290 // msg is the input message to hash, must be at least 2*(FP_BYTES+16) = 128 bytes 291 static void map_to_G1_local(ep_t p, const uint8_t *msg, int len) { 292 RLC_TRY { 293 if (len < 2*(Fp_BYTES+16)) { 294 RLC_THROW(ERR_NO_BUFFER); 295 } 296 297 fp_t t1, t2; 298 bn_t tmp; 299 bn_new(tmp); 300 bn_read_bin(tmp, msg, len/2); 301 fp_prime_conv(t1, tmp); 302 bn_read_bin(tmp, msg + len/2, len - len/2); 303 fp_prime_conv(t2, tmp); 304 bn_free(tmp); 305 306 ep_t p_temp; 307 ep_new(p_temp); 308 // first mapping 309 map_to_E1_osswu(p_temp, t1); // map to E1 310 eval_iso11(p_temp, p_temp); // map to E 311 312 // second mapping 313 map_to_E1_osswu(p, t2); // map to E1 314 eval_iso11(p, p); // map to E 315 // sum 316 // TODO: implement point addition in E1 and apply the isogeny map only once. 317 // Gives 4% improvement for map-to-curve overall 318 ep_add_jacob(p, p, p_temp); 319 320 // clear the cofactor 321 clear_cofactor(p, p); // map to G1 322 ep_free(p_temp); 323 } 324 RLC_CATCH_ANY { 325 RLC_THROW(ERR_CAUGHT); 326 } 327 } 328 #endif 329 330 // computes a hash of input data to G1 331 // construction 2 from section 5 in https://eprint.iacr.org/2019/403.pdf 332 void map_to_G1(ep_t h, const byte* data, const int len) { 333 #if hashToPoint==LOCAL_SSWU 334 map_to_G1_local(h, data, len); 335 #elif hashToPoint==RELIC_SSWU 336 ep_map_from_field(h, data, len); 337 #endif 338 }