github.com/platonnetwork/platon-go@v0.7.6/cases/tool/win/bls_win/include/mcl/conversion.hpp (about) 1 #pragma once 2 #include <cybozu/itoa.hpp> 3 #include <cybozu/stream.hpp> 4 /** 5 @file 6 @brief convertion bin/dec/hex <=> array 7 @author MITSUNARI Shigeo(@herumi) 8 @license modified new BSD license 9 http://opensource.org/licenses/BSD-3-Clause 10 */ 11 #ifdef _MSC_VER 12 #pragma warning(push) 13 #pragma warning(disable : 4127) 14 #endif 15 16 namespace mcl { namespace fp { 17 18 namespace local { 19 20 inline bool isSpace(char c) 21 { 22 return c == ' ' || c == '\t' || c == '\r' || c == '\n'; 23 } 24 template<class InputStream> 25 bool skipSpace(char *c, InputStream& is) 26 { 27 for (;;) { 28 if (!cybozu::readChar(c, is)) return false; 29 if (!isSpace(*c)) return true; 30 } 31 } 32 33 #ifndef CYBOZU_DONT_USE_STRING 34 template<class InputStream> 35 void loadWord(std::string& s, InputStream& is) 36 { 37 s.clear(); 38 char c; 39 if (!skipSpace(&c, is)) return; 40 s = c; 41 for (;;) { 42 if (!cybozu::readChar(&c, is)) return; 43 if (isSpace(c)) break; 44 s += c; 45 } 46 } 47 #endif 48 49 template<class InputStream> 50 size_t loadWord(char *buf, size_t bufSize, InputStream& is) 51 { 52 if (bufSize == 0) return 0; 53 char c; 54 if (!skipSpace(&c, is)) return 0; 55 size_t pos = 0; 56 buf[pos++] = c; 57 for (;;) { 58 if (!cybozu::readChar(&c, is)) break; 59 if (isSpace(c)) break; 60 if (pos == bufSize) return 0; 61 buf[pos++] = c; 62 } 63 return pos; 64 } 65 66 67 /* 68 q = x[] / x 69 @retval r = x[] % x 70 @note accept q == x 71 */ 72 inline uint32_t divU32(uint32_t *q, const uint32_t *x, size_t xn, uint32_t y) 73 { 74 if (xn == 0) return 0; 75 uint32_t r = 0; 76 for (int i = (int)xn - 1; i >= 0; i--) { 77 uint64_t t = (uint64_t(r) << 32) | x[i]; 78 q[i] = uint32_t(t / y); 79 r = uint32_t(t % y); 80 } 81 return r; 82 } 83 84 /* 85 z[0, xn) = x[0, xn) * y 86 return z[xn] 87 @note accept z == x 88 */ 89 inline uint32_t mulU32(uint32_t *z, const uint32_t *x, size_t xn, uint32_t y) 90 { 91 uint32_t H = 0; 92 for (size_t i = 0; i < xn; i++) { 93 uint32_t t = H; 94 uint64_t v = uint64_t(x[i]) * y; 95 uint32_t L = uint32_t(v); 96 H = uint32_t(v >> 32); 97 z[i] = t + L; 98 if (z[i] < t) { 99 H++; 100 } 101 } 102 return H; 103 } 104 105 /* 106 x[0, xn) += y 107 return 1 if overflow else 0 108 */ 109 inline uint32_t addU32(uint32_t *x, size_t xn, uint32_t y) 110 { 111 uint32_t t = x[0] + y; 112 x[0] = t; 113 if (t >= y) return 0; 114 for (size_t i = 1; i < xn; i++) { 115 t = x[i] + 1; 116 x[i] = t; 117 if (t != 0) return 0; 118 } 119 return 1; 120 } 121 122 inline uint32_t decToU32(const char *p, size_t size, bool *pb) 123 { 124 assert(0 < size && size <= 9); 125 uint32_t x = 0; 126 for (size_t i = 0; i < size; i++) { 127 char c = p[i]; 128 if (c < '0' || c > '9') { 129 *pb = false; 130 return 0; 131 } 132 x = x * 10 + uint32_t(c - '0'); 133 } 134 *pb = true; 135 return x; 136 } 137 138 inline bool hexCharToUint8(uint8_t *v, char _c) 139 { 140 uint32_t c = uint8_t(_c); // cast is necessary 141 if (c - '0' <= '9' - '0') { 142 c = c - '0'; 143 } else if (c - 'a' <= 'f' - 'a') { 144 c = (c - 'a') + 10; 145 } else if (c - 'A' <= 'F' - 'A') { 146 c = (c - 'A') + 10; 147 } else { 148 return false; 149 } 150 *v = uint8_t(c); 151 return true; 152 } 153 154 template<class UT> 155 bool hexToUint(UT *px, const char *p, size_t size) 156 { 157 assert(0 < size && size <= sizeof(UT) * 2); 158 UT x = 0; 159 for (size_t i = 0; i < size; i++) { 160 uint8_t v; 161 if (!hexCharToUint8(&v, p[i])) return false; 162 x = x * 16 + v; 163 } 164 *px = x; 165 return true; 166 } 167 168 template<class UT> 169 bool binToUint(UT *px, const char *p, size_t size) 170 { 171 assert(0 < size && size <= sizeof(UT) * 8); 172 UT x = 0; 173 for (size_t i = 0; i < size; i++) { 174 UT c = static_cast<uint8_t>(p[i]); 175 if (c == '0') { 176 x = x * 2; 177 } else if (c == '1') { 178 x = x * 2 + 1; 179 } else { 180 return false; 181 } 182 } 183 *px = x; 184 return true; 185 } 186 187 inline bool parsePrefix(size_t *readSize, bool *isMinus, int *base, const char *buf, size_t bufSize) 188 { 189 if (bufSize == 0) return false; 190 size_t pos = 0; 191 if (*buf == '-') { 192 if (bufSize == 1) return false; 193 *isMinus = true; 194 buf++; 195 pos++; 196 } else { 197 *isMinus = false; 198 } 199 if (buf[0] == '0') { 200 if (bufSize > 1 && buf[1] == 'x') { 201 if (*base == 0 || *base == 16) { 202 *base = 16; 203 pos += 2; 204 } else { 205 return false; 206 } 207 } else if (bufSize > 1 && buf[1] == 'b') { 208 if (*base == 0 || *base == 2) { 209 *base = 2; 210 pos += 2; 211 } 212 } 213 } 214 if (*base == 0) *base = 10; 215 if (pos == bufSize) return false; 216 *readSize = pos; 217 return true; 218 } 219 220 } // mcl::fp::local 221 222 /* 223 convert little endian x[0, xn) to buf 224 return written size if success else 0 225 data is buf[bufSize - retval, bufSize) 226 start "0x" if withPrefix 227 */ 228 template<class T> 229 size_t arrayToHex(char *buf, size_t bufSize, const T *x, size_t n, bool withPrefix = false) 230 { 231 size_t fullN = 0; 232 if (n > 1) { 233 size_t pos = n - 1; 234 while (pos > 0) { 235 if (x[pos]) break; 236 pos--; 237 } 238 if (pos > 0) fullN = pos; 239 } 240 const T v = n == 0 ? 0 : x[fullN]; 241 const size_t topLen = cybozu::getHexLength(v); 242 const size_t startPos = withPrefix ? 2 : 0; 243 const size_t lenT = sizeof(T) * 2; 244 const size_t totalSize = startPos + fullN * lenT + topLen; 245 if (totalSize > bufSize) return 0; 246 char *const top = buf + bufSize - totalSize; 247 if (withPrefix) { 248 top[0] = '0'; 249 top[1] = 'x'; 250 } 251 cybozu::itohex(&top[startPos], topLen, v, false); 252 for (size_t i = 0; i < fullN; i++) { 253 cybozu::itohex(&top[startPos + topLen + i * lenT], lenT, x[fullN - 1 - i], false); 254 } 255 return totalSize; 256 } 257 258 /* 259 convert little endian x[0, xn) to buf 260 return written size if success else 0 261 data is buf[bufSize - retval, bufSize) 262 start "0b" if withPrefix 263 */ 264 template<class T> 265 size_t arrayToBin(char *buf, size_t bufSize, const T *x, size_t n, bool withPrefix) 266 { 267 size_t fullN = 0; 268 if (n > 1) { 269 size_t pos = n - 1; 270 while (pos > 0) { 271 if (x[pos]) break; 272 pos--; 273 } 274 if (pos > 0) fullN = pos; 275 } 276 const T v = n == 0 ? 0 : x[fullN]; 277 const size_t topLen = cybozu::getBinLength(v); 278 const size_t startPos = withPrefix ? 2 : 0; 279 const size_t lenT = sizeof(T) * 8; 280 const size_t totalSize = startPos + fullN * lenT + topLen; 281 if (totalSize > bufSize) return 0; 282 char *const top = buf + bufSize - totalSize; 283 if (withPrefix) { 284 top[0] = '0'; 285 top[1] = 'b'; 286 } 287 cybozu::itobin(&top[startPos], topLen, v); 288 for (size_t i = 0; i < fullN; i++) { 289 cybozu::itobin(&top[startPos + topLen + i * lenT], lenT, x[fullN - 1 - i]); 290 } 291 return totalSize; 292 } 293 294 /* 295 convert hex string to x[0..xn) 296 hex string = [0-9a-fA-F]+ 297 */ 298 template<class UT> 299 inline size_t hexToArray(UT *x, size_t maxN, const char *buf, size_t bufSize) 300 { 301 if (bufSize == 0) return 0; 302 const size_t unitLen = sizeof(UT) * 2; 303 const size_t q = bufSize / unitLen; 304 const size_t r = bufSize % unitLen; 305 const size_t requireSize = q + (r ? 1 : 0); 306 if (maxN < requireSize) return 0; 307 for (size_t i = 0; i < q; i++) { 308 if (!local::hexToUint(&x[i], &buf[r + (q - 1 - i) * unitLen], unitLen)) return 0; 309 } 310 if (r) { 311 if (!local::hexToUint(&x[q], buf, r)) return 0; 312 } 313 return requireSize; 314 } 315 /* 316 convert bin string to x[0..xn) 317 bin string = [01]+ 318 */ 319 template<class UT> 320 inline size_t binToArray(UT *x, size_t maxN, const char *buf, size_t bufSize) 321 { 322 if (bufSize == 0) return 0; 323 const size_t unitLen = sizeof(UT) * 8; 324 const size_t q = bufSize / unitLen; 325 const size_t r = bufSize % unitLen; 326 const size_t requireSize = q + (r ? 1 : 0); 327 if (maxN < requireSize) return 0; 328 for (size_t i = 0; i < q; i++) { 329 if (!local::binToUint(&x[i], &buf[r + (q - 1 - i) * unitLen], unitLen)) return 0; 330 } 331 if (r) { 332 if (!local::binToUint(&x[q], buf, r)) return 0; 333 } 334 return requireSize; 335 } 336 337 /* 338 little endian x[0, xn) to buf 339 return written size if success else 0 340 data is buf[bufSize - retval, bufSize) 341 */ 342 template<class UT> 343 inline size_t arrayToDec(char *buf, size_t bufSize, const UT *x, size_t xn) 344 { 345 const size_t maxN = 64; 346 uint32_t t[maxN]; 347 if (sizeof(UT) == 8) { 348 xn *= 2; 349 } 350 if (xn > maxN) return 0; 351 memcpy(t, x, xn * sizeof(t[0])); 352 353 const size_t width = 9; 354 const uint32_t i1e9 = 1000000000U; 355 size_t pos = 0; 356 for (;;) { 357 uint32_t r = local::divU32(t, t, xn, i1e9); 358 while (xn > 0 && t[xn - 1] == 0) xn--; 359 size_t len = cybozu::itoa_local::uintToDec(buf, bufSize - pos, r); 360 if (len == 0) return 0; 361 assert(0 < len && len <= width); 362 if (xn == 0) return pos + len; 363 // fill (width - len) '0' 364 for (size_t j = 0; j < width - len; j++) { 365 buf[bufSize - pos - width + j] = '0'; 366 } 367 pos += width; 368 } 369 } 370 371 /* 372 convert buf[0, bufSize) to x[0, num) 373 return written num if success else 0 374 */ 375 template<class UT> 376 inline size_t decToArray(UT *_x, size_t maxN, const char *buf, size_t bufSize) 377 { 378 assert(sizeof(UT) == 4 || sizeof(UT) == 8); 379 const size_t width = 9; 380 const uint32_t i1e9 = 1000000000U; 381 if (maxN == 0) return 0; 382 if (sizeof(UT) == 8) { 383 maxN *= 2; 384 } 385 uint32_t *x = reinterpret_cast<uint32_t*>(_x); 386 size_t xn = 1; 387 x[0] = 0; 388 while (bufSize > 0) { 389 size_t n = bufSize % width; 390 if (n == 0) n = width; 391 bool b; 392 uint32_t v = local::decToU32(buf, n, &b); 393 if (!b) return 0; 394 uint32_t H = local::mulU32(x, x, xn, i1e9); 395 if (H > 0) { 396 if (xn == maxN) return 0; 397 x[xn++] = H; 398 } 399 H = local::addU32(x, xn, v); 400 if (H > 0) { 401 if (xn == maxN) return 0; 402 x[xn++] = H; 403 } 404 buf += n; 405 bufSize -= n; 406 } 407 if (sizeof(UT) == 8 && (xn & 1)) { 408 x[xn++] = 0; 409 } 410 return xn / (sizeof(UT) / 4); 411 } 412 413 /* 414 return retavl is written size if success else 0 415 REMARK : the top of string is buf + bufSize - retval 416 */ 417 template<class UT> 418 size_t arrayToStr(char *buf, size_t bufSize, const UT *x, size_t n, int base, bool withPrefix) 419 { 420 switch (base) { 421 case 0: 422 case 10: 423 return arrayToDec(buf, bufSize, x, n); 424 case 16: 425 return arrayToHex(buf, bufSize, x, n, withPrefix); 426 case 2: 427 return arrayToBin(buf, bufSize, x, n, withPrefix); 428 default: 429 return 0; 430 } 431 } 432 433 template<class UT> 434 size_t strToArray(bool *pIsMinus, UT *x, size_t xN, const char *buf, size_t bufSize, int ioMode) 435 { 436 ioMode &= 31; 437 size_t readSize; 438 if (!local::parsePrefix(&readSize, pIsMinus, &ioMode, buf, bufSize)) return 0; 439 switch (ioMode) { 440 case 10: 441 return decToArray(x, xN, buf + readSize, bufSize - readSize); 442 case 16: 443 return hexToArray(x, xN, buf + readSize, bufSize - readSize); 444 case 2: 445 return binToArray(x, xN, buf + readSize, bufSize - readSize); 446 default: 447 return 0; 448 } 449 } 450 451 /* 452 convert src[0, n) to (n * 2) byte hex string and write it to os 453 return true if success else flase 454 */ 455 template<class OutputStream> 456 void writeHexStr(bool *pb, OutputStream& os, const void *src, size_t n) 457 { 458 const uint8_t *p = (const uint8_t *)src; 459 for (size_t i = 0; i < n; i++) { 460 char hex[2]; 461 cybozu::itohex(hex, sizeof(hex), p[i], false); 462 cybozu::write(pb, os, hex, sizeof(hex)); 463 if (!*pb) return; 464 } 465 *pb = true; 466 } 467 /* 468 read hex string from is and convert it to byte array 469 return written buffer size 470 */ 471 template<class InputStream> 472 inline size_t readHexStr(void *buf, size_t n, InputStream& is) 473 { 474 bool b; 475 uint8_t *dst = (uint8_t *)buf; 476 for (size_t i = 0; i < n; i++) { 477 uint8_t L, H; 478 char c[2]; 479 if (cybozu::readSome(c, sizeof(c), is) != sizeof(c)) return i; 480 b = local::hexCharToUint8(&H, c[0]); 481 if (!b) return i; 482 b = local::hexCharToUint8(&L, c[1]); 483 if (!b) return i; 484 dst[i] = (H << 4) | L; 485 } 486 return n; 487 } 488 489 } } // mcl::fp 490 491 #ifdef _MSC_VER 492 #pragma warning(pop) 493 #endif